From c2dd25fc7cd184f236324582595ae68d5fb93ba0 Mon Sep 17 00:00:00 2001 From: Tim Neumann Date: Sun, 24 Sep 2023 21:42:44 +0200 Subject: [PATCH] Allow admins to remove entries from some config arrays (#1155) This is done by setting the respective value to null --- README.md | 2 +- config/config.default.php | 10 ++++- src/Config/ConfigServiceProvider.php | 10 +++++ .../Unit/Config/ConfigServiceProviderTest.php | 40 +++++++++++++++++-- 4 files changed, 56 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 0a81e446..5afb1481 100644 --- a/README.md +++ b/README.md @@ -40,7 +40,7 @@ The Engelsystem may be installed manually or by using the provided [docker setup * Recommended: Directory Listing should be disabled. * There must be a MySQL database set up with a user who has full rights to that database. * If necessary, create a `config/config.php` to override values from `config/config.default.php`. - * To edit values from the `footer_items`, `themes`, `locales`, `tshirt_sizes` or `headers` lists, directly modify the `config/config.default.php` file or rename it to `config/config.php`. + * To disable/remove values from the `themes`, `tshirt_sizes`, `headers`, `header_items`, `footer_items`, or `locales` lists, set the value of the entry to `null`. * To import the database, the `bin/migrate` script has to be run. If you can't execute scripts, you can use the `initial-install.sql` file from the release zip. * In the browser, login with credentials `admin` : `asdfasdf` and change the password. diff --git a/config/config.default.php b/config/config.default.php index 97da2129..d0365987 100644 --- a/config/config.default.php +++ b/config/config.default.php @@ -30,11 +30,13 @@ return [ // Header links // Available link placeholders: %lang% + // To disable a header_item in the config.php, you can set its value to null 'header_items' => [ //'Foo' => 'https://foo.bar/batz-%lang%.html', ], // Footer links + // To disable a footer item in the config.php, you can set its value to null 'footer_items' => [ // URL to the angel faq and job description 'FAQ' => env('FAQ_URL', '/faq'), @@ -131,6 +133,8 @@ return [ // Default theme, 1=style1.css 'theme' => env('THEME', 1), + // Supported themes + // To disable a theme in the config.php, you can set its value to null 'themes' => [ 16 => [ 'name' => 'Engelsystem cccamp23 (2023)', @@ -331,6 +335,7 @@ return [ && env('IFSG_ENABLED', false), // Available locales in /resources/lang/ + // To disable a locale in the config.php, you can set its value to null 'locales' => [ 'de_DE' => 'Deutsch', 'en_US' => 'English', @@ -339,7 +344,8 @@ return [ // The default locale to use 'default_locale' => env('DEFAULT_LOCALE', 'en_US'), - // Available T-Shirt sizes, set value to null if not available + // Available T-Shirt sizes + // To disable a t-shirt size in the config.php, you can set its value to null 'tshirt_sizes' => [ 'S' => 'Small Straight-Cut', 'S-G' => 'Small Fitted-Cut', @@ -388,6 +394,8 @@ return [ // Add additional headers 'add_headers' => (bool) env('ADD_HEADERS', true), + // Predefined headers + // To disable a header in the config.php, you can set its value to null 'headers' => [ 'X-Content-Type-Options' => 'nosniff', 'X-Frame-Options' => 'sameorigin', diff --git a/src/Config/ConfigServiceProvider.php b/src/Config/ConfigServiceProvider.php index 42099caa..51f691b4 100644 --- a/src/Config/ConfigServiceProvider.php +++ b/src/Config/ConfigServiceProvider.php @@ -14,6 +14,10 @@ class ConfigServiceProvider extends ServiceProvider { protected array $configFiles = ['app.php', 'config.default.php', 'config.php']; + # remember to update ConfigServiceProviderTest, config.default.php, and README.md + protected array $configVarsToPruneNulls + = ['themes', 'tshirt_sizes', 'headers', 'header_items', 'footer_items', 'locales']; + public function __construct(Application $app, protected ?EventConfig $eventConfig = null) { parent::__construct($app); @@ -42,6 +46,12 @@ class ConfigServiceProvider extends ServiceProvider if (empty($config->get(null))) { throw new Exception('Configuration not found'); } + + foreach ($this->configVarsToPruneNulls as $key) { + $config->set($key, array_filter($config->get($key), function ($v) { + return !is_null($v); + })); + } } public function boot(): void diff --git a/tests/Unit/Config/ConfigServiceProviderTest.php b/tests/Unit/Config/ConfigServiceProviderTest.php index e8d688af..0817d381 100644 --- a/tests/Unit/Config/ConfigServiceProviderTest.php +++ b/tests/Unit/Config/ConfigServiceProviderTest.php @@ -19,6 +19,9 @@ class ConfigServiceProviderTest extends ServiceProviderTest { use ArraySubsetAsserts; + private array $configVarsWhereNullIsPruned = + ['themes', 'tshirt_sizes', 'headers', 'header_items', 'footer_items', 'locales']; + /** * @covers \Engelsystem\Config\ConfigServiceProvider::getConfigPath * @covers \Engelsystem\Config\ConfigServiceProvider::register @@ -29,11 +32,40 @@ class ConfigServiceProviderTest extends ServiceProviderTest /** @var Config|MockObject $config */ list($app, $config) = $this->getConfiguredApp(__DIR__ . '/../../../config'); - $this->setExpects($config, 'set', null, null, $this->exactly(3)); - $config->expects($this->exactly(4)) + $config + ->expects($this->exactly(4 + sizeof($this->configVarsWhereNullIsPruned))) ->method('get') - ->with(null) - ->willReturnOnConsecutiveCalls([], [], [], ['lor' => 'em']); + ->with($this->callback(function (mixed $arg) { + return is_null($arg) || in_array($arg, $this->configVarsWhereNullIsPruned); + })) + ->will($this->returnCallback(function (mixed $arg) { + if (in_array($arg, $this->configVarsWhereNullIsPruned)) { + return [$arg . '_foo' => $arg . '_bar', $arg . '_willBePruned' => null]; + } elseif (is_null($arg)) { + return ['some' => 'value']; + } else { + throw new Exception('Unexpected arg: ' . $arg); + } + })); + + $config + ->expects($this->exactly(3 + sizeof($this->configVarsWhereNullIsPruned))) + ->method('set') + //With does not support a callback funtion with multiple args ... + //Therefore, we misuse will + ->will($this->returnCallback(function (mixed $key, mixed $value = null) { + if (is_array($key)) { + return null; + } + if (in_array($key, $this->configVarsWhereNullIsPruned)) { + if ($value == [$key . '_foo' => $key . '_bar']) { + return null; + } + throw new Exception('Value for key ' . print_r($key, true) . + 'is not as expected: ' . print_r($value, true)); + } + throw new Exception('Unexpected key: ' . print_r($key, true)); + })); $configFile = __DIR__ . '/../../../config/config.php'; $configExists = file_exists($configFile);