diff --git a/Build/Sources/TypeScript/install/installer.ts b/Build/Sources/TypeScript/install/installer.ts index 6e72da364713fe939592c944a88ed61527cfafe1..949b5ac2af700f8e9aa3e3a78d7d3807232756aa 100644 --- a/Build/Sources/TypeScript/install/installer.ts +++ b/Build/Sources/TypeScript/install/installer.ts @@ -224,7 +224,7 @@ class Installer { .then(async (response: AjaxResponse): Promise<void> => { const data = await response.resolve(); if (data.success === true) { - this.executeSilentConfigurationUpdate(); + this.checkDatabaseConnect(); } else { this.executeAdjustTrustedHostsPattern(); } @@ -235,33 +235,7 @@ class Installer { (new AjaxRequest(this.getUrl('executeAdjustTrustedHostsPattern'))) .get({ cache: 'no-cache' }) .then((): void => { - this.executeSilentConfigurationUpdate(); - }); - } - - private executeSilentConfigurationUpdate(): void { - (new AjaxRequest(this.getUrl('executeSilentConfigurationUpdate'))) - .get({ cache: 'no-cache' }) - .then(async (response: AjaxResponse): Promise<void> => { - const data = await response.resolve(); - if (data.success === true) { - this.executeSilentTemplateFileUpdate(); - } else { - this.executeSilentConfigurationUpdate(); - } - }); - } - - private executeSilentTemplateFileUpdate(): void { - (new AjaxRequest(this.getUrl('executeSilentTemplateFileUpdate'))) - .get({ cache: 'no-cache' }) - .then(async (response: AjaxResponse): Promise<void> => { - const data = await response.resolve(); - if (data.success === true) { - this.checkDatabaseConnect(); - } else { - this.executeSilentTemplateFileUpdate(); - } + this.checkDatabaseConnect(); }); } diff --git a/typo3/sysext/install/Classes/Command/SetupCommand.php b/typo3/sysext/install/Classes/Command/SetupCommand.php index 9874d17eb4ed48c525e2e917dc20156f9d3c847e..b62151c750b5706ff6644253989874caf74fa987 100644 --- a/typo3/sysext/install/Classes/Command/SetupCommand.php +++ b/typo3/sysext/install/Classes/Command/SetupCommand.php @@ -29,11 +29,9 @@ use Symfony\Component\Console\Question\ConfirmationQuestion; use Symfony\Component\Console\Question\Question; use TYPO3\CMS\Core\Configuration\ConfigurationManager; use TYPO3\CMS\Core\Database\ConnectionPool; -use TYPO3\CMS\Core\Package\FailsafePackageManager; -use TYPO3\CMS\Core\Resource\Exception\ExistingTargetFileNameException; use TYPO3\CMS\Core\Type\ContextualFeedbackSeverity; use TYPO3\CMS\Core\Utility\GeneralUtility; -use TYPO3\CMS\Install\FolderStructure\DefaultFactory; +use TYPO3\CMS\Install\Service\Exception\ConfigurationFileAlreadyExistsException; use TYPO3\CMS\Install\Service\LateBootService; use TYPO3\CMS\Install\Service\SetupDatabaseService; use TYPO3\CMS\Install\Service\SetupService; @@ -59,7 +57,6 @@ class SetupCommand extends Command private readonly SetupService $setupService, private readonly ConfigurationManager $configurationManager, private readonly LateBootService $lateBootService, - private readonly FailsafePackageManager $packageManager, ) { parent::__construct($name); } @@ -209,16 +206,12 @@ EOT $questionHelper = $this->getHelper('question'); // Ensure all required files and folders exist - $serverType = $this->getServerType($questionHelper, $input, $output); - $folderStructureFactory = GeneralUtility::makeInstance(DefaultFactory::class); - $folderStructureFactory->getStructure($serverType)->fix(); - // Ensure existing PackageStates.php for non-composer installation. - $this->packageManager->recreatePackageStatesFileIfMissing(true); + $this->setupService->createDirectoryStructure($this->getServerType($questionHelper, $input, $output)); try { $force = $input->getOption('force'); $this->setupService->prepareSystemSettings($force); - } catch (ExistingTargetFileNameException $exception) { + } catch (ConfigurationFileAlreadyExistsException) { $configOverwriteQuestion = new ConfirmationQuestion( 'Configuration already exists do you want to overwrite it [default: no] ? ', false diff --git a/typo3/sysext/install/Classes/Controller/InstallerController.php b/typo3/sysext/install/Classes/Controller/InstallerController.php index e0e81557cb62564e6856492399615e326796f99f..2a313db9140bf1c27985d9b714507ae0cd6ebdce 100644 --- a/typo3/sysext/install/Classes/Controller/InstallerController.php +++ b/typo3/sysext/install/Classes/Controller/InstallerController.php @@ -23,8 +23,6 @@ use Psr\Http\Message\ServerRequestInterface; use TYPO3\CMS\Backend\Routing\RouteRedirect; use TYPO3\CMS\Backend\Routing\UriBuilder; use TYPO3\CMS\Core\Configuration\ConfigurationManager; -use TYPO3\CMS\Core\Configuration\Exception\SettingsWriteException; -use TYPO3\CMS\Core\Configuration\ExtensionConfiguration; use TYPO3\CMS\Core\Core\Environment; use TYPO3\CMS\Core\Crypto\HashService; use TYPO3\CMS\Core\Database\ConnectionPool; @@ -45,17 +43,12 @@ use TYPO3\CMS\Core\Utility\GeneralUtility; use TYPO3\CMS\Core\View\FluidViewAdapter; use TYPO3\CMS\Core\View\ViewInterface; use TYPO3\CMS\Fluid\Core\Rendering\RenderingContextFactory; -use TYPO3\CMS\Install\Configuration\FeatureManager; use TYPO3\CMS\Install\FolderStructure\DefaultFactory; use TYPO3\CMS\Install\Service\EnableFileService; -use TYPO3\CMS\Install\Service\Exception\ConfigurationChangedException; -use TYPO3\CMS\Install\Service\Exception\SilentConfigurationUpgradeReadonlyException; -use TYPO3\CMS\Install\Service\Exception\TemplateFileChangedException; +use TYPO3\CMS\Install\Service\Exception\ConfigurationDirectoryDoesNotExistException; use TYPO3\CMS\Install\Service\LateBootService; use TYPO3\CMS\Install\Service\SetupDatabaseService; use TYPO3\CMS\Install\Service\SetupService; -use TYPO3\CMS\Install\Service\SilentConfigurationUpgradeService; -use TYPO3\CMS\Install\Service\SilentTemplateFileUpgradeService; use TYPO3\CMS\Install\SystemEnvironment\Check; use TYPO3\CMS\Install\SystemEnvironment\SetupCheck; use TYPO3\CMS\Install\WebserverType; @@ -73,8 +66,6 @@ final class InstallerController public function __construct( private readonly LateBootService $lateBootService, - private readonly SilentConfigurationUpgradeService $silentConfigurationUpgradeService, - private readonly SilentTemplateFileUpgradeService $silentTemplateFileUpgradeService, private readonly ConfigurationManager $configurationManager, private readonly FailsafePackageManager $packageManager, private readonly VerifyHostHeader $verifyHostHeader, @@ -184,27 +175,18 @@ final class InstallerController */ public function executeEnvironmentAndFoldersAction(ServerRequestInterface $request): ResponseInterface { - $folderStructureFactory = GeneralUtility::makeInstance(DefaultFactory::class); - $structureFacade = $folderStructureFactory->getStructure(WebserverType::fromRequest($request)); - $structureFixMessageQueue = $structureFacade->fix(); - $errorsFromStructure = $structureFixMessageQueue->getAllMessages(ContextualFeedbackSeverity::ERROR); - - if ($this->configurationManager->canWriteConfiguration()) { - $this->configurationManager->createLocalConfigurationFromFactoryConfiguration(); - // Create a PackageStates.php with all packages activated marked as "part of factory default" - $this->packageManager->recreatePackageStatesFileIfMissing(true); - $extensionConfiguration = new ExtensionConfiguration(); - $extensionConfiguration->synchronizeExtConfTemplateWithLocalConfigurationOfAllExtensions(); - + $errorsFromStructure = $this->setupService->createDirectoryStructure(WebserverType::fromRequest($request)); + try { + $this->setupService->prepareSystemSettings(); + } catch (ConfigurationDirectoryDoesNotExistException) { return new JsonResponse([ - 'success' => true, + 'success' => false, + 'status' => $errorsFromStructure, ]); } - $errorsFromStructure[] = new FlashMessage('Unable to write configuration file', 'Error', ContextualFeedbackSeverity::ERROR); return new JsonResponse([ - 'success' => false, - 'status' => $errorsFromStructure, + 'success' => true, ]); } @@ -237,44 +219,6 @@ final class InstallerController ]); } - /** - * Execute silent configuration update. May be called multiple times until success = true is returned. - * - * @return ResponseInterface success = true if no change has been done - */ - public function executeSilentConfigurationUpdateAction(): ResponseInterface - { - $success = true; - try { - $this->silentConfigurationUpgradeService->execute(); - } catch (ConfigurationChangedException) { - $success = false; - } catch (SettingsWriteException $e) { - throw new SilentConfigurationUpgradeReadonlyException(code: 1688464086, throwable: $e); - } - return new JsonResponse([ - 'success' => $success, - ]); - } - - /** - * Execute silent template files update. May be called multiple times until success = true is returned. - * - * @return ResponseInterface success = true if no change has been done - */ - public function executeSilentTemplateFileUpdateAction(): ResponseInterface - { - $success = true; - try { - $this->silentTemplateFileUpgradeService->execute(); - } catch (TemplateFileChangedException $e) { - $success = false; - } - return new JsonResponse([ - 'success' => $success, - ]); - } - /** * Check if database connect step needs to be shown */ @@ -606,10 +550,6 @@ final class InstallerController */ public function executeDefaultConfigurationAction(ServerRequestInterface $request): ResponseInterface { - $featureManager = new FeatureManager(); - // Get best matching configuration presets - $configurationValues = $featureManager->getBestMatchingConfigurationForAllFeatures(); - $container = $this->lateBootService->loadExtLocalconfDatabaseAndExtTables(); // Use the container here instead of makeInstance() to use the factory of the container for building the UriBuilder $uriBuilder = $container->get(UriBuilder::class); @@ -651,8 +591,6 @@ final class InstallerController // Mark upgrade wizards as done $this->setupDatabaseService->markWizardsDone($container); - $this->configurationManager->setLocalConfigurationValuesByPathValuePairs($configurationValues); - $formProtection = $this->formProtectionFactory->createFromRequest($request); $formProtection->clean(); diff --git a/typo3/sysext/install/Classes/Service/Exception/ConfigurationDirectoryDoesNotExistException.php b/typo3/sysext/install/Classes/Service/Exception/ConfigurationDirectoryDoesNotExistException.php new file mode 100644 index 0000000000000000000000000000000000000000..ab575633e55ede06cd64c1d26922dbec2799544b --- /dev/null +++ b/typo3/sysext/install/Classes/Service/Exception/ConfigurationDirectoryDoesNotExistException.php @@ -0,0 +1,25 @@ +<?php + +declare(strict_types=1); + +/* + * This file is part of the TYPO3 CMS project. + * + * It is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, either version 2 + * of the License, or any later version. + * + * For the full copyright and license information, please read the + * LICENSE.txt file that was distributed with this source code. + * + * The TYPO3 project - inspiring people to share! + */ + +namespace TYPO3\CMS\Install\Service\Exception; + +use TYPO3\CMS\Install\Service\Exception; + +/** + * An exception thrown during setup, when the config dir was not created, but config file must be written + */ +class ConfigurationDirectoryDoesNotExistException extends Exception {} diff --git a/typo3/sysext/install/Classes/Service/Exception/ConfigurationFileAlreadyExistsException.php b/typo3/sysext/install/Classes/Service/Exception/ConfigurationFileAlreadyExistsException.php new file mode 100644 index 0000000000000000000000000000000000000000..3e31ac09e5267dd62e83f02eb82050f2d3f85e77 --- /dev/null +++ b/typo3/sysext/install/Classes/Service/Exception/ConfigurationFileAlreadyExistsException.php @@ -0,0 +1,25 @@ +<?php + +declare(strict_types=1); + +/* + * This file is part of the TYPO3 CMS project. + * + * It is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, either version 2 + * of the License, or any later version. + * + * For the full copyright and license information, please read the + * LICENSE.txt file that was distributed with this source code. + * + * The TYPO3 project - inspiring people to share! + */ + +namespace TYPO3\CMS\Install\Service\Exception; + +use TYPO3\CMS\Install\Service\Exception; + +/** + * An exception thrown during setup, when the config file should be written, but already exists + */ +class ConfigurationFileAlreadyExistsException extends Exception {} diff --git a/typo3/sysext/install/Classes/Service/SetupService.php b/typo3/sysext/install/Classes/Service/SetupService.php index 699d9dec5895197d7e88e39e8f58ebcd3aa987d7..05108785a87764b058cba87b473b98e42456797d 100644 --- a/typo3/sysext/install/Classes/Service/SetupService.php +++ b/typo3/sysext/install/Classes/Service/SetupService.php @@ -19,8 +19,10 @@ namespace TYPO3\CMS\Install\Service; use TYPO3\CMS\Core\Configuration\ConfigurationManager; use TYPO3\CMS\Core\Configuration\Exception\SiteConfigurationWriteException; +use TYPO3\CMS\Core\Configuration\ExtensionConfiguration; use TYPO3\CMS\Core\Configuration\Loader\YamlFileLoader; use TYPO3\CMS\Core\Configuration\SiteWriter; +use TYPO3\CMS\Core\Core\Environment; use TYPO3\CMS\Core\Crypto\PasswordHashing\Argon2idPasswordHash; use TYPO3\CMS\Core\Crypto\PasswordHashing\Argon2iPasswordHash; use TYPO3\CMS\Core\Crypto\PasswordHashing\BcryptPasswordHash; @@ -28,10 +30,16 @@ use TYPO3\CMS\Core\Crypto\PasswordHashing\InvalidPasswordHashException; use TYPO3\CMS\Core\Crypto\PasswordHashing\PasswordHashInterface; use TYPO3\CMS\Core\Crypto\Random; use TYPO3\CMS\Core\Database\ConnectionPool; -use TYPO3\CMS\Core\Resource\Exception\ExistingTargetFileNameException; +use TYPO3\CMS\Core\Messaging\FlashMessage; +use TYPO3\CMS\Core\Package\FailsafePackageManager; +use TYPO3\CMS\Core\Type\ContextualFeedbackSeverity; use TYPO3\CMS\Core\Utility\GeneralUtility; use TYPO3\CMS\Install\Command\BackendUserGroupType; use TYPO3\CMS\Install\Configuration\FeatureManager; +use TYPO3\CMS\Install\FolderStructure\DefaultFactory; +use TYPO3\CMS\Install\Service\Exception\ConfigurationDirectoryDoesNotExistException; +use TYPO3\CMS\Install\Service\Exception\ConfigurationFileAlreadyExistsException; +use TYPO3\CMS\Install\WebserverType; /** * Service class helping to manage parts of the setup process (set configuration, @@ -44,8 +52,20 @@ readonly class SetupService private ConfigurationManager $configurationManager, private SiteWriter $siteWriter, private YamlFileLoader $yamlFileLoader, + private FailsafePackageManager $packageManager, ) {} + /** + * @param WebserverType $webserverType + * @return FlashMessage[] + */ + public function createDirectoryStructure(WebserverType $webserverType): array + { + $folderStructureFactory = GeneralUtility::makeInstance(DefaultFactory::class); + $structureFixMessageQueue = $folderStructureFactory->getStructure($webserverType)->fix(); + return $structureFixMessageQueue->getAllMessages(ContextualFeedbackSeverity::ERROR); + } + public function setSiteName(string $name): bool { return $this->configurationManager->setLocalConfigurationValueByPath('SYS/sitename', $name); @@ -126,34 +146,41 @@ readonly class SetupService } /** - * @throws ExistingTargetFileNameException + * @throws ConfigurationFileAlreadyExistsException + * @throws ConfigurationDirectoryDoesNotExistException */ public function prepareSystemSettings(bool $forceOverwrite = false): void { $configurationFileLocation = $this->configurationManager->getSystemConfigurationFileLocation(); - if (!$forceOverwrite && @is_file($configurationFileLocation)) { - throw new ExistingTargetFileNameException( - 'Configuration file ' . $configurationFileLocation . ' already exists!', - 1669747685, + $configDir = dirname($configurationFileLocation); + if (!is_dir($configDir)) { + throw new ConfigurationDirectoryDoesNotExistException( + 'Configuration directory ' . $this->makePathRelativeToProjectDirectory($configDir) . ' does not exist!', + 1700401774, ); } - - // @todo Remove once LocalConfiguration.php support was dropped. - // @todo Web installer creates default configuration based on default factory configuration. Recheck if we - // should use this here too instead of an empty array. - // Ugly hack to write system/settings.php, to avoid fallback to - // LocalConfiguration.php causing issues because it does not exist! - @unlink($configurationFileLocation); - $this->configurationManager->writeLocalConfiguration([]); + if (@is_file($configurationFileLocation)) { + if (!$forceOverwrite) { + throw new ConfigurationFileAlreadyExistsException( + 'Configuration file ' . $this->makePathRelativeToProjectDirectory($configurationFileLocation) . ' already exists!', + 1669747685, + ); + } + unlink($configurationFileLocation); + } + $this->configurationManager->createLocalConfigurationFromFactoryConfiguration(); + $randomKey = GeneralUtility::makeInstance(Random::class)->generateRandomHexString(96); + $this->configurationManager->setLocalConfigurationValueByPath('SYS/encryptionKey', $randomKey); + $extensionConfiguration = new ExtensionConfiguration(); + $extensionConfiguration->synchronizeExtConfTemplateWithLocalConfigurationOfAllExtensions(); // Get best matching configuration presets $featureManager = new FeatureManager(); $configurationValues = $featureManager->getBestMatchingConfigurationForAllFeatures(); $this->configurationManager->setLocalConfigurationValuesByPathValuePairs($configurationValues); - $randomKey = GeneralUtility::makeInstance(Random::class)->generateRandomHexString(96); - $this->configurationManager->setLocalConfigurationValueByPath('SYS/encryptionKey', $randomKey); - $this->configurationManager->setLocalConfigurationValueByPath('SYS/trustedHostsPattern', '.*.*'); + // In non Composer mode, create a PackageStates.php with all packages activated marked as "part of factory default" + $this->packageManager->recreatePackageStatesFileIfMissing(true); } public function createSite(): string @@ -316,4 +343,9 @@ For each website you need a TypoScript record on the main page of your website ( ); } } + + private function makePathRelativeToProjectDirectory(string $absolutePath): string + { + return str_replace(Environment::getProjectPath(), '', $absolutePath); + } } diff --git a/typo3/sysext/install/Classes/ServiceProvider.php b/typo3/sysext/install/Classes/ServiceProvider.php index 2a512cf16d89f6b56bfce6b464a800e120690af7..332e45be82ff66503275baf4e59e125137d20a64 100644 --- a/typo3/sysext/install/Classes/ServiceProvider.php +++ b/typo3/sysext/install/Classes/ServiceProvider.php @@ -238,7 +238,8 @@ class ServiceProvider extends AbstractServiceProvider return new Service\SetupService( $container->get(ConfigurationManager::class), $container->get(SiteWriter::class), - $container->get(YamlFileLoader::class) + $container->get(YamlFileLoader::class), + $container->get(FailsafePackageManager::class), ); } @@ -295,8 +296,6 @@ class ServiceProvider extends AbstractServiceProvider { return new Controller\InstallerController( $container->get(Service\LateBootService::class), - $container->get(Service\SilentConfigurationUpgradeService::class), - $container->get(Service\SilentTemplateFileUpgradeService::class), $container->get(ConfigurationManager::class), $container->get(FailsafePackageManager::class), $container->get(VerifyHostHeader::class), @@ -413,7 +412,6 @@ class ServiceProvider extends AbstractServiceProvider $container->get(Service\SetupService::class), $container->get(ConfigurationManager::class), $container->get(LateBootService::class), - $container->get(FailsafePackageManager::class), ); } diff --git a/typo3/sysext/install/Resources/Public/JavaScript/installer.js b/typo3/sysext/install/Resources/Public/JavaScript/installer.js index a42058587f9bcd2f3249bb2ebb29711ffb7eea66..2e86c46901b436126d6a752f342874b7d97e2a3b 100644 --- a/typo3/sysext/install/Resources/Public/JavaScript/installer.js +++ b/typo3/sysext/install/Resources/Public/JavaScript/installer.js @@ -10,4 +10,4 @@ * * The TYPO3 project - inspiring people to share! */ -import DocumentService from"@typo3/core/document-service.js";import RegularEvent from"@typo3/core/event/regular-event.js";import AjaxRequest from"@typo3/core/ajax/ajax-request.js";import PasswordStrength from"@typo3/install/module/password-strength.js";import{InfoBox}from"@typo3/install/renderable/info-box.js";import"@typo3/backend/element/icon-element.js";import{selector}from"@typo3/core/literals.js";import"@typo3/backend/element/progress-bar-element.js";var Identifiers;!function(e){e.body=".t3js-body",e.moduleContent=".t3js-module-content",e.mainContent=".t3js-installer-content",e.progressBar=".t3js-installer-progress",e.databaseConnectOutput=".t3js-installer-databaseConnect-output",e.databaseSelectOutput=".t3js-installer-databaseSelect-output",e.databaseDataOutput=".t3js-installer-databaseData-output"}(Identifiers||(Identifiers={}));class Installer{constructor(){this.initializeEvents(),DocumentService.ready().then((()=>{this.initialize()}))}initializeEvents(){new RegularEvent("click",(e=>{e.preventDefault(),this.showEnvironmentAndFolders()})).delegateTo(document,".t3js-installer-environmentFolders-retry"),new RegularEvent("click",(e=>{e.preventDefault(),this.executeEnvironmentAndFolders()})).delegateTo(document,".t3js-installer-environmentFolders-execute"),new RegularEvent("click",(e=>{e.preventDefault(),this.executeDatabaseConnect()})).delegateTo(document,".t3js-installer-databaseConnect-execute"),new RegularEvent("click",(e=>{e.preventDefault(),this.executeDatabaseSelect()})).delegateTo(document,".t3js-installer-databaseSelect-execute"),new RegularEvent("click",(e=>{e.preventDefault(),this.executeDatabaseData()})).delegateTo(document,".t3js-installer-databaseData-execute"),new RegularEvent("click",(e=>{e.preventDefault(),this.executeDefaultConfiguration()})).delegateTo(document,".t3js-installer-defaultConfiguration-execute"),new RegularEvent("click",((e,t)=>{e.preventDefault();const a=document.querySelector(t.dataset.toggleTarget);"invisible"===t.dataset.toggleState?(t.dataset.toggleState="visible",a.setAttribute("type","text")):(t.dataset.toggleState="invisible",a.setAttribute("type","password"))})).delegateTo(document,".t3-install-form-password-toggle"),new RegularEvent("change",((e,t)=>{const a=t.value;document.querySelectorAll(".t3-install-driver-data").forEach((e=>e.setAttribute("hidden",""))),document.querySelectorAll(".t3-install-driver-data input").forEach((e=>e.setAttribute("disabled","disabled"))),document.querySelectorAll(selector`#${a} input`).forEach((e=>e.removeAttribute("disabled"))),document.querySelector("#"+a)?.removeAttribute("hidden")})).delegateTo(document,"#t3js-connect-database-driver")}initialize(){this.setProgress(0),this.getMainLayout()}getUrl(e){let t=location.href;return t=t.replace(location.search,""),void 0!==e&&(t=t+"?install[action]="+e),t}setProgress(e){const t=document.querySelector(Identifiers.progressBar);null!==t&&0!==e&&(t.value=e,t.label=`Step ${e} of 5 completed`)}getMainLayout(){new AjaxRequest(this.getUrl("mainLayout")).get({cache:"no-cache"}).then((async e=>{const t=await e.resolve();document.querySelector(Identifiers.body).innerHTML=t.html,this.checkInstallerAvailable()}))}checkInstallerAvailable(){new AjaxRequest(this.getUrl("checkInstallerAvailable")).get({cache:"no-cache"}).then((async e=>{(await e.resolve()).success?this.checkEnvironmentAndFolders():this.showInstallerNotAvailable()}))}showInstallerNotAvailable(){const e=document.querySelector(Identifiers.mainContent);new AjaxRequest(this.getUrl("showInstallerNotAvailable")).get({cache:"no-cache"}).then((async t=>{const a=await t.resolve();!0===a.success&&(e.innerHTML=a.html)}))}checkEnvironmentAndFolders(){this.setProgress(1),new AjaxRequest(this.getUrl("checkEnvironmentAndFolders")).get({cache:"no-cache"}).then((async e=>{!0===(await e.resolve()).success?this.checkTrustedHostsPattern():this.showEnvironmentAndFolders()}))}showEnvironmentAndFolders(){const e=document.querySelector(Identifiers.mainContent);new AjaxRequest(this.getUrl("showEnvironmentAndFolders")).get({cache:"no-cache"}).then((async t=>{const a=await t.resolve();if(!0===a.success){e.innerHTML=a.html;const t=document.querySelector(".t3js-installer-environment-details");let s=!1;Array.isArray(a.environmentStatusErrors)&&a.environmentStatusErrors.forEach((e=>{s=!0,t.append(InfoBox.create(e.severity,e.title,e.message))})),Array.isArray(a.environmentStatusWarnings)&&a.environmentStatusWarnings.forEach((e=>{s=!0,t.append(InfoBox.create(e.severity,e.title,e.message))})),Array.isArray(a.structureErrors)&&a.structureErrors.forEach((e=>{s=!0,t.append(InfoBox.create(e.severity,e.title,e.message))})),s?(t.removeAttribute("hidden"),document.querySelectorAll(".t3js-installer-environmentFolders-bad").forEach((e=>e.removeAttribute("hidden")))):document.querySelectorAll(".t3js-installer-environmentFolders-good").forEach((e=>e.removeAttribute("hidden")))}}))}executeEnvironmentAndFolders(){new AjaxRequest(this.getUrl("executeEnvironmentAndFolders")).get({cache:"no-cache"}).then((async e=>{!0===(await e.resolve()).success&&this.checkTrustedHostsPattern()}))}checkTrustedHostsPattern(){new AjaxRequest(this.getUrl("checkTrustedHostsPattern")).get({cache:"no-cache"}).then((async e=>{!0===(await e.resolve()).success?this.executeSilentConfigurationUpdate():this.executeAdjustTrustedHostsPattern()}))}executeAdjustTrustedHostsPattern(){new AjaxRequest(this.getUrl("executeAdjustTrustedHostsPattern")).get({cache:"no-cache"}).then((()=>{this.executeSilentConfigurationUpdate()}))}executeSilentConfigurationUpdate(){new AjaxRequest(this.getUrl("executeSilentConfigurationUpdate")).get({cache:"no-cache"}).then((async e=>{!0===(await e.resolve()).success?this.executeSilentTemplateFileUpdate():this.executeSilentConfigurationUpdate()}))}executeSilentTemplateFileUpdate(){new AjaxRequest(this.getUrl("executeSilentTemplateFileUpdate")).get({cache:"no-cache"}).then((async e=>{!0===(await e.resolve()).success?this.checkDatabaseConnect():this.executeSilentTemplateFileUpdate()}))}checkDatabaseConnect(){this.setProgress(2),new AjaxRequest(this.getUrl("checkDatabaseConnect")).get({cache:"no-cache"}).then((async e=>{!0===(await e.resolve()).success?this.checkDatabaseSelect():this.showDatabaseConnect()}))}showDatabaseConnect(){const e=document.querySelector(Identifiers.mainContent);new AjaxRequest(this.getUrl("showDatabaseConnect")).get({cache:"no-cache"}).then((async t=>{const a=await t.resolve();!0===a.success&&(e.innerHTML=a.html,document.querySelector("#t3js-connect-database-driver").dispatchEvent(new Event("change",{bubbles:!0})),PasswordStrength.initialize(document.querySelector(".t3-install-form-password-strength")))}))}executeDatabaseConnect(){const e=document.querySelector(Identifiers.databaseConnectOutput),t={"install[action]":"executeDatabaseConnect","install[token]":document.querySelector(Identifiers.moduleContent).dataset.installerDatabaseConnectExecuteToken};for(const[e,a]of new FormData(document.querySelector(Identifiers.body+" form")))t[e]=a.toString();new AjaxRequest(this.getUrl()).post(t).then((async t=>{const a=await t.resolve();!0===a.success?this.checkDatabaseSelect():Array.isArray(a.status)&&(e.replaceChildren(),a.status.forEach((t=>{e.append(InfoBox.create(t.severity,t.title,t.message))})))}))}checkDatabaseSelect(){this.setProgress(3),new AjaxRequest(this.getUrl("checkDatabaseSelect")).get({cache:"no-cache"}).then((async e=>{!0===(await e.resolve()).success?this.checkDatabaseData():this.showDatabaseSelect()}))}showDatabaseSelect(){const e=document.querySelector(Identifiers.mainContent);new AjaxRequest(this.getUrl("showDatabaseSelect")).get({cache:"no-cache"}).then((async t=>{const a=await t.resolve();!0===a.success&&(e.innerHTML=a.html)}))}executeDatabaseSelect(){const e=document.querySelector(Identifiers.databaseSelectOutput),t={"install[action]":"executeDatabaseSelect","install[token]":document.querySelector(Identifiers.moduleContent).dataset.installerDatabaseSelectExecuteToken};for(const[e,a]of new FormData(document.querySelector(Identifiers.body+" form")))t[e]=a.toString();new AjaxRequest(this.getUrl()).post(t).then((async t=>{const a=await t.resolve();!0===a.success?this.checkDatabaseRequirements():Array.isArray(a.status)&&a.status.forEach((t=>{e.replaceChildren(InfoBox.create(t.severity,t.title,t.message))}))}))}checkDatabaseRequirements(){const e=document.querySelector(Identifiers.databaseSelectOutput),t={"install[action]":"checkDatabaseRequirements","install[token]":document.querySelector(Identifiers.moduleContent).dataset.installerDatabaseCheckRequirementsExecuteToken};for(const[e,a]of new FormData(document.querySelector(Identifiers.body+" form")))t[e]=a.toString();new AjaxRequest(this.getUrl()).post(t).then((async t=>{const a=await t.resolve();!0===a.success?this.checkDatabaseData():Array.isArray(a.status)&&(e.replaceChildren(),a.status.forEach((t=>{e.append(InfoBox.create(t.severity,t.title,t.message))})))}))}checkDatabaseData(){this.setProgress(4),new AjaxRequest(this.getUrl("checkDatabaseData")).get({cache:"no-cache"}).then((async e=>{!0===(await e.resolve()).success?this.showDefaultConfiguration():this.showDatabaseData()}))}showDatabaseData(){const e=document.querySelector(Identifiers.mainContent);new AjaxRequest(this.getUrl("showDatabaseData")).get({cache:"no-cache"}).then((async t=>{const a=await t.resolve();!0===a.success&&(e.innerHTML=a.html,PasswordStrength.initialize(document.querySelector(".t3-install-form-password-strength")))}))}executeDatabaseData(){const e=document.querySelector(Identifiers.databaseDataOutput),t={"install[action]":"executeDatabaseData","install[token]":document.querySelector(Identifiers.moduleContent).dataset.installerDatabaseDataExecuteToken};for(const[e,a]of new FormData(document.querySelector(Identifiers.body+" form")))t[e]=a.toString();const a=document.createElement("typo3-backend-progress-bar");e.replaceChildren(a),new AjaxRequest(this.getUrl()).post(t).then((async t=>{const a=await t.resolve();!0===a.success?this.showDefaultConfiguration():Array.isArray(a.status)&&(e.replaceChildren(),a.status.forEach((t=>{e.append(InfoBox.create(t.severity,t.title,t.message))})))}))}showDefaultConfiguration(){const e=document.querySelector(Identifiers.mainContent);this.setProgress(5),new AjaxRequest(this.getUrl("showDefaultConfiguration")).get({cache:"no-cache"}).then((async t=>{const a=await t.resolve();!0===a.success&&(e.innerHTML=a.html)}))}executeDefaultConfiguration(){const e={"install[action]":"executeDefaultConfiguration","install[token]":document.querySelector(Identifiers.moduleContent).dataset.installerDefaultConfigurationExecuteToken};for(const[t,a]of new FormData(document.querySelector(Identifiers.body+" form")))e[t]=a.toString();new AjaxRequest(this.getUrl()).post(e).then((async e=>{const t=await e.resolve();top.location.href=t.redirect}))}}export default new Installer; \ No newline at end of file +import DocumentService from"@typo3/core/document-service.js";import RegularEvent from"@typo3/core/event/regular-event.js";import AjaxRequest from"@typo3/core/ajax/ajax-request.js";import PasswordStrength from"@typo3/install/module/password-strength.js";import{InfoBox}from"@typo3/install/renderable/info-box.js";import"@typo3/backend/element/icon-element.js";import{selector}from"@typo3/core/literals.js";import"@typo3/backend/element/progress-bar-element.js";var Identifiers;!function(e){e.body=".t3js-body",e.moduleContent=".t3js-module-content",e.mainContent=".t3js-installer-content",e.progressBar=".t3js-installer-progress",e.databaseConnectOutput=".t3js-installer-databaseConnect-output",e.databaseSelectOutput=".t3js-installer-databaseSelect-output",e.databaseDataOutput=".t3js-installer-databaseData-output"}(Identifiers||(Identifiers={}));class Installer{constructor(){this.initializeEvents(),DocumentService.ready().then((()=>{this.initialize()}))}initializeEvents(){new RegularEvent("click",(e=>{e.preventDefault(),this.showEnvironmentAndFolders()})).delegateTo(document,".t3js-installer-environmentFolders-retry"),new RegularEvent("click",(e=>{e.preventDefault(),this.executeEnvironmentAndFolders()})).delegateTo(document,".t3js-installer-environmentFolders-execute"),new RegularEvent("click",(e=>{e.preventDefault(),this.executeDatabaseConnect()})).delegateTo(document,".t3js-installer-databaseConnect-execute"),new RegularEvent("click",(e=>{e.preventDefault(),this.executeDatabaseSelect()})).delegateTo(document,".t3js-installer-databaseSelect-execute"),new RegularEvent("click",(e=>{e.preventDefault(),this.executeDatabaseData()})).delegateTo(document,".t3js-installer-databaseData-execute"),new RegularEvent("click",(e=>{e.preventDefault(),this.executeDefaultConfiguration()})).delegateTo(document,".t3js-installer-defaultConfiguration-execute"),new RegularEvent("click",((e,t)=>{e.preventDefault();const a=document.querySelector(t.dataset.toggleTarget);"invisible"===t.dataset.toggleState?(t.dataset.toggleState="visible",a.setAttribute("type","text")):(t.dataset.toggleState="invisible",a.setAttribute("type","password"))})).delegateTo(document,".t3-install-form-password-toggle"),new RegularEvent("change",((e,t)=>{const a=t.value;document.querySelectorAll(".t3-install-driver-data").forEach((e=>e.setAttribute("hidden",""))),document.querySelectorAll(".t3-install-driver-data input").forEach((e=>e.setAttribute("disabled","disabled"))),document.querySelectorAll(selector`#${a} input`).forEach((e=>e.removeAttribute("disabled"))),document.querySelector("#"+a)?.removeAttribute("hidden")})).delegateTo(document,"#t3js-connect-database-driver")}initialize(){this.setProgress(0),this.getMainLayout()}getUrl(e){let t=location.href;return t=t.replace(location.search,""),void 0!==e&&(t=t+"?install[action]="+e),t}setProgress(e){const t=document.querySelector(Identifiers.progressBar);null!==t&&0!==e&&(t.value=e,t.label=`Step ${e} of 5 completed`)}getMainLayout(){new AjaxRequest(this.getUrl("mainLayout")).get({cache:"no-cache"}).then((async e=>{const t=await e.resolve();document.querySelector(Identifiers.body).innerHTML=t.html,this.checkInstallerAvailable()}))}checkInstallerAvailable(){new AjaxRequest(this.getUrl("checkInstallerAvailable")).get({cache:"no-cache"}).then((async e=>{(await e.resolve()).success?this.checkEnvironmentAndFolders():this.showInstallerNotAvailable()}))}showInstallerNotAvailable(){const e=document.querySelector(Identifiers.mainContent);new AjaxRequest(this.getUrl("showInstallerNotAvailable")).get({cache:"no-cache"}).then((async t=>{const a=await t.resolve();!0===a.success&&(e.innerHTML=a.html)}))}checkEnvironmentAndFolders(){this.setProgress(1),new AjaxRequest(this.getUrl("checkEnvironmentAndFolders")).get({cache:"no-cache"}).then((async e=>{!0===(await e.resolve()).success?this.checkTrustedHostsPattern():this.showEnvironmentAndFolders()}))}showEnvironmentAndFolders(){const e=document.querySelector(Identifiers.mainContent);new AjaxRequest(this.getUrl("showEnvironmentAndFolders")).get({cache:"no-cache"}).then((async t=>{const a=await t.resolve();if(!0===a.success){e.innerHTML=a.html;const t=document.querySelector(".t3js-installer-environment-details");let s=!1;Array.isArray(a.environmentStatusErrors)&&a.environmentStatusErrors.forEach((e=>{s=!0,t.append(InfoBox.create(e.severity,e.title,e.message))})),Array.isArray(a.environmentStatusWarnings)&&a.environmentStatusWarnings.forEach((e=>{s=!0,t.append(InfoBox.create(e.severity,e.title,e.message))})),Array.isArray(a.structureErrors)&&a.structureErrors.forEach((e=>{s=!0,t.append(InfoBox.create(e.severity,e.title,e.message))})),s?(t.removeAttribute("hidden"),document.querySelectorAll(".t3js-installer-environmentFolders-bad").forEach((e=>e.removeAttribute("hidden")))):document.querySelectorAll(".t3js-installer-environmentFolders-good").forEach((e=>e.removeAttribute("hidden")))}}))}executeEnvironmentAndFolders(){new AjaxRequest(this.getUrl("executeEnvironmentAndFolders")).get({cache:"no-cache"}).then((async e=>{!0===(await e.resolve()).success&&this.checkTrustedHostsPattern()}))}checkTrustedHostsPattern(){new AjaxRequest(this.getUrl("checkTrustedHostsPattern")).get({cache:"no-cache"}).then((async e=>{!0===(await e.resolve()).success?this.checkDatabaseConnect():this.executeAdjustTrustedHostsPattern()}))}executeAdjustTrustedHostsPattern(){new AjaxRequest(this.getUrl("executeAdjustTrustedHostsPattern")).get({cache:"no-cache"}).then((()=>{this.checkDatabaseConnect()}))}checkDatabaseConnect(){this.setProgress(2),new AjaxRequest(this.getUrl("checkDatabaseConnect")).get({cache:"no-cache"}).then((async e=>{!0===(await e.resolve()).success?this.checkDatabaseSelect():this.showDatabaseConnect()}))}showDatabaseConnect(){const e=document.querySelector(Identifiers.mainContent);new AjaxRequest(this.getUrl("showDatabaseConnect")).get({cache:"no-cache"}).then((async t=>{const a=await t.resolve();!0===a.success&&(e.innerHTML=a.html,document.querySelector("#t3js-connect-database-driver").dispatchEvent(new Event("change",{bubbles:!0})),PasswordStrength.initialize(document.querySelector(".t3-install-form-password-strength")))}))}executeDatabaseConnect(){const e=document.querySelector(Identifiers.databaseConnectOutput),t={"install[action]":"executeDatabaseConnect","install[token]":document.querySelector(Identifiers.moduleContent).dataset.installerDatabaseConnectExecuteToken};for(const[e,a]of new FormData(document.querySelector(Identifiers.body+" form")))t[e]=a.toString();new AjaxRequest(this.getUrl()).post(t).then((async t=>{const a=await t.resolve();!0===a.success?this.checkDatabaseSelect():Array.isArray(a.status)&&(e.replaceChildren(),a.status.forEach((t=>{e.append(InfoBox.create(t.severity,t.title,t.message))})))}))}checkDatabaseSelect(){this.setProgress(3),new AjaxRequest(this.getUrl("checkDatabaseSelect")).get({cache:"no-cache"}).then((async e=>{!0===(await e.resolve()).success?this.checkDatabaseData():this.showDatabaseSelect()}))}showDatabaseSelect(){const e=document.querySelector(Identifiers.mainContent);new AjaxRequest(this.getUrl("showDatabaseSelect")).get({cache:"no-cache"}).then((async t=>{const a=await t.resolve();!0===a.success&&(e.innerHTML=a.html)}))}executeDatabaseSelect(){const e=document.querySelector(Identifiers.databaseSelectOutput),t={"install[action]":"executeDatabaseSelect","install[token]":document.querySelector(Identifiers.moduleContent).dataset.installerDatabaseSelectExecuteToken};for(const[e,a]of new FormData(document.querySelector(Identifiers.body+" form")))t[e]=a.toString();new AjaxRequest(this.getUrl()).post(t).then((async t=>{const a=await t.resolve();!0===a.success?this.checkDatabaseRequirements():Array.isArray(a.status)&&a.status.forEach((t=>{e.replaceChildren(InfoBox.create(t.severity,t.title,t.message))}))}))}checkDatabaseRequirements(){const e=document.querySelector(Identifiers.databaseSelectOutput),t={"install[action]":"checkDatabaseRequirements","install[token]":document.querySelector(Identifiers.moduleContent).dataset.installerDatabaseCheckRequirementsExecuteToken};for(const[e,a]of new FormData(document.querySelector(Identifiers.body+" form")))t[e]=a.toString();new AjaxRequest(this.getUrl()).post(t).then((async t=>{const a=await t.resolve();!0===a.success?this.checkDatabaseData():Array.isArray(a.status)&&(e.replaceChildren(),a.status.forEach((t=>{e.append(InfoBox.create(t.severity,t.title,t.message))})))}))}checkDatabaseData(){this.setProgress(4),new AjaxRequest(this.getUrl("checkDatabaseData")).get({cache:"no-cache"}).then((async e=>{!0===(await e.resolve()).success?this.showDefaultConfiguration():this.showDatabaseData()}))}showDatabaseData(){const e=document.querySelector(Identifiers.mainContent);new AjaxRequest(this.getUrl("showDatabaseData")).get({cache:"no-cache"}).then((async t=>{const a=await t.resolve();!0===a.success&&(e.innerHTML=a.html,PasswordStrength.initialize(document.querySelector(".t3-install-form-password-strength")))}))}executeDatabaseData(){const e=document.querySelector(Identifiers.databaseDataOutput),t={"install[action]":"executeDatabaseData","install[token]":document.querySelector(Identifiers.moduleContent).dataset.installerDatabaseDataExecuteToken};for(const[e,a]of new FormData(document.querySelector(Identifiers.body+" form")))t[e]=a.toString();const a=document.createElement("typo3-backend-progress-bar");e.replaceChildren(a),new AjaxRequest(this.getUrl()).post(t).then((async t=>{const a=await t.resolve();!0===a.success?this.showDefaultConfiguration():Array.isArray(a.status)&&(e.replaceChildren(),a.status.forEach((t=>{e.append(InfoBox.create(t.severity,t.title,t.message))})))}))}showDefaultConfiguration(){const e=document.querySelector(Identifiers.mainContent);this.setProgress(5),new AjaxRequest(this.getUrl("showDefaultConfiguration")).get({cache:"no-cache"}).then((async t=>{const a=await t.resolve();!0===a.success&&(e.innerHTML=a.html)}))}executeDefaultConfiguration(){const e={"install[action]":"executeDefaultConfiguration","install[token]":document.querySelector(Identifiers.moduleContent).dataset.installerDefaultConfigurationExecuteToken};for(const[t,a]of new FormData(document.querySelector(Identifiers.body+" form")))e[t]=a.toString();new AjaxRequest(this.getUrl()).post(e).then((async e=>{const t=await e.resolve();top.location.href=t.redirect}))}}export default new Installer; \ No newline at end of file