Store office suite choice in a single config option

Previously it was three boolean options, which were supposed to be mutually
exclusive, which had to be taken care of manually.

Also previously there was only indirect indication of the choice "none", which
is brittle, too.

Signed-off-by: Pablo Zmdl <pablo@nextcloud.com>
This commit is contained in:
Pablo Zmdl
2026-07-17 19:24:49 +02:00
parent 4285168457
commit fd4e0ddcb2
8 changed files with 121 additions and 115 deletions
+7 -6
View File
@@ -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') {
+5 -18
View File
@@ -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']);
+2 -1
View File
@@ -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);
}
+75 -25
View File
@@ -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,
+18
View File
@@ -0,0 +1,18 @@
<?php
declare(strict_types=1);
/**
* SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
namespace AIO\Data;
enum OfficeSuite: string
{
case Collabora = 'collabora';
case Onlyoffice = 'onlyoffice';
case Eurooffice = 'eurooffice';
case None = '';
}