Skip to content

Commit 5a8e422

Browse files
committed
feat(lexicon): add options
Signed-off-by: Maxence Lange <maxence@artificial-owl.com>
1 parent c43070e commit 5a8e422

File tree

8 files changed

+94
-94
lines changed

8 files changed

+94
-94
lines changed

core/Command/Config/App/Base.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,14 @@
77
*/
88
namespace OC\Core\Command\Config\App;
99

10+
use OC\Config\ConfigManager;
1011
use OCP\IAppConfig;
1112
use Stecman\Component\Symfony\Console\BashCompletion\CompletionContext;
1213

1314
abstract class Base extends \OC\Core\Command\Base {
1415
public function __construct(
1516
protected IAppConfig $appConfig,
17+
protected readonly ConfigManager $configManager,
1618
) {
1719
parent::__construct();
1820
}

core/Command/Config/App/SetConfig.php

Lines changed: 4 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,6 @@ protected function execute(InputInterface $input, OutputInterface $output): int
161161
}
162162

163163
$value = (string)$input->getOption('value');
164-
165164
switch ($type) {
166165
case IAppConfig::VALUE_MIXED:
167166
$updated = $this->appConfig->setValueMixed($appName, $configName, $value, $lazy, $sensitive);
@@ -172,34 +171,19 @@ protected function execute(InputInterface $input, OutputInterface $output): int
172171
break;
173172

174173
case IAppConfig::VALUE_INT:
175-
if ($value !== ((string)((int)$value))) {
176-
throw new AppConfigIncorrectTypeException('Value is not an integer');
177-
}
178-
$updated = $this->appConfig->setValueInt($appName, $configName, (int)$value, $lazy, $sensitive);
174+
$updated = $this->appConfig->setValueInt($appName, $configName, $this->configManager->convertToInt($value), $lazy, $sensitive);
179175
break;
180176

181177
case IAppConfig::VALUE_FLOAT:
182-
if ($value !== ((string)((float)$value))) {
183-
throw new AppConfigIncorrectTypeException('Value is not a float');
184-
}
185-
$updated = $this->appConfig->setValueFloat($appName, $configName, (float)$value, $lazy, $sensitive);
178+
$updated = $this->appConfig->setValueFloat($appName, $configName, $this->configManager->convertToFloat($value), $lazy, $sensitive);
186179
break;
187180

188181
case IAppConfig::VALUE_BOOL:
189-
if (in_array(strtolower($value), ['true', '1', 'on', 'yes'])) {
190-
$valueBool = true;
191-
} elseif (in_array(strtolower($value), ['false', '0', 'off', 'no'])) {
192-
$valueBool = false;
193-
} else {
194-
throw new AppConfigIncorrectTypeException('Value is not a boolean, please use \'true\' or \'false\'');
195-
}
196-
$updated = $this->appConfig->setValueBool($appName, $configName, $valueBool, $lazy);
182+
$updated = $this->appConfig->setValueBool($appName, $configName, $this->configManager->convertToBool($value), $lazy);
197183
break;
198184

199185
case IAppConfig::VALUE_ARRAY:
200-
$valueArray = json_decode($value, true, flags: JSON_THROW_ON_ERROR);
201-
$valueArray = (is_array($valueArray)) ? $valueArray : throw new AppConfigIncorrectTypeException('Value is not an array');
202-
$updated = $this->appConfig->setValueArray($appName, $configName, $valueArray, $lazy, $sensitive);
186+
$updated = $this->appConfig->setValueArray($appName, $configName, $this->configManager->convertToArray($value), $lazy, $sensitive);
203187
break;
204188
}
205189
}

core/Command/Config/ListConfigs.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ protected function configure() {
4646
InputOption::VALUE_NONE,
4747
'Use this option when you want to include sensitive configs like passwords, salts, ...'
4848
)
49-
->addOption('migrate',null,InputOption::VALUE_NONE,'Rename config keys of all enabled apps, based on ConfigLexicon')
49+
->addOption('migrate', null, InputOption::VALUE_NONE, 'Rename config keys of all enabled apps, based on ConfigLexicon')
5050
;
5151
}
5252

lib/private/App/AppManager.php

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ public function __construct(
8282
private IEventDispatcher $dispatcher,
8383
private LoggerInterface $logger,
8484
private ServerVersion $serverVersion,
85+
private readonly ConfigManager $configManager,
8586
) {
8687
}
8788

