From d17a21601c7153d9517230bc94078f24ba2f0ac6 Mon Sep 17 00:00:00 2001 From: Philipp Date: Mon, 16 Jan 2023 21:12:47 +0100 Subject: [PATCH 01/53] Add Dice.php patch --- composer.json | 11 ++- composer.lock | 96 +++++++++++++++++++++++- mods/patches/level-2-dice-dice-php.patch | 10 +++ 3 files changed, 115 insertions(+), 2 deletions(-) create mode 100644 mods/patches/level-2-dice-dice-php.patch diff --git a/composer.json b/composer.json index c6746c1231..aab60ee5c6 100644 --- a/composer.json +++ b/composer.json @@ -28,6 +28,7 @@ "ext-xml": "*", "asika/simple-console": "^1.0", "bacon/bacon-qr-code": "^2.0.0", + "cweagans/composer-patches": "^1.7", "divineomega/password_exposed": "^2.8", "ezyang/htmlpurifier": "^4.7", "friendica/json-ld": "^1.0", @@ -126,7 +127,8 @@ "mockery/mockery": "^1.3", "mikey179/vfsstream": "^1.6", "phpunit/phpunit": "^9", - "dms/phpunit-arraysubset-asserts": "^0.3.1" + "dms/phpunit-arraysubset-asserts": "^0.3.1", + "symplify/vendor-patches": "11.2.0.72" }, "scripts": { "test": "phpunit", @@ -134,5 +136,12 @@ "cs:install": "@composer install --working-dir=bin/dev/php-cs-fixer", "cs:check": ["@cs:install", "bin/dev/php-cs-fixer/vendor/bin/php-cs-fixer fix --dry-run --diff"], "cs:fix": ["@cs:install", "bin/dev/php-cs-fixer/vendor/bin/php-cs-fixer fix"] + }, + "extra": { + "patches": { + "level-2/dice": [ + "mods/patches/level-2-dice-dice-php.patch" + ] + } } } diff --git a/composer.lock b/composer.lock index 63f8a0d5b0..aa3f7eed3f 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "5af9ac9003f4653f3aa1860dd5a4d821", + "content-hash": "0bbc4011b7628c0d563f80f361e98cdd", "packages": [ { "name": "asika/simple-console", @@ -368,6 +368,50 @@ ], "time": "2022-07-20T07:14:26+00:00" }, + { + "name": "cweagans/composer-patches", + "version": "1.7.3", + "source": { + "type": "git", + "url": "https://github.com/cweagans/composer-patches.git", + "reference": "e190d4466fe2b103a55467dfa83fc2fecfcaf2db" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/cweagans/composer-patches/zipball/e190d4466fe2b103a55467dfa83fc2fecfcaf2db", + "reference": "e190d4466fe2b103a55467dfa83fc2fecfcaf2db", + "shasum": "" + }, + "require": { + "composer-plugin-api": "^1.0 || ^2.0", + "php": ">=5.3.0" + }, + "require-dev": { + "composer/composer": "~1.0 || ~2.0", + "phpunit/phpunit": "~4.6" + }, + "type": "composer-plugin", + "extra": { + "class": "cweagans\\Composer\\Patches" + }, + "autoload": { + "psr-4": { + "cweagans\\Composer\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Cameron Eagans", + "email": "me@cweagans.net" + } + ], + "description": "Provides a way to patch Composer packages.", + "time": "2022-12-20T22:53:13+00:00" + }, { "name": "dasprid/enum", "version": "1.0.3", @@ -666,6 +710,7 @@ "x509", "x690" ], + "abandoned": true, "time": "2021-12-11T12:41:06+00:00" }, { @@ -1263,6 +1308,11 @@ "phpunit/phpunit": "^6.5" }, "type": "library", + "extra": { + "patches_applied": [ + "mods/patches/level-2-dice-dice-php.patch" + ] + }, "autoload": { "psr-4": { "Dice\\": "./" @@ -6368,6 +6418,50 @@ ], "time": "2020-09-28T06:39:44+00:00" }, + { + "name": "symplify/vendor-patches", + "version": "11.2.0.72", + "source": { + "type": "git", + "url": "https://github.com/symplify/vendor-patches.git", + "reference": "83204e1a7a33ca958f9d1cc9c3b1b25f75270775" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symplify/vendor-patches/zipball/83204e1a7a33ca958f9d1cc9c3b1b25f75270775", + "reference": "83204e1a7a33ca958f9d1cc9c3b1b25f75270775", + "shasum": "" + }, + "require": { + "cweagans/composer-patches": "^1.7", + "php": ">=7.2" + }, + "bin": [ + "bin/vendor-patches" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "10.3-dev" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Generate vendor patches for packages with single command", + "funding": [ + { + "url": "https://www.paypal.me/rectorphp", + "type": "custom" + }, + { + "url": "https://github.com/tomasvotruba", + "type": "github" + } + ], + "time": "2023-01-11T09:41:31+00:00" + }, { "name": "theseer/tokenizer", "version": "1.2.1", diff --git a/mods/patches/level-2-dice-dice-php.patch b/mods/patches/level-2-dice-dice-php.patch new file mode 100644 index 0000000000..5319804cf5 --- /dev/null +++ b/mods/patches/level-2-dice-dice-php.patch @@ -0,0 +1,10 @@ +--- /dev/null ++++ ../Dice.php +@@ -257,6 +257,7 @@ + for ($i = 0; $i < count($args); $i++) { + if (call_user_func('is_' . $param->getType()->getName(), $args[$i])) { + $parameters[] = array_splice($args, $i, 1)[0]; ++ break; + } + } + } From f609e38600f54fe8465d1194008d823103f41baa Mon Sep 17 00:00:00 2001 From: Philipp Date: Sun, 15 Jan 2023 22:31:19 +0100 Subject: [PATCH 02/53] Introduce new Hook logic - InstanceManager for computing strategies and to allow decorators - Adapting Core\Logger to use it --- src/Core/Hooks/Capabilities/IAmAStrategy.php | 29 ++ .../Capabilities/ICanManageInstances.php | 81 ++++++ .../Exceptions/HookInstanceException.php | 30 ++ .../HookRegisterArgumentException.php | 30 ++ src/Core/Hooks/Model/InstanceManager.php | 104 +++++++ .../Exception/LoggerInvalidException.php | 32 +++ src/Core/Logger/Factory/Logger.php | 188 +++---------- src/Core/Logger/Type/StreamLogger.php | 12 +- src/Core/Logger/Type/SyslogLogger.php | 13 +- src/Database/Database.php | 26 +- static/dependencies.config.php | 8 + tests/Util/CreateDatabaseTrait.php | 3 +- .../Util/Hooks/InstanceMocks/FakeInstance.php | 60 ++++ .../InstanceMocks/FakeInstanceDecorator.php | 59 ++++ .../InstanceMocks/IAmADecoratedInterface.php | 33 +++ tests/functional/DependencyCheckTest.php | 20 +- tests/src/Core/Cache/DatabaseCacheTest.php | 2 +- .../Core/Hooks/Model/InstanceManagerTest.php | 258 ++++++++++++++++++ tests/src/Core/Logger/AbstractLoggerTest.php | 7 + tests/src/Core/Logger/StreamLoggerTest.php | 68 ++--- tests/src/Core/Logger/SyslogLoggerTest.php | 12 +- tests/src/Core/Logger/SyslogLoggerWrapper.php | 5 +- 22 files changed, 844 insertions(+), 236 deletions(-) create mode 100644 src/Core/Hooks/Capabilities/IAmAStrategy.php create mode 100644 src/Core/Hooks/Capabilities/ICanManageInstances.php create mode 100644 src/Core/Hooks/Exceptions/HookInstanceException.php create mode 100644 src/Core/Hooks/Exceptions/HookRegisterArgumentException.php create mode 100644 src/Core/Hooks/Model/InstanceManager.php create mode 100644 src/Core/Logger/Exception/LoggerInvalidException.php create mode 100644 tests/Util/Hooks/InstanceMocks/FakeInstance.php create mode 100644 tests/Util/Hooks/InstanceMocks/FakeInstanceDecorator.php create mode 100644 tests/Util/Hooks/InstanceMocks/IAmADecoratedInterface.php create mode 100644 tests/src/Core/Hooks/Model/InstanceManagerTest.php diff --git a/src/Core/Hooks/Capabilities/IAmAStrategy.php b/src/Core/Hooks/Capabilities/IAmAStrategy.php new file mode 100644 index 0000000000..a830d912c0 --- /dev/null +++ b/src/Core/Hooks/Capabilities/IAmAStrategy.php @@ -0,0 +1,29 @@ +. + * + */ + +namespace Friendica\Core\Hooks\Capabilities; + +/** + * All interfaces, marking this interface are valid Strategies for Hook calls + */ +interface IAmAStrategy +{ +} diff --git a/src/Core/Hooks/Capabilities/ICanManageInstances.php b/src/Core/Hooks/Capabilities/ICanManageInstances.php new file mode 100644 index 0000000000..08802a08e6 --- /dev/null +++ b/src/Core/Hooks/Capabilities/ICanManageInstances.php @@ -0,0 +1,81 @@ +. + * + */ + +namespace Friendica\Core\Hooks\Capabilities; + +use Friendica\Core\Hooks\Exceptions\HookInstanceException; +use Friendica\Core\Hooks\Exceptions\HookRegisterArgumentException; + +/** + * Managing special instance and decorator treatments for classes + */ +interface ICanManageInstances +{ + /** + * Register a class(strategy) for a given interface with a unique name. + * + * @see https://refactoring.guru/design-patterns/strategy + * + * @param string $interface The interface, which the given class implements + * @param string $name The name of the given class, which will be used for factories, dependency injections etc. + * @param string $class The class of the given class + * @param ?array $arguments Additional arguments, which can be passed to the constructor + * + * @return $this This interface for chain-calls + * + * @throws HookRegisterArgumentException in case the given class for the interface isn't valid or already set + */ + public function registerStrategy(string $interface, string $name, string $class, array $arguments = null): self; + + /** + * Register a new decorator for a given class or interface + * @see https://refactoring.guru/design-patterns/decorator + * + * @note Decorator attach new behaviors to classes without changing them or without letting them know about it. + * + * @param string $class The class or interface, which gets decorated by a class + * @param string $decoratorClass The class, which mimics the given class or interface and adds new functionality + * @param array $arguments Additional arguments, which can be passed to the constructor of "decoratorClass" + * + * @return $this This interface for chain-calls + * + * @throws HookRegisterArgumentException in case the given class for the class or interface isn't valid + */ + public function registerDecorator(string $class, string $decoratorClass, array $arguments = []): self; + + /** + * Returns a new instance of a given class for the corresponding name + * + * The instance will be build based on the registered strategy and the (unique) name + * + * In case, there are registered decorators for this class as well, all decorators of the list will be wrapped + * around the instance before returning it + * + * @param string $class A given class or interface, which will get returned + * @param string $name The name of the concrete class, wich + * @param array $arguments Additional arguments, which can be passed to the constructor of "$class" at runtime + * + * @return object The concrete instance of the type "$class" + * + * @throws HookInstanceException In case the class cannot get created + */ + public function getInstance(string $class, string $name, array $arguments = []): object; +} diff --git a/src/Core/Hooks/Exceptions/HookInstanceException.php b/src/Core/Hooks/Exceptions/HookInstanceException.php new file mode 100644 index 0000000000..bda8e7c8fb --- /dev/null +++ b/src/Core/Hooks/Exceptions/HookInstanceException.php @@ -0,0 +1,30 @@ +. + * + */ + +namespace Friendica\Core\Hooks\Exceptions; + +class HookInstanceException extends \RuntimeException +{ + public function __construct($message = "", \Throwable $previous = null) + { + parent::__construct($message, 500, $previous); + } +} diff --git a/src/Core/Hooks/Exceptions/HookRegisterArgumentException.php b/src/Core/Hooks/Exceptions/HookRegisterArgumentException.php new file mode 100644 index 0000000000..799c4294be --- /dev/null +++ b/src/Core/Hooks/Exceptions/HookRegisterArgumentException.php @@ -0,0 +1,30 @@ +. + * + */ + +namespace Friendica\Core\Hooks\Exceptions; + +class HookRegisterArgumentException extends \RuntimeException +{ + public function __construct($message = "", \Throwable $previous = null) + { + parent::__construct($message, 500, $previous); + } +} diff --git a/src/Core/Hooks/Model/InstanceManager.php b/src/Core/Hooks/Model/InstanceManager.php new file mode 100644 index 0000000000..4b8a0e6de8 --- /dev/null +++ b/src/Core/Hooks/Model/InstanceManager.php @@ -0,0 +1,104 @@ +. + * + */ + +namespace Friendica\Core\Hooks\Model; + +use Dice\Dice; +use Friendica\Core\Hooks\Capabilities\IAmAStrategy; +use Friendica\Core\Hooks\Capabilities\ICanManageInstances; +use Friendica\Core\Hooks\Exceptions\HookInstanceException; +use Friendica\Core\Hooks\Exceptions\HookRegisterArgumentException; + +/** {@inheritDoc} */ +class InstanceManager implements ICanManageInstances +{ + protected $instance = []; + protected $instanceArguments = []; + protected $decorator = []; + + /** @var Dice */ + protected $dice; + + public function __construct(Dice $dice) + { + $this->dice = $dice; + } + + /** {@inheritDoc} */ + public function registerStrategy(string $interface, string $name, string $class, array $arguments = null): ICanManageInstances + { + if (!is_a($class, $interface, true)) { + throw new HookRegisterArgumentException(sprintf('%s is not a valid class for the interface %s', $class, $interface)); + } + + if (!is_a($class, IAmAStrategy::class, true)) { + throw new HookRegisterArgumentException(sprintf('%s does not inherit from the marker interface %s', $class, IAmAStrategy::class)); + } + + if (!empty($this->instance[$interface][$name])) { + throw new HookRegisterArgumentException(sprintf('A class with the name %s is already set for the interface %s', $name, $interface)); + } + + $this->instance[$interface][$name] = $class; + $this->instanceArguments[$interface][$name] = $arguments; + + return $this; + } + + /** {@inheritDoc} */ + public function registerDecorator(string $class, string $decoratorClass, array $arguments = []): ICanManageInstances + { + if (!is_a($decoratorClass, $class, true)) { + throw new HookRegisterArgumentException(sprintf('%s is not a valid subsituation for the given class or interface %s', $decoratorClass, $class)); + } + + $this->decorator[$class][] = [ + 'class' => $decoratorClass, + 'arguments' => $arguments, + ]; + + return $this; + } + + /** {@inheritDoc} */ + public function getInstance(string $class, string $name, array $arguments = []): object + { + if (empty($this->instance[$class][$name])) { + throw new HookInstanceException(sprintf('The class with the name %s isn\'t registered for the class or interface %s', $name, $class)); + } + + $instance = $this->dice->create($this->instance[$class][$name], array_merge($this->instanceArguments[$class][$name] ?? [], $arguments)); + + foreach ($this->decorator[$class] ?? [] as $decorator) { + $this->dice = $this->dice->addRule($class, [ + 'instanceOf' => $decorator['class'], + 'constructParams' => empty($decorator['arguments']) ? null : $decorator['arguments'], + /// @todo maybe support call structures for hooks as well in a later stage - could make factory calls easier + 'call' => null, + 'substitutions' => [$class => $instance], + ]); + + $instance = $this->dice->create($class); + } + + return $instance; + } +} diff --git a/src/Core/Logger/Exception/LoggerInvalidException.php b/src/Core/Logger/Exception/LoggerInvalidException.php new file mode 100644 index 0000000000..db6ecb78c5 --- /dev/null +++ b/src/Core/Logger/Exception/LoggerInvalidException.php @@ -0,0 +1,32 @@ +. + * + */ + +namespace Friendica\Core\Logger\Exception; + +use Throwable; + +class LoggerInvalidException extends \RuntimeException +{ + public function __construct($message = "", Throwable $previous = null) + { + parent::__construct($message, 500, $previous); + } +} diff --git a/src/Core/Logger/Factory/Logger.php b/src/Core/Logger/Factory/Logger.php index 3dd2a81dc2..2821a813c2 100644 --- a/src/Core/Logger/Factory/Logger.php +++ b/src/Core/Logger/Factory/Logger.php @@ -22,16 +22,11 @@ namespace Friendica\Core\Logger\Factory; use Friendica\Core\Config\Capability\IManageConfigValues; -use Friendica\Core; -use Friendica\Core\Logger\Capabilities\IHaveCallIntrospections; +use Friendica\Core\Hooks\Capabilities\ICanManageInstances; use Friendica\Core\Logger\Exception\LogLevelException; -use Friendica\Database\Database; -use Friendica\Network\HTTPException\InternalServerErrorException; -use Friendica\Util\FileSystem; use Friendica\Core\Logger\Type\ProfilerLogger; use Friendica\Core\Logger\Type\StreamLogger; use Friendica\Core\Logger\Type\SyslogLogger; -use Friendica\Util\Profiler; use Psr\Log\LoggerInterface; use Psr\Log\LogLevel; use Psr\Log\NullLogger; @@ -44,115 +39,55 @@ class Logger const DEV_CHANNEL = 'dev'; /** @var string The log-channel (app, worker, ...) */ - private $channel; + protected $channel; + /** @var ICanManageInstances */ + protected $instanceManager; + /** @var IManageConfigValues */ + protected $config; - public function __construct(string $channel, bool $includeAddon = true) + public function __construct(string $channel, ICanManageInstances $instanceManager, IManageConfigValues $config, string $logfile = null) { - $this->channel = $channel; + $this->channel = $channel; + $this->instanceManager = $instanceManager; + $this->config = $config; - /// @fixme clean solution = Making Addon & Hook dynamic and load them inside the constructor, so there's no custom load logic necessary anymore - if ($includeAddon) { - Core\Addon::loadAddons(); - Core\Hook::loadHooks(); + $this->instanceManager + ->registerStrategy(LoggerInterface::class, 'syslog', SyslogLogger::class) + ->registerStrategy(LoggerInterface::class, 'stream', StreamLogger::class, isset($logfile) ? [$logfile] : null); + + if ($this->config->get('system', 'profiling') ?? false) { + $this->instanceManager->registerDecorator(LoggerInterface::class, ProfilerLogger::class); } } /** * Creates a new PSR-3 compliant logger instances * - * @param Database $database The Friendica Database instance - * @param IManageConfigValues $config The config - * @param Profiler $profiler The profiler of the app - * @param FileSystem $fileSystem FileSystem utils - * @param string|null $minLevel (optional) Override minimum Loglevel to log + * @param string|null $loglevel (optional) A given loglevel in case the loglevel in the config isn't applicable * * @return LoggerInterface The PSR-3 compliant logger instance */ - public function create(Database $database, IManageConfigValues $config, Profiler $profiler, FileSystem $fileSystem, IHaveCallIntrospections $introspection, ?string $minLevel = null): LoggerInterface + public function create(string $loglevel = null): LoggerInterface { - if (empty($config->get('system', 'debugging', false))) { - $logger = new NullLogger(); - $database->setLogger($logger); + if (empty($this->config->get('system', 'debugging') ?? false)) { + return new NullLogger(); + } + + $loglevel = $loglevel ?? static::mapLegacyConfigDebugLevel($this->config->get('system', 'loglevel')); + $name = $this->config->get('system', 'logger_config') ?? 'stream'; + + try { + /** @var LoggerInterface */ + return $this->instanceManager->getInstance(LoggerInterface::class, $name, [$this->channel, $loglevel]); + } catch (LogLevelException $exception) { + // If there's a wrong config value for loglevel, try again with standard + $logger = $this->create(LogLevel::NOTICE); + $logger->warning('Invalid loglevel set in config.', ['loglevel' => $loglevel]); return $logger; + } catch (\Throwable $e) { + // No logger ... + return new NullLogger(); } - - $minLevel = $minLevel ?? $config->get('system', 'loglevel'); - $loglevel = self::mapLegacyConfigDebugLevel((string)$minLevel); - - $name = $config->get('system', 'logger_config', 'stream'); - - switch ($name) { - case 'syslog': - try { - $logger = new SyslogLogger($this->channel, $introspection, $loglevel, $config->get('system', 'syslog_flags', SyslogLogger::DEFAULT_FLAGS), $config->get('system', 'syslog_facility', SyslogLogger::DEFAULT_FACILITY)); - } catch (LogLevelException $exception) { - // If there's a wrong config value for loglevel, try again with standard - $logger = $this->create($database, $config, $profiler, $fileSystem, $introspection, LogLevel::NOTICE); - $logger->warning('Invalid loglevel set in config.', ['loglevel' => $loglevel]); - } catch (\Throwable $e) { - // No logger ... - $logger = new NullLogger(); - } - break; - - case 'stream': - default: - $data = [ - 'name' => $name, - 'channel' => $this->channel, - 'introspection' => $introspection, - 'loglevel' => $loglevel, - 'logger' => null, - ]; - try { - Core\Hook::callAll('logger_instance', $data); - } catch (InternalServerErrorException $exception) { - $data['logger'] = null; - } - - if (($data['logger'] ?? null) instanceof LoggerInterface) { - $logger = $data['logger']; - } - - if (empty($logger)) { - $stream = $config->get('system', 'logfile'); - // just add a stream in case it's either writable or not file - if (!is_file($stream) || is_writable($stream)) { - try { - $logger = new StreamLogger($this->channel, $stream, $introspection, $fileSystem, $loglevel); - } catch (LogLevelException $exception) { - // If there's a wrong config value for loglevel, try again with standard - $logger = $this->create($database, $config, $profiler, $fileSystem, $introspection, LogLevel::NOTICE); - $logger->warning('Invalid loglevel set in config.', ['loglevel' => $loglevel]); - } catch (\Throwable $t) { - // No logger ... - $logger = new NullLogger(); - } - } else { - try { - $logger = new SyslogLogger($this->channel, $introspection, $loglevel); - } catch (LogLevelException $exception) { - // If there's a wrong config value for loglevel, try again with standard - $logger = $this->create($database, $config, $profiler, $fileSystem, $introspection, LogLevel::NOTICE); - $logger->warning('Invalid loglevel set in config.', ['loglevel' => $loglevel]); - } catch (\Throwable $e) { - // No logger ... - $logger = new NullLogger(); - } - } - } - break; - } - - $profiling = $config->get('system', 'profiling', false); - - // In case profiling is enabled, wrap the ProfilerLogger around the current logger - if (isset($profiling) && $profiling !== false) { - $logger = new ProfilerLogger($logger, $profiler); - } - - $database->setLogger($logger); - return $logger; } /** @@ -163,63 +98,24 @@ class Logger * * It should never get filled during normal usage of Friendica * - * @param IManageConfigValues $config The config - * @param Profiler $profiler The profiler of the app - * @param FileSystem $fileSystem FileSystem utils - * * @return LoggerInterface The PSR-3 compliant logger instance * @throws \Exception */ - public static function createDev(IManageConfigValues $config, Profiler $profiler, FileSystem $fileSystem, IHaveCallIntrospections $introspection) + public function createDev() { - $debugging = $config->get('system', 'debugging'); - $stream = $config->get('system', 'dlogfile'); - $developerIp = $config->get('system', 'dlogip'); + $debugging = $this->config->get('system', 'debugging'); + $stream = $this->config->get('system', 'dlogfile'); + $developerIp = $this->config->get('system', 'dlogip'); if ((!isset($developerIp) || !$debugging) && (!is_file($stream) || is_writable($stream))) { return new NullLogger(); } - $name = $config->get('system', 'logger_config', 'stream'); + $name = $this->config->get('system', 'logger_config') ?? 'stream'; - switch ($name) { - - case 'syslog': - $logger = new SyslogLogger(self::DEV_CHANNEL, $introspection, LogLevel::DEBUG); - break; - - case 'stream': - default: - $data = [ - 'name' => $name, - 'channel' => self::DEV_CHANNEL, - 'introspection' => $introspection, - 'loglevel' => LogLevel::DEBUG, - 'logger' => null, - ]; - try { - Core\Hook::callAll('logger_instance', $data); - } catch (InternalServerErrorException $exception) { - $data['logger'] = null; - } - - if (($data['logger'] ?? null) instanceof LoggerInterface) { - return $data['logger']; - } - - $logger = new StreamLogger(self::DEV_CHANNEL, $stream, $introspection, $fileSystem, LogLevel::DEBUG); - break; - } - - $profiling = $config->get('system', 'profiling', false); - - // In case profiling is enabled, wrap the ProfilerLogger around the current logger - if (isset($profiling) && $profiling !== false) { - $logger = new ProfilerLogger($logger, $profiler); - } - - return $logger; + /** @var LoggerInterface */ + return $this->instanceManager->getInstance(LoggerInterface::class, $name, [self::DEV_CHANNEL, LogLevel::DEBUG, $stream]); } /** diff --git a/src/Core/Logger/Type/StreamLogger.php b/src/Core/Logger/Type/StreamLogger.php index a444faaaba..2568fb4a2e 100644 --- a/src/Core/Logger/Type/StreamLogger.php +++ b/src/Core/Logger/Type/StreamLogger.php @@ -21,6 +21,8 @@ namespace Friendica\Core\Logger\Type; +use Friendica\Core\Config\Capability\IManageConfigValues; +use Friendica\Core\Hooks\Capabilities\IAmAStrategy; use Friendica\Core\Logger\Exception\LoggerArgumentException; use Friendica\Core\Logger\Exception\LoggerException; use Friendica\Core\Logger\Exception\LogLevelException; @@ -32,7 +34,7 @@ use Psr\Log\LogLevel; /** * A Logger instance for logging into a stream (file, stdout, stderr) */ -class StreamLogger extends AbstractLogger +class StreamLogger extends AbstractLogger implements IAmAStrategy { /** * The minimum loglevel at which this logger will be triggered @@ -80,16 +82,20 @@ class StreamLogger extends AbstractLogger /** * {@inheritdoc} - * @param string|resource $stream The stream to write with this logger (either a file or a stream, i.e. stdout) * @param string $level The minimum loglevel at which this logger will be triggered * * @throws LoggerArgumentException * @throws LogLevelException */ - public function __construct($channel, $stream, Introspection $introspection, FileSystem $fileSystem, string $level = LogLevel::DEBUG) + public function __construct(string $channel, IManageConfigValues $config, Introspection $introspection, FileSystem $fileSystem, string $level = LogLevel::DEBUG) { $this->fileSystem = $fileSystem; + $stream = $this->logfile ?? $config->get('system', 'logfile'); + if ((file_exists($stream) && !is_writable($stream)) || is_writable(basename($stream))) { + throw new LoggerArgumentException(sprintf('%s is not a valid logfile', $stream)); + } + parent::__construct($channel, $introspection); if (is_resource($stream)) { diff --git a/src/Core/Logger/Type/SyslogLogger.php b/src/Core/Logger/Type/SyslogLogger.php index b38cb01855..2e4bc94077 100644 --- a/src/Core/Logger/Type/SyslogLogger.php +++ b/src/Core/Logger/Type/SyslogLogger.php @@ -21,6 +21,8 @@ namespace Friendica\Core\Logger\Type; +use Friendica\Core\Config\Capability\IManageConfigValues; +use Friendica\Core\Hooks\Capabilities\IAmAStrategy; use Friendica\Core\Logger\Exception\LoggerException; use Friendica\Core\Logger\Exception\LogLevelException; use Friendica\Core\Logger\Util\Introspection; @@ -30,7 +32,7 @@ use Psr\Log\LogLevel; * A Logger instance for syslogging (fast, but simple) * @see http://php.net/manual/en/function.syslog.php */ -class SyslogLogger extends AbstractLogger +class SyslogLogger extends AbstractLogger implements IAmAStrategy { const IDENT = 'Friendica'; @@ -100,17 +102,16 @@ class SyslogLogger extends AbstractLogger /** * {@inheritdoc} * @param string $level The minimum loglevel at which this logger will be triggered - * @param int $logOpts Indicates what logging options will be used when generating a log message - * @param int $logFacility Used to specify what type of program is logging the message * * @throws LogLevelException * @throws LoggerException */ - public function __construct($channel, Introspection $introspection, string $level = LogLevel::NOTICE, int $logOpts = self::DEFAULT_FLAGS, int $logFacility = self::DEFAULT_FACILITY ) + public function __construct(string $channel, IManageConfigValues $config, Introspection $introspection, string $level = LogLevel::NOTICE) { parent::__construct($channel, $introspection); - $this->logOpts = $logOpts; - $this->logFacility = $logFacility; + + $this->logOpts = $config->get('system', 'syslog_flags') ?? static::DEFAULT_FLAGS; + $this->logFacility = $config->get('system', 'syslog_facility') ?? static::DEFAULT_FACILITY; $this->logLevel = $this->mapLevelToPriority($level); $this->introspection->addClasses([self::class]); } diff --git a/src/Database/Database.php b/src/Database/Database.php index 032a282030..a5fe7f978a 100644 --- a/src/Database/Database.php +++ b/src/Database/Database.php @@ -36,7 +36,6 @@ use PDO; use PDOException; use PDOStatement; use Psr\Log\LoggerInterface; -use Psr\Log\NullLogger; /** * This class is for the low level database stuff that does driver specific things. @@ -81,16 +80,14 @@ class Database /** @var ViewDefinition */ protected $viewDefinition; - public function __construct(IManageConfigValues $config, Profiler $profiler, DbaDefinition $dbaDefinition, ViewDefinition $viewDefinition) + public function __construct(IManageConfigValues $config, Profiler $profiler, DbaDefinition $dbaDefinition, ViewDefinition $viewDefinition, LoggerInterface $logger) { // We are storing these values for being able to perform a reconnect - $this->config = $config; - $this->profiler = $profiler; + $this->config = $config; + $this->profiler = $profiler; $this->dbaDefinition = $dbaDefinition; $this->viewDefinition = $viewDefinition; - - // Temporary NullLogger until we can fetch the logger class from the config - $this->logger = new NullLogger(); + $this->logger = $logger; $this->connect(); } @@ -196,21 +193,6 @@ class Database $this->testmode = $test; } - /** - * Sets the logger for DBA - * - * @note this is necessary because if we want to load the logger configuration - * from the DB, but there's an error, we would print out an exception. - * So the logger gets updated after the logger configuration can be retrieved - * from the database - * - * @param LoggerInterface $logger - */ - public function setLogger(LoggerInterface $logger) - { - $this->logger = $logger; - } - /** * Sets the profiler for DBA * diff --git a/static/dependencies.config.php b/static/dependencies.config.php index 1836a44dd5..5b7a345685 100644 --- a/static/dependencies.config.php +++ b/static/dependencies.config.php @@ -37,6 +37,8 @@ use Dice\Dice; use Friendica\App; use Friendica\Core\Cache; use Friendica\Core\Config; +use Friendica\Core\Hooks\Capabilities\ICanManageInstances; +use Friendica\Core\Hooks\Model\InstanceManager; use Friendica\Core\PConfig; use Friendica\Core\L10n; use Friendica\Core\Lock; @@ -76,6 +78,12 @@ return [ $_SERVER ] ], + ICanManageInstances::class => [ + 'instanceOf' => InstanceManager::class, + 'constructParams' => [ + [Dice::INSTANCE => Dice::SELF], + ], + ], Config\Util\ConfigFileManager::class => [ 'instanceOf' => Config\Factory\Config::class, 'call' => [ diff --git a/tests/Util/CreateDatabaseTrait.php b/tests/Util/CreateDatabaseTrait.php index 51f74c7a52..127d8da2f1 100644 --- a/tests/Util/CreateDatabaseTrait.php +++ b/tests/Util/CreateDatabaseTrait.php @@ -30,6 +30,7 @@ use Friendica\Database\Definition\ViewDefinition; use Friendica\Test\DatabaseTestTrait; use Friendica\Test\Util\Database\StaticDatabase; use Friendica\Util\Profiler; +use Psr\Log\NullLogger; trait CreateDatabaseTrait { @@ -45,7 +46,7 @@ trait CreateDatabaseTrait ], ])); - $database = new StaticDatabase($config, new Profiler($config), (new DbaDefinition($this->root->url()))->load(), (new ViewDefinition($this->root->url()))->load()); + $database = new StaticDatabase($config, new Profiler($config), (new DbaDefinition($this->root->url()))->load(), (new ViewDefinition($this->root->url()))->load(), new NullLogger()); $database->setTestmode(true); return $database; diff --git a/tests/Util/Hooks/InstanceMocks/FakeInstance.php b/tests/Util/Hooks/InstanceMocks/FakeInstance.php new file mode 100644 index 0000000000..70fdbcd4fe --- /dev/null +++ b/tests/Util/Hooks/InstanceMocks/FakeInstance.php @@ -0,0 +1,60 @@ +. + * + */ + +namespace Friendica\Test\Util\Hooks\InstanceMocks; + +use Friendica\Core\Hooks\Capabilities\IAmAStrategy; + +class FakeInstance implements IAmADecoratedInterface, IAmAStrategy +{ + protected $aText = null; + protected $cBool = null; + protected $bText = null; + + public function __construct(string $aText = null, bool $cBool = null, string $bText = null) + { + $this->aText = $aText; + $this->cBool = $cBool; + $this->bText = $bText; + } + + public function createSomething(string $aText, bool $cBool, string $bText): string + { + $this->aText = $aText; + $this->cBool = $cBool; + $this->bText = $bText; + } + + public function getAText(): ?string + { + return $this->aText; + } + + public function getBText(): ?string + { + return $this->bText; + } + + public function getCBool(): ?bool + { + return $this->cBool; + } +} diff --git a/tests/Util/Hooks/InstanceMocks/FakeInstanceDecorator.php b/tests/Util/Hooks/InstanceMocks/FakeInstanceDecorator.php new file mode 100644 index 0000000000..af4db96c44 --- /dev/null +++ b/tests/Util/Hooks/InstanceMocks/FakeInstanceDecorator.php @@ -0,0 +1,59 @@ +. + * + */ + +namespace Friendica\Test\Util\Hooks\InstanceMocks; + +class FakeInstanceDecorator implements IAmADecoratedInterface +{ + public static $countInstance = 0; + + /** @var IAmADecoratedInterface */ + protected $orig; + protected $prefix = ''; + + public function __construct(IAmADecoratedInterface $orig, string $prefix = '') + { + $this->orig = $orig; + $this->prefix = $prefix; + + self::$countInstance++; + } + + public function createSomething(string $aText, bool $cBool, string $bText): string + { + return $this->orig->createSomething($aText, $cBool, $bText); + } + + public function getAText(): ?string + { + return $this->prefix . $this->orig->getAText(); + } + + public function getBText(): ?string + { + return $this->prefix . $this->orig->getBText(); + } + + public function getCBool(): ?bool + { + return $this->prefix . $this->orig->getCBool(); + } +} diff --git a/tests/Util/Hooks/InstanceMocks/IAmADecoratedInterface.php b/tests/Util/Hooks/InstanceMocks/IAmADecoratedInterface.php new file mode 100644 index 0000000000..fe93aa998d --- /dev/null +++ b/tests/Util/Hooks/InstanceMocks/IAmADecoratedInterface.php @@ -0,0 +1,33 @@ +. + * + */ + +namespace Friendica\Test\Util\Hooks\InstanceMocks; + +interface IAmADecoratedInterface +{ + public function createSomething(string $aText, bool $cBool, string $bText): string; + + public function getAText(): ?string; + + public function getBText(): ?string; + + public function getCBool(): ?bool; +} diff --git a/tests/functional/DependencyCheckTest.php b/tests/functional/DependencyCheckTest.php index 86724bf437..27e693295e 100644 --- a/tests/functional/DependencyCheckTest.php +++ b/tests/functional/DependencyCheckTest.php @@ -25,7 +25,6 @@ use Dice\Dice; use Friendica\App; use Friendica\Core\Cache\Capability\ICanCache; use Friendica\Core\Cache\Capability\ICanCacheInMemory; -use Friendica\Core\Config\Model\Config; use Friendica\Core\Config\ValueObject\Cache; use Friendica\Core\Config\Capability\IManageConfigValues; use Friendica\Core\Lock\Capability\ICanLock; @@ -33,7 +32,6 @@ use Friendica\Database\Database; use Friendica\Test\Util\VFSTrait; use Friendica\Util\BasePath; use Friendica\Core\Config\Util\ConfigFileManager; -use Friendica\Util\Profiler; use PHPUnit\Framework\TestCase; use Psr\Log\LoggerInterface; @@ -53,7 +51,18 @@ class DependencyCheckTest extends TestCase $this->setUpVfsDir(); $this->dice = (new Dice()) - ->addRules(include __DIR__ . '/../../static/dependencies.config.php'); + ->addRules(include __DIR__ . '/../../static/dependencies.config.php') + ->addRule(BasePath::class, [ + 'constructParams' => [ + $this->root->url(), + [], + ], + ]) + ->addRule(LoggerInterface::class, ['constructParams' => ['test']]); + + /** @var IManageConfigValues $config */ + $config = $this->dice->create(IManageConfigValues::class); + $config->set('system', 'logfile', $this->root->url() . '/logs/friendica.log'); } /** @@ -142,7 +151,7 @@ class DependencyCheckTest extends TestCase public function testLogger() { /** @var LoggerInterface $logger */ - $logger = $this->dice->create(LoggerInterface::class, ['test']); + $logger = $this->dice->create(LoggerInterface::class, [['$channel' => 'test']]); self::assertInstanceOf(LoggerInterface::class, $logger); } @@ -154,7 +163,7 @@ class DependencyCheckTest extends TestCase $config->set('system', 'dlogfile', $this->root->url() . '/friendica.log'); /** @var LoggerInterface $logger */ - $logger = $this->dice->create('$devLogger', ['dev']); + $logger = $this->dice->create('$devLogger', [['$channel' => 'dev']]); self::assertInstanceOf(LoggerInterface::class, $logger); } @@ -164,6 +173,7 @@ class DependencyCheckTest extends TestCase /** @var ICanCache $cache */ $cache = $this->dice->create(ICanCache::class); + self::assertInstanceOf(ICanCache::class, $cache); } diff --git a/tests/src/Core/Cache/DatabaseCacheTest.php b/tests/src/Core/Cache/DatabaseCacheTest.php index e5f3359580..81804a806e 100644 --- a/tests/src/Core/Cache/DatabaseCacheTest.php +++ b/tests/src/Core/Cache/DatabaseCacheTest.php @@ -62,7 +62,7 @@ class DatabaseCacheTest extends CacheTest $dbaDefinition = (new DbaDefinition($configCache->get('system', 'basepath')))->load(); $viewDefinition = (new ViewDefinition($configCache->get('system', 'basepath')))->load(); - $dba = new StaticDatabase($config, $profiler, $dbaDefinition, $viewDefinition); + $dba = new StaticDatabase($config, $profiler, $dbaDefinition, $viewDefinition, new NullLogger()); $this->cache = new Cache\Type\DatabaseCache('database', $dba); return $this->cache; diff --git a/tests/src/Core/Hooks/Model/InstanceManagerTest.php b/tests/src/Core/Hooks/Model/InstanceManagerTest.php new file mode 100644 index 0000000000..94340b012f --- /dev/null +++ b/tests/src/Core/Hooks/Model/InstanceManagerTest.php @@ -0,0 +1,258 @@ +. + * + */ + +namespace Friendica\Test\src\Core\Hooks\Model; + +use Dice\Dice; +use Friendica\Core\Hooks\Model\InstanceManager; +use Friendica\Test\MockedTest; +use Friendica\Test\Util\Hooks\InstanceMocks\FakeInstance; +use Friendica\Test\Util\Hooks\InstanceMocks\FakeInstanceDecorator; +use Friendica\Test\Util\Hooks\InstanceMocks\IAmADecoratedInterface; + +class InstanceManagerTest extends MockedTest +{ + public function testEqualButNotSameInstance() + { + $instance = new InstanceManager(new Dice()); + + $instance->registerStrategy(IAmADecoratedInterface::class, 'fake', FakeInstance::class); + + $getInstanceA = $instance->getInstance(IAmADecoratedInterface::class, 'fake'); + $getInstanceB = $instance->getInstance(IAmADecoratedInterface::class, 'fake'); + + self::assertEquals($getInstanceA, $getInstanceB); + self::assertNotSame($getInstanceA, $getInstanceB); + } + + protected function tearDown(): void + { + FakeInstanceDecorator::$countInstance = 0; + + parent::tearDown(); + } + + public function dataTests(): array + { + return [ + 'only_a' => [ + 'aString' => 'test', + ], + 'a_b' => [ + 'aString' => 'test', + 'cBool' => false, + 'bString' => 'test23', + + ], + 'a_c' => [ + 'aString' => 'test', + 'cBool' => false, + 'bString' => null, + ], + 'a_b_c' => [ + 'aString' => 'test', + 'cBool' => false, + 'bString' => 'test23', + ], + 'null' => [], + ]; + } + + /** + * @dataProvider dataTests + */ + public function testInstanceWithConstructorAnonymArgs(string $aString = null, bool $cBool = null, string $bString = null) + { + $instance = new InstanceManager(new Dice()); + + $args = []; + + if (isset($aString)) { + $args[] = $aString; + } + if (isset($bString)) { + $args[] = $bString; + } + if (isset($cBool)) { + $args[] = $cBool; + } + + $instance->registerStrategy(IAmADecoratedInterface::class, 'fake', FakeInstance::class, $args); + + /** @var IAmADecoratedInterface $getInstanceA */ + $getInstanceA = $instance->getInstance(IAmADecoratedInterface::class, 'fake'); + /** @var IAmADecoratedInterface $getInstanceB */ + $getInstanceB = $instance->getInstance(IAmADecoratedInterface::class, 'fake'); + + self::assertEquals($getInstanceA, $getInstanceB); + self::assertNotSame($getInstanceA, $getInstanceB); + self::assertEquals($aString, $getInstanceA->getAText()); + self::assertEquals($aString, $getInstanceB->getAText()); + self::assertEquals($bString, $getInstanceA->getBText()); + self::assertEquals($bString, $getInstanceB->getBText()); + self::assertEquals($cBool, $getInstanceA->getCBool()); + self::assertEquals($cBool, $getInstanceB->getCBool()); + } + + /** + * @dataProvider dataTests + */ + public function testInstanceConstructorAndGetInstanceWithNamedArgs(string $aString = null, bool $cBool = null, string $bString = null) + { + $instance = new InstanceManager(new Dice()); + + $args = []; + + if (isset($aString)) { + $args[] = $aString; + } + if (isset($cBool)) { + $args[] = $cBool; + } + + $instance->registerStrategy(IAmADecoratedInterface::class, 'fake', FakeInstance::class, $args); + + /** @var IAmADecoratedInterface $getInstanceA */ + $getInstanceA = $instance->getInstance(IAmADecoratedInterface::class, 'fake', [$bString]); + /** @var IAmADecoratedInterface $getInstanceB */ + $getInstanceB = $instance->getInstance(IAmADecoratedInterface::class, 'fake', [$bString]); + + self::assertEquals($getInstanceA, $getInstanceB); + self::assertNotSame($getInstanceA, $getInstanceB); + self::assertEquals($aString, $getInstanceA->getAText()); + self::assertEquals($aString, $getInstanceB->getAText()); + self::assertEquals($bString, $getInstanceA->getBText()); + self::assertEquals($bString, $getInstanceB->getBText()); + self::assertEquals($cBool, $getInstanceA->getCBool()); + self::assertEquals($cBool, $getInstanceB->getCBool()); + } + + /** + * @dataProvider dataTests + */ + public function testInstanceWithTwoStrategies(string $aString = null, bool $cBool = null, string $bString = null) + { + $instance = new InstanceManager(new Dice()); + + $args = []; + + if (isset($aString)) { + $args[] = $aString; + } + if (isset($cBool)) { + $args[] = $cBool; + } + + $instance->registerStrategy(IAmADecoratedInterface::class, 'fake', FakeInstance::class, $args); + $instance->registerStrategy(IAmADecoratedInterface::class, 'fake23', FakeInstance::class, $args); + + /** @var IAmADecoratedInterface $getInstanceA */ + $getInstanceA = $instance->getInstance(IAmADecoratedInterface::class, 'fake', [$bString]); + /** @var IAmADecoratedInterface $getInstanceB */ + $getInstanceB = $instance->getInstance(IAmADecoratedInterface::class, 'fake23', [$bString]); + + self::assertEquals($getInstanceA, $getInstanceB); + self::assertNotSame($getInstanceA, $getInstanceB); + self::assertEquals($aString, $getInstanceA->getAText()); + self::assertEquals($aString, $getInstanceB->getAText()); + self::assertEquals($bString, $getInstanceA->getBText()); + self::assertEquals($bString, $getInstanceB->getBText()); + self::assertEquals($cBool, $getInstanceA->getCBool()); + self::assertEquals($cBool, $getInstanceB->getCBool()); + } + + /** + * @dataProvider dataTests + */ + public function testDecorator(string $aString = null, bool $cBool = null, string $bString = null) + { + $instance = new InstanceManager(new Dice()); + + $args = []; + + if (isset($aString)) { + $args[] = $aString; + } + if (isset($cBool)) { + $args[] = $cBool; + } + + $prefix = 'prefix1'; + + $instance->registerStrategy(IAmADecoratedInterface::class, 'fake', FakeInstance::class, $args); + $instance->registerStrategy(IAmADecoratedInterface::class, 'fake23', FakeInstance::class, $args); + $instance->registerDecorator(IAmADecoratedInterface::class, FakeInstanceDecorator::class, [$prefix]); + + /** @var IAmADecoratedInterface $getInstanceA */ + $getInstanceA = $instance->getInstance(IAmADecoratedInterface::class, 'fake', [$bString]); + /** @var IAmADecoratedInterface $getInstanceB */ + $getInstanceB = $instance->getInstance(IAmADecoratedInterface::class, 'fake23', [$bString]); + + self::assertEquals(2, FakeInstanceDecorator::$countInstance); + self::assertEquals($getInstanceA, $getInstanceB); + self::assertNotSame($getInstanceA, $getInstanceB); + self::assertEquals($prefix . $aString, $getInstanceA->getAText()); + self::assertEquals($prefix . $aString, $getInstanceB->getAText()); + self::assertEquals($prefix . $bString, $getInstanceA->getBText()); + self::assertEquals($prefix . $bString, $getInstanceB->getBText()); + self::assertEquals($prefix . $cBool, $getInstanceA->getCBool()); + self::assertEquals($prefix . $cBool, $getInstanceB->getCBool()); + } + + /** + * @dataProvider dataTests + */ + public function testTwoDecoratorWithPrefix(string $aString = null, bool $cBool = null, string $bString = null) + { + $instance = new InstanceManager(new Dice()); + + $args = []; + + if (isset($aString)) { + $args[] = $aString; + } + if (isset($cBool)) { + $args[] = $cBool; + } + + $prefix = 'prefix1'; + + $instance->registerStrategy(IAmADecoratedInterface::class, 'fake', FakeInstance::class, $args); + $instance->registerStrategy(IAmADecoratedInterface::class, 'fake23', FakeInstance::class, $args); + $instance->registerDecorator(IAmADecoratedInterface::class, FakeInstanceDecorator::class, [$prefix]); + $instance->registerDecorator(IAmADecoratedInterface::class, FakeInstanceDecorator::class); + + /** @var IAmADecoratedInterface $getInstanceA */ + $getInstanceA = $instance->getInstance(IAmADecoratedInterface::class, 'fake', [$bString]); + /** @var IAmADecoratedInterface $getInstanceB */ + $getInstanceB = $instance->getInstance(IAmADecoratedInterface::class, 'fake23', [$bString]); + + self::assertEquals(4, FakeInstanceDecorator::$countInstance); + self::assertEquals($getInstanceA, $getInstanceB); + self::assertNotSame($getInstanceA, $getInstanceB); + self::assertEquals($prefix . $aString, $getInstanceA->getAText()); + self::assertEquals($prefix . $aString, $getInstanceB->getAText()); + self::assertEquals($prefix . $bString, $getInstanceA->getBText()); + self::assertEquals($prefix . $bString, $getInstanceB->getBText()); + self::assertEquals($prefix . $cBool, $getInstanceA->getCBool()); + self::assertEquals($prefix . $cBool, $getInstanceB->getCBool()); + } +} diff --git a/tests/src/Core/Logger/AbstractLoggerTest.php b/tests/src/Core/Logger/AbstractLoggerTest.php index 3a5e0ecd11..4605f6f75a 100644 --- a/tests/src/Core/Logger/AbstractLoggerTest.php +++ b/tests/src/Core/Logger/AbstractLoggerTest.php @@ -21,6 +21,7 @@ namespace Friendica\Test\src\Core\Logger; +use Friendica\Core\Config\Capability\IManageConfigValues; use Friendica\Test\MockedTest; use Friendica\Core\Logger\Util\Introspection; use Mockery\MockInterface; @@ -41,6 +42,10 @@ abstract class AbstractLoggerTest extends MockedTest * @var Introspection|MockInterface */ protected $introspection; + /** + * @var IManageConfigValues|MockInterface + */ + protected $config; /** * Returns the content of the current logger instance @@ -68,6 +73,8 @@ abstract class AbstractLoggerTest extends MockedTest 'line' => self::LINE, 'function' => self::FUNC ]); + + $this->config = \Mockery::mock(IManageConfigValues::class); } public function assertLogline($string) diff --git a/tests/src/Core/Logger/StreamLoggerTest.php b/tests/src/Core/Logger/StreamLoggerTest.php index a83a5c2e4e..1ddddf4c1b 100644 --- a/tests/src/Core/Logger/StreamLoggerTest.php +++ b/tests/src/Core/Logger/StreamLoggerTest.php @@ -62,7 +62,9 @@ class StreamLoggerTest extends AbstractLoggerTest $this->logfile = vfsStream::newFile('friendica.log') ->at($this->root); - $logger = new StreamLogger('test', $this->logfile->url(), $this->introspection, $this->fileSystem, $level); + $this->config->shouldReceive('get')->with('system', 'logfile')->andReturn($this->logfile->url())->once(); + + $logger = new StreamLogger('test', $this->config, $this->introspection, $this->fileSystem, $level); return $logger; } @@ -75,43 +77,6 @@ class StreamLoggerTest extends AbstractLoggerTest return $this->logfile->getContent(); } - /** - * Test if a stream is working - */ - public function testStream() - { - $logfile = vfsStream::newFile('friendica.log') - ->at($this->root); - - $filehandler = fopen($logfile->url(), 'ab'); - - $logger = new \Friendica\Core\Logger\Type\StreamLogger('test', $filehandler, $this->introspection, $this->fileSystem); - $logger->emergency('working'); - - $text = $logfile->getContent(); - - self::assertLogline($text); - } - - /** - * Test if the close statement is working - */ - public function testClose() - { - $logfile = vfsStream::newFile('friendica.log') - ->at($this->root); - - $logger = new StreamLogger('test', $logfile->url(), $this->introspection, $this->fileSystem); - $logger->emergency('working'); - $logger->close(); - // close doesn't affect - $logger->emergency('working too'); - - $text = $logfile->getContent(); - - self::assertLoglineNums(2, $text); - } - /** * Test when a file isn't set */ @@ -120,7 +85,9 @@ class StreamLoggerTest extends AbstractLoggerTest $this->expectException(LoggerArgumentException::class); $this->expectExceptionMessage("Missing stream URL."); - $logger = new StreamLogger('test', '', $this->introspection, $this->fileSystem); + $this->config->shouldReceive('get')->with('system', 'logfile')->andReturn('')->once(); + + $logger = new StreamLogger('test', $this->config, $this->introspection, $this->fileSystem); $logger->emergency('not working'); } @@ -130,13 +97,14 @@ class StreamLoggerTest extends AbstractLoggerTest */ public function testWrongUrl() { - $this->expectException(LoggerException::class); - $this->expectExceptionMessage("Cannot create stream."); + $this->expectException(LoggerArgumentException::class); $logfile = vfsStream::newFile('friendica.log') ->at($this->root)->chmod(0); - $logger = new StreamLogger('test', $logfile->url(), $this->introspection, $this->fileSystem); + $this->config->shouldReceive('get')->with('system', 'logfile')->andReturn($logfile->url())->once(); + + $logger = new StreamLogger('test', $this->config, $this->introspection, $this->fileSystem); $logger->emergency('not working'); } @@ -164,7 +132,9 @@ class StreamLoggerTest extends AbstractLoggerTest $this->expectException(LogLevelException::class); $this->expectExceptionMessageMatches("/The level \".*\" is not valid./"); - $logger = new StreamLogger('test', 'file.text', $this->introspection, $this->fileSystem, 'NOPE'); + $this->config->shouldReceive('get')->with('system', 'logfile')->andReturn('file.text')->once(); + + $logger = new StreamLogger('test', $this->config, $this->introspection, $this->fileSystem, 'NOPE'); } /** @@ -178,7 +148,9 @@ class StreamLoggerTest extends AbstractLoggerTest $logfile = vfsStream::newFile('friendica.log') ->at($this->root); - $logger = new StreamLogger('test', $logfile->url(), $this->introspection, $this->fileSystem); + $this->config->shouldReceive('get')->with('system', 'logfile')->andReturn($logfile->url())->once(); + + $logger = new StreamLogger('test', $this->config, $this->introspection, $this->fileSystem); $logger->log('NOPE', 'a test'); } @@ -191,7 +163,9 @@ class StreamLoggerTest extends AbstractLoggerTest $this->expectException(LoggerArgumentException::class); $this->expectExceptionMessage("A stream must either be a resource or a string."); - $logger = new StreamLogger('test', null, $this->introspection, $this->fileSystem); + $this->config->shouldReceive('get')->with('system', 'logfile')->andReturn(null)->once(); + + $logger = new StreamLogger('test', $this->config, $this->introspection, $this->fileSystem); } /** @@ -207,7 +181,9 @@ class StreamLoggerTest extends AbstractLoggerTest chdir($this->root->getChild('logs')->url()); - $logger = new StreamLogger('test', '../friendica.log' , $this->introspection, $this->fileSystem); + $this->config->shouldReceive('get')->with('system', 'logfile')->andReturn('../friendica.log')->once(); + + $logger = new StreamLogger('test', $this->config, $this->introspection, $this->fileSystem); $logger->info('Test'); } diff --git a/tests/src/Core/Logger/SyslogLoggerTest.php b/tests/src/Core/Logger/SyslogLoggerTest.php index 89f9d82e6c..53ace79c08 100644 --- a/tests/src/Core/Logger/SyslogLoggerTest.php +++ b/tests/src/Core/Logger/SyslogLoggerTest.php @@ -39,6 +39,10 @@ class SyslogLoggerTest extends AbstractLoggerTest parent::setUp(); $this->introspection->shouldReceive('addClasses')->with([SyslogLogger::class]); + $this->config->shouldReceive('get')->with('system', 'syslog_flags')->andReturn(SyslogLogger::DEFAULT_FLAGS) + ->once(); + $this->config->shouldReceive('get')->with('system', 'syslog_facility') + ->andReturn(SyslogLogger::DEFAULT_FACILITY)->once(); } /** @@ -54,7 +58,7 @@ class SyslogLoggerTest extends AbstractLoggerTest */ protected function getInstance($level = LogLevel::DEBUG) { - $this->logger = new SyslogLoggerWrapper('test', $this->introspection, $level); + $this->logger = new SyslogLoggerWrapper('test', $this->config, $this->introspection, $level); return $this->logger; } @@ -68,7 +72,7 @@ class SyslogLoggerTest extends AbstractLoggerTest $this->expectException(LogLevelException::class); $this->expectExceptionMessageMatches("/The level \".*\" is not valid./"); - $logger = new SyslogLoggerWrapper('test', $this->introspection, 'NOPE'); + $logger = new SyslogLoggerWrapper('test', $this->config, $this->introspection, 'NOPE'); } /** @@ -79,7 +83,7 @@ class SyslogLoggerTest extends AbstractLoggerTest $this->expectException(LogLevelException::class); $this->expectExceptionMessageMatches("/The level \".*\" is not valid./"); - $logger = new SyslogLoggerWrapper('test', $this->introspection); + $logger = new SyslogLoggerWrapper('test', $this->config, $this->introspection); $logger->log('NOPE', 'a test'); } @@ -90,7 +94,7 @@ class SyslogLoggerTest extends AbstractLoggerTest */ public function testClose() { - $logger = new SyslogLoggerWrapper('test', $this->introspection); + $logger = new SyslogLoggerWrapper('test', $this->config, $this->introspection); $logger->emergency('test'); $logger->close(); // Reopened itself diff --git a/tests/src/Core/Logger/SyslogLoggerWrapper.php b/tests/src/Core/Logger/SyslogLoggerWrapper.php index 634edc1195..9fd16706a8 100644 --- a/tests/src/Core/Logger/SyslogLoggerWrapper.php +++ b/tests/src/Core/Logger/SyslogLoggerWrapper.php @@ -21,6 +21,7 @@ namespace Friendica\Test\src\Core\Logger; +use Friendica\Core\Config\Capability\IManageConfigValues; use Friendica\Core\Logger\Type\SyslogLogger; use Friendica\Core\Logger\Util\Introspection; use Psr\Log\LogLevel; @@ -32,9 +33,9 @@ class SyslogLoggerWrapper extends SyslogLogger { private $content; - public function __construct($channel, Introspection $introspection, $level = LogLevel::NOTICE, $logOpts = LOG_PID, $logFacility = LOG_USER) + public function __construct($channel, IManageConfigValues $config, Introspection $introspection, $level = LogLevel::NOTICE) { - parent::__construct($channel, $introspection, $level, $logOpts, $logFacility); + parent::__construct($channel, $config, $introspection, $level); $this->content = ''; } From 293c121c48623d39768ed3933b8236f5564b6150 Mon Sep 17 00:00:00 2001 From: Philipp Date: Mon, 16 Jan 2023 22:25:26 +0100 Subject: [PATCH 03/53] Adhere PHP-CS.. --- src/Core/Hooks/Model/InstanceManager.php | 4 ++-- tests/Util/Hooks/InstanceMocks/FakeInstance.php | 12 ++++++------ tests/src/Core/Hooks/Model/InstanceManagerTest.php | 12 ++++++------ 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/Core/Hooks/Model/InstanceManager.php b/src/Core/Hooks/Model/InstanceManager.php index 4b8a0e6de8..7a3697062d 100644 --- a/src/Core/Hooks/Model/InstanceManager.php +++ b/src/Core/Hooks/Model/InstanceManager.php @@ -92,8 +92,8 @@ class InstanceManager implements ICanManageInstances 'instanceOf' => $decorator['class'], 'constructParams' => empty($decorator['arguments']) ? null : $decorator['arguments'], /// @todo maybe support call structures for hooks as well in a later stage - could make factory calls easier - 'call' => null, - 'substitutions' => [$class => $instance], + 'call' => null, + 'substitutions' => [$class => $instance], ]); $instance = $this->dice->create($class); diff --git a/tests/Util/Hooks/InstanceMocks/FakeInstance.php b/tests/Util/Hooks/InstanceMocks/FakeInstance.php index 70fdbcd4fe..ff99002f7c 100644 --- a/tests/Util/Hooks/InstanceMocks/FakeInstance.php +++ b/tests/Util/Hooks/InstanceMocks/FakeInstance.php @@ -31,16 +31,16 @@ class FakeInstance implements IAmADecoratedInterface, IAmAStrategy public function __construct(string $aText = null, bool $cBool = null, string $bText = null) { - $this->aText = $aText; - $this->cBool = $cBool; - $this->bText = $bText; + $this->aText = $aText; + $this->cBool = $cBool; + $this->bText = $bText; } public function createSomething(string $aText, bool $cBool, string $bText): string { - $this->aText = $aText; - $this->cBool = $cBool; - $this->bText = $bText; + $this->aText = $aText; + $this->cBool = $cBool; + $this->bText = $bText; } public function getAText(): ?string diff --git a/tests/src/Core/Hooks/Model/InstanceManagerTest.php b/tests/src/Core/Hooks/Model/InstanceManagerTest.php index 94340b012f..4e4c0135cb 100644 --- a/tests/src/Core/Hooks/Model/InstanceManagerTest.php +++ b/tests/src/Core/Hooks/Model/InstanceManagerTest.php @@ -53,26 +53,26 @@ class InstanceManagerTest extends MockedTest public function dataTests(): array { return [ - 'only_a' => [ + 'only_a' => [ 'aString' => 'test', ], - 'a_b' => [ + 'a_b' => [ 'aString' => 'test', - 'cBool' => false, + 'cBool' => false, 'bString' => 'test23', ], - 'a_c' => [ + 'a_c' => [ 'aString' => 'test', 'cBool' => false, 'bString' => null, ], - 'a_b_c' => [ + 'a_b_c' => [ 'aString' => 'test', 'cBool' => false, 'bString' => 'test23', ], - 'null' => [], + 'null' => [], ]; } From eed6db24656361d7055e6b409984c6ed6a4e595e Mon Sep 17 00:00:00 2001 From: Philipp Date: Tue, 17 Jan 2023 19:12:33 +0100 Subject: [PATCH 04/53] Apply suggestions from code review Co-authored-by: Hypolite Petovan --- src/Core/Hooks/Capabilities/ICanManageInstances.php | 10 +++++----- src/Core/Hooks/Model/InstanceManager.php | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Core/Hooks/Capabilities/ICanManageInstances.php b/src/Core/Hooks/Capabilities/ICanManageInstances.php index 08802a08e6..d6a7f244c7 100644 --- a/src/Core/Hooks/Capabilities/ICanManageInstances.php +++ b/src/Core/Hooks/Capabilities/ICanManageInstances.php @@ -35,8 +35,8 @@ interface ICanManageInstances * @see https://refactoring.guru/design-patterns/strategy * * @param string $interface The interface, which the given class implements - * @param string $name The name of the given class, which will be used for factories, dependency injections etc. - * @param string $class The class of the given class + * @param string $name An arbitrary identifier for the given class, which will be used for factories, dependency injections etc. + * @param string $class The fully-qualified given class name * @param ?array $arguments Additional arguments, which can be passed to the constructor * * @return $this This interface for chain-calls @@ -51,8 +51,8 @@ interface ICanManageInstances * * @note Decorator attach new behaviors to classes without changing them or without letting them know about it. * - * @param string $class The class or interface, which gets decorated by a class - * @param string $decoratorClass The class, which mimics the given class or interface and adds new functionality + * @param string $class The fully-qualified class or interface name, which gets decorated by a class + * @param string $decoratorClass The fully-qualified name of the class which mimics the given class or interface and adds new functionality * @param array $arguments Additional arguments, which can be passed to the constructor of "decoratorClass" * * @return $this This interface for chain-calls @@ -69,7 +69,7 @@ interface ICanManageInstances * In case, there are registered decorators for this class as well, all decorators of the list will be wrapped * around the instance before returning it * - * @param string $class A given class or interface, which will get returned + * @param string $class The fully-qualified name of the given class or interface which will get returned * @param string $name The name of the concrete class, wich * @param array $arguments Additional arguments, which can be passed to the constructor of "$class" at runtime * diff --git a/src/Core/Hooks/Model/InstanceManager.php b/src/Core/Hooks/Model/InstanceManager.php index 7a3697062d..7bfcfa420d 100644 --- a/src/Core/Hooks/Model/InstanceManager.php +++ b/src/Core/Hooks/Model/InstanceManager.php @@ -67,7 +67,7 @@ class InstanceManager implements ICanManageInstances public function registerDecorator(string $class, string $decoratorClass, array $arguments = []): ICanManageInstances { if (!is_a($decoratorClass, $class, true)) { - throw new HookRegisterArgumentException(sprintf('%s is not a valid subsituation for the given class or interface %s', $decoratorClass, $class)); + throw new HookRegisterArgumentException(sprintf('%s is not a valid substitution for the given class or interface %s', $decoratorClass, $class)); } $this->decorator[$class][] = [ From 3b262f44a36c06f38c0e576852403c6eb89a9fae Mon Sep 17 00:00:00 2001 From: Philipp Date: Tue, 17 Jan 2023 19:15:37 +0100 Subject: [PATCH 05/53] Adhere feedback --- composer.json | 2 +- src/Core/Hooks/Capabilities/IAmAStrategy.php | 2 +- src/Core/Hooks/Capabilities/ICanManageInstances.php | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/composer.json b/composer.json index aab60ee5c6..a86354acd9 100644 --- a/composer.json +++ b/composer.json @@ -140,7 +140,7 @@ "extra": { "patches": { "level-2/dice": [ - "mods/patches/level-2-dice-dice-php.patch" + "mods/patches/level-2-dice-dice-php.patch" ] } } diff --git a/src/Core/Hooks/Capabilities/IAmAStrategy.php b/src/Core/Hooks/Capabilities/IAmAStrategy.php index a830d912c0..017cb56c4e 100644 --- a/src/Core/Hooks/Capabilities/IAmAStrategy.php +++ b/src/Core/Hooks/Capabilities/IAmAStrategy.php @@ -22,7 +22,7 @@ namespace Friendica\Core\Hooks\Capabilities; /** - * All interfaces, marking this interface are valid Strategies for Hook calls + * All classes, implementing this interface are valid Strategies for Hook calls */ interface IAmAStrategy { diff --git a/src/Core/Hooks/Capabilities/ICanManageInstances.php b/src/Core/Hooks/Capabilities/ICanManageInstances.php index d6a7f244c7..252f3d03bd 100644 --- a/src/Core/Hooks/Capabilities/ICanManageInstances.php +++ b/src/Core/Hooks/Capabilities/ICanManageInstances.php @@ -70,7 +70,7 @@ interface ICanManageInstances * around the instance before returning it * * @param string $class The fully-qualified name of the given class or interface which will get returned - * @param string $name The name of the concrete class, wich + * @param string $name An arbitrary identifier to find a concrete instance strategy. * @param array $arguments Additional arguments, which can be passed to the constructor of "$class" at runtime * * @return object The concrete instance of the type "$class" From 8eed43a7dd113473767617a7b157134cdb25242f Mon Sep 17 00:00:00 2001 From: Philipp Date: Tue, 17 Jan 2023 19:23:20 +0100 Subject: [PATCH 06/53] Add whitespace .. --- src/Core/Hooks/Capabilities/ICanManageInstances.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Core/Hooks/Capabilities/ICanManageInstances.php b/src/Core/Hooks/Capabilities/ICanManageInstances.php index 252f3d03bd..bdad1b9235 100644 --- a/src/Core/Hooks/Capabilities/ICanManageInstances.php +++ b/src/Core/Hooks/Capabilities/ICanManageInstances.php @@ -34,9 +34,9 @@ interface ICanManageInstances * * @see https://refactoring.guru/design-patterns/strategy * - * @param string $interface The interface, which the given class implements - * @param string $name An arbitrary identifier for the given class, which will be used for factories, dependency injections etc. - * @param string $class The fully-qualified given class name + * @param string $interface The interface, which the given class implements + * @param string $name An arbitrary identifier for the given class, which will be used for factories, dependency injections etc. + * @param string $class The fully-qualified given class name * @param ?array $arguments Additional arguments, which can be passed to the constructor * * @return $this This interface for chain-calls From 5358e195d7c57cbb87a066ad6fa79aca10ba0250 Mon Sep 17 00:00:00 2001 From: Philipp Date: Tue, 17 Jan 2023 20:11:48 +0100 Subject: [PATCH 07/53] Fix Introspection --- src/Core/Logger/Type/AbstractLogger.php | 8 ++++---- src/Core/Logger/Type/StreamLogger.php | 4 ++-- src/Core/Logger/Type/SyslogLogger.php | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/Core/Logger/Type/AbstractLogger.php b/src/Core/Logger/Type/AbstractLogger.php index bc4b00ecea..77a61e9206 100644 --- a/src/Core/Logger/Type/AbstractLogger.php +++ b/src/Core/Logger/Type/AbstractLogger.php @@ -21,8 +21,8 @@ namespace Friendica\Core\Logger\Type; +use Friendica\Core\Logger\Capabilities\IHaveCallIntrospections; use Friendica\Core\Logger\Exception\LoggerException; -use Friendica\Core\Logger\Util\Introspection; use Friendica\Util\Strings; use Psr\Log\LoggerInterface; use Psr\Log\LogLevel; @@ -46,7 +46,7 @@ abstract class AbstractLogger implements LoggerInterface /** * The Introspection for the current call - * @var Introspection + * @var IHaveCallIntrospections */ protected $introspection; @@ -69,11 +69,11 @@ abstract class AbstractLogger implements LoggerInterface /** * @param string $channel The output channel - * @param Introspection $introspection The introspection of the current call + * @param IHaveCallIntrospections $introspection The introspection of the current call * * @throws LoggerException */ - public function __construct(string $channel, Introspection $introspection) + public function __construct(string $channel, IHaveCallIntrospections $introspection) { $this->channel = $channel; $this->introspection = $introspection; diff --git a/src/Core/Logger/Type/StreamLogger.php b/src/Core/Logger/Type/StreamLogger.php index 2568fb4a2e..6e0f657978 100644 --- a/src/Core/Logger/Type/StreamLogger.php +++ b/src/Core/Logger/Type/StreamLogger.php @@ -23,12 +23,12 @@ namespace Friendica\Core\Logger\Type; use Friendica\Core\Config\Capability\IManageConfigValues; use Friendica\Core\Hooks\Capabilities\IAmAStrategy; +use Friendica\Core\Logger\Capabilities\IHaveCallIntrospections; use Friendica\Core\Logger\Exception\LoggerArgumentException; use Friendica\Core\Logger\Exception\LoggerException; use Friendica\Core\Logger\Exception\LogLevelException; use Friendica\Util\DateTimeFormat; use Friendica\Util\FileSystem; -use Friendica\Core\Logger\Util\Introspection; use Psr\Log\LogLevel; /** @@ -87,7 +87,7 @@ class StreamLogger extends AbstractLogger implements IAmAStrategy * @throws LoggerArgumentException * @throws LogLevelException */ - public function __construct(string $channel, IManageConfigValues $config, Introspection $introspection, FileSystem $fileSystem, string $level = LogLevel::DEBUG) + public function __construct(string $channel, IManageConfigValues $config, IHaveCallIntrospections $introspection, FileSystem $fileSystem, string $level = LogLevel::DEBUG) { $this->fileSystem = $fileSystem; diff --git a/src/Core/Logger/Type/SyslogLogger.php b/src/Core/Logger/Type/SyslogLogger.php index 2e4bc94077..3c9ab581a0 100644 --- a/src/Core/Logger/Type/SyslogLogger.php +++ b/src/Core/Logger/Type/SyslogLogger.php @@ -23,9 +23,9 @@ namespace Friendica\Core\Logger\Type; use Friendica\Core\Config\Capability\IManageConfigValues; use Friendica\Core\Hooks\Capabilities\IAmAStrategy; +use Friendica\Core\Logger\Capabilities\IHaveCallIntrospections; use Friendica\Core\Logger\Exception\LoggerException; use Friendica\Core\Logger\Exception\LogLevelException; -use Friendica\Core\Logger\Util\Introspection; use Psr\Log\LogLevel; /** @@ -106,7 +106,7 @@ class SyslogLogger extends AbstractLogger implements IAmAStrategy * @throws LogLevelException * @throws LoggerException */ - public function __construct(string $channel, IManageConfigValues $config, Introspection $introspection, string $level = LogLevel::NOTICE) + public function __construct(string $channel, IManageConfigValues $config, IHaveCallIntrospections $introspection, string $level = LogLevel::NOTICE) { parent::__construct($channel, $introspection); From 73e163100c108caee1e295d00ac8433ea62405be Mon Sep 17 00:00:00 2001 From: Michael Date: Wed, 18 Jan 2023 05:04:37 +0000 Subject: [PATCH 08/53] Nodeinfo data has moved to key values --- database.sql | 2 +- src/Model/Nodeinfo.php | 24 ++++++++++++------------ src/Module/Statistics.php | 19 +++++++++++-------- src/Object/Api/Mastodon/Stats.php | 7 +++---- static/dbstructure.config.php | 2 +- update.php | 17 +++++++++++++++++ 6 files changed, 45 insertions(+), 26 deletions(-) diff --git a/database.sql b/database.sql index 48e0930e67..0b91aedc06 100644 --- a/database.sql +++ b/database.sql @@ -1,6 +1,6 @@ -- ------------------------------------------ -- Friendica 2023.03-dev (Giant Rhubarb) --- DB_UPDATE_VERSION 1511 +-- DB_UPDATE_VERSION 1512 -- ------------------------------------------ diff --git a/src/Model/Nodeinfo.php b/src/Model/Nodeinfo.php index 0fbaf93c7e..07f56dd7bb 100644 --- a/src/Model/Nodeinfo.php +++ b/src/Model/Nodeinfo.php @@ -55,17 +55,17 @@ class Nodeinfo $userStats = User::getStatistics(); - $config->set('nodeinfo', 'total_users', $userStats['total_users']); - $config->set('nodeinfo', 'active_users_halfyear', $userStats['active_users_halfyear']); - $config->set('nodeinfo', 'active_users_monthly', $userStats['active_users_monthly']); - $config->set('nodeinfo', 'active_users_weekly', $userStats['active_users_weekly']); + DI::keyValue()->set('nodeinfo_total_users', $userStats['total_users']); + DI::keyValue()->set('nodeinfo_active_users_halfyear', $userStats['active_users_halfyear']); + DI::keyValue()->set('nodeinfo_active_users_monthly', $userStats['active_users_monthly']); + DI::keyValue()->set('nodeinfo_active_users_weekly', $userStats['active_users_weekly']); $logger->info('user statistics', $userStats); $posts = DBA::count('post-thread', ["`uri-id` IN (SELECT `uri-id` FROM `post-user` WHERE NOT `deleted` AND `origin`)"]); $comments = DBA::count('post', ["NOT `deleted` AND `gravity` = ? AND `uri-id` IN (SELECT `uri-id` FROM `post-user` WHERE `origin`)", Item::GRAVITY_COMMENT]); - $config->set('nodeinfo', 'local_posts', $posts); - $config->set('nodeinfo', 'local_comments', $comments); + DI::keyValue()->set('nodeinfo_local_posts', $posts); + DI::keyValue()->set('nodeinfo_local_comments', $comments); $logger->info('User actitivy', ['posts' => $posts, 'comments' => $comments]); } @@ -83,14 +83,14 @@ class Nodeinfo $usage->users = new \stdClass; if (!empty($config->get('system', 'nodeinfo'))) { - $usage->users->total = intval($config->get('nodeinfo', 'total_users')); - $usage->users->activeHalfyear = intval($config->get('nodeinfo', 'active_users_halfyear')); - $usage->users->activeMonth = intval($config->get('nodeinfo', 'active_users_monthly')); - $usage->localPosts = intval($config->get('nodeinfo', 'local_posts')); - $usage->localComments = intval($config->get('nodeinfo', 'local_comments')); + $usage->users->total = intval(DI::keyValue()->get('nodeinfo_total_users')); + $usage->users->activeHalfyear = intval(DI::keyValue()->get('nodeinfo_active_users_halfyear')); + $usage->users->activeMonth = intval(DI::keyValue()->get('nodeinfo_active_users_monthly')); + $usage->localPosts = intval(DI::keyValue()->get('nodeinfo_local_posts')); + $usage->localComments = intval(DI::keyValue()->get('nodeinfo_local_comments')); if ($version2) { - $usage->users->activeWeek = intval($config->get('nodeinfo', 'active_users_weekly')); + $usage->users->activeWeek = intval(DI::keyValue()->get('nodeinfo_active_users_weekly')); } } diff --git a/src/Module/Statistics.php b/src/Module/Statistics.php index 75d3e6432b..514f10bb73 100644 --- a/src/Module/Statistics.php +++ b/src/Module/Statistics.php @@ -25,6 +25,7 @@ use Friendica\App; use Friendica\BaseModule; use Friendica\Core\Addon; use Friendica\Core\Config\Capability\IManageConfigValues; +use Friendica\Core\KeyValueStorage\Capabilities\IManageKeyValuePairs; use Friendica\Core\L10n; use Friendica\Core\System; use Friendica\Network\HTTPException\NotFoundException; @@ -35,13 +36,15 @@ class Statistics extends BaseModule { /** @var IManageConfigValues */ protected $config; - - public function __construct(L10n $l10n, App\BaseURL $baseUrl, App\Arguments $args, LoggerInterface $logger, Profiler $profiler, IManageConfigValues $config, Response $response, array $server, array $parameters = []) + /** @var IManageKeyValuePairs */ + protected $keyValue; + + public function __construct(L10n $l10n, App\BaseURL $baseUrl, App\Arguments $args, LoggerInterface $logger, Profiler $profiler, IManageConfigValues $config, IManageKeyValuePairs $keyValue, Response $response, array $server, array $parameters = []) { parent::__construct($l10n, $baseUrl, $args, $logger, $profiler, $response, $server, $parameters); - $this->config = $config; - + $this->config = $config; + $this->keyValue = $keyValue; if (!$this->config->get("system", "nodeinfo")) { throw new NotFoundException(); } @@ -72,10 +75,10 @@ class Statistics extends BaseModule 'network' => App::PLATFORM, 'version' => App::VERSION . '-' . DB_UPDATE_VERSION, 'registrations_open' => $registration_open, - 'total_users' => $this->config->get('nodeinfo', 'total_users'), - 'active_users_halfyear' => $this->config->get('nodeinfo', 'active_users_halfyear'), - 'active_users_monthly' => $this->config->get('nodeinfo', 'active_users_monthly'), - 'local_posts' => $this->config->get('nodeinfo', 'local_posts'), + 'total_users' => $this->keyValue->get('nodeinfo_total_users'), + 'active_users_halfyear' => $this->keyValue->get('nodeinfo_active_users_halfyear'), + 'active_users_monthly' => $this->keyValue->get('nodeinfo_active_users_monthly'), + 'local_posts' => $this->keyValue->get('nodeinfo_local_posts'), 'services' => $services, ], $services); diff --git a/src/Object/Api/Mastodon/Stats.php b/src/Object/Api/Mastodon/Stats.php index 1f08ab2ed7..335c82d431 100644 --- a/src/Object/Api/Mastodon/Stats.php +++ b/src/Object/Api/Mastodon/Stats.php @@ -25,7 +25,6 @@ use Friendica\BaseDataTransferObject; use Friendica\Core\Config\Capability\IManageConfigValues; use Friendica\Core\Protocol; use Friendica\Database\Database; -use Friendica\Database\DBA; use Friendica\DI; /** @@ -45,9 +44,9 @@ class Stats extends BaseDataTransferObject public function __construct(IManageConfigValues $config, Database $database) { if (!empty($config->get('system', 'nodeinfo'))) { - $this->user_count = intval($config->get('nodeinfo', 'total_users')); - $this->status_count = $config->get('nodeinfo', 'local_posts') + $config->get('nodeinfo', 'local_comments'); - $this->domain_count = $database->count('gserver', ["`network` in (?, ?) AND NOT `failed`", Protocol::DFRN, Protocol::ACTIVITYPUB]); + $this->user_count = intval(DI::keyValue()->get('nodeinfo_total_users')); + $this->status_count = DI::keyValue()->get('nodeinfo_local_posts') + DI::keyValue()->get('nodeinfo_local_comments'); + $this->domain_count = $database->count('gserver', ["`network` in (?, ?) AND NOT `failed` AND NOT `blocked`", Protocol::DFRN, Protocol::ACTIVITYPUB]); } } } diff --git a/static/dbstructure.config.php b/static/dbstructure.config.php index a6459f16ba..4329410b4a 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', 1511); + define('DB_UPDATE_VERSION', 1512); } return [ diff --git a/update.php b/update.php index 85a06892f0..8f93775259 100644 --- a/update.php +++ b/update.php @@ -1227,3 +1227,20 @@ function update_1510() } return Update::SUCCESS; } + +function update_1512() +{ + DI::keyValue()->set('nodeinfo_total_users', DI::config()->get('nodeinfo', 'total_users')); + DI::keyValue()->set('nodeinfo_active_users_halfyear', DI::config()->get('nodeinfo', 'active_users_halfyear')); + DI::keyValue()->set('nodeinfo_active_users_monthly', DI::config()->get('nodeinfo', 'active_users_monthly')); + DI::keyValue()->set('nodeinfo_active_users_weekly', DI::config()->get('nodeinfo', 'active_users_weekly')); + DI::keyValue()->set('nodeinfo_local_posts', DI::config()->get('nodeinfo', 'local_posts')); + DI::keyValue()->set('nodeinfo_local_comments', DI::config()->get('nodeinfo', 'local_comments')); + + DI::config()->delete('nodeinfo', 'total_users'); + DI::config()->delete('nodeinfo', 'active_users_halfyear'); + DI::config()->delete('nodeinfo', 'active_users_monthly'); + DI::config()->delete('nodeinfo', 'active_users_weekly'); + DI::config()->delete('nodeinfo', 'local_posts'); + DI::config()->delete('nodeinfo', 'local_comments'); +} From 81cd33466457a31e7694e503e32ff2cc90dce047 Mon Sep 17 00:00:00 2001 From: Hypolite Petovan Date: Wed, 18 Jan 2023 20:27:29 -0500 Subject: [PATCH 09/53] Fix wrong logic in password allowed regular expression --- src/Model/User.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Model/User.php b/src/Model/User.php index bd7351f072..35ea835b30 100644 --- a/src/Model/User.php +++ b/src/Model/User.php @@ -776,7 +776,7 @@ class User $allowed_characters = preg_quote($allowed_characters, $delimiter); } - return '^[a-zA-Z0-9' . $allowed_characters . ']' . (PASSWORD_DEFAULT !== PASSWORD_BCRYPT ? '{1,72}' : '+') . '$'; + return '^[a-zA-Z0-9' . $allowed_characters . ']' . (PASSWORD_DEFAULT === PASSWORD_BCRYPT ? '{1,72}' : '+') . '$'; } /** From d2033d4c927929e4db59e5a2e8fd8eb8037375c3 Mon Sep 17 00:00:00 2001 From: Hypolite Petovan Date: Wed, 18 Jan 2023 20:33:39 -0500 Subject: [PATCH 10/53] Allow colon in password - It was disallowed because of a too strict intepretation of RFC2617 --- src/Model/User.php | 6 +++--- src/Module/OAuth/Token.php | 5 ++++- src/Module/Security/PasswordTooLong.php | 2 +- src/Module/Settings/Account.php | 2 +- 4 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/Model/User.php b/src/Model/User.php index 35ea835b30..75b913250c 100644 --- a/src/Model/User.php +++ b/src/Model/User.php @@ -757,7 +757,7 @@ class User } /** - * Allowed characters are a-z, A-Z, 0-9 and special characters except white spaces, accentuated letters and colon (:). + * Allowed characters are a-z, A-Z, 0-9 and special characters except white spaces and accentuated letters. * * Password length is limited to 72 characters if the current default password hashing algorithm is Blowfish. * From the manual: "Using the PASSWORD_BCRYPT as the algorithm, will result in the password parameter being @@ -770,7 +770,7 @@ class User */ public static function getPasswordRegExp(string $delimiter = null): string { - $allowed_characters = '!"#$%&\'()*+,-./;<=>?@[\]^_`{|}~'; + $allowed_characters = ':!"#$%&\'()*+,-./;<=>?@[\]^_`{|}~'; if ($delimiter) { $allowed_characters = preg_quote($allowed_characters, $delimiter); @@ -804,7 +804,7 @@ class User } if (!preg_match('/' . self::getPasswordRegExp('/') . '/', $password)) { - throw new Exception(DI::l10n()->t('The password can\'t contain accentuated letters, white spaces or colons (:)')); + throw new Exception(DI::l10n()->t("The password can't contain white spaces nor accentuated letters")); } return self::updatePasswordHashed($uid, self::hashPassword($password)); diff --git a/src/Module/OAuth/Token.php b/src/Module/OAuth/Token.php index 7481bf75f5..6f68215cc6 100644 --- a/src/Module/OAuth/Token.php +++ b/src/Module/OAuth/Token.php @@ -61,7 +61,10 @@ class Token extends BaseApi } if (empty($request['client_id']) && substr($authorization, 0, 6) == 'Basic ') { - $datapair = explode(':', base64_decode(trim(substr($authorization, 6)))); + // Per RFC2617, usernames can't contain a colon but password can, + // so we cut on the first colon to obtain the username and the password + // @see https://www.rfc-editor.org/rfc/rfc2617#section-2 + $datapair = explode(':', base64_decode(trim(substr($authorization, 6))), 2); if (count($datapair) == 2) { $request['client_id'] = $datapair[0]; $request['client_secret'] = $datapair[1]; diff --git a/src/Module/Security/PasswordTooLong.php b/src/Module/Security/PasswordTooLong.php index 1934556b3f..53fafea41e 100644 --- a/src/Module/Security/PasswordTooLong.php +++ b/src/Module/Security/PasswordTooLong.php @@ -98,7 +98,7 @@ class PasswordTooLong extends \Friendica\BaseModule '$return_url' => $request['return_url'] ?? '', '$password_current' => ['password_current', $this->l10n->t('Current Password:'), '', $this->l10n->t('Your current password to confirm the changes'), 'required', 'autocomplete="off"'], - '$password' => ['password', $this->l10n->t('New Password:'), '', $this->l10n->t('Allowed characters are a-z, A-Z, 0-9 and special characters except white spaces, accentuated letters and colon (:).') . ' ' . $this->l10n->t('Password length is limited to 72 characters.'), 'required', 'autocomplete="off"', User::getPasswordRegExp()], + '$password' => ['password', $this->l10n->t('New Password:'), '', $this->l10n->t('Allowed characters are a-z, A-Z, 0-9 and special characters except white spaces and accentuated letters.') . ' ' . $this->l10n->t('Password length is limited to 72 characters.'), 'required', 'autocomplete="off"', User::getPasswordRegExp()], '$password_confirm' => ['password_confirm', $this->l10n->t('Confirm:'), '', '', 'required', 'autocomplete="off"'], ]); diff --git a/src/Module/Settings/Account.php b/src/Module/Settings/Account.php index df8d41519c..f8f65e7206 100644 --- a/src/Module/Settings/Account.php +++ b/src/Module/Settings/Account.php @@ -549,7 +549,7 @@ class Account extends BaseSettings $notify_type = DI::pConfig()->get(DI::userSession()->getLocalUserId(), 'system', 'notify_type'); - $passwordRules = DI::l10n()->t('Allowed characters are a-z, A-Z, 0-9 and special characters except white spaces, accentuated letters and colon (:).') + $passwordRules = DI::l10n()->t('Allowed characters are a-z, A-Z, 0-9 and special characters except white spaces and accentuated letters.') . (PASSWORD_DEFAULT === PASSWORD_BCRYPT ? ' ' . DI::l10n()->t('Password length is limited to 72 characters.') : ''); $tpl = Renderer::getMarkupTemplate('settings/account.tpl'); From da4441875dab374eac12546ec63eef062fe3dfc5 Mon Sep 17 00:00:00 2001 From: Hypolite Petovan Date: Wed, 18 Jan 2023 20:42:10 -0500 Subject: [PATCH 11/53] Updated main translation file after editing strings --- view/lang/C/messages.po | 211 ++++++++++++++++++++-------------------- 1 file changed, 105 insertions(+), 106 deletions(-) diff --git a/view/lang/C/messages.po b/view/lang/C/messages.po index 938c5665ed..4dbb35b9df 100644 --- a/view/lang/C/messages.po +++ b/view/lang/C/messages.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: 2023.03-dev\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-01-14 21:19+0000\n" +"POT-Creation-Date: 2023-01-18 20:40-0500\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -49,7 +49,7 @@ msgstr "" #: src/Module/Attach.php:55 src/Module/BaseApi.php:95 #: src/Module/BaseNotifications.php:98 src/Module/BaseSettings.php:52 #: src/Module/Calendar/Event/API.php:88 src/Module/Calendar/Event/Form.php:84 -#: src/Module/Calendar/Export.php:62 src/Module/Calendar/Show.php:82 +#: src/Module/Calendar/Export.php:82 src/Module/Calendar/Show.php:82 #: src/Module/Contact/Advanced.php:60 src/Module/Contact/Follow.php:86 #: src/Module/Contact/Follow.php:159 src/Module/Contact/MatchInterests.php:86 #: src/Module/Contact/Suggestions.php:54 src/Module/Contact/Unfollow.php:66 @@ -385,7 +385,7 @@ msgstr "" #: mod/photos.php:67 mod/photos.php:132 mod/photos.php:577 #: src/Model/Event.php:514 src/Model/Profile.php:234 -#: src/Module/Calendar/Export.php:67 src/Module/Calendar/Show.php:74 +#: src/Module/Calendar/Export.php:74 src/Module/Calendar/Show.php:74 #: src/Module/DFRN/Poll.php:43 src/Module/Feed.php:65 src/Module/HCard.php:51 #: src/Module/Profile/Common.php:62 src/Module/Profile/Common.php:71 #: src/Module/Profile/Contacts.php:64 src/Module/Profile/Contacts.php:72 @@ -649,11 +649,11 @@ msgstr "" msgid "Map" msgstr "" -#: src/App.php:472 +#: src/App.php:470 msgid "No system theme config value set." msgstr "" -#: src/App.php:594 +#: src/App.php:592 msgid "Apologies but the website is unavailable at the moment." msgstr "" @@ -1877,9 +1877,9 @@ msgstr "" #: src/Content/Nav.php:335 src/Module/BaseModeration.php:127 #: src/Module/Moderation/Blocklist/Contact.php:110 -#: src/Module/Moderation/Blocklist/Server/Add.php:119 -#: src/Module/Moderation/Blocklist/Server/Import.php:115 -#: src/Module/Moderation/Blocklist/Server/Index.php:92 +#: src/Module/Moderation/Blocklist/Server/Add.php:121 +#: src/Module/Moderation/Blocklist/Server/Import.php:118 +#: src/Module/Moderation/Blocklist/Server/Index.php:95 #: src/Module/Moderation/Item/Delete.php:61 #: src/Module/Moderation/Summary.php:76 #: src/Module/Moderation/Users/Active.php:133 @@ -3296,7 +3296,7 @@ msgstr "" msgid "Title/Description:" msgstr "" -#: src/Model/Profile.php:1023 src/Module/Admin/Summary.php:222 +#: src/Model/Profile.php:1023 src/Module/Admin/Summary.php:220 #: src/Module/Moderation/Summary.php:77 msgid "Summary" msgstr "" @@ -3368,8 +3368,7 @@ msgid "The password length is limited to 72 characters." msgstr "" #: src/Model/User.php:807 -msgid "" -"The password can't contain accentuated letters, white spaces or colons (:)" +msgid "The password can't contain white spaces nor accentuated letters" msgstr "" #: src/Model/User.php:1002 @@ -3624,7 +3623,7 @@ msgstr "" #: src/Module/Admin/Federation.php:207 src/Module/Admin/Logs/Settings.php:79 #: src/Module/Admin/Logs/View.php:84 src/Module/Admin/Queue.php:72 #: src/Module/Admin/Site.php:435 src/Module/Admin/Storage.php:138 -#: src/Module/Admin/Summary.php:221 src/Module/Admin/Themes/Details.php:90 +#: src/Module/Admin/Summary.php:219 src/Module/Admin/Themes/Details.php:90 #: src/Module/Admin/Themes/Index.php:111 src/Module/Admin/Tos.php:77 #: src/Module/Moderation/Users/Create.php:61 #: src/Module/Moderation/Users/Pending.php:96 @@ -5007,12 +5006,12 @@ msgstr "" msgid "Database (legacy)" msgstr "" -#: src/Module/Admin/Summary.php:57 +#: src/Module/Admin/Summary.php:55 #, php-format msgid "Template engine (%s) error: %s" msgstr "" -#: src/Module/Admin/Summary.php:61 +#: src/Module/Admin/Summary.php:59 #, php-format msgid "" "Your DB still runs with MyISAM tables. You should change the engine type to " @@ -5023,7 +5022,7 @@ msgid "" "automatic conversion.
" msgstr "" -#: src/Module/Admin/Summary.php:66 +#: src/Module/Admin/Summary.php:64 #, php-format msgid "" "Your DB still runs with InnoDB tables in the Antelope file format. You " @@ -5034,7 +5033,7 @@ msgid "" "installation for an automatic conversion.
" msgstr "" -#: src/Module/Admin/Summary.php:76 +#: src/Module/Admin/Summary.php:74 #, php-format msgid "" "Your table_definition_cache is too low (%d). This can lead to the database " @@ -5042,39 +5041,39 @@ msgid "" "to %d. See here for more information.
" msgstr "" -#: src/Module/Admin/Summary.php:86 +#: src/Module/Admin/Summary.php:84 #, php-format msgid "" "There is a new version of Friendica available for download. Your current " "version is %1$s, upstream version is %2$s" msgstr "" -#: src/Module/Admin/Summary.php:95 +#: src/Module/Admin/Summary.php:93 msgid "" "The database update failed. Please run \"php bin/console.php dbstructure " "update\" from the command line and have a look at the errors that might " "appear." msgstr "" -#: src/Module/Admin/Summary.php:99 +#: src/Module/Admin/Summary.php:97 msgid "" "The last update failed. Please run \"php bin/console.php dbstructure update" "\" from the command line and have a look at the errors that might appear. " "(Some of the errors are possibly inside the logfile.)" msgstr "" -#: src/Module/Admin/Summary.php:104 +#: src/Module/Admin/Summary.php:102 msgid "The worker was never executed. Please check your database structure!" msgstr "" -#: src/Module/Admin/Summary.php:106 +#: src/Module/Admin/Summary.php:104 #, php-format msgid "" "The last worker execution was on %s UTC. This is older than one hour. Please " "check your crontab settings." msgstr "" -#: src/Module/Admin/Summary.php:111 +#: src/Module/Admin/Summary.php:109 #, php-format msgid "" "Friendica's configuration now is stored in config/local.config.php, please " @@ -5083,7 +5082,7 @@ msgid "" "with the transition." msgstr "" -#: src/Module/Admin/Summary.php:115 +#: src/Module/Admin/Summary.php:113 #, php-format msgid "" "Friendica's configuration now is stored in config/local.config.php, please " @@ -5092,7 +5091,7 @@ msgid "" "with the transition." msgstr "" -#: src/Module/Admin/Summary.php:119 +#: src/Module/Admin/Summary.php:117 #, php-format msgid "" "Friendica's configuration store \"%s\" isn't writable. Until then database " @@ -5100,7 +5099,7 @@ msgid "" "configuration changes won't be saved." msgstr "" -#: src/Module/Admin/Summary.php:125 +#: src/Module/Admin/Summary.php:123 #, php-format msgid "" "%s is not reachable on your system. This is a severe " @@ -5108,50 +5107,50 @@ msgid "" "href=\"%s\">the installation page for help." msgstr "" -#: src/Module/Admin/Summary.php:143 +#: src/Module/Admin/Summary.php:141 #, php-format msgid "The logfile '%s' is not usable. No logging possible (error: '%s')" msgstr "" -#: src/Module/Admin/Summary.php:157 +#: src/Module/Admin/Summary.php:155 #, php-format msgid "The debug logfile '%s' is not usable. No logging possible (error: '%s')" msgstr "" -#: src/Module/Admin/Summary.php:173 +#: src/Module/Admin/Summary.php:171 #, php-format msgid "" "Friendica's system.basepath was updated from '%s' to '%s'. Please remove the " "system.basepath from your db to avoid differences." msgstr "" -#: src/Module/Admin/Summary.php:181 +#: src/Module/Admin/Summary.php:179 #, php-format msgid "" "Friendica's current system.basepath '%s' is wrong and the config file '%s' " "isn't used." msgstr "" -#: src/Module/Admin/Summary.php:189 +#: src/Module/Admin/Summary.php:187 #, php-format msgid "" "Friendica's current system.basepath '%s' is not equal to the config file " "'%s'. Please fix your configuration." msgstr "" -#: src/Module/Admin/Summary.php:200 +#: src/Module/Admin/Summary.php:198 msgid "Message queues" msgstr "" -#: src/Module/Admin/Summary.php:206 +#: src/Module/Admin/Summary.php:204 msgid "Server Settings" msgstr "" -#: src/Module/Admin/Summary.php:224 +#: src/Module/Admin/Summary.php:222 msgid "Version" msgstr "" -#: src/Module/Admin/Summary.php:228 +#: src/Module/Admin/Summary.php:226 msgid "Active addons" msgstr "" @@ -5543,13 +5542,13 @@ msgstr "" #: src/Module/Install.php:286 src/Module/Install.php:291 #: src/Module/Install.php:305 src/Module/Install.php:320 #: src/Module/Install.php:347 -#: src/Module/Moderation/Blocklist/Server/Add.php:134 #: src/Module/Moderation/Blocklist/Server/Add.php:136 -#: src/Module/Moderation/Blocklist/Server/Import.php:126 -#: src/Module/Moderation/Blocklist/Server/Index.php:83 -#: src/Module/Moderation/Blocklist/Server/Index.php:84 -#: src/Module/Moderation/Blocklist/Server/Index.php:112 -#: src/Module/Moderation/Blocklist/Server/Index.php:113 +#: src/Module/Moderation/Blocklist/Server/Add.php:138 +#: src/Module/Moderation/Blocklist/Server/Import.php:129 +#: src/Module/Moderation/Blocklist/Server/Index.php:86 +#: src/Module/Moderation/Blocklist/Server/Index.php:87 +#: src/Module/Moderation/Blocklist/Server/Index.php:115 +#: src/Module/Moderation/Blocklist/Server/Index.php:116 #: src/Module/Moderation/Item/Delete.php:67 src/Module/Register.php:148 #: src/Module/Security/TwoFactor/Verify.php:101 #: src/Module/Settings/TwoFactor/Index.php:140 @@ -5589,15 +5588,15 @@ msgstr "" msgid "Basic" msgstr "" -#: src/Module/Calendar/Export.php:77 +#: src/Module/Calendar/Export.php:94 msgid "This calendar format is not supported" msgstr "" -#: src/Module/Calendar/Export.php:79 +#: src/Module/Calendar/Export.php:96 msgid "No exportable data found" msgstr "" -#: src/Module/Calendar/Export.php:96 +#: src/Module/Calendar/Export.php:113 msgid "calendar" msgstr "" @@ -6725,8 +6724,8 @@ msgid "On this server the following remote servers are blocked." msgstr "" #: src/Module/Friendica.php:84 -#: src/Module/Moderation/Blocklist/Server/Index.php:84 -#: src/Module/Moderation/Blocklist/Server/Index.php:108 +#: src/Module/Moderation/Blocklist/Server/Index.php:87 +#: src/Module/Moderation/Blocklist/Server/Index.php:111 msgid "Reason for the block" msgstr "" @@ -7399,32 +7398,32 @@ msgid "" msgstr "" #: src/Module/Moderation/Blocklist/Contact.php:135 -#: src/Module/Moderation/Blocklist/Server/Import.php:121 +#: src/Module/Moderation/Blocklist/Server/Import.php:124 msgid "Block Reason" msgstr "" -#: src/Module/Moderation/Blocklist/Server/Add.php:78 +#: src/Module/Moderation/Blocklist/Server/Add.php:80 msgid "Server domain pattern added to the blocklist." msgstr "" -#: src/Module/Moderation/Blocklist/Server/Add.php:86 +#: src/Module/Moderation/Blocklist/Server/Add.php:88 #, php-format msgid "%s server scheduled to be purged." msgid_plural "%s servers scheduled to be purged." msgstr[0] "" msgstr[1] "" -#: src/Module/Moderation/Blocklist/Server/Add.php:118 -#: src/Module/Moderation/Blocklist/Server/Import.php:114 +#: src/Module/Moderation/Blocklist/Server/Add.php:120 +#: src/Module/Moderation/Blocklist/Server/Import.php:117 msgid "← Return to the list" msgstr "" -#: src/Module/Moderation/Blocklist/Server/Add.php:120 +#: src/Module/Moderation/Blocklist/Server/Add.php:122 msgid "Block A New Server Domain Pattern" msgstr "" -#: src/Module/Moderation/Blocklist/Server/Add.php:121 -#: src/Module/Moderation/Blocklist/Server/Index.php:96 +#: src/Module/Moderation/Blocklist/Server/Add.php:123 +#: src/Module/Moderation/Blocklist/Server/Index.php:99 msgid "" "

The server domain pattern syntax is case-insensitive shell wildcard, " "comprising the following special characters:

\n" @@ -7434,55 +7433,55 @@ msgid "" "" msgstr "" -#: src/Module/Moderation/Blocklist/Server/Add.php:126 -#: src/Module/Moderation/Blocklist/Server/Index.php:104 +#: src/Module/Moderation/Blocklist/Server/Add.php:128 +#: src/Module/Moderation/Blocklist/Server/Index.php:107 msgid "Check pattern" msgstr "" -#: src/Module/Moderation/Blocklist/Server/Add.php:127 +#: src/Module/Moderation/Blocklist/Server/Add.php:129 msgid "Matching known servers" msgstr "" -#: src/Module/Moderation/Blocklist/Server/Add.php:128 +#: src/Module/Moderation/Blocklist/Server/Add.php:130 msgid "Server Name" msgstr "" -#: src/Module/Moderation/Blocklist/Server/Add.php:129 +#: src/Module/Moderation/Blocklist/Server/Add.php:131 msgid "Server Domain" msgstr "" -#: src/Module/Moderation/Blocklist/Server/Add.php:130 +#: src/Module/Moderation/Blocklist/Server/Add.php:132 msgid "Known Contacts" msgstr "" -#: src/Module/Moderation/Blocklist/Server/Add.php:131 +#: src/Module/Moderation/Blocklist/Server/Add.php:133 #, php-format msgid "%d known server" msgid_plural "%d known servers" msgstr[0] "" msgstr[1] "" -#: src/Module/Moderation/Blocklist/Server/Add.php:132 +#: src/Module/Moderation/Blocklist/Server/Add.php:134 msgid "Add pattern to the blocklist" msgstr "" -#: src/Module/Moderation/Blocklist/Server/Add.php:134 -#: src/Module/Moderation/Blocklist/Server/Index.php:113 +#: src/Module/Moderation/Blocklist/Server/Add.php:136 +#: src/Module/Moderation/Blocklist/Server/Index.php:116 msgid "Server Domain Pattern" msgstr "" -#: src/Module/Moderation/Blocklist/Server/Add.php:134 -#: src/Module/Moderation/Blocklist/Server/Index.php:113 +#: src/Module/Moderation/Blocklist/Server/Add.php:136 +#: src/Module/Moderation/Blocklist/Server/Index.php:116 msgid "" "The domain pattern of the new server to add to the blocklist. Do not include " "the protocol." msgstr "" -#: src/Module/Moderation/Blocklist/Server/Add.php:135 +#: src/Module/Moderation/Blocklist/Server/Add.php:137 msgid "Purge server" msgstr "" -#: src/Module/Moderation/Blocklist/Server/Add.php:135 +#: src/Module/Moderation/Blocklist/Server/Add.php:137 msgid "" "Also purges all the locally stored content authored by the known contacts " "registered on that server. Keeps the contacts and the server records. This " @@ -7494,149 +7493,149 @@ msgid_plural "" msgstr[0] "" msgstr[1] "" -#: src/Module/Moderation/Blocklist/Server/Add.php:136 +#: src/Module/Moderation/Blocklist/Server/Add.php:138 msgid "Block reason" msgstr "" -#: src/Module/Moderation/Blocklist/Server/Add.php:136 +#: src/Module/Moderation/Blocklist/Server/Add.php:138 msgid "" "The reason why you blocked this server domain pattern. This reason will be " "shown publicly in the server information page." msgstr "" -#: src/Module/Moderation/Blocklist/Server/Import.php:73 -#: src/Module/Moderation/Blocklist/Server/Import.php:82 +#: src/Module/Moderation/Blocklist/Server/Import.php:74 +#: src/Module/Moderation/Blocklist/Server/Import.php:83 msgid "Error importing pattern file" msgstr "" -#: src/Module/Moderation/Blocklist/Server/Import.php:88 +#: src/Module/Moderation/Blocklist/Server/Import.php:89 msgid "Local blocklist replaced with the provided file." msgstr "" -#: src/Module/Moderation/Blocklist/Server/Import.php:92 +#: src/Module/Moderation/Blocklist/Server/Import.php:93 #, php-format msgid "%d pattern was added to the local blocklist." msgid_plural "%d patterns were added to the local blocklist." msgstr[0] "" msgstr[1] "" -#: src/Module/Moderation/Blocklist/Server/Import.php:94 +#: src/Module/Moderation/Blocklist/Server/Import.php:95 msgid "No pattern was added to the local blocklist." msgstr "" -#: src/Module/Moderation/Blocklist/Server/Import.php:116 +#: src/Module/Moderation/Blocklist/Server/Import.php:119 msgid "Import a Server Domain Pattern Blocklist" msgstr "" -#: src/Module/Moderation/Blocklist/Server/Import.php:117 +#: src/Module/Moderation/Blocklist/Server/Import.php:120 msgid "" "

This file can be downloaded from the /friendica path of any " "Friendica server.

" msgstr "" -#: src/Module/Moderation/Blocklist/Server/Import.php:118 -#: src/Module/Moderation/Blocklist/Server/Index.php:103 +#: src/Module/Moderation/Blocklist/Server/Import.php:121 +#: src/Module/Moderation/Blocklist/Server/Index.php:106 msgid "Upload file" msgstr "" -#: src/Module/Moderation/Blocklist/Server/Import.php:119 +#: src/Module/Moderation/Blocklist/Server/Import.php:122 msgid "Patterns to import" msgstr "" -#: src/Module/Moderation/Blocklist/Server/Import.php:120 +#: src/Module/Moderation/Blocklist/Server/Import.php:123 msgid "Domain Pattern" msgstr "" -#: src/Module/Moderation/Blocklist/Server/Import.php:122 +#: src/Module/Moderation/Blocklist/Server/Import.php:125 msgid "Import Mode" msgstr "" -#: src/Module/Moderation/Blocklist/Server/Import.php:123 +#: src/Module/Moderation/Blocklist/Server/Import.php:126 msgid "Import Patterns" msgstr "" -#: src/Module/Moderation/Blocklist/Server/Import.php:124 +#: src/Module/Moderation/Blocklist/Server/Import.php:127 #, php-format msgid "%d total pattern" msgid_plural "%d total patterns" msgstr[0] "" msgstr[1] "" -#: src/Module/Moderation/Blocklist/Server/Import.php:126 -#: src/Module/Moderation/Blocklist/Server/Index.php:112 +#: src/Module/Moderation/Blocklist/Server/Import.php:129 +#: src/Module/Moderation/Blocklist/Server/Index.php:115 msgid "Server domain pattern blocklist CSV file" msgstr "" -#: src/Module/Moderation/Blocklist/Server/Import.php:127 +#: src/Module/Moderation/Blocklist/Server/Import.php:130 msgid "Append" msgstr "" -#: src/Module/Moderation/Blocklist/Server/Import.php:127 +#: src/Module/Moderation/Blocklist/Server/Import.php:130 msgid "" "Imports patterns from the file that weren't already existing in the current " "blocklist." msgstr "" -#: src/Module/Moderation/Blocklist/Server/Import.php:128 +#: src/Module/Moderation/Blocklist/Server/Import.php:131 msgid "Replace" msgstr "" -#: src/Module/Moderation/Blocklist/Server/Import.php:128 +#: src/Module/Moderation/Blocklist/Server/Import.php:131 msgid "Replaces the current blocklist by the imported patterns." msgstr "" -#: src/Module/Moderation/Blocklist/Server/Index.php:83 -#: src/Module/Moderation/Blocklist/Server/Index.php:107 +#: src/Module/Moderation/Blocklist/Server/Index.php:86 +#: src/Module/Moderation/Blocklist/Server/Index.php:110 msgid "Blocked server domain pattern" msgstr "" -#: src/Module/Moderation/Blocklist/Server/Index.php:85 +#: src/Module/Moderation/Blocklist/Server/Index.php:88 msgid "Delete server domain pattern" msgstr "" -#: src/Module/Moderation/Blocklist/Server/Index.php:85 +#: src/Module/Moderation/Blocklist/Server/Index.php:88 msgid "Check to delete this entry from the blocklist" msgstr "" -#: src/Module/Moderation/Blocklist/Server/Index.php:93 +#: src/Module/Moderation/Blocklist/Server/Index.php:96 msgid "Server Domain Pattern Blocklist" msgstr "" -#: src/Module/Moderation/Blocklist/Server/Index.php:94 +#: src/Module/Moderation/Blocklist/Server/Index.php:97 msgid "" "This page can be used to define a blocklist of server domain patterns from " "the federated network that are not allowed to interact with your node. For " "each domain pattern you should also provide the reason why you block it." msgstr "" -#: src/Module/Moderation/Blocklist/Server/Index.php:95 +#: src/Module/Moderation/Blocklist/Server/Index.php:98 msgid "" "The list of blocked server domain patterns will be made publically available " "on the /friendica page so that your users and " "people investigating communication problems can find the reason easily." msgstr "" -#: src/Module/Moderation/Blocklist/Server/Index.php:101 +#: src/Module/Moderation/Blocklist/Server/Index.php:104 msgid "Import server domain pattern blocklist" msgstr "" -#: src/Module/Moderation/Blocklist/Server/Index.php:102 +#: src/Module/Moderation/Blocklist/Server/Index.php:105 msgid "Add new entry to the blocklist" msgstr "" -#: src/Module/Moderation/Blocklist/Server/Index.php:105 +#: src/Module/Moderation/Blocklist/Server/Index.php:108 msgid "Save changes to the blocklist" msgstr "" -#: src/Module/Moderation/Blocklist/Server/Index.php:106 +#: src/Module/Moderation/Blocklist/Server/Index.php:109 msgid "Current Entries in the Blocklist" msgstr "" -#: src/Module/Moderation/Blocklist/Server/Index.php:109 +#: src/Module/Moderation/Blocklist/Server/Index.php:112 msgid "Delete entry from the blocklist" msgstr "" -#: src/Module/Moderation/Blocklist/Server/Index.php:110 +#: src/Module/Moderation/Blocklist/Server/Index.php:113 msgid "Delete entry from the blocklist?" msgstr "" @@ -8071,7 +8070,7 @@ msgstr "" msgid "Unsupported or missing response type" msgstr "" -#: src/Module/OAuth/Authorize.php:59 src/Module/OAuth/Token.php:73 +#: src/Module/OAuth/Authorize.php:59 src/Module/OAuth/Token.php:76 msgid "Incomplete request data" msgstr "" @@ -8082,11 +8081,11 @@ msgid "" "close this window: %s" msgstr "" -#: src/Module/OAuth/Token.php:78 +#: src/Module/OAuth/Token.php:81 msgid "Invalid data or unknown client" msgstr "" -#: src/Module/OAuth/Token.php:97 +#: src/Module/OAuth/Token.php:100 msgid "Unsupported or missing grant type" msgstr "" @@ -8767,7 +8766,7 @@ msgstr "" #: src/Module/Settings/Account.php:552 msgid "" "Allowed characters are a-z, A-Z, 0-9 and special characters except white " -"spaces, accentuated letters and colon (:)." +"spaces and accentuated letters." msgstr "" #: src/Module/Security/PasswordTooLong.php:101 From 594f738c6d0cbfd4e5bf5240c3e535cb8eb74b56 Mon Sep 17 00:00:00 2001 From: Hypolite Petovan Date: Wed, 18 Jan 2023 20:49:08 -0500 Subject: [PATCH 12/53] Create base `sub/direction.tpl` template from vier - Address https://github.com/friendica/friendica/issues/12486#issuecomment-1383249754 --- view/{theme/vier => }/templates/sub/direction.tpl | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename view/{theme/vier => }/templates/sub/direction.tpl (100%) diff --git a/view/theme/vier/templates/sub/direction.tpl b/view/templates/sub/direction.tpl similarity index 100% rename from view/theme/vier/templates/sub/direction.tpl rename to view/templates/sub/direction.tpl From 3b99b98678077914bc8798f7cc535c0b007545fd Mon Sep 17 00:00:00 2001 From: Hypolite Petovan Date: Wed, 18 Jan 2023 20:58:49 -0500 Subject: [PATCH 13/53] Truncate integer values before inserting them - Address https://github.com/friendica/friendica/issues/12486#issuecomment-1383250353 --- src/Database/Definition/DbaDefinition.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Database/Definition/DbaDefinition.php b/src/Database/Definition/DbaDefinition.php index b65a7d30ed..1e597bd64b 100644 --- a/src/Database/Definition/DbaDefinition.php +++ b/src/Database/Definition/DbaDefinition.php @@ -87,6 +87,10 @@ class DbaDefinition $data[$field] = mb_substr($data[$field], 0, $result[1]); } elseif (is_string($data[$field]) && preg_match("/binary\((\d*)\)/", $definition[$table]['fields'][$field]['type'], $result)) { $data[$field] = substr($data[$field], 0, $result[1]); + } elseif (is_numeric($data[$field]) && $definition[$table]['fields'][$field]['type'] === 'int') { + $data[$field] = min(max((int)$data[$field], -2147483648), 2147483647); + } elseif (is_numeric($data[$field]) && $definition[$table]['fields'][$field]['type'] === 'int unsigned') { + $data[$field] = min(max((int)$data[$field], 0), 4294967295); } $fields[$field] = $data[$field]; } From c05956137af4775f89865f8e207ace4b73c9a315 Mon Sep 17 00:00:00 2001 From: Hypolite Petovan Date: Wed, 18 Jan 2023 21:01:07 -0500 Subject: [PATCH 14/53] Default maintenance reason to empty string in Module\Maintenance - Address https://github.com/friendica/friendica/issues/12486#issuecomment-1383250546 --- src/Module/Maintenance.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Module/Maintenance.php b/src/Module/Maintenance.php index 412723db31..67f65b8e39 100644 --- a/src/Module/Maintenance.php +++ b/src/Module/Maintenance.php @@ -36,7 +36,7 @@ class Maintenance extends BaseModule { protected function content(array $request = []): string { - $reason = DI::config()->get('system', 'maintenance_reason'); + $reason = DI::config()->get('system', 'maintenance_reason') ?? ''; if ((substr(Strings::normaliseLink($reason), 0, 7) === 'http://') || (substr(Strings::normaliseLink($reason), 0, 8) === 'https://')) { From 1e219456581b0a6563f915b2d9aa41c87eea2343 Mon Sep 17 00:00:00 2001 From: Damian Wajer Date: Tue, 17 Jan 2023 19:05:24 +0100 Subject: [PATCH 15/53] [frio] Larger clickable area for tabs --- view/theme/frio/css/style.css | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/view/theme/frio/css/style.css b/view/theme/frio/css/style.css index 3c4aaa7c6e..c32a6b8141 100644 --- a/view/theme/frio/css/style.css +++ b/view/theme/frio/css/style.css @@ -2190,7 +2190,6 @@ ul.tabs { list-style: none; height: 100%; padding: 0; - padding-top: 10px; margin: 0; } ul.tabs li { @@ -2203,8 +2202,8 @@ ul.tabs li { transition: all 0.15s ease; } ul.tabs li a { - margin-left: 10px; - margin-right: 10px; + display: block; + padding: 11px 10px; } ul.tabs li:hover, ul.tabs li.active { @@ -2214,7 +2213,7 @@ ul.tabs li.active { padding-top: 0; } #dropdownMenuTools-xs { - padding: 9px 10px; + padding: 9px 15px; } ul.tabbar ul.tabs-extended:hover li.dropdown { border-bottom: 0; From 9dcc0f6f20903dec7117b560e54ba7402c32fb5c Mon Sep 17 00:00:00 2001 From: Damian Wajer Date: Tue, 17 Jan 2023 19:36:36 +0100 Subject: [PATCH 16/53] [frio] Larger clickable area for aside links --- view/theme/frio/css/style.css | 33 ++++++++++++++----- view/theme/frio/templates/group_side.tpl | 4 +-- .../frio/templates/widget/peoplefind.tpl | 12 +++---- 3 files changed, 33 insertions(+), 16 deletions(-) diff --git a/view/theme/frio/css/style.css b/view/theme/frio/css/style.css index c32a6b8141..537652cd14 100644 --- a/view/theme/frio/css/style.css +++ b/view/theme/frio/css/style.css @@ -367,6 +367,10 @@ btn-eventnav:hover { aside .badge { opacity: 0.7; } +.forum-widget-entry .badge, +.sidebar-group-li .badge { + margin-top: 6px; +} /* disabled elements */ .community-content-wrapper > h3, @@ -1044,7 +1048,6 @@ aside .widget, position: relative; margin-bottom: 20px; padding: 10px; - font-size: 13px; overflow: auto; } aside .widget h3, @@ -1052,7 +1055,7 @@ aside .widget h3, font-weight: bold; font-size: 16px; margin: 0; - padding-bottom: 20px; + padding-bottom: 10px; } aside .widget ul, @@ -1065,10 +1068,11 @@ aside .widget ul, list-style: none; } +aside .widget li .label { + float: left; +} aside .widget li, .nav-container .widget li { - padding-top: 2px; - padding-bottom: 2px; padding-left: 20px; padding-right: 10px; } @@ -1081,6 +1085,12 @@ aside .widget li.selected, border-left: 3px solid $link_color !important; padding-left: 17px; } +.side-link-link, +aside .widget li a { + display: block; + padding-top: 6px; + padding-bottom: 6px; +} aside .widget li a, aside .widget li a:hover { color: $font_color_darker; @@ -1300,8 +1310,12 @@ div#sidebar-group-list { } .group-edit-tool { + padding-top: 0; color: $font_color_darker; } +.sidebar-widget-header .group-edit-tool { + margin-top: -5px; +} .faded-icon { color: $font_color_darker; @@ -1316,9 +1330,12 @@ div#sidebar-group-list { margin-left: 20px; } -aside #group-sidebar .sidebar-group-li:hover .group-edit-tool.faded-icon, -aside #saved-search-list .saved-search-li:hover .savedsearchdrop.faded-icon, -aside .widget:hover .widget-action.faded-icon { +aside .widget-action { + padding: 5px 10px; +} +aside #group-sidebar .sidebar-group-li .group-edit-tool.faded-icon:hover, +aside #saved-search-list .saved-search-li .savedsearchdrop.faded-icon:hover, +aside .widget.widget-action.faded-icon:hover { opacity: 0.8; transition: all 0.25s ease-in-out; } @@ -1328,7 +1345,7 @@ aside .widget .widget-action.faded-icon:hover { opacity: 1; } aside #group-sidebar li .group-checkbox { - margin: 0; + margin: 6px 0 0; } aside #group-sidebar li .group-edit-tool { padding-right: 10px; diff --git a/view/theme/frio/templates/group_side.tpl b/view/theme/frio/templates/group_side.tpl index 0c5e76a05e..f9027e6123 100644 --- a/view/theme/frio/templates/group_side.tpl +++ b/view/theme/frio/templates/group_side.tpl @@ -2,7 +2,7 @@

{{$title}}

-