Skip to content

Commit

Permalink
feat(config): frame config keys/values
Browse files Browse the repository at this point in the history
Signed-off-by: Maxence Lange <[email protected]>
  • Loading branch information
ArtificialOwl committed Mar 21, 2024
1 parent c451829 commit f374de6
Show file tree
Hide file tree
Showing 7 changed files with 308 additions and 0 deletions.
47 changes: 47 additions & 0 deletions lib/private/AppConfig.php
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@

use InvalidArgumentException;
use JsonException;
use OC\AppFramework\Bootstrap\Coordinator;
use OC\AppFramework\ConfigValues\AppConfigValue;
use OCP\AppFramework\ConfigValues\IConfigValue;
use OCP\DB\Exception as DBException;
use OCP\DB\QueryBuilder\IQueryBuilder;
use OCP\Exceptions\AppConfigIncorrectTypeException;
Expand Down Expand Up @@ -97,6 +100,7 @@ public function __construct(
protected IDBConnection $connection,
protected LoggerInterface $logger,
protected ICrypto $crypto,
private Coordinator $coordinator,
) {
}

Expand Down Expand Up @@ -457,6 +461,8 @@ private function getTypedValue(
$this->assertParams($app, $key, valueType: $type);
$this->loadConfig($lazy);

$this->compareRegisteredConfigValues($app, $key, $default, $lazy, $type);

/**
* We ignore check if mixed type is requested.
* If type of stored value is set as mixed, we don't filter.
Expand Down Expand Up @@ -1506,4 +1512,45 @@ private function getSensitiveKeys(string $app): array {
public function clearCachedConfig(): void {
$this->clearCache();
}



private function compareRegisteredConfigValues(
string $app,
string $key,
string &$default,
bool &$lazy,
int &$type
): void {
$context = $this->coordinator->getRegistrationContext();
$configValues = $context->getConfigValues($app, AppConfigValue::TYPE);

if (!array_key_exists($key, $configValues)) {
if ($context->strictConfigValues($app)) {
throw new AppConfigUnknownKeyException('This key is not defined in the list of available AppConfig keys for this app');
}
return;
}

$configValue = $configValues[$key];

if ($configValue->getValueType() !== match($type) {
self::VALUE_STRING => IConfigValue::TYPE_STRING,
self::VALUE_INT => IConfigValue::TYPE_INT,
self::VALUE_FLOAT => IConfigValue::TYPE_FLOAT,
self::VALUE_BOOL => IConfigValue::TYPE_BOOL,
self::VALUE_ARRAY => IConfigValue::TYPE_ARRAY,
}) {
throw new AppConfigTypeConflictException('This key is mistyped compare to the list of available AppConfig keys for this app');
}

$lazy = $configValue->isLazy();
$default = $configValue->getDefault();
if ($configValue->isSensitive()) {
$type |= self::VALUE_SENSITIVE;
}
if ($configValue->isDeprecated()) {
$this->logger->notice('config value ' . $key . ' from ' . $app . ' is set as deprecated');
}
}
}
34 changes: 34 additions & 0 deletions lib/private/AppFramework/Bootstrap/RegistrationContext.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
use OC\Support\CrashReport\Registry;
use OCP\AppFramework\App;
use OCP\AppFramework\Bootstrap\IRegistrationContext;
use OCP\AppFramework\ConfigValues\IConfigValue;
use OCP\AppFramework\Middleware;
use OCP\AppFramework\Services\InitialStateProvider;
use OCP\Authentication\IAlternativeLogin;
Expand Down Expand Up @@ -160,6 +161,7 @@ class RegistrationContext {
/** @var ServiceRegistration<IDeclarativeSettingsForm>[] */
private array $declarativeSettings = [];

private array $configValues = [];
/** @var ServiceRegistration<ITeamResourceProvider>[] */
private array $teamResourceProviders = [];

Expand Down Expand Up @@ -411,6 +413,14 @@ public function registerDeclarativeSettings(string $declarativeSettingsClass): v
$declarativeSettingsClass
);
}

