diff --git a/php/public/containers-form-submit.js b/php/public/containers-form-submit.js index 3c163cab..f6e5c447 100644 --- a/php/public/containers-form-submit.js +++ b/php/public/containers-form-submit.js @@ -1,6 +1,7 @@ document.addEventListener("DOMContentLoaded", function () { + const optionsForm = document.getElementById('options-form'); // Don't run if the expected form isn't present. - if (document.getElementById('options-form') === null) { + if (optionsForm === null) { return; } @@ -20,14 +21,8 @@ document.addEventListener("DOMContentLoaded", function () { const communityContainersCheckboxes = document.querySelectorAll("#community-form input[type='checkbox']"); // Office suite radio buttons - const collaboraRadio = document.getElementById('office-collabora'); - const onlyofficeRadio = document.getElementById('office-onlyoffice'); - const euroofficeRadio = document.getElementById('office-eurooffice'); - const noneRadio = document.getElementById('office-none'); - const collaboraHidden = document.getElementById('collabora'); - const onlyofficeHidden = document.getElementById('onlyoffice'); - const euroofficeHidden = document.getElementById('eurooffice'); - let initialOfficeSelection = null; + const officeSuiteChoiceList = optionsForm.elements['office_suite_choice']; + const initialOfficeSelection = document.getElementById('initial-office-suite')?.value ?? ''; optionsContainersCheckboxes.forEach(checkbox => { initialStateOptionsContainers[checkbox.id] = checkbox.checked; // Use checked property to capture actual initial state @@ -37,19 +32,6 @@ document.addEventListener("DOMContentLoaded", function () { initialStateCommunityContainers[checkbox.id] = checkbox.checked; // Use checked property to capture actual initial state }); - // Store initial office suite selection - if (collaboraRadio && onlyofficeRadio && euroofficeRadio && noneRadio) { - if (collaboraRadio.checked) { - initialOfficeSelection = 'collabora'; - } else if (onlyofficeRadio.checked) { - initialOfficeSelection = 'onlyoffice'; - } else if (euroofficeRadio.checked) { - initialOfficeSelection = 'eurooffice'; - } else { - initialOfficeSelection = 'none'; - } - } - // Function to compare current states to initial states function checkForOptionContainerChanges() { let hasChanges = false; @@ -60,32 +42,8 @@ document.addEventListener("DOMContentLoaded", function () { } }); - // Check office suite changes and sync to hidden inputs - if (collaboraRadio && onlyofficeRadio && euroofficeRadio && noneRadio && collaboraHidden && onlyofficeHidden && euroofficeHidden) { - let currentOfficeSelection = null; - if (collaboraRadio.checked) { - currentOfficeSelection = 'collabora'; - collaboraHidden.value = 'on'; - onlyofficeHidden.value = ''; - euroofficeHidden.value = ''; - } else if (onlyofficeRadio.checked) { - currentOfficeSelection = 'onlyoffice'; - collaboraHidden.value = ''; - onlyofficeHidden.value = 'on'; - euroofficeHidden.value = ''; - } else if (euroofficeRadio.checked) { - currentOfficeSelection = 'eurooffice'; - collaboraHidden.value = ''; - onlyofficeHidden.value = ''; - euroofficeHidden.value = 'on'; - } else { - currentOfficeSelection = 'none'; - collaboraHidden.value = ''; - onlyofficeHidden.value = ''; - euroofficeHidden.value = ''; - } - - if (currentOfficeSelection !== initialOfficeSelection) { + if (officeSuiteChoiceList) { + if (officeSuiteChoiceList.value !== initialOfficeSelection) { hasChanges = true; } } @@ -156,12 +114,7 @@ document.addEventListener("DOMContentLoaded", function () { handleTalkVisibility(); // Ensure talk-recording is correctly initialized // Add event listeners for office suite radio buttons - if (collaboraRadio && onlyofficeRadio && euroofficeRadio && noneRadio) { - collaboraRadio.addEventListener('change', checkForOptionContainerChanges); - onlyofficeRadio.addEventListener('change', checkForOptionContainerChanges); - euroofficeRadio.addEventListener('change', checkForOptionContainerChanges); - noneRadio.addEventListener('change', checkForOptionContainerChanges); - } + officeSuiteChoiceList?.forEach((elem) => elem.addEventListener('change', checkForOptionContainerChanges)); // Initial call to check for changes checkForOptionContainerChanges(); diff --git a/php/public/index.php b/php/public/index.php index 46c39786..1b0a675f 100644 --- a/php/public/index.php +++ b/php/public/index.php @@ -153,9 +153,7 @@ $app->get('/containers', function (Request $request, Response $response, array $ 'backup_times' => $configurationManager->getBackupTimes(), 'current_channel' => $dockerActionManager->GetCurrentChannel(), 'is_clamav_enabled' => $configurationManager->isClamavEnabled, - 'is_onlyoffice_enabled' => $configurationManager->isOnlyofficeEnabled, - 'is_eurooffice_enabled' => $configurationManager->isEuroofficeEnabled, - 'is_collabora_enabled' => $configurationManager->isCollaboraEnabled, + 'office_suite' => $configurationManager->getOfficeSuiteString(), 'is_talk_enabled' => $configurationManager->isTalkEnabled, 'borg_restore_password' => $configurationManager->borgRestorePassword, 'daily_backup_time' => $configurationManager->getDailyBackupTime(), diff --git a/php/src/ContainerDefinitionFetcher.php b/php/src/ContainerDefinitionFetcher.php index 7fb8604a..44ab329e 100644 --- a/php/src/ContainerDefinitionFetcher.php +++ b/php/src/ContainerDefinitionFetcher.php @@ -12,6 +12,7 @@ use AIO\Container\ContainerVolume; use AIO\Container\ContainerVolumes; use AIO\Data\ConfigurationManager; use AIO\Data\DataConst; +use AIO\Data\OfficeSuite; use AIO\Docker\DockerActionManager; readonly class ContainerDefinitionFetcher { @@ -75,15 +76,15 @@ readonly class ContainerDefinitionFetcher { continue; } } elseif ($entry['container_name'] === 'nextcloud-aio-onlyoffice') { - if (!$this->configurationManager->isOnlyofficeEnabled) { + if ($this->configurationManager->officeSuite !== OfficeSuite::Onlyoffice) { continue; } } elseif ($entry['container_name'] === 'nextcloud-aio-eurooffice') { - if (!$this->configurationManager->isEuroofficeEnabled) { + if ($this->configurationManager->officeSuite !== OfficeSuite::Eurooffice) { continue; } } elseif ($entry['container_name'] === 'nextcloud-aio-collabora') { - if (!$this->configurationManager->isCollaboraEnabled) { + if ($this->configurationManager->officeSuite !== OfficeSuite::Collabora) { continue; } } elseif ($entry['container_name'] === 'nextcloud-aio-talk') { @@ -192,15 +193,15 @@ readonly class ContainerDefinitionFetcher { continue; } } elseif ($value === 'nextcloud-aio-onlyoffice') { - if (!$this->configurationManager->isOnlyofficeEnabled) { + if ($this->configurationManager->officeSuite !== OfficeSuite::Onlyoffice) { continue; } } elseif ($value === 'nextcloud-aio-eurooffice') { - if (!$this->configurationManager->isEuroofficeEnabled) { + if ($this->configurationManager->officeSuite !== OfficeSuite::Eurooffice) { continue; } } elseif ($value === 'nextcloud-aio-collabora') { - if (!$this->configurationManager->isCollaboraEnabled) { + if ($this->configurationManager->officeSuite !== OfficeSuite::Collabora) { continue; } } elseif ($value === 'nextcloud-aio-talk') { diff --git a/php/src/Controller/ConfigurationController.php b/php/src/Controller/ConfigurationController.php index 0fa7a2ba..f96c8723 100644 --- a/php/src/Controller/ConfigurationController.php +++ b/php/src/Controller/ConfigurationController.php @@ -5,6 +5,7 @@ namespace AIO\Controller; use AIO\Data\ConfigurationManager; use AIO\Data\InvalidSettingConfigurationException; +use AIO\Data\OfficeSuite; use Psr\Http\Message\ResponseInterface as Response; use Psr\Http\Message\ServerRequestInterface as Request; @@ -76,24 +77,10 @@ readonly class ConfigurationController { } if (isset($request->getParsedBody()['options-form'])) { - $officeSuiteChoice = $request->getParsedBody()['office_suite_choice'] ?? ''; - - if ($officeSuiteChoice === 'collabora') { - $this->configurationManager->isCollaboraEnabled = true; - $this->configurationManager->isOnlyofficeEnabled = false; - $this->configurationManager->isEuroofficeEnabled = false; - } elseif ($officeSuiteChoice === 'onlyoffice') { - $this->configurationManager->isCollaboraEnabled = false; - $this->configurationManager->isOnlyofficeEnabled = true; - $this->configurationManager->isEuroofficeEnabled = false; - } elseif ($officeSuiteChoice === 'eurooffice') { - $this->configurationManager->isCollaboraEnabled = false; - $this->configurationManager->isOnlyofficeEnabled = false; - $this->configurationManager->isEuroofficeEnabled = true; - } else { - $this->configurationManager->isCollaboraEnabled = false; - $this->configurationManager->isOnlyofficeEnabled = false; - $this->configurationManager->isEuroofficeEnabled = false; + if (isset($request->getParsedBody()['office_suite_choice'])) { + $inputValue = strval($request->getParsedBody()['office_suite_choice'] ?? ''); + $officeSuite = OfficeSuite::tryFrom($inputValue) ?? OfficeSuite::None; + $this->configurationManager->officeSuite = $officeSuite; } $this->configurationManager->isClamavEnabled = isset($request->getParsedBody()['clamav']); $this->configurationManager->isTalkEnabled = isset($request->getParsedBody()['talk']); diff --git a/php/src/Controller/DockerController.php b/php/src/Controller/DockerController.php index 86f7c78c..a3656415 100644 --- a/php/src/Controller/DockerController.php +++ b/php/src/Controller/DockerController.php @@ -11,6 +11,7 @@ use AIO\Docker\DockerActionManager; use Psr\Http\Message\ResponseInterface as Response; use Psr\Http\Message\ServerRequestInterface as Request; use AIO\Data\ConfigurationManager; +use AIO\Data\OfficeSuite; use Slim\Psr7\NonBufferedBody; readonly class DockerController { @@ -299,7 +300,7 @@ readonly class DockerController { // This is a hack but no better solution was found for the meantime // Stop Collabora first to make sure it force-saves // See https://github.com/nextcloud/richdocuments/issues/3799 - if ($id === self::TOP_CONTAINER && $this->configurationManager->isCollaboraEnabled) { + if ($id === self::TOP_CONTAINER && $this->configurationManager->officeSuite === OfficeSuite::Collabora) { $this->PerformRecursiveContainerStop('nextcloud-aio-collabora', false, $addToStreamingResponseBody); } diff --git a/php/src/Data/ConfigurationManager.php b/php/src/Data/ConfigurationManager.php index 3398f5c6..e268fea1 100644 --- a/php/src/Data/ConfigurationManager.php +++ b/php/src/Data/ConfigurationManager.php @@ -95,22 +95,9 @@ class ConfigurationManager set { $this->set('isClamavEnabled', $value); } } - public bool $isOnlyofficeEnabled { - // Type-cast because old configs could have 1/0 for this key. - get => (bool) $this->get('isOnlyofficeEnabled', false); - set { $this->set('isOnlyofficeEnabled', $value); } - } - - public bool $isEuroofficeEnabled { - // Only enabled if no other office suite is enabled. - get => !$this->isOtherOfficeThanEuroOfficeEnabled() && $this->get('isEuroofficeEnabled', true); - set { $this->set('isEuroofficeEnabled', $value); } - } - - public bool $isCollaboraEnabled { - // Type-cast because old configs could have 1/0 for this key. - get => (bool) $this->get('isCollaboraEnabled', false); - set { $this->set('isCollaboraEnabled', $value); } + public OfficeSuite $officeSuite { + get => $this->readOfficeSuite(); + set { $this->writeOfficeSuite($value); } } public bool $isTalkEnabled { @@ -416,6 +403,75 @@ class ConfigurationManager } } + private function has(string $key) : bool { + return array_key_exists($key, $this->getConfig()); + } + + private function unset(string ...$keys) : void { + $changed = false; + $this->getConfig(); + foreach ($keys as $key) { + if ($this->has($key)) { + unset($this->config[$key]); + $changed = true; + } + } + // Only write if this isn't called in between startTransaction() and commitTransaction(). + if ($changed && $this->noWrite !== true) { + $this->writeConfig(); + } + } + + private function writeOfficeSuite(OfficeSuite $officeSuite) : void + { + $this->set('officeSuite', $officeSuite->value); + // Remove the deprecated options. + $this->unset('isCollaboraEnabled', 'isOnlyofficeEnabled', 'isEuroofficeEnabled'); + } + + private function readOfficeSuite() : OfficeSuite + { + if ($this->has('officeSuite')) { + $configValue = (string) $this->get('officeSuite', ''); + return OfficeSuite::tryFrom($configValue) ?? OfficeSuite::None; + } + + // Check the three boolean legacy options. Convert to boolean because very old configs could have + // `1`/`0` or even `"1"`/`"0"`/`""` as values. + if (boolval($this->get('isCollaboraEnabled', false)) === true) { + return OfficeSuite::Collabora; + } + if (boolval($this->get('isOnlyofficeEnabled', false)) === true) { + return OfficeSuite::Onlyoffice; + } + if (boolval($this->get('isEuroofficeEnabled', false)) === true) { + return OfficeSuite::Eurooffice; + } + + // All offices disabled. + if ( + $this->has('isCollaboraEnabled') && boolval($this->get('isCollaboraEnabled')) === false + && $this->has('isOnlyofficeEnabled') && boolval($this->get('isOnlyofficeEnabled')) === false + && ( + // Eurooffice can be unset, which should be treated as `false`, too, because it means that + // the office choice wasn't ever saved after Eurooffice was introduced, but the user had + // previously disabled both available options, which means they want no office. + !$this->has('isEuroofficeEnabled') + || boolval($this->get('isEuroofficeEnabled')) === false + ) + ) { + return OfficeSuite::None; + } + + // Default + return OfficeSuite::Eurooffice; + } + + public function getOfficeSuiteString() : string + { + return $this->officeSuite->value; + } + /** * This allows to assign multiple attributes without saving the config to disk in between. It must be * followed by a call to commitTransaction(), which then writes all changes to disk. @@ -532,12 +588,6 @@ class ConfigurationManager return ''; } - // Helper function for EuroOffice to make sure that it does not - // get enabled on existing instances after updating the default - private function isOtherOfficeThanEuroOfficeEnabled() : bool { - return $this->isCollaboraEnabled || $this->isOnlyofficeEnabled; - } - /** * @throws InvalidSettingConfigurationException * @@ -1164,9 +1214,9 @@ class ConfigurationManager 'BACKUP_RESTORE_PASSWORD' => $this->borgRestorePassword, 'CLAMAV_ENABLED' => $this->isClamavEnabled ? 'yes' : '', 'TALK_RECORDING_ENABLED' => $this->isTalkRecordingEnabled ? 'yes' : '', - 'ONLYOFFICE_ENABLED' => $this->isOnlyofficeEnabled ? 'yes' : '', - 'EUROOFFICE_ENABLED' => $this->isEuroofficeEnabled ? 'yes' : '', - 'COLLABORA_ENABLED' => $this->isCollaboraEnabled ? 'yes' : '', + 'ONLYOFFICE_ENABLED' => $this->officeSuite === OfficeSuite::Onlyoffice ? 'yes' : '', + 'EUROOFFICE_ENABLED' => $this->officeSuite === OfficeSuite::Eurooffice ? 'yes' : '', + 'COLLABORA_ENABLED' => $this->officeSuite === OfficeSuite::Collabora ? 'yes' : '', 'TALK_ENABLED' => $this->isTalkEnabled ? 'yes' : '', 'UPDATE_NEXTCLOUD_APPS' => ($this->isDailyBackupRunning() && $this->areAutomaticUpdatesEnabled()) ? 'yes' : '', 'TIMEZONE' => $this->timezone === '' ? 'Etc/UTC' : $this->timezone, diff --git a/php/src/Data/OfficeSuite.php b/php/src/Data/OfficeSuite.php new file mode 100644 index 00000000..61b8abd7 --- /dev/null +++ b/php/src/Data/OfficeSuite.php @@ -0,0 +1,18 @@ + @@ -49,14 +49,13 @@ {% endif %} - @@ -86,14 +85,13 @@ {% endif %} - @@ -123,7 +121,6 @@ {% endif %} - {% if isAnyRunning == false %}
@@ -270,7 +268,7 @@ {% endif %} -{% if is_collabora_enabled == true and isAnyRunning == false and was_start_button_clicked == true %} +{% if office_suite == 'collabora' and isAnyRunning == false and was_start_button_clicked == true %}