@@ -562,9 +563,7 @@ public function enableApp(string $appId, bool $forceEnable = false): void {
562563
ManagerEvent::EVENT_APP_ENABLE, $appId
563564
));
564565
$this->clearAppsCache();
565-
566-
$configManager = \OCP\Server::get(ConfigManager::class);
567-
$configManager->migrateConfigLexiconKeys($appId);
566+
$this->configManager->migrateConfigLexiconKeys($appId);
568567
}
569568

570569
/**
@@ -619,9 +618,7 @@ public function enableAppForGroups(string $appId, array $groups, bool $forceEnab
619618
ManagerEvent::EVENT_APP_ENABLE_FOR_GROUPS, $appId, $groups
620619
));
621620
$this->clearAppsCache();
622-
623-
$configManager = \OCP\Server::get(ConfigManager::class);
624-
$configManager->migrateConfigLexiconKeys($appId);
621+
$this->configManager->migrateConfigLexiconKeys($appId);
625622
}
626623

627624
/**

lib/private/AppConfig.php

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -435,6 +435,7 @@ private function getTypedValue(
435435
int $type,
436436
): string {
437437
$this->assertParams($app, $key, valueType: $type);
438+
$origKey = $key;
438439
if (!$this->matchAndApplyLexiconDefinition($app, $key, $lazy, $type, $default)) {
439440
return $default; // returns default if strictness of lexicon is set to WARNING (block and report)
440441
}
@@ -475,6 +476,15 @@ private function getTypedValue(
475476
$value = $this->crypto->decrypt(substr($value, self::ENCRYPTION_PREFIX_LENGTH));
476477
}
477478

479+
// in case the key was modified while running matchAndApplyLexiconDefinition() we are
480+
// interested to check options in case a modification of the value is needed
481+
if ($origKey !== $key) {
482+
$lexiconEntry = $this->getLexiconEntry($app, $key);
483+
if ($type === self::VALUE_BOOL && $lexiconEntry?->hasOption(ConfigLexiconEntry::RENAME_INVERT_BOOLEAN)) {
484+
$value = (in_array(strtolower($value), ['1', 'true', 'yes', 'on'])) ? '0' : '1';
485+
}
486+
}
487+
478488
return $value;
479489
}
480490

@@ -1598,7 +1608,7 @@ private function matchAndApplyLexiconDefinition(
15981608
}
15991609

16001610
if (!array_key_exists($key, $configDetails['entries'])) {
1601-
return $this->applyLexiconStrictness($configDetails['strictness'],'The app config key ' . $app . '/' . $key . ' is not defined in the config lexicon');
1611+
return $this->applyLexiconStrictness($configDetails['strictness'], 'The app config key ' . $app . '/' . $key . ' is not defined in the config lexicon');
16021612
}
16031613

16041614
// if lazy is NULL, we ignore all check on the type/lazyness/default from Lexicon
@@ -1691,6 +1701,10 @@ public function getConfigDetailsFromLexicon(string $appId): array {
16911701
return $this->configLexiconDetails[$appId];
16921702
}
16931703

1704+
private function getLexiconEntry(string $appId, string $key): ?ConfigLexiconEntry {
1705+
return $this->getConfigDetailsFromLexicon($appId)['entries'][$key] ?? null;
1706+
}
1707+
16941708
/**
16951709
* if set to TRUE, ignore aliases defined in Config Lexicon during the use of the methods of this class
16961710
*

lib/private/Config/ConfigManager.php

Lines changed: 55 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ class ConfigManager {
2020
public function __construct(
2121
private readonly AppConfig $appConfig,
2222
private readonly UserConfig $userConfig,
23-
private readonly IAppManager $appManager,
2423
private readonly LoggerInterface $logger,
2524
) {
2625
}
@@ -41,7 +40,8 @@ public function __construct(
4140
public function migrateConfigLexiconKeys(?string $appId = null): void {
4241
if ($appId === null) {
4342
$this->migrateConfigLexiconKeys('core');
44-
foreach ($this->appManager->getEnabledApps() as $app) {
43+
$appManager = \OCP\Server::get(IAppManager::class);
44+
foreach ($appManager->getEnabledApps() as $app) {
4545
$this->migrateConfigLexiconKeys($app);
4646
}
4747

@@ -124,7 +124,7 @@ private function migrateUserConfigKeys(string $appId): void {
124124
continue;
125125
}
126126

127-
foreach($this->userConfig->getValuesByUsers($appId, $entry->getRename()) as $userId => $value) {
127+
foreach ($this->userConfig->getValuesByUsers($appId, $entry->getRename()) as $userId => $value) {
128128
if ($this->userConfig->hasKey($userId, $appId, $entry->getKey())) {
129129
continue;
130130
}
@@ -155,38 +155,19 @@ private function migrateAppConfigValue(string $appId, ConfigLexiconEntry $entry)
155155
return;
156156

157157
case ValueType::INT:
158-
if ($value !== ((string)((int)$value))) {
159-
throw new TypeConflictException('Value is not an integer');
160-
}
161-
$this->appConfig->setValueInt($appId, $entry->getKey(), (int)$value);
158+
$this->appConfig->setValueInt($appId, $entry->getKey(), $this->convertToInt($value));
162159
return;
163160

164161
case ValueType::FLOAT:
165-
if ($value !== ((string)((float)$value))) {
166-
throw new TypeConflictException('Value is not a float');
167-
}
168-
$this->appConfig->setValueFloat($appId, $entry->getKey(), (float)$value);
162+
$this->appConfig->setValueFloat($appId, $entry->getKey(), $this->convertToFloat($value));
169163
return;
170164

171165
case ValueType::BOOL:
172-
if (in_array(strtolower($value), ['true', '1', 'on', 'yes'])) {
173-
$valueBool = true;
174-
} elseif (in_array(strtolower($value), ['false', '0', 'off', 'no'])) {
175-
$valueBool = false;
176-
} else {
177-
throw new TypeConflictException('Value cannot be converted to boolean');
178-
}
179-
$this->appConfig->setValueBool($appId, $entry->getKey(), $valueBool);
166+
$this->appConfig->setValueBool($appId, $entry->getKey(), $this->convertToBool($value, $entry));
180167
return;
181168

182169
case ValueType::ARRAY:
183-
try {
184-
$valueArray = json_decode($value, true, flags: JSON_THROW_ON_ERROR);
185-
} catch (JsonException) {
186-
throw new TypeConflictException('Value is not a valid json');
187-
}
188-
$valueArray = (is_array($valueArray)) ? $valueArray : throw new TypeConflictException('Value is not an array');
189-
$this->appConfig->setValueArray($appId, $entry->getKey(), $valueArray);
170+
$this->appConfig->setValueArray($appId, $entry->getKey(), $this->convertToArray($value));
190171
return;
191172
}
192173
}
@@ -204,39 +185,64 @@ private function migrateUserConfigValue(string $userId, string $appId, ConfigLex
204185
return;
205186

206187
case ValueType::INT:
207-
if ($value !== ((string)((int)$value))) {
208-
throw new TypeConflictException('Value is not an integer');
209-
}
210-
$this->userConfig->setValueInt($userId, $appId, $entry->getKey(), (int)$value);
188+
$this->userConfig->setValueInt($userId, $appId, $entry->getKey(), $this->convertToInt($value));
211189
return;
212190

213191
case ValueType::FLOAT:
214-
if ($value !== ((string)((float)$value))) {
215-
throw new TypeConflictException('Value is not a float');
216-
}
217-
$this->userConfig->setValueFloat($userId, $appId, $entry->getKey(), (float)$value);
192+
$this->userConfig->setValueFloat($userId, $appId, $entry->getKey(), $this->convertToFloat($value));
218193
return;
219194

220195
case ValueType::BOOL:
221-
if (in_array(strtolower($value), ['true', '1', 'on', 'yes'])) {
222-
$valueBool = true;
223-
} elseif (in_array(strtolower($value), ['false', '0', 'off', 'no'])) {
224-
$valueBool = false;
225-
} else {
226-
throw new TypeConflictException('Value cannot be converted to boolean');
227-
}
228-
$this->userConfig->setValueBool($userId, $appId, $entry->getKey(), $valueBool);
196+
$this->userConfig->setValueBool($userId, $appId, $entry->getKey(), $this->convertToBool($value, $entry));
229197
return;
230198

231199
case ValueType::ARRAY:
232-
try {
233-
$valueArray = json_decode($value, true, flags: JSON_THROW_ON_ERROR);
234-
} catch (JsonException) {
235-
throw new TypeConflictException('Value is not a valid json');
236-
}
237-
$valueArray = (is_array($valueArray)) ? $valueArray : throw new TypeConflictException('Value is not an array');
238-
$this->userConfig->setValueArray($userId, $appId, $entry->getKey(), $valueArray);
200+
$this->userConfig->setValueArray($userId, $appId, $entry->getKey(), $this->convertToArray($value));
239201
return;
240202
}
241203
}
204+
205+
public function convertToInt(string $value): int {
206+
if ($value !== ((string)((int)$value))) {
207+
throw new TypeConflictException('Value is not an integer');
208+
}
209+
210+
return (int)$value;
211+
}
212+
213+
public function convertToFloat(string $value): float {
214+
if ($value !== ((string)((float)$value))) {
215+
throw new TypeConflictException('Value is not a float');
216+
}
217+
218+
return (float)$value;
219+
}
220+
221+
public function convertToBool(string $value, ?ConfigLexiconEntry $entry = null): bool {
222+
if (in_array(strtolower($value), ['true', '1', 'on', 'yes'])) {
223+
$valueBool = true;
224+
} elseif (in_array(strtolower($value), ['false', '0', 'off', 'no'])) {
225+
$valueBool = false;
226+
} else {
227+
throw new TypeConflictException('Value cannot be converted to boolean');
228+
}
229+
if ($entry?->hasOption(ConfigLexiconEntry::RENAME_INVERT_BOOLEAN) === true) {
230+
$valueBool = !$valueBool;
231+
}
232+
233+
return $valueBool;
234+
}
235+
236+
public function convertToArray(string $value): array {
237+
try {
238+
$valueArray = json_decode($value, true, flags: JSON_THROW_ON_ERROR);
239+
} catch (JsonException) {
240+
throw new TypeConflictException('Value is not a valid json');
241+
}
242+
if (!is_array($valueArray)) {
243+
throw new TypeConflictException('Value is not an array');
244+
}
245+
246+
return $valueArray;
247+
}
242248
}

lib/private/Server.php

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -783,21 +783,7 @@ public function __construct($webRoot, \OC\Config $config) {
783783
});
784784

785785
$this->registerAlias(ITempManager::class, TempManager::class);
786-
787-
$this->registerService(AppManager::class, function (ContainerInterface $c) {
788-
// TODO: use auto-wiring
789-
return new \OC\App\AppManager(
790-
$c->get(IUserSession::class),
791-
$c->get(\OCP\IConfig::class),
792-
$c->get(IGroupManager::class),
793-
$c->get(ICacheFactory::class),
794-
$c->get(IEventDispatcher::class),
795-
$c->get(LoggerInterface::class),
796-
$c->get(ServerVersion::class),
797-
);
798-
});
799786
$this->registerAlias(IAppManager::class, AppManager::class);
800-
801787
$this->registerAlias(IDateTimeZone::class, DateTimeZone::class);
802788

803789
$this->registerService(IDateTimeFormatter::class, function (Server $c) {

lib/unstable/Config/Lexicon/ConfigLexiconEntry.php

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
* @experimental 31.0.0
1818
*/
1919
class ConfigLexiconEntry {
20+
public const RENAME_INVERT_BOOLEAN = 1;
21+
2022
private string $definition = '';
2123
private ?string $default = null;
2224

@@ -26,7 +28,7 @@ class ConfigLexiconEntry {
2628
* @param string $definition optional description of config key available when using occ command
2729
* @param bool $lazy set config value as lazy
2830
* @param int $flags set flags
29-
* @param string $rename previous config key to migrate config value from
31+
* @param string|null $rename previous config key to migrate config value from
3032
* @param bool $deprecated set config key as deprecated
3133
*
3234
* @experimental 31.0.0
@@ -40,8 +42,9 @@ public function __construct(
4042
string $definition = '',
4143
private readonly bool $lazy = false,
4244
private readonly int $flags = 0,
43-
private readonly ?string $rename = null,
4445
private readonly bool $deprecated = false,
46+
private readonly ?string $rename = null,
47+
private readonly int $options = 0,
4548
) {
4649
/** @psalm-suppress UndefinedClass */
4750
if (\OC::$CLI) { // only store definition if ran from CLI
@@ -205,12 +208,20 @@ public function isFlagged(int $flag): bool {
205208
* link to an old config key.
206209
*
207210
* @return string|null not NULL if value can be imported from a previous key
208-
* @since 32.0.0
211+
* @experimental 32.0.0
209212
*/
210213
public function getRename(): ?string {
211214
return $this->rename;
212215
}
213216

217+
/**
218+
* @experimental 32.0.0
219+
* @return bool TRUE if $option was set during the creation of the entry.
220+
*/
221+
public function hasOption(int $option): bool {
222+
return (($option & $this->options) !== 0);
223+
}
224+
214225
/**
215226
* returns if config key is set as deprecated
216227
*

0 commit comments

Comments
 (0)