public function registerConfigValues(bool $strict, IConfigValue ...$configValues): void {
$this->context->registerConfigValues(
$this->appId,
$strict,
...$configValues
);
}
};
}

Expand Down Expand Up @@ -590,6 +600,16 @@ public function registerDeclarativeSettings(string $appId, string $declarativeSe
$this->declarativeSettings[] = new ServiceRegistration($appId, $declarativeSettingsClass);
}

public function registerConfigValues(string $appId, bool $strict, IConfigValue ...$configValues): void {
$values = ['_strict' => $strict];
foreach ($configValues as $configValue) {
$values[$configValue->getConfigType()][$configValue->getKey()] = $configValue;
}

$this->configValues[$appId] = $values;
}


/**
* @param App[] $apps
*/
Expand Down Expand Up @@ -920,4 +940,18 @@ public function getTeamResourceProviders(): array {
public function getDeclarativeSettings(): array {
return $this->declarativeSettings;
}

/**
* @param string $app
* @param string $configType
*
* @return array<string, IConfigValue>
*/
public function getConfigValues(string $app, string $configType): array {
return $this->configValues[$app][$configType] ?? [];
}

public function strictConfigValues(string $app): bool {
return $this->configValues[$app]['_strict'] ?? false;
}
}
106 changes: 106 additions & 0 deletions lib/private/AppFramework/ConfigValues/AConfigValue.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
<?php

declare(strict_types=1);
/**
* @copyright Copyright (c) 2024 Maxence Lange <[email protected]>
*
* @author Maxence Lange <[email protected]>
*
* @license AGPL-3.0 or later
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License, version 3,
* along with this program. If not, see <http://www.gnu.org/licenses/>
*
*/

namespace OC\AppFramework\ConfigValues;

use OCP\AppFramework\ConfigValues\IConfigValue;

