--- /dev/null
+<?php
+
+namespace wcf\acp\form;
+
+use CuyZ\Valinor\Mapper\MappingError;
+use CuyZ\Valinor\Mapper\Source\Source;
+use CuyZ\Valinor\MapperBuilder;
+use GuzzleHttp\Exception\ConnectException;
+use GuzzleHttp\Psr7\Request;
+use Psr\Http\Client\ClientExceptionInterface;
+use wcf\data\option\Option;
+use wcf\data\option\OptionAction;
+use wcf\data\package\update\server\PackageUpdateServerAction;
+use wcf\data\package\update\server\PackageUpdateServerList;
+use wcf\form\AbstractForm;
+use wcf\form\AbstractFormBuilderForm;
+use wcf\system\exception\PermissionDeniedException;
+use wcf\system\form\builder\container\FormContainer;
+use wcf\system\form\builder\field\CheckboxFormField;
+use wcf\system\form\builder\field\dependency\EmptyFormFieldDependency;
+use wcf\system\form\builder\field\TextFormField;
+use wcf\system\form\builder\field\validation\FormFieldValidationError;
+use wcf\system\form\builder\field\validation\FormFieldValidator;
+use wcf\system\form\builder\LanguageItemFormNode;
+use wcf\system\io\HttpFactory;
+use wcf\system\request\LinkHandler;
+use wcf\util\HeaderUtil;
+
+/**
+ * Sets up license data during first time setup.
+ *
+ * @author Tim Duesterhus
+ * @copyright 2001-2023 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ */
+final class FirstTimeSetupLicenseForm extends AbstractFormBuilderForm
+{
+ /**
+ * @inheritDoc
+ */
+ public $neededPermissions = ['admin.configuration.package.canEditServer'];
+
+ private array $apiResponse;
+
+ /**
+ * @inheritDoc
+ */
+ public function readParameters()
+ {
+ parent::readParameters();
+
+ if (\FIRST_TIME_SETUP_STATE == -1) {
+ throw new PermissionDeniedException();
+ }
+ }
+
+ /**
+ * @inheritDoc
+ */
+ protected function createForm()
+ {
+ parent::createForm();
+
+ $this->form->appendChildren([
+ LanguageItemFormNode::create('explanation')
+ ->languageItem('wcf.acp.firstTimeSetup.license.explanation'),
+ $credentialsContainer = FormContainer::create('credentials')
+ ->label('wcf.acp.firstTimeSetup.license.credentials')
+ ->appendChildren([
+ TextFormField::create('licenseNo')
+ ->label('wcf.acp.package.update.licenseNo')
+ ->required()
+ ->maximumLength(255)
+ ->placeholder('123456'),
+ TextFormField::create('serialNo')
+ ->label('wcf.acp.package.update.serialNo')
+ ->required()
+ ->maximumLength(255)
+ ->placeholder('AB12-34CD-E56F-12AB-7890')
+ ->addValidator(new FormFieldValidator('serialNo', function (TextFormField $serialNo) {
+ $licenseNo = $serialNo->getDocument()->getNodeById('licenseNo');
+ \assert($licenseNo instanceof TextFormField);
+
+ try {
+ $this->apiResponse = $this->getLicenseData($licenseNo->getValue(), $serialNo->getValue());
+ } catch (ConnectException) {
+ $serialNo->addValidationError(new FormFieldValidationError(
+ 'failedConnect',
+ 'wcf.acp.firstTimeSetup.license.credentials.error.failedConnect'
+ ));
+ } catch (ClientExceptionInterface | MappingError) {
+ $serialNo->addValidationError(new FormFieldValidationError(
+ 'failedValidation',
+ 'wcf.acp.firstTimeSetup.license.credentials.error.failedValidation'
+ ));
+ }
+ })),
+ ]),
+ FormContainer::create('noCredentials')
+ ->label('wcf.acp.firstTimeSetup.license.noCredentials')
+ ->appendChildren([
+ CheckboxFormField::create('noCredentialsConfirm')
+ ->label('wcf.acp.firstTimeSetup.license.noCredentialsConfirm')
+ ->description('wcf.acp.firstTimeSetup.license.noCredentialsConfirm.description'),
+ ]),
+ ]);
+
+ $credentialsContainer->addDependency(
+ EmptyFormFieldDependency::create('noCredentialsConfirm')
+ ->fieldId('noCredentialsConfirm')
+ );
+ }
+
+ private function getLicenseData(string $licenseNo, string $serialNo): array
+ {
+ $request = new Request(
+ 'POST',
+ 'https://api.woltlab.com/2.0/customer/license/list.json',
+ [
+ 'content-type' => 'application/x-www-form-urlencoded',
+ ],
+ \http_build_query([
+ 'licenseNo' => $licenseNo,
+ 'serialNo' => $serialNo,
+ 'instanceId' => \hash_hmac('sha256', 'api.woltlab.com', \WCF_UUID),
+ ], '', '&', \PHP_QUERY_RFC1738)
+ );
+
+ $response = HttpFactory::makeClientWithTimeout(5)->send($request);
+ return (new MapperBuilder())
+ ->allowSuperfluousKeys()
+ ->mapper()
+ ->map(
+ <<<'EOT'
+ array {
+ status: 200,
+ license: array {
+ authCode: string,
+ type: string,
+ expiryDates?: array<string, int>,
+ },
+ pluginstore: array<string, string>,
+ woltlab: array<string, string>,
+ }
+ EOT,
+ Source::json($response->getBody())
+ );
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function save()
+ {
+ AbstractForm::save();
+
+ $data = $this->form->getData();
+
+ if (!$data['data']['noCredentialsConfirm']) {
+ $packageServerList = new PackageUpdateServerList();
+ $packageServerList->readObjects();
+
+ foreach ($packageServerList as $packageServer) {
+ if (
+ !$packageServer->isWoltLabUpdateServer()
+ && !$packageServer->isWoltLabStoreServer()
+ ) {
+ continue;
+ }
+
+ $objectAction = new PackageUpdateServerAction(
+ [$packageServer],
+ 'update',
+ [
+ 'data' => [
+ 'loginUsername' => $data['data']['licenseNo'],
+ 'loginPassword' => $data['data']['serialNo'],
+ ],
+ ]
+ );
+ $objectAction->executeAction();
+ }
+ }
+
+ $optionData = [
+ Option::getOptionByName('first_time_setup_state')->optionID => 1,
+ ];
+
+ if (isset($this->apiResponse)) {
+ $optionData[Option::getOptionByName('package_server_auth_code')->optionID] = $this->apiResponse['license']['authCode'];
+ }
+
+ $objectAction = new OptionAction(
+ [],
+ 'updateAll',
+ [
+ 'data' => $optionData,
+ ]
+ );
+ $objectAction->executeAction();
+
+ $this->saved();
+
+ \http_response_code(303);
+ HeaderUtil::redirect(LinkHandler::getInstance()->getControllerLink(
+ FirstTimeSetupAction::class,
+ ));
+
+ exit;
+ }
+}
ACHTUNG: Die oben genannten Meldungen sind stark gekürzt. Sie können Details zu einzelnen Fehlermeldungen in der Administrationsoberfläche unter „Verwaltung » Protokoll » Fehler“ einsehen.
Sie erreichen das Fehlerprotokoll unter: {link controller='ExceptionLogView' isEmail=true isACP=true}{/link}]]></item>
</category>
+ <category name="wcf.acp.firstTimeSetup">
+ <item name="wcf.acp.firstTimeSetup.license"><![CDATA[Erstmalige Einrichtung: Lizenz]]></item>
+ <item name="wcf.acp.firstTimeSetup.license.credentials"><![CDATA[Lizenzdaten]]></item>
+ <item name="wcf.acp.firstTimeSetup.license.credentials.error.failedConnect"><![CDATA[Es konnte keine ausgehende Verbindung zur Überprüfung der Lizenzdaten aufgebaut werden.]]></item>
+ <item name="wcf.acp.firstTimeSetup.license.credentials.error.failedValidation"><![CDATA[Die Gültigkeit der Lizenzdaten konnte nicht bestätigt werden.]]></item>
+ <item name="wcf.acp.firstTimeSetup.license.noCredentials"><![CDATA[Jetzt nicht?]]></item>
+ <item name="wcf.acp.firstTimeSetup.license.noCredentialsConfirm"><![CDATA[Ohne Eingabe der Lizenzdaten fortfahren]]></item>
+ <item name="wcf.acp.firstTimeSetup.license.explanation"><![CDATA[<p>Die Eingabe von Lizenzdaten ist zur Installation und zur Aktualisierung der gekauften WoltLab Suite™-Apps erforderlich.</p>]]></item>
+ <item name="wcf.acp.firstTimeSetup.license.noCredentialsConfirm.description"><![CDATA[Die Eingabe der Lizenzdaten wird empfohlen. Falls noch keine Internetverbindung zu unseren Paket-Servern zur Verfügung steht oder Sie noch keine Lizenzdaten besitzen, können Sie die Eingabe überspringen. Lizenzdaten können jederzeit hinterlegt werden, um die gekauften WoltLab Suite™-Apps zu installieren.]]></item>
+ <item name="wcf.acp.firstTimeSetup.options"><![CDATA[Erstmalige Einrichtung: Einstellungen]]></item>
+ <item name="wcf.acp.firstTimeSetup.options.description"><![CDATA[{if LANGUAGE_USE_INFORMAL_VARIANT}Konfiguriere{else}Konfigurieren Sie{/if} die wichtigsten Einstellungen, diese können auch später über die Optionen verändert werden.]]></item>
+ <item name="wcf.acp.firstTimeSetup.completed"><![CDATA[Erstmalige Einrichtung abgeschlossen]]></item>
+ </category>
<category name="wcf.acp.group">
<item name="wcf.acp.group.add"><![CDATA[Benutzergruppe hinzufügen]]></item>
<item name="wcf.acp.group.edit"><![CDATA[Benutzergruppe bearbeiten]]></item>
<item name="wcf.acp.option.contact_form_enable_attachments"><![CDATA[Dateianhänge im Kontaktformular aktivieren]]></item>
<item name="wcf.acp.option.contact_form_prune_attachments"><![CDATA[Dateianhänge automatisch entfernen]]></item>
<item name="wcf.acp.option.contact_form_prune_attachments.description"><![CDATA[Alte Dateianhänge werden nach Ablauf der Frist automatisch gelöscht. [0, um die Löschung zu deaktivieren]]]></item>
- <item name="wcf.acp.option.firstTimeSetup"><![CDATA[Erstmalige Einrichtung]]></item>
- <item name="wcf.acp.option.firstTimeSetup.description"><![CDATA[{if LANGUAGE_USE_INFORMAL_VARIANT}Konfiguriere{else}Konfigurieren Sie{/if} die wichtigsten Einstellungen, diese können auch später über die Optionen verändert werden.]]></item>
<item name="wcf.acp.option.category.security.blacklist.sfs"><![CDATA[Stop Forum Spam]]></item>
<item name="wcf.acp.option.category.security.blacklist.sfs.description"><![CDATA[Datenschutzkonforme Überprüfung auf Basis einer lokalen Kopie der StopForumSpam.com-Datenbestände.]]></item>
<item name="wcf.acp.option.category.security.blacklist.custom"><![CDATA[Eigene Sperrlisten]]></item>
ATTENTION: The messages listed above are greatly shortened. You can view details of individual error messages in the admin panel under “Management » Logs » Errors”.
You can access the error log at: {link controller='ExceptionLogView' isEmail=true isACP=true}{/link}]]></item>
</category>
+ <category name="wcf.acp.firstTimeSetup">
+ <item name="wcf.acp.firstTimeSetup.license"><![CDATA[First Time Setup: License]]></item>
+ <item name="wcf.acp.firstTimeSetup.license.credentials"><![CDATA[License Data]]></item>
+ <item name="wcf.acp.firstTimeSetup.license.credentials.error.failedConnect"><![CDATA[Failed to establish a connection to confirm the license data.]]></item>
+ <item name="wcf.acp.firstTimeSetup.license.credentials.error.failedValidation"><![CDATA[The license data could not be confirmed as valid.]]></item>
+ <item name="wcf.acp.firstTimeSetup.license.noCredentials"><![CDATA[Not now?]]></item>
+ <item name="wcf.acp.firstTimeSetup.license.noCredentialsConfirm"><![CDATA[Continue without entering license information]]></item>
+ <item name="wcf.acp.firstTimeSetup.license.explanation"><![CDATA[<p>Entering license credentials is required to install and update the purchased WoltLab Suite™ Apps.</p>]]></item>
+ <item name="wcf.acp.firstTimeSetup.license.noCredentialsConfirm.description"><![CDATA[Entering license information is recommended. If no network connection to our package servers is available yet, or if you do not yet have license information, you can skip this step. License information can be entered at any time to install purchased WoltLab Suite™ Apps.]]></item>
+ <item name="wcf.acp.firstTimeSetup.options"><![CDATA[First Time Setup: Settings]]></item>
+ <item name="wcf.acp.firstTimeSetup.options.description"><![CDATA[Configure the most important settings now, you can change them later at any time.]]></item>
+ <item name="wcf.acp.firstTimeSetup.completed"><![CDATA[First Time Setup Completed]]></item>
+ </category>
<category name="wcf.acp.group">
<item name="wcf.acp.group.add"><![CDATA[Add User Group]]></item>
<item name="wcf.acp.group.edit"><![CDATA[Edit User Group]]></item>
<item name="wcf.acp.option.contact_form_enable_attachments"><![CDATA[Enable attachments for contact messages]]></item>
<item name="wcf.acp.option.contact_form_prune_attachments"><![CDATA[Prune old attachments]]></item>
<item name="wcf.acp.option.contact_form_prune_attachments.description"><![CDATA[Older attachments are automatically removed to recover disk space. Use 0 to disable.]]></item>
- <item name="wcf.acp.option.firstTimeSetup"><![CDATA[First Time Setup]]></item>
- <item name="wcf.acp.option.firstTimeSetup.description"><![CDATA[Configure the most important settings now, you can change them later at any time.]]></item>
<item name="wcf.acp.option.category.security.blacklist.sfs"><![CDATA[Stop Forum Spam]]></item>
<item name="wcf.acp.option.category.security.blacklist.sfs.description"><![CDATA[Privacy compliant verification based on a local copy of the StopForumSpam.com database.]]></item>
<item name="wcf.acp.option.category.security.blacklist.custom"><![CDATA[Own Blacklists]]></item>