}
});
-/**
- * Namespace for classes related to the WoltLab Plugin-Store.
- */
-WCF.ACP.PluginStore = { };
-
-/**
- * Namespace for classes handling items purchased in the WoltLab Plugin-Store.
- */
-WCF.ACP.PluginStore.PurchasedItems = { };
-
-/**
- * Searches for purchased items available for install but not yet installed.
- */
-WCF.ACP.PluginStore.PurchasedItems.Search = Class.extend({
- /**
- * dialog overlay
- * @var jQuery
- */
- _dialog: null,
-
- /**
- * action proxy
- * @var WCF.Action.Proxy
- */
- _proxy: null,
-
- /**
- * Initializes the WCF.ACP.PluginStore.PurchasedItems.Search class.
- */
- init: function() {
- this._dialog = null;
- this._proxy = new WCF.Action.Proxy({
- success: $.proxy(this._success, this)
- });
-
- var $button = $(`<li>
- <button type="button" class="button">
- <fa-icon size="16" name="cart-shopping"></fa-icon>
- <span>${WCF.Language.get('wcf.acp.pluginStore.purchasedItems.button.search')}</span>
- </button>
- </li>`);
- $button.prependTo($('.contentHeaderNavigation > ul')).click($.proxy(this._click, this));
- },
-
- /**
- * Handles clicks on the search button.
- */
- _click: function() {
- this._proxy.setOption('data', {
- actionName: 'searchForPurchasedItems',
- className: 'wcf\\data\\package\\PackageAction'
- });
- this._proxy.sendRequest();
- },
-
- /**
- * Handles successful AJAX requests.
- *
- * @param object data
- * @param string textStatus
- * @param jQuery jqXHR
- */
- _success: function(data, textStatus, jqXHR) {
- // prompt for credentials
- if (data.returnValues.template) {
- if (this._dialog === null) {
- this._dialog = $('<div />').hide().appendTo(document.body);
- this._dialog.html(data.returnValues.template).wcfDialog({
- title: WCF.Language.get('wcf.acp.pluginStore.authorization')
- });
- }
- else {
- this._dialog.html(data.returnValues.template);
- this._dialog.wcfDialog('open');
- }
-
- var $button = this._dialog.find('button').click($.proxy(this._submit, this));
- this._dialog.find('input').keyup(function(event) {
- if (event.which == $.ui.keyCode.ENTER) {
- $button.trigger('click');
- return false;
- }
- });
- }
- else if (data.returnValues.noResults) {
- // there are no purchased products yet
- if (this._dialog === null) {
- this._dialog = $('<div />').hide().appendTo(document.body);
- this._dialog.html(data.returnValues.noResults).wcfDialog({
- title: WCF.Language.get('wcf.acp.pluginStore.purchasedItems')
- });
- } else {
- this._dialog.wcfDialog('option', 'title', WCF.Language.get('wcf.acp.pluginStore.purchasedItems'));
- this._dialog.html(data.returnValues.noResults);
- this._dialog.wcfDialog('open');
- }
- }
- else if (data.returnValues.noSSL) {
- // PHP was compiled w/o OpenSSL support
- if (this._dialog === null) {
- this._dialog = $('<div />').hide().appendTo(document.body);
- this._dialog.html(data.returnValues.noSSL).wcfDialog({
- title: WCF.Language.get('wcf.global.error.title')
- });
- }
- else {
- this._dialog.wcfDialog('option', 'title', WCF.Language.get('wcf.global.error.title'));
- this._dialog.html(data.returnValues.noSSL);
- this._dialog.wcfDialog('open');
- }
- }
- else if (data.returnValues.redirectURL) {
- // redirect to list of purchased products
- window.location = data.returnValues.redirectURL;
- }
- },
-
- /**
- * Submits the user credentials.
- */
- _submit: function() {
- this._dialog.wcfDialog('close');
-
- this._proxy.setOption('data', {
- actionName: 'searchForPurchasedItems',
- className: 'wcf\\data\\package\\PackageAction',
- parameters: {
- password: $('#pluginStorePassword').val(),
- username: $('#pluginStoreUsername').val()
- }
- });
- this._proxy.sendRequest();
- }
-});
-
/**
* Worker support for ACP.
*
'wcf.acp.package.searchForUpdates': '{jslang}wcf.acp.package.searchForUpdates{/jslang}',
'wcf.acp.package.searchForUpdates.noResults': '{jslang}wcf.acp.package.searchForUpdates.noResults{/jslang}',
'wcf.acp.package.uninstallation.title': '{jslang}wcf.acp.package.uninstallation.title{/jslang}',
- 'wcf.acp.pluginStore.authorization': '{jslang}wcf.acp.pluginStore.authorization{/jslang}',
- 'wcf.acp.pluginStore.purchasedItems': '{jslang}wcf.acp.pluginStore.purchasedItems{/jslang}',
- 'wcf.acp.pluginStore.purchasedItems.button.search': '{jslang}wcf.acp.pluginStore.purchasedItems.button.search{/jslang}',
- 'wcf.acp.pluginStore.purchasedItems.noResults': '{jslang}wcf.acp.pluginStore.purchasedItems.noResults{/jslang}'
});
{if $__wcf->session->getPermission('admin.configuration.package.canUninstallPackage')}
{if $__wcf->session->getPermission('admin.configuration.package.canUpdatePackage')}
new WCF.ACP.Package.Update.Search(true);
{/if}
-
- {if $__wcf->session->getPermission('admin.configuration.package.canInstallPackage') && $__wcf->session->getPermission('admin.configuration.package.canUpdatePackage')}
- new WCF.ACP.PluginStore.PurchasedItems.Search();
- {/if}
});
</script>
+++ /dev/null
-{if $rejected}
- <p class="error">{lang}wcf.acp.pluginStore.authorization.credentials.rejected{/lang}</p>
-{/if}
-
-<section class="section">
- <header class="sectionHeader">
- <h2 class="sectionTitle">{lang}wcf.acp.pluginStore.authorization.credentials{/lang}</h2>
- <p class="sectionDescription">{lang}wcf.acp.pluginStore.authorization.credentials.description{/lang}</p>
- </header>
-
- <dl>
- <dt><label for="pluginStoreUsername">{lang}wcf.acp.pluginStore.authorization.username{/lang}</label></dt>
- <dd><input type="text" id="pluginStoreUsername" value="" class="long"></dd>
- </dl>
-
- <dl>
- <dt><label for="pluginStorePassword">{lang}wcf.acp.pluginStore.authorization.password{/lang}</label></dt>
- <dd><input type="password" id="pluginStorePassword" value="" class="long" autocomplete="off"></dd>
- </dl>
-</section>
-
-<div class="formSubmit">
- <button type="button" class="button buttonPrimary">{lang}wcf.global.button.submit{/lang}</button>
-</div>
\ No newline at end of file
+++ /dev/null
-{include file='header' pageTitle='wcf.acp.pluginStore.purchasedItems'}
-
-<script data-relocate="true">
- $(function() {
- WCF.Language.addObject({
- 'wcf.acp.package.install.title': '{jslang}wcf.acp.package.install.title{/jslang}',
- 'wcf.acp.package.searchForUpdates': '{jslang}wcf.acp.package.searchForUpdates{/jslang}',
- 'wcf.acp.package.searchForUpdates.noResults': '{jslang}wcf.acp.package.searchForUpdates.noResults{/jslang}',
- 'wcf.acp.package.update.unauthorized': '{jslang}wcf.acp.package.update.unauthorized{/jslang}'
- });
-
- var $installer = new WCF.ACP.Package.Server.Installation();
- $installer.bind();
-
- new WCF.ACP.Package.Update.Search(true);
- });
-</script>
-
-<header class="contentHeader">
- <h1 class="contentTitle">{lang}wcf.acp.pluginStore.purchasedItems{/lang}</h1>
-</header>
-
-{if !$fetchedPackageServers}
- <p class="warning">{lang}wcf.acp.pluginStore.purchasedItems.updateServer.requireUpdate{/lang}</p>
-{/if}
-
-<section class="section tabularBox">
- <table class="table">
- <thead>
- <tr>
- <th class="columnText" colspan="2">{lang}wcf.acp.package.name{/lang}</th>
- <th class="columnText">{lang}wcf.acp.package.author{/lang}</th>
- <th class="columnText">{lang}wcf.acp.package.version{/lang}</th>
- <th class="columnText">{lang}wcf.acp.package.installedVersion{/lang}</th>
- </tr>
- </thead>
-
- <tbody>
- {foreach from=$productData item=product}
- <tr>
- <td class="columnIcon">
- {if $product[status] == 'install'}
- <button type="button" class="jsButtonPackageInstall jsTooltip" title="{lang}wcf.acp.package.button.installPackage{/lang}" data-confirm-message="{lang __encode=true}wcf.acp.pluginStore.purchasedItems.status.install.confirmMessage{/lang}" data-package="{$product[package]}" data-package-version="{$product[version][available]}">
- {icon name='plus'}
- </button>
- {elseif $product[status] == 'update'}
- <button type="button" class="jsButtonPackageUpdate jsTooltip" title="{lang}wcf.acp.pluginStore.purchasedItems.status.update{/lang}">
- {icon name='arrows-rotate'}
- </button>
- {elseif $product[status] == 'upToDate'}
- <span class="jsTooltip" title="{lang}wcf.acp.pluginStore.purchasedItems.status.upToDate{/lang}">
- {icon name='check'}
- </span>
- {elseif $product[status] == 'requireUpdate'}
- <span class="jsTooltip" title="{lang}wcf.acp.pluginStore.purchasedItems.status.requireUpdate{/lang}">
- {icon name='ban'}
- </span>
- {else}
- <span class="jsTooltip" title="{lang}wcf.acp.pluginStore.purchasedItems.status.unavailable{/lang}">
- {icon name='ban'}
- </span>
- {/if}
- </td>
- <td class="columnText"><a href="{$product[pluginStoreURL]}" class="externalURL">{$product[packageName]}</a></td>
- <td class="columnText">{if $product[authorURL]}<a href="{$product[authorURL]}" class="externalURL">{$product[author]}</a>{else}{$product[author]}{/if}</td>
- <td class="columnText">{$product[version][available]}</td>
- <td class="columnText">{if $product[version][installed]}{$product[version][installed]}{else}-{/if}</td>
- </tr>
- {/foreach}
- </tbody>
- </table>
-</section>
-
-{include file='footer'}
+++ /dev/null
-<?php
-
-namespace wcf\acp\page;
-
-use wcf\data\package\Package;
-use wcf\data\package\PackageCache;
-use wcf\data\package\update\server\PackageUpdateServer;
-use wcf\page\AbstractPage;
-use wcf\system\exception\IllegalLinkException;
-use wcf\system\WCF;
-
-/**
- * Shows a list of purchased plugin store items.
- *
- * @author Alexander Ebert
- * @copyright 2001-2019 WoltLab GmbH
- * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
- */
-class PluginStorePurchasedItemsPage extends AbstractPage
-{
- /**
- * @inheritDoc
- */
- public $activeMenuItem = 'wcf.acp.menu.link.package.list';
-
- /**
- * @inheritDoc
- */
- public $neededPermissions = [
- 'admin.configuration.package.canUpdatePackage',
- 'admin.configuration.package.canUninstallPackage',
- ];
-
- public $fetchedPackageServers = false;
-
- /**
- * list of purchased products grouped by WCF major release
- * @var array<array>
- */
- public $products = [];
-
- /**
- * list of product data grouped by WCF major release
- * @var array<array>
- */
- public $productData = [];
-
- /**
- * list of installed update servers (Plugin-Store only)
- * @var PackageUpdateServer[]
- */
- public $updateServers = [];
-
- /**
- * list of supported WCF major releases (Plugin-Store)
- * @var string[]
- */
- public $wcfMajorReleases = [];
-
- /**
- * @inheritDoc
- */
- public function readParameters()
- {
- parent::readParameters();
-
- $this->products = WCF::getSession()->getVar('__pluginStoreProducts');
- if (empty($this->products)) {
- throw new IllegalLinkException();
- }
-
- $this->wcfMajorReleases = WCF::getSession()->getVar('__pluginStoreWcfMajorReleases');
- if (empty($this->wcfMajorReleases)) {
- throw new IllegalLinkException();
- }
- }
-
- /**
- * @inheritDoc
- */
- public function readData()
- {
- parent::readData();
-
- foreach (PackageUpdateServer::getActiveUpdateServers() as $packageUpdateServer) {
- if ($packageUpdateServer->isWoltLabUpdateServer() || $packageUpdateServer->isWoltLabStoreServer()) {
- $this->fetchedPackageServers = $packageUpdateServer->lastUpdateTime > 0;
- break;
- }
- }
-
- foreach ($this->products as $packageUpdateID => $product) {
- $languageCode = WCF::getLanguage()->languageCode;
- $packageName = $product['packageName'][$languageCode] ?? $product['packageName']['en'];
-
- $this->productData[$packageUpdateID] = [
- 'author' => $product['author'],
- 'authorURL' => $product['authorURL'],
- 'package' => $product['package'],
- 'packageName' => $packageName,
- 'pluginStoreURL' => $product['pluginStoreURL'],
- 'version' => [
- 'available' => $product['lastVersion'],
- 'installed' => '',
- ],
- 'status' => 'install',
- ];
-
- $package = PackageCache::getInstance()->getPackageByIdentifier($product['package']);
- if ($package !== null) {
- $this->productData[$packageUpdateID]['version']['installed'] = $package->packageVersion;
-
- if (Package::compareVersion($product['lastVersion'], $package->packageVersion, '>')) {
- $this->productData[$packageUpdateID]['status'] = 'update';
- } elseif (Package::compareVersion($product['lastVersion'], $package->packageVersion, '<=')) {
- $this->productData[$packageUpdateID]['status'] = 'upToDate';
- }
- }
-
- if (!$this->fetchedPackageServers) {
- $this->productData[$packageUpdateID]['status'] = 'requireUpdate';
- }
- }
-
- \uasort($this->productData, static function (array $a, array $b) {
- return \strcasecmp($a['packageName'], $b['packageName']);
- });
- }
-
- /**
- * @inheritDoc
- */
- public function assignVariables()
- {
- parent::assignVariables();
-
- WCF::getTPL()->assign([
- 'fetchedPackageServers' => $this->fetchedPackageServers,
- 'productData' => $this->productData,
- ]);
- }
-}
namespace wcf\data\package;
-use GuzzleHttp\Psr7\Request;
use wcf\data\AbstractDatabaseObjectAction;
-use wcf\system\database\util\PreparedStatementConditionBuilder;
-use wcf\system\exception\SystemException;
-use wcf\system\io\HttpFactory;
-use wcf\system\request\LinkHandler;
-use wcf\system\WCF;
-use wcf\util\JSON;
/**
* Executes package-related actions.
* @inheritDoc
*/
protected $permissionsUpdate = ['admin.configuration.package.canUpdatePackage'];
-
- /**
- * @inheritDoc
- */
- protected $requireACP = ['searchForPurchasedItems'];
-
- /**
- * Validates parameters to search for purchased items in the WoltLab Plugin-Store.
- */
- public function validateSearchForPurchasedItems()
- {
- WCF::getSession()->checkPermissions([
- 'admin.configuration.package.canInstallPackage',
- 'admin.configuration.package.canUpdatePackage',
- ]);
-
- $this->readString('password', true);
- $this->readString('username', true);
-
- if (empty($this->parameters['username'])) {
- $conditions = new PreparedStatementConditionBuilder();
- $conditions->add("serverURL REGEXP ?", ['^https?://update\.woltlab\.com/']);
- $conditions->add("loginUsername <> ''");
- $conditions->add("loginPassword <> ''");
-
- // check if user has already provided credentials
- $sql = "SELECT loginUsername, loginPassword
- FROM wcf" . WCF_N . "_package_update_server
- " . $conditions;
- $statement = WCF::getDB()->prepareStatement($sql, 1);
- $statement->execute($conditions->getParameters());
- $row = $statement->fetchArray();
- if (!empty($row['loginUsername']) && !empty($row['loginPassword'])) {
- $this->parameters['password'] = $row['loginPassword'];
- $this->parameters['username'] = $row['loginUsername'];
- }
- }
- }
-
- /**
- * Searches for purchased items in the WoltLab Plugin-Store.
- *
- * @return string[]
- * @throws SystemException
- */
- public function searchForPurchasedItems()
- {
- if (empty($this->parameters['username']) || empty($this->parameters['password'])) {
- return [
- 'template' => $this->renderAuthorizationDialog(false),
- ];
- }
-
- $client = HttpFactory::makeClientWithTimeout(5);
- $request = new Request(
- 'POST',
- 'https://api.woltlab.com/1.1/customer/purchases/list.json',
- [
- 'content-type' => 'application/x-www-form-urlencoded',
- ],
- \http_build_query(
- [
- 'username' => $this->parameters['username'],
- 'password' => $this->parameters['password'],
- 'wcfVersion' => WCF_VERSION,
- ],
- '',
- '&',
- \PHP_QUERY_RFC1738
- )
- );
-
- $response = $client->send($request);
- $payload = JSON::decode((string)$response->getBody());
-
- $code = $payload['status'] ?? 500;
- switch ($code) {
- case 200:
- if (empty($payload['products'])) {
- return [
- 'noResults' => WCF::getLanguage()->getDynamicVariable('wcf.acp.pluginStore.purchasedItems.noResults'),
- ];
- } else {
- WCF::getSession()->register('__pluginStoreProducts', $payload['products']);
- WCF::getSession()->register('__pluginStoreWcfMajorReleases', $payload['wcfMajorReleases']);
-
- return [
- 'redirectURL' => LinkHandler::getInstance()->getLink('PluginStorePurchasedItems'),
- ];
- }
- break;
-
- case 401: // authentication error
- return [
- 'template' => $this->renderAuthorizationDialog(true),
- ];
- break;
-
- default: // any other kind of errors
- throw new SystemException(WCF::getLanguage()->getDynamicVariable(
- 'wcf.acp.pluginStore.api.error',
- ['status' => $code]
- ));
- break;
- }
- }
-
- /**
- * Renders the authentication dialog.
- *
- * @param bool $rejected
- * @return string
- */
- protected function renderAuthorizationDialog($rejected)
- {
- WCF::getTPL()->assign([
- 'rejected' => $rejected,
- ]);
-
- return WCF::getTPL()->fetch('pluginStoreAuthorization');
- }
}
<item name="wcf.acp.paidSubscription.user.edit"><![CDATA[Aktive Mitgliedschaft bearbeiten]]></item>
<item name="wcf.acp.paidSubscription.error.noPaymentMethods"><![CDATA[Es muss mindestens ein Zahlungsanbieter in den Optionen unter „Zahlungsoptionen“ ausgewählt sein, um bezahlte Mitgliedschaften erstellen zu können.]]></item>
</category>
- <category name="wcf.acp.pluginStore">
- <item name="wcf.acp.pluginStore.api.error"><![CDATA[Fehler {@$status}: Der Server konnte die Anfrage nicht erfolgreich bearbeiten.]]></item>
- <item name="wcf.acp.pluginStore.authorization"><![CDATA[Autorisierung erforderlich]]></item>
- <item name="wcf.acp.pluginStore.authorization.credentials"><![CDATA[Zugangsdaten]]></item>
- <item name="wcf.acp.pluginStore.authorization.credentials.description"><![CDATA[Bitte {if LANGUAGE_USE_INFORMAL_VARIANT}gib{else}geben Sie{/if} Lizenz- und Seriennummer einer {if LANGUAGE_USE_INFORMAL_VARIANT}deiner{else}Ihrer{/if} Lizenzen auf WoltLab.com ein.]]></item>
- <item name="wcf.acp.pluginStore.authorization.credentials.rejected"><![CDATA[{if LANGUAGE_USE_INFORMAL_VARIANT}Deine{else}Ihre{/if} Zugangsdaten wurden vom Server abgewiesen, bitte {if LANGUAGE_USE_INFORMAL_VARIANT}überprüfe{else}überprüfen Sie{/if} Benutzername und Kennwort!]]></item>
- <item name="wcf.acp.pluginStore.authorization.username"><![CDATA[Lizenznummer]]></item>
- <item name="wcf.acp.pluginStore.authorization.password"><![CDATA[Seriennummer]]></item>
- <item name="wcf.acp.pluginStore.authorization.saveCredentials"><![CDATA[Zugangsdaten für aktuelle Sitzung speichern]]></item>
- <item name="wcf.acp.pluginStore.file"><![CDATA[WoltLab® Plugin-Store]]></item>
- <item name="wcf.acp.pluginStore.file.link"><![CDATA[Eintrag im Plugin-Store anzeigen]]></item>
- <item name="wcf.acp.pluginStore.purchasedItems.button.search"><![CDATA[Erworbene Produkte (Plugin-Store)]]></item>
- <item name="wcf.acp.pluginStore.purchasedItems"><![CDATA[Erworbene Produkte (Plugin-Store)]]></item>
- <item name="wcf.acp.pluginStore.purchasedItems.noResults"><![CDATA[Die Suche ergab keine Treffer, entweder {if LANGUAGE_USE_INFORMAL_VARIANT}hast du{else}haben Sie{/if} noch keine Produkte erworben oder diese sind nicht kompatibel.]]></item>
- <item name="wcf.acp.pluginStore.purchasedItems.status.requireUpdate"><![CDATA[Paket-Server muss abgefragt werden]]></item>
- <item name="wcf.acp.pluginStore.purchasedItems.status.update"><![CDATA[Neuere Version verfügbar]]></item>
- <item name="wcf.acp.pluginStore.purchasedItems.status.unavailable"><![CDATA[Paket-Server nicht installiert]]></item>
- <item name="wcf.acp.pluginStore.purchasedItems.status.upToDate"><![CDATA[Aktuelle Version bereits installiert]]></item>
- <item name="wcf.acp.pluginStore.purchasedItems.status.install.confirmMessage"><![CDATA[{if LANGUAGE_USE_INFORMAL_VARIANT}Willst du{else}Wollen Sie{/if} das Produkt <span class="confirmationObject">{$product[packageName]}</span> wirklich installieren?]]></item>
- <item name="wcf.acp.pluginStore.purchasedItems.updateServer.requireUpdate"><![CDATA[Die Paket-Server wurden noch nicht vollständig abgefragt, bitte {if LANGUAGE_USE_INFORMAL_VARIANT}lass{else}lassen Sie{/if} zuerst nach Updates suchen.]]></item>
- <item name="wcf.acp.pluginStore.purchasedItems.wcfMajorRelease"><![CDATA[Paket-Server für „{$wcfMajorRelease}“]]></item>
- </category>
<category name="wcf.acp.pip">
<item name="wcf.acp.pip.objectType.com.woltlab.wcf.attachment.objectType.data.title"><![CDATA[Daten des Dateianhangtyps]]></item>
<item name="wcf.acp.pip.objectType.com.woltlab.wcf.attachment.objectType.private.description"><![CDATA[Private Dateianhänge werden in der Dateianhangsverwaltung im ACP ignoriert.]]></item>
<item name="wcf.acp.paidSubscription.user.edit"><![CDATA[Edit Active Subscription]]></item>
<item name="wcf.acp.paidSubscription.error.noPaymentMethods"><![CDATA[Adding subscriptions requires at least one active payment provider for the “Supported Payment Methods” option.]]></item>
</category>
- <category name="wcf.acp.pluginStore">
- <item name="wcf.acp.pluginStore.api.error"><![CDATA[Error {@$status}: The server was unable to process your request.]]></item>
- <item name="wcf.acp.pluginStore.authorization"><![CDATA[Authorization Required]]></item>
- <item name="wcf.acp.pluginStore.authorization.credentials"><![CDATA[Credentials]]></item>
- <item name="wcf.acp.pluginStore.authorization.credentials.description"><![CDATA[Please enter the license and serial number of one of your licenses on WoltLab.com.]]></item>
- <item name="wcf.acp.pluginStore.authorization.credentials.rejected"><![CDATA[Your provided credentials are invalid, please check your username and password!]]></item>
- <item name="wcf.acp.pluginStore.authorization.username"><![CDATA[License Number]]></item>
- <item name="wcf.acp.pluginStore.authorization.password"><![CDATA[Serial Number]]></item>
- <item name="wcf.acp.pluginStore.authorization.saveCredentials"><![CDATA[Save credentials for this session only]]></item>
- <item name="wcf.acp.pluginStore.file"><![CDATA[WoltLab® Plugin-Store]]></item>
- <item name="wcf.acp.pluginStore.file.link"><![CDATA[Show listing in the Plugin-Store]]></item>
- <item name="wcf.acp.pluginStore.purchasedItems.button.search"><![CDATA[Purchased Products (Plugin-Store)]]></item>
- <item name="wcf.acp.pluginStore.purchasedItems"><![CDATA[Purchased Products (Plugin-Store)]]></item>
- <item name="wcf.acp.pluginStore.purchasedItems.noResults"><![CDATA[The search returned no results, because either you have not purchased any products yet, or your purchases are not compatible with this version.]]></item>
- <item name="wcf.acp.pluginStore.purchasedItems.status.update"><![CDATA[Newer Version Available]]></item>
- <item name="wcf.acp.pluginStore.purchasedItems.status.unavailable"><![CDATA[Package server not installed]]></item>
- <item name="wcf.acp.pluginStore.purchasedItems.status.upToDate"><![CDATA[You already have the most recent version installed]]></item>
- <item name="wcf.acp.pluginStore.purchasedItems.status.requireUpdate"><![CDATA[Package server must be updated]]></item>
- <item name="wcf.acp.pluginStore.purchasedItems.status.install.confirmMessage"><![CDATA[Do you really want to install the product <span class="confirmationObject">{$product[packageName]}</span>?]]></item>
- <item name="wcf.acp.pluginStore.purchasedItems.updateServer.requireUpdate"><![CDATA[The package servers have not been fetched yet, please search for available updates first.]]></item>
- <item name="wcf.acp.pluginStore.purchasedItems.wcfMajorRelease"><![CDATA[Package server for “{$wcfMajorRelease}”]]></item>
- </category>
<category name="wcf.acp.pip">
<item name="wcf.acp.pip.objectType.com.woltlab.wcf.adLocation.data.title"><![CDATA[Ad Location Data]]></item>
<item name="wcf.acp.pip.objectType.com.woltlab.wcf.adLocation.categoryName"><![CDATA[Category]]></item>