From cd11088cc408de3bcf1081b2ecb9850b39563b28 Mon Sep 17 00:00:00 2001 From: Philipp Date: Tue, 3 Jan 2023 19:54:05 +0100 Subject: [PATCH 1/4] Move 'addon' table into config --- database.sql | 2 +- src/Database/DBStructure.php | 2 +- static/dbstructure.config.php | 2 +- update.php | 20 +++++++++++++++++++- 4 files changed, 22 insertions(+), 4 deletions(-) diff --git a/database.sql b/database.sql index c413f2c24a..9ffa3544ac 100644 --- a/database.sql +++ b/database.sql @@ -1,6 +1,6 @@ -- ------------------------------------------ -- Friendica 2023.03-dev (Giant Rhubarb) --- DB_UPDATE_VERSION 1508 +-- DB_UPDATE_VERSION 1509 -- ------------------------------------------ diff --git a/src/Database/DBStructure.php b/src/Database/DBStructure.php index 7b284bf6d5..c0bd005d1e 100644 --- a/src/Database/DBStructure.php +++ b/src/Database/DBStructure.php @@ -74,7 +74,7 @@ class DBStructure $old_tables = ['fserver', 'gcign', 'gcontact', 'gcontact-relation', 'gfollower' ,'glink', 'item-delivery-data', 'item-activity', 'item-content', 'item_id', 'participation', 'poll', 'poll_result', 'queue', 'retriever_rule', 'deliverq', 'dsprphotoq', 'ffinder', 'sign', 'spam', 'term', 'user-item', 'thread', 'item', 'challenge', - 'auth_codes', 'tokens', 'clients', 'profile_check', 'host', 'conversation', 'fcontact', 'config']; + 'auth_codes', 'tokens', 'clients', 'profile_check', 'host', 'conversation', 'fcontact', 'config', 'addon']; $tables = DBA::selectToArray('INFORMATION_SCHEMA.TABLES', ['TABLE_NAME'], ['TABLE_SCHEMA' => DBA::databaseName(), 'TABLE_TYPE' => 'BASE TABLE']); diff --git a/static/dbstructure.config.php b/static/dbstructure.config.php index 018bbf2c31..848da04040 100644 --- a/static/dbstructure.config.php +++ b/static/dbstructure.config.php @@ -55,7 +55,7 @@ use Friendica\Database\DBA; if (!defined('DB_UPDATE_VERSION')) { - define('DB_UPDATE_VERSION', 1508); + define('DB_UPDATE_VERSION', 1509); } return [ diff --git a/update.php b/update.php index 1dbf78e06f..584b8d788c 100644 --- a/update.php +++ b/update.php @@ -1192,5 +1192,23 @@ function update_1508() $newConfig->commit(); - DBA::e("TRUNCATE TABLE `config`"); + return DBA::e("TRUNCATE TABLE `config`") ? Update::SUCCESS : Update::FAILED; +} + +function update_1509() +{ + $addons = DBA::selectToArray('addon'); + + $newConfig = DI::config()->beginTransaction(); + + foreach ($addons as $addon) { + $newConfig->set('addons', $addon['name'], [ + 'last_update' => $addon['timestamp'], + 'admin' => (bool)$addon['plugin_admin'], + ]); + } + + $newConfig->commit(); + + return DBA::e("TRUNCATE TABLE `addon`") ? Update::SUCCESS : Update::FAILED; } From 13b234d279a7de89c718c446a85238bff7d873ca Mon Sep 17 00:00:00 2001 From: Philipp Date: Tue, 3 Jan 2023 20:24:48 +0100 Subject: [PATCH 2/4] Use addons config entries instead of the addon table --- src/Core/Addon.php | 52 ++++--- .../Config/Capability/IManageConfigValues.php | 6 +- src/Core/Config/Model/Config.php | 2 +- src/Core/L10n.php | 11 +- static/settings.config.php | 4 - tests/src/Core/Config/Cache/CacheTest.php | 129 ++++++++++++++++++ tests/src/Core/Config/ConfigTest.php | 129 ++++++++++++++++++ 7 files changed, 294 insertions(+), 39 deletions(-) diff --git a/src/Core/Addon.php b/src/Core/Addon.php index cea814f320..be3e70a540 100644 --- a/src/Core/Addon.php +++ b/src/Core/Addon.php @@ -21,7 +21,6 @@ namespace Friendica\Core; -use Friendica\Database\DBA; use Friendica\DI; use Friendica\Model\Contact; use Friendica\Util\Strings; @@ -85,15 +84,18 @@ class Addon public static function getAdminList() { $addons_admin = []; - $addonsAdminStmt = DBA::select('addon', ['name'], ['plugin_admin' => 1], ['order' => ['name']]); - while ($addon = DBA::fetch($addonsAdminStmt)) { - $addons_admin[$addon['name']] = [ - 'url' => 'admin/addons/' . $addon['name'], - 'name' => $addon['name'], + $addons = DI::config()->get('addons'); + foreach ($addons as $name => $data) { + if (empty($data['admin'])) { + continue; + } + + $addons_admin[$name] = [ + 'url' => 'admin/addons/' . $name, + 'name' => $name, 'class' => 'addon' ]; } - DBA::close($addonsAdminStmt); return $addons_admin; } @@ -113,8 +115,7 @@ class Addon */ public static function loadAddons() { - $installed_addons = DBA::selectToArray('addon', ['name'], ['installed' => true]); - self::$addons = array_column($installed_addons, 'name'); + self::$addons = array_keys(DI::config()->get('addons') ?? []); } /** @@ -129,7 +130,7 @@ class Addon $addon = Strings::sanitizeFilePathItem($addon); Logger::debug("Addon {addon}: {action}", ['action' => 'uninstall', 'addon' => $addon]); - DBA::delete('addon', ['name' => $addon]); + DI::config()->delete('addons', $addon); @include_once('addon/' . $addon . '/' . $addon . '.php'); if (function_exists($addon . '_uninstall')) { @@ -168,12 +169,9 @@ class Addon $func(DI::app()); } - DBA::insert('addon', [ - 'name' => $addon, - 'installed' => true, - 'timestamp' => $t, - 'plugin_admin' => function_exists($addon . '_addon_admin'), - 'hidden' => file_exists('addon/' . $addon . '/.hidden') + DI::config()->set('addons', $addon,[ + 'last_update' => $t, + 'admin' => function_exists($addon . '_addon_admin'), ]); if (!self::isEnabled($addon)) { @@ -190,20 +188,20 @@ class Addon */ public static function reload() { - $addons = DBA::selectToArray('addon', [], ['installed' => true]); + $addons = DI::config()->get('addons'); - foreach ($addons as $addon) { - $addonname = Strings::sanitizeFilePathItem(trim($addon['name'])); + foreach ($addons as $name => $data) { + $addonname = Strings::sanitizeFilePathItem(trim($name)); $addon_file_path = 'addon/' . $addonname . '/' . $addonname . '.php'; - if (file_exists($addon_file_path) && $addon['timestamp'] == filemtime($addon_file_path)) { + if (file_exists($addon_file_path) && $data['last_update'] == filemtime($addon_file_path)) { // Addon unmodified, skipping continue; } - Logger::debug("Addon {addon}: {action}", ['action' => 'reload', 'addon' => $addon['name']]); + Logger::debug("Addon {addon}: {action}", ['action' => 'reload', 'addon' => $name]); - self::uninstall($addon['name']); - self::install($addon['name']); + self::uninstall($name); + self::install($name); } } @@ -313,11 +311,9 @@ class Addon public static function getVisibleList(): array { $visible_addons = []; - $stmt = DBA::select('addon', ['name'], ['hidden' => false, 'installed' => true]); - if (DBA::isResult($stmt)) { - foreach (DBA::toArray($stmt) as $addon) { - $visible_addons[] = $addon['name']; - } + $addons = DI::config()->get('addons'); + foreach ($addons as $name => $data) { + $visible_addons[] = $name; } return $visible_addons; diff --git a/src/Core/Config/Capability/IManageConfigValues.php b/src/Core/Config/Capability/IManageConfigValues.php index 715887ddf3..09e2cd9144 100644 --- a/src/Core/Config/Capability/IManageConfigValues.php +++ b/src/Core/Config/Capability/IManageConfigValues.php @@ -47,8 +47,8 @@ interface IManageConfigValues * * Get a particular config value from the given category ($cat) * - * @param string $cat The category of the configuration value - * @param string $key The configuration key to query + * @param string $cat The category of the configuration value + * @param ?string $key The configuration key to query (if null, the whole array at the category will get returned) * @param mixed $default_value Deprecated, use `Config->get($cat, $key, null, $refresh) ?? $default_value` instead * * @return mixed Stored value or null if it does not exist @@ -56,7 +56,7 @@ interface IManageConfigValues * @throws ConfigPersistenceException In case the persistence layer throws errors * */ - public function get(string $cat, string $key, $default_value = null); + public function get(string $cat, string $key = null, $default_value = null); /** * Load all configuration values from a given cache and saves it back in the configuration node store diff --git a/src/Core/Config/Model/Config.php b/src/Core/Config/Model/Config.php index 29ea6b12d3..593ab04070 100644 --- a/src/Core/Config/Model/Config.php +++ b/src/Core/Config/Model/Config.php @@ -102,7 +102,7 @@ class Config implements IManageConfigValues } /** {@inheritDoc} */ - public function get(string $cat, string $key, $default_value = null) + public function get(string $cat, string $key = null, $default_value = null) { return $this->configCache->get($cat, $key) ?? $default_value; } diff --git a/src/Core/L10n.php b/src/Core/L10n.php index 0a91677b5d..3f74a40849 100644 --- a/src/Core/L10n.php +++ b/src/Core/L10n.php @@ -85,10 +85,15 @@ class L10n * @var Database */ private $dba; + /** + * @var IManageConfigValues + */ + private $config; public function __construct(IManageConfigValues $config, Database $dba, IHandleSessions $session, array $server, array $get) { $this->dba = $dba; + $this->config = $config; $this->loadTranslationTable(L10n::detectLanguage($server, $get, $config->get('system', 'language', self::DEFAULT))); $this->setSessionVariable($session); @@ -157,9 +162,9 @@ class L10n $a->strings = []; // load enabled addons strings - $addons = $this->dba->select('addon', ['name'], ['installed' => true]); - while ($p = $this->dba->fetch($addons)) { - $name = Strings::sanitizeFilePathItem($p['name']); + $addons = array_keys($this->config->get('addons') ?? []); + foreach ($addons as $addon) { + $name = Strings::sanitizeFilePathItem($addon); if (file_exists(__DIR__ . "/../../addon/$name/lang/$lang/strings.php")) { include __DIR__ . "/../../addon/$name/lang/$lang/strings.php"; } diff --git a/static/settings.config.php b/static/settings.config.php index c7d4b6a9c2..04994bc73e 100644 --- a/static/settings.config.php +++ b/static/settings.config.php @@ -52,10 +52,6 @@ return [ // Enter 0 for no time limit. 'account_abandon_days' => 0, - // addon (Comma-separated list) - // Manual list of addons which are enabled on this system. - 'addon' => '', - // add_missing_posts (boolean) // Checks for missing entries in "post", "post-thread" or "post-thread-user" and creates them 'add_missing_posts' => false, diff --git a/tests/src/Core/Config/Cache/CacheTest.php b/tests/src/Core/Config/Cache/CacheTest.php index 2db6196b7b..024c9c7e3e 100644 --- a/tests/src/Core/Config/Cache/CacheTest.php +++ b/tests/src/Core/Config/Cache/CacheTest.php @@ -410,4 +410,133 @@ class CacheTest extends MockedTest // the newCache entry wasn't set, because we Diff self::assertNull($mergedCache->get('system', 'test_3')); } + + public function dataTestCat() + { + return [ + 'test_with_hashmap' => [ + 'data' => [ + 'test_with_hashmap' => [ + 'notifyall' => [ + 'last_update' => 1671051565, + 'admin' => true, + ], + 'blockbot' => [ + 'last_update' => 1658952852, + 'admin' => true, + ], + ], + 'config' => [ + 'register_policy' => 2, + 'register_text' => '', + 'sitename' => 'Friendica Social Network23', + 'hostname' => 'friendica.local', + 'private_addons' => false, + ], + 'system' => [ + 'dbclean_expire_conversation' => 90, + ], + ], + 'cat' => 'test_with_hashmap', + 'assertion' => [ + 'notifyall' => [ + 'last_update' => 1671051565, + 'admin' => true, + ], + 'blockbot' => [ + 'last_update' => 1658952852, + 'admin' => true, + ], + ], + ], + 'test_with_keys' => [ + 'data' => [ + 'test_with_keys' => [ + [ + 'last_update' => 1671051565, + 'admin' => true, + ], + [ + 'last_update' => 1658952852, + 'admin' => true, + ], + ], + 'config' => [ + 'register_policy' => 2, + 'register_text' => '', + 'sitename' => 'Friendica Social Network23', + 'hostname' => 'friendica.local', + 'private_addons' => false, + ], + 'system' => [ + 'dbclean_expire_conversation' => 90, + ], + ], + 'cat' => 'test_with_keys', + 'assertion' => [ + [ + 'last_update' => 1671051565, + 'admin' => true, + ], + [ + 'last_update' => 1658952852, + 'admin' => true, + ], + ], + ], + 'test_with_inner_array' => [ + 'data' => [ + 'test_with_inner_array' => [ + 'notifyall' => [ + 'last_update' => 1671051565, + 'admin' => [ + 'yes' => true, + 'no' => 1.5, + ], + ], + 'blogbot' => [ + 'last_update' => 1658952852, + 'admin' => true, + ], + ], + 'config' => [ + 'register_policy' => 2, + 'register_text' => '', + 'sitename' => 'Friendica Social Network23', + 'hostname' => 'friendica.local', + 'private_addons' => false, + ], + 'system' => [ + 'dbclean_expire_conversation' => 90, + ], + ], + 'cat' => 'test_with_inner_array', + 'assertion' => [ + 'notifyall' => [ + 'last_update' => 1671051565, + 'admin' => [ + 'yes' => true, + 'no' => 1.5, + ], + ], + 'blogbot' => [ + 'last_update' => 1658952852, + 'admin' => true, + ], + ], + ], + ]; + } + + /** + * Tests that the Cache can return a whole category at once + * + * @dataProvider dataTestCat + */ + public function testGetCategory(array $data, string $category, array $assertion) + { + $cache = new Cache($data); + + self::assertEquals($assertion, $cache->get($category)); + } } diff --git a/tests/src/Core/Config/ConfigTest.php b/tests/src/Core/Config/ConfigTest.php index c85cf3f708..876a0b05b3 100644 --- a/tests/src/Core/Config/ConfigTest.php +++ b/tests/src/Core/Config/ConfigTest.php @@ -403,4 +403,133 @@ class ConfigTest extends MockedTest self::assertFalse($this->testedConfig->set('config', 'test', '123')); self::assertEquals('prio', $this->testedConfig->get('config', 'test', '', true)); } + + + public function dataTestCat() + { + return [ + 'test_with_hashmap' => [ + 'data' => [ + 'test_with_hashmap' => [ + 'notifyall' => [ + 'last_update' => 1671051565, + 'admin' => true, + ], + 'blockbot' => [ + 'last_update' => 1658952852, + 'admin' => true, + ], + ], + 'config' => [ + 'register_policy' => 2, + 'register_text' => '', + 'sitename' => 'Friendica Social Network23', + 'hostname' => 'friendica.local', + 'private_addons' => false, + ], + 'system' => [ + 'dbclean_expire_conversation' => 90, + ], + ], + 'cat' => 'test_with_hashmap', + 'assertion' => [ + 'notifyall' => [ + 'last_update' => 1671051565, + 'admin' => true, + ], + 'blockbot' => [ + 'last_update' => 1658952852, + 'admin' => true, + ], + ], + ], + 'test_with_keys' => [ + 'data' => [ + 'test_with_keys' => [ + [ + 'last_update' => 1671051565, + 'admin' => true, + ], + [ + 'last_update' => 1658952852, + 'admin' => true, + ], + ], + 'config' => [ + 'register_policy' => 2, + 'register_text' => '', + 'sitename' => 'Friendica Social Network23', + 'hostname' => 'friendica.local', + 'private_addons' => false, + ], + 'system' => [ + 'dbclean_expire_conversation' => 90, + ], + ], + 'cat' => 'test_with_keys', + 'assertion' => [ + [ + 'last_update' => 1671051565, + 'admin' => true, + ], + [ + 'last_update' => 1658952852, + 'admin' => true, + ], + ], + ], + 'test_with_inner_array' => [ + 'data' => [ + 'test_with_inner_array' => [ + 'notifyall' => [ + 'last_update' => 1671051565, + 'admin' => [ + 'yes' => true, + 'no' => 1.5, + ], + ], + 'blogbot' => [ + 'last_update' => 1658952852, + 'admin' => true, + ], + ], + 'config' => [ + 'register_policy' => 2, + 'register_text' => '', + 'sitename' => 'Friendica Social Network23', + 'hostname' => 'friendica.local', + 'private_addons' => false, + ], + 'system' => [ + 'dbclean_expire_conversation' => 90, + ], + ], + 'cat' => 'test_with_inner_array', + 'assertion' => [ + 'notifyall' => [ + 'last_update' => 1671051565, + 'admin' => [ + 'yes' => true, + 'no' => 1.5, + ], + ], + 'blogbot' => [ + 'last_update' => 1658952852, + 'admin' => true, + ], + ], + ], + ]; + } + + /** + * @dataProvider dataTestCat + */ + public function testGetCategory(array $data, string $category, array $assertion) + { + $this->configCache = new Cache($data); + $config = new Config($this->configFileManager, $this->configCache); + + self::assertEquals($assertion, $config->get($category)); + } } From 01403d15c4ac402ba8b0b5eb084573331275c092 Mon Sep 17 00:00:00 2001 From: Philipp Date: Wed, 4 Jan 2023 01:05:02 +0100 Subject: [PATCH 3/4] sort addon array --- src/Core/Addon.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Core/Addon.php b/src/Core/Addon.php index be3e70a540..419fb4bd9b 100644 --- a/src/Core/Addon.php +++ b/src/Core/Addon.php @@ -85,6 +85,7 @@ class Addon { $addons_admin = []; $addons = DI::config()->get('addons'); + ksort($addons); foreach ($addons as $name => $data) { if (empty($data['admin'])) { continue; From 4b17d6f3bfecadb35e3148589386a55e94b77356 Mon Sep 17 00:00:00 2001 From: Philipp Date: Wed, 4 Jan 2023 23:12:41 +0100 Subject: [PATCH 4/4] Update src/Core/Addon.php Co-authored-by: Hypolite Petovan --- src/Core/Addon.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Core/Addon.php b/src/Core/Addon.php index 419fb4bd9b..ef2289ca59 100644 --- a/src/Core/Addon.php +++ b/src/Core/Addon.php @@ -170,7 +170,7 @@ class Addon $func(DI::app()); } - DI::config()->set('addons', $addon,[ + DI::config()->set('addons', $addon, [ 'last_update' => $t, 'admin' => function_exists($addon . '_addon_admin'), ]);