abstract class AConfigValue implements IConfigValue {
private ?string $default = null;
private bool $lazy = false;
private bool $sensitive = false;
private bool $deprecated = false;

public function __construct(
private string $key,
private int $valueType
) {
}

abstract public function getConfigType(): string;

public function getKey(): string {
return $this->key;
}

public function getValueType(): int {
return $this->valueType;
}

public function withDefaultString(string $default): self {
$this->default = $default;
return $this;
}

public function withDefaultInt(int $default): self {
$this->default = (string) $default;
return $this;
}

public function withDefaultFloat(float $default): self {
$this->default = (string) $default;
return $this;
}

public function withDefaultBool(bool $default): self {
$this->default = ($default) ? '1' : '0';
return $this;
}

public function withDefaultArray(array $default): self {
$this->default = json_encode($default);
return $this;
}

public function getDefault(): string {

Check failure

Code scanning / Psalm

InvalidNullableReturnType Error

The declared return type 'string' for OC\AppFramework\ConfigValues\AConfigValue::getDefault is not nullable, but 'null|string' contains null

Check failure on line 76 in lib/private/AppFramework/ConfigValues/AConfigValue.php

View workflow job for this annotation

GitHub Actions / static-code-analysis

InvalidNullableReturnType

lib/private/AppFramework/ConfigValues/AConfigValue.php:76:32: InvalidNullableReturnType: The declared return type 'string' for OC\AppFramework\ConfigValues\AConfigValue::getDefault is not nullable, but 'null|string' contains null (see https://psalm.dev/144)
return $this->default;

Check failure

Code scanning / Psalm

NullableReturnStatement Error

The declared return type 'string' for OC\AppFramework\ConfigValues\AConfigValue::getDefault is not nullable, but the function returns 'null|string'

Check failure on line 77 in lib/private/AppFramework/ConfigValues/AConfigValue.php

View workflow job for this annotation

GitHub Actions / static-code-analysis

NullableReturnStatement

lib/private/AppFramework/ConfigValues/AConfigValue.php:77:10: NullableReturnStatement: The declared return type 'string' for OC\AppFramework\ConfigValues\AConfigValue::getDefault is not nullable, but the function returns 'null|string' (see https://psalm.dev/139)
}

public function asLazy(bool $lazy = true): self {
$this->lazy = $lazy;
return $this;
}

public function isLazy(): bool {
return $this->lazy;
}

public function asSensitive(bool $sensitive = true): self {
$this->sensitive = $sensitive;
return $this;
}

public function isSensitive(): bool {
return $this->sensitive;
}

public function asDeprecated(bool $deprecated = true): self {
$this->deprecated = $deprecated;
return $this;
}

public function isDeprecated(): bool {
return $this->deprecated;
}
}
33 changes: 33 additions & 0 deletions lib/private/AppFramework/ConfigValues/AppConfigValue.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?php

declare(strict_types=1);
/**
* @copyright Copyright (c) 2024 Maxence Lange <[email protected]>
*
* @author Maxence Lange <[email protected]>
*
* @license AGPL-3.0 or later
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License, version 3,
* along with this program. If not, see <http://www.gnu.org/licenses/>
*
*/

namespace OC\AppFramework\ConfigValues;

class AppConfigValue extends AConfigValue {
public const TYPE = 'AppConfig';

public function getConfigType(): string {
return self::TYPE;
}
}
33 changes: 33 additions & 0 deletions lib/private/AppFramework/ConfigValues/UserPreferenceValue.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?php

declare(strict_types=1);
/**
* @copyright Copyright (c) 2024 Maxence Lange <[email protected]>
*
* @author Maxence Lange <[email protected]>
*
* @license AGPL-3.0 or later
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License, version 3,
* along with this program. If not, see <http://www.gnu.org/licenses/>
*
*/

namespace OC\AppFramework\ConfigValues;

class UserPreferenceValue extends AConfigValue {
public const TYPE = 'UserPreference';

public function getConfigType(): string {
return self::TYPE;
}
}
3 changes: 3 additions & 0 deletions lib/public/AppFramework/Bootstrap/IRegistrationContext.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@

namespace OCP\AppFramework\Bootstrap;

use OCP\AppFramework\ConfigValues\IConfigValue;
use OCP\AppFramework\IAppContainer;
use OCP\Authentication\TwoFactorAuth\IProvider;
use OCP\Calendar\ICalendarProvider;
Expand Down Expand Up @@ -410,4 +411,6 @@ public function registerSetupCheck(string $setupCheckClass): void;
* @since 29.0.0
*/
public function registerDeclarativeSettings(string $declarativeSettingsClass): void;

public function registerConfigValues(bool $strict, IConfigValue ...$configValues): void;

Check failure on line 415 in lib/public/AppFramework/Bootstrap/IRegistrationContext.php

View workflow job for this annotation

GitHub Actions / static-code-analysis-ocp

InvalidDocblock

lib/public/AppFramework/Bootstrap/IRegistrationContext.php:415:2: InvalidDocblock: PHPDoc is required for methods in OCP. (see https://psalm.dev/008)
}
52 changes: 52 additions & 0 deletions lib/public/AppFramework/ConfigValues/IConfigValue.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
<?php

declare(strict_types=1);
/**
* @copyright Copyright (c) 2024 Maxence Lange <[email protected]>
*
* @author Maxence Lange <[email protected]>
*
* @license AGPL-3.0 or later
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License, version 3,
* along with this program. If not, see <http://www.gnu.org/licenses/>
*
*/

namespace OCP\AppFramework\ConfigValues;

interface IConfigValue {

Check failure on line 27 in lib/public/AppFramework/ConfigValues/IConfigValue.php

View workflow job for this annotation

GitHub Actions / static-code-analysis-ocp

InvalidDocblock

lib/public/AppFramework/ConfigValues/IConfigValue.php:27:1: InvalidDocblock: PHPDoc is required for classes/interfaces in OCP. (see https://psalm.dev/008)
public const TYPE_STRING = 1;

Check failure on line 28 in lib/public/AppFramework/ConfigValues/IConfigValue.php

View workflow job for this annotation

GitHub Actions / static-code-analysis-ocp

InvalidDocblock

lib/public/AppFramework/ConfigValues/IConfigValue.php:28:2: InvalidDocblock: PHPDoc is required for constants in OCP. (see https://psalm.dev/008)
public const TYPE_INT = 2;

Check failure on line 29 in lib/public/AppFramework/ConfigValues/IConfigValue.php

View workflow job for this annotation

GitHub Actions / static-code-analysis-ocp

InvalidDocblock

lib/public/AppFramework/ConfigValues/IConfigValue.php:29:2: InvalidDocblock: PHPDoc is required for constants in OCP. (see https://psalm.dev/008)
public const TYPE_FLOAT = 3;

Check failure on line 30 in lib/public/AppFramework/ConfigValues/IConfigValue.php

View workflow job for this annotation

GitHub Actions / static-code-analysis-ocp

InvalidDocblock

lib/public/AppFramework/ConfigValues/IConfigValue.php:30:2: InvalidDocblock: PHPDoc is required for constants in OCP. (see https://psalm.dev/008)
public const TYPE_BOOL = 4;

Check failure on line 31 in lib/public/AppFramework/ConfigValues/IConfigValue.php

View workflow job for this annotation

GitHub Actions / static-code-analysis-ocp

InvalidDocblock

lib/public/AppFramework/ConfigValues/IConfigValue.php:31:2: InvalidDocblock: PHPDoc is required for constants in OCP. (see https://psalm.dev/008)
public const TYPE_ARRAY = 5;

Check failure on line 32 in lib/public/AppFramework/ConfigValues/IConfigValue.php

View workflow job for this annotation

GitHub Actions / static-code-analysis-ocp

InvalidDocblock

lib/public/AppFramework/ConfigValues/IConfigValue.php:32:2: InvalidDocblock: PHPDoc is required for constants in OCP. (see https://psalm.dev/008)

public function getConfigType(): string;

Check failure on line 34 in lib/public/AppFramework/ConfigValues/IConfigValue.php

View workflow job for this annotation

GitHub Actions / static-code-analysis-ocp

InvalidDocblock

lib/public/AppFramework/ConfigValues/IConfigValue.php:34:2: InvalidDocblock: PHPDoc is required for methods in OCP. (see https://psalm.dev/008)

public function getKey(): string;

Check failure on line 36 in lib/public/AppFramework/ConfigValues/IConfigValue.php

View workflow job for this annotation

GitHub Actions / static-code-analysis-ocp

InvalidDocblock

lib/public/AppFramework/ConfigValues/IConfigValue.php:36:2: InvalidDocblock: PHPDoc is required for methods in OCP. (see https://psalm.dev/008)
public function getValueType(): int;

Check failure on line 37 in lib/public/AppFramework/ConfigValues/IConfigValue.php

View workflow job for this annotation

GitHub Actions / static-code-analysis-ocp

InvalidDocblock

lib/public/AppFramework/ConfigValues/IConfigValue.php:37:2: InvalidDocblock: PHPDoc is required for methods in OCP. (see https://psalm.dev/008)

public function withDefaultString(string $default): self;
public function withDefaultInt(int $default): self;
public function withDefaultFloat(float $default): self;
public function withDefaultBool(bool $default): self;
public function withDefaultArray(array $default): self;
public function getDefault(): ?string;

public function asLazy(bool $lazy = true): self;
public function isLazy(): bool;
public function asSensitive(bool $sensitive = true): self;
public function isSensitive(): bool;
public function asDeprecated(bool $deprecated = true): self;
public function isDeprecated(): bool;
}

0 comments on commit f374de6

Please sign in to comment.