Merge branch 'develop' into eventdispatcher-part3

This commit is contained in:
Art4 2025-04-28 11:02:09 +00:00
commit ec16994738
21 changed files with 572 additions and 132 deletions

View file

@ -51,6 +51,11 @@ class L10n
'zh-cn' => '简体中文',
];
const LANG_PARENTS = [
'en-gb' => 'en', 'da-dk' => 'da', 'fi-fi' => 'fi',
'nb-no' => 'nb', 'pt-br' => 'pt', 'zh-cn' => 'zh'
];
/** @var string Undetermined language */
const UNDETERMINED_LANGUAGE = 'un';
@ -150,6 +155,11 @@ class L10n
$a = new \stdClass();
$a->strings = [];
$child = array_search($lang, $this::LANG_PARENTS);
if ($child) {
$lang = $child;
}
// load enabled addons strings
$addons = array_keys($this->config->get('addons') ?? []);
foreach ($addons as $addon) {
@ -203,6 +213,8 @@ class L10n
// start with quality zero (every guessed language is more acceptable ..)
$current_q = 0;
$supported = self::getSupportedLanguages();
foreach ($acceptedLanguages as $acceptedLanguage) {
$res = preg_match(
'/^([a-z]{1,8}(?:-[a-z]{1,8})*)(?:;\s*q=(0(?:\.[0-9]{1,3})?|1(?:\.0{1,3})?))?$/i',
@ -230,8 +242,7 @@ class L10n
while (count($lang_code)) {
// try to mix them so we can get double-code parts too
$match_lang = strtolower(join('-', $lang_code));
if (file_exists(__DIR__ . "/../../view/lang/$match_lang") &&
is_dir(__DIR__ . "/../../view/lang/$match_lang")) {
if (in_array($match_lang, $supported)) {
if ($lang_quality > $current_q) {
$current_lang = $match_lang;
$current_q = $lang_quality;
@ -247,6 +258,20 @@ class L10n
return $current_lang;
}
private static function getSupportedLanguages(): array
{
$languages = [];
foreach (glob('view/lang/*/strings.php') as $language) {
$code = str_replace(['view/lang/', '/strings.php'], [], $language);
if (!empty(self::LANG_PARENTS[$code])) {
$languages[] = self::LANG_PARENTS[$code];
}
$languages[] = $code;
}
return $languages;
}
/**
* Return the localized version of the provided string with optional string interpolation
*
@ -402,8 +427,10 @@ class L10n
];
if (in_array('cld2', get_loaded_extensions())) {
$additional_langs = array_merge($additional_langs,
['dv', 'kn', 'lo', 'ml', 'or', 'pa', 'sd', 'si', 'te', 'yi']);
$additional_langs = array_merge(
$additional_langs,
['dv', 'kn', 'lo', 'ml', 'or', 'pa', 'sd', 'si', 'te', 'yi']
);
}
$langs = array_merge($additional_langs, array_keys($this->getAvailableLanguages()));
@ -419,7 +446,7 @@ class L10n
*/
public function getLanguageCodes(bool $international = false): array
{
$iso639 = new \Matriphe\ISO639\ISO639;
$iso639 = new \Matriphe\ISO639\ISO639();
// In ISO 639-2 undetermined languages have got the code "und".
// There is no official code for ISO 639-1, but "un" is not assigned to any language.
@ -477,13 +504,17 @@ class L10n
*/
public function getDay(string $s): string
{
$ret = str_replace(['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'],
$ret = str_replace(
['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'],
[$this->t('Monday'), $this->t('Tuesday'), $this->t('Wednesday'), $this->t('Thursday'), $this->t('Friday'), $this->t('Saturday'), $this->t('Sunday')],
$s);
$s
);
$ret = str_replace(['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
$ret = str_replace(
['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
[$this->t('January'), $this->t('February'), $this->t('March'), $this->t('April'), $this->t('May'), $this->t('June'), $this->t('July'), $this->t('August'), $this->t('September'), $this->t('October'), $this->t('November'), $this->t('December')],
$ret);
$ret
);
return $ret;
}
@ -496,13 +527,17 @@ class L10n
*/
public function getDayShort(string $s): string
{
$ret = str_replace(['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
$ret = str_replace(
['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
[$this->t('Mon'), $this->t('Tue'), $this->t('Wed'), $this->t('Thu'), $this->t('Fri'), $this->t('Sat'), $this->t('Sun')],
$s);
$s
);
$ret = str_replace(['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
$ret = str_replace(
['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
[$this->t('Jan'), $this->t('Feb'), $this->t('Mar'), $this->t('Apr'), $this->t('May'), $this->t('Jun'), $this->t('Jul'), $this->t('Aug'), $this->t('Sep'), $this->t('Oct'), $this->t('Nov'), $this->t('Dec')],
$ret);
$ret
);
return $ret;
}

View file

@ -12,6 +12,8 @@ use Psr\Log\LogLevel;
/**
* Abstract class for creating logger types, which includes common necessary logic/content
*
* @deprecated 2025.02 Implement `\Friendica\Core\Logger\Factory\LoggerFactory` instead
*/
abstract class AbstractLoggerTypeFactory
{
@ -25,6 +27,8 @@ abstract class AbstractLoggerTypeFactory
*/
public function __construct(IHaveCallIntrospections $introspection, string $channel)
{
@trigger_error('Class `' . __CLASS__ . '` is deprecated since 2025.02 and will be removed after 5 months, implement `\Friendica\Core\Logger\Factory\LoggerFactory` instead.', E_USER_DEPRECATED);
$this->channel = $channel;
$this->introspection = $introspection;
}
@ -44,21 +48,21 @@ abstract class AbstractLoggerTypeFactory
// legacy WARNING
case "0":
return LogLevel::ERROR;
// legacy INFO
// legacy INFO
case "1":
return LogLevel::WARNING;
// legacy TRACE
// legacy TRACE
case "2":
return LogLevel::NOTICE;
// legacy DEBUG
// legacy DEBUG
case "3":
return LogLevel::INFO;
// legacy DATA
// legacy DATA
case "4":
// legacy ALL
// legacy ALL
case "5":
return LogLevel::DEBUG;
// default if nothing set
// default if nothing set
default:
return $level;
}

View file

@ -0,0 +1,73 @@
<?php
// Copyright (C) 2010-2024, the Friendica project
// SPDX-FileCopyrightText: 2010-2024 the Friendica project
//
// SPDX-License-Identifier: AGPL-3.0-or-later
declare(strict_types=1);
namespace Friendica\Core\Logger\Factory;
use Friendica\Core\Config\Capability\IManageConfigValues;
use Psr\Log\LoggerInterface;
use Psr\Log\NullLogger;
/**
* Delegates the creation of a logger based on config to other factories
*
* @internal
*/
final class DelegatingLoggerFactory implements LoggerFactory
{
private IManageConfigValues $config;
/** @var array<string,LoggerFactory> */
private array $factories = [];
public function __construct(IManageConfigValues $config)
{
$this->config = $config;
}
public function registerFactory(string $name, LoggerFactory $factory): void
{
$this->factories[$name] = $factory;
}
/**
* Creates and returns a PSR-3 Logger instance.
*
* Calling this method multiple times with the same parameters SHOULD return the same object.
*
* @param \Psr\Log\LogLevel::* $logLevel The log level
* @param \Friendica\Core\Logger\Capability\LogChannel::* $logChannel The log channel
*/
public function createLogger(string $logLevel, string $logChannel): LoggerInterface
{
$factoryName = $this->config->get('system', 'logger_config') ?? '';
/**
* @deprecated 2025.02 The value `monolog` for `system.logger_config` inside the `config/local.config.php` file is deprecated, please use `stream` or `syslog` instead.
*/
if ($factoryName === 'monolog') {
@trigger_error('The config `system.logger_config` with value `monolog` is deprecated since 2025.02 and will stop working in 5 months, please change the value to `stream` or `syslog` in the `config/local.config.php` file.', \E_USER_DEPRECATED);
$factoryName = 'stream';
}
if (!array_key_exists($factoryName, $this->factories)) {
return new NullLogger();
}
$factory = $this->factories[$factoryName];
try {
$logger = $factory->createLogger($logLevel, $logChannel);
} catch (\Throwable $th) {
return new NullLogger();
}
return $logger;
}
}

View file

@ -1,61 +0,0 @@
<?php
// Copyright (C) 2010-2024, the Friendica project
// SPDX-FileCopyrightText: 2010-2024 the Friendica project
//
// SPDX-License-Identifier: AGPL-3.0-or-later
declare(strict_types=1);
namespace Friendica\Core\Logger\Factory;
use Friendica\Core\Config\Capability\IManageConfigValues;
use Friendica\Core\Hooks\Capability\ICanCreateInstances;
use Friendica\Util\Profiler;
use Psr\Log\LoggerInterface;
/**
* Bridge for the legacy Logger factory.
*
* This class can be removed after the following classes are replaced or
* refactored implementing the `\Friendica\Core\Logger\Factory\LoggerFactory`:
*
* - Friendica\Core\Logger\Factory\StreamLogger
* - Friendica\Core\Logger\Factory\SyslogLogger
* - monolog addon: Friendica\Addon\monolog\src\Factory\Monolog
*
* @see \Friendica\Core\Logger\Factory\StreamLogger
* @see \Friendica\Core\Logger\Factory\SyslogLogger
*
* @internal
*/
final class LegacyLoggerFactory implements LoggerFactory
{
private ICanCreateInstances $instanceCreator;
private IManageConfigValues $config;
private Profiler $profiler;
public function __construct(ICanCreateInstances $instanceCreator, IManageConfigValues $config, Profiler $profiler)
{
$this->instanceCreator = $instanceCreator;
$this->config = $config;
$this->profiler = $profiler;
}
/**
* Creates and returns a PSR-3 Logger instance.
*
* Calling this method multiple times with the same parameters SHOULD return the same object.
*
* @param \Psr\Log\LogLevel::* $logLevel The log level
* @param \Friendica\Core\Logger\Capability\LogChannel::* $logChannel The log channel
*/
public function createLogger(string $logLevel, string $logChannel): LoggerInterface
{
$factory = new Logger($logChannel);
return $factory->create($this->instanceCreator, $this->config, $this->profiler);
}
}

View file

@ -18,6 +18,8 @@ use Throwable;
/**
* The logger factory for the core logging instances
*
* @deprecated 2025.02 Implement `\Friendica\Core\Logger\Factory\LoggerFactory` instead
*/
class Logger
{
@ -26,6 +28,8 @@ class Logger
public function __construct(string $channel = LogChannel::DEFAULT)
{
@trigger_error('Class `' . __CLASS__ . '` is deprecated since 2025.02 and will be removed after 5 months, implement `\Friendica\Core\Logger\Factory\LoggerFactory` instead.', E_USER_DEPRECATED);
$this->channel = $channel;
}

View file

@ -20,6 +20,8 @@ use Psr\Log\NullLogger;
/**
* The logger factory for the StreamLogger instance
*
* @deprecated 2025.02 Implement `\Friendica\Core\Logger\Factory\LoggerFactory` instead
* @see StreamLoggerFactory
* @see StreamLoggerClass
*/
class StreamLogger extends AbstractLoggerTypeFactory
@ -38,6 +40,8 @@ class StreamLogger extends AbstractLoggerTypeFactory
*/
public function create(IManageConfigValues $config, string $logfile = null, string $channel = null): LoggerInterface
{
@trigger_error('Class `' . __CLASS__ . '` is deprecated since 2025.02 and will be removed after 5 months, implement `\Friendica\Core\Logger\Factory\LoggerFactory` instead.', E_USER_DEPRECATED);
$fileSystem = new FileSystem();
$logfile = $logfile ?? $config->get('system', 'logfile');

View file

@ -0,0 +1,76 @@
<?php
// Copyright (C) 2010-2024, the Friendica project
// SPDX-FileCopyrightText: 2010-2024 the Friendica project
//
// SPDX-License-Identifier: AGPL-3.0-or-later
declare(strict_types=1);
namespace Friendica\Core\Logger\Factory;
use Friendica\Core\Config\Capability\IManageConfigValues;
use Friendica\Core\Logger\Capability\IHaveCallIntrospections;
use Friendica\Core\Logger\Exception\LoggerArgumentException;
use Friendica\Core\Logger\Exception\LogLevelException;
use Friendica\Core\Logger\Type\StreamLogger;
use Friendica\Core\Logger\Util\FileSystemUtil;
use Psr\Log\LoggerInterface;
/**
* The logger factory for the StreamLogger instance
*
* @see StreamLogger
*
* @internal
*/
final class StreamLoggerFactory implements LoggerFactory
{
private IManageConfigValues $config;
private IHaveCallIntrospections $introspection;
private FileSystemUtil $fileSystem;
public function __construct(
IManageConfigValues $config,
IHaveCallIntrospections $introspection,
FileSystemUtil $fileSystem
) {
$this->config = $config;
$this->introspection = $introspection;
$this->fileSystem = $fileSystem;
}
/**
* Creates and returns a PSR-3 Logger instance.
*
* Calling this method multiple times with the same parameters SHOULD return the same object.
*
* @param \Psr\Log\LogLevel::* $logLevel The log level
* @param \Friendica\Core\Logger\Capability\LogChannel::* $logChannel The log channel
*
* @throws LoggerArgumentException
* @throws LogLevelException
*/
public function createLogger(string $logLevel, string $logChannel): LoggerInterface
{
$logfile = $this->config->get('system', 'logfile');
if (!file_exists($logfile) || !is_writable($logfile)) {
throw new LoggerArgumentException(sprintf('"%s" is not a valid logfile.', $logfile));
}
if (! array_key_exists($logLevel, StreamLogger::levelToInt)) {
throw new LogLevelException(sprintf('The log level "%s" is not supported by "%s".', $logLevel, StreamLogger::class));
}
return new StreamLogger(
$logChannel,
$this->introspection,
$this->fileSystem->createStream($logfile),
StreamLogger::levelToInt[$logLevel],
getmypid()
);
}
}

View file

@ -16,6 +16,8 @@ use Psr\Log\LoggerInterface;
/**
* The logger factory for the SyslogLogger instance
*
* @deprecated 2025.02 Implement `\Friendica\Core\Logger\Factory\LoggerFactory` instead
* @see SyslogLoggerFactory
* @see SyslogLoggerClass
*/
class SyslogLogger extends AbstractLoggerTypeFactory
@ -31,6 +33,8 @@ class SyslogLogger extends AbstractLoggerTypeFactory
*/
public function create(IManageConfigValues $config): LoggerInterface
{
@trigger_error('Class `' . __CLASS__ . '` is deprecated since 2025.02 and will be removed after 5 months, implement `\Friendica\Core\Logger\Factory\LoggerFactory` instead.', E_USER_DEPRECATED);
$logOpts = $config->get('system', 'syslog_flags') ?? SyslogLoggerClass::DEFAULT_FLAGS;
$logFacility = $config->get('system', 'syslog_facility') ?? SyslogLoggerClass::DEFAULT_FACILITY;
$loglevel = SyslogLogger::mapLegacyConfigDebugLevel($config->get('system', 'loglevel'));

View file

@ -0,0 +1,66 @@
<?php
// Copyright (C) 2010-2024, the Friendica project
// SPDX-FileCopyrightText: 2010-2024 the Friendica project
//
// SPDX-License-Identifier: AGPL-3.0-or-later
declare(strict_types=1);
namespace Friendica\Core\Logger\Factory;
use Friendica\Core\Config\Capability\IManageConfigValues;
use Friendica\Core\Logger\Capability\IHaveCallIntrospections;
use Friendica\Core\Logger\Exception\LogLevelException;
use Friendica\Core\Logger\Type\SyslogLogger;
use Psr\Log\LoggerInterface;
/**
* The logger factory for the SyslogLogger instance
*
* @see SyslogLogger
*
* @internal
*/
final class SyslogLoggerFactory implements LoggerFactory
{
private IManageConfigValues $config;
private IHaveCallIntrospections $introspection;
public function __construct(
IManageConfigValues $config,
IHaveCallIntrospections $introspection
) {
$this->config = $config;
$this->introspection = $introspection;
}
/**
* Creates and returns a PSR-3 Logger instance.
*
* Calling this method multiple times with the same parameters SHOULD return the same object.
*
* @param \Psr\Log\LogLevel::* $logLevel The log level
* @param \Friendica\Core\Logger\Capability\LogChannel::* $logChannel The log channel
*
* @throws LogLevelException
*/
public function createLogger(string $logLevel, string $logChannel): LoggerInterface
{
$logOpts = (string) $this->config->get('system', 'syslog_flags') ?? SyslogLogger::DEFAULT_FLAGS;
$logFacility = (string) $this->config->get('system', 'syslog_facility') ?? SyslogLogger::DEFAULT_FACILITY;
if (!array_key_exists($logLevel, SyslogLogger::logLevels)) {
throw new LogLevelException(sprintf('The log level "%s" is not supported by "%s".', $logLevel, SyslogLogger::class));
}
return new SyslogLogger(
$logChannel,
$this->introspection,
(string) SyslogLogger::logLevels[$logLevel],
$logOpts,
$logFacility
);
}
}

View file

@ -12,7 +12,7 @@ use Friendica\Core\Logger\Exception\LoggerUnusableException;
/**
* Util class for filesystem manipulation for Logger classes
*/
class FileSystem
class FileSystem implements FileSystemUtil
{
/**
* @var string a error message
@ -31,7 +31,7 @@ class FileSystem
public function createDir(string $file): string
{
$dirname = null;
$pos = strpos($file, '://');
$pos = strpos($file, '://');
if (!$pos) {
$dirname = realpath(dirname($file));

View file

@ -0,0 +1,40 @@
<?php
// Copyright (C) 2010-2024, the Friendica project
// SPDX-FileCopyrightText: 2010-2024 the Friendica project
//
// SPDX-License-Identifier: AGPL-3.0-or-later
namespace Friendica\Core\Logger\Util;
use Friendica\Core\Logger\Exception\LoggerUnusableException;
/**
* interface for Util class for filesystem manipulation for Logger classes
*
* @internal
*/
interface FileSystemUtil
{
/**
* Creates a directory based on a file, which gets accessed
*
* @param string $file The file
*
* @return string The directory name (empty if no directory is found, like urls)
*
* @throws LoggerUnusableException
*/
public function createDir(string $file): string;
/**
* Creates a stream based on a URL (could be a local file or a real URL)
*
* @param string $url The file/url
*
* @return resource the open stream resource
*
* @throws LoggerUnusableException
*/
public function createStream(string $url);
}

View file

@ -1729,7 +1729,7 @@ class Probe
$data = [
'network' => Protocol::BLUESKY,
'url' => $profile->did,
'alias' => ATProtocol::WEB . '/profile/' . $nick,
'alias' => ATProtocol::WEB . '/profile/' . $profile->did,
'name' => $name ?: $nick,
'nick' => $nick,
'addr' => $nick,

View file

@ -117,7 +117,7 @@ class Actor
$name = $profile->displayName ?? $nick;
$fields = [
'alias' => ATProtocol::WEB . '/profile/' . $nick,
'alias' => ATProtocol::WEB . '/profile/' . $profile->did,
'name' => $name ?: $nick,
'nick' => $nick,
'addr' => $nick,

View file

@ -72,7 +72,7 @@ class Processor
public function processIdentity(stdClass $data)
{
$fields = [
'alias' => ATProtocol::WEB . '/profile/' . $data->identity->handle,
'alias' => ATProtocol::WEB . '/profile/' . $data->identity->did,
'nick' => $data->identity->handle,
'addr' => $data->identity->handle,
'updated' => DateTimeFormat::utc($data->identity->time, DateTimeFormat::MYSQL),

View file

@ -334,7 +334,8 @@ return [
'lock_driver' => '',
// logger_config (String)
// Sets the logging adapter of Friendica globally (monolog, syslog, stream)
// Sets the logging adapter of Friendica globally (syslog, stream)
// @deprecated 2025.02 The value `monolog` is deprecated, please use `stream` or `syslog` instead.
'logger_config' => 'stream',
// syslog_flags (Integer)

View file

@ -171,11 +171,24 @@ return (function(string $basepath, array $getVars, array $serverVars, array $coo
],
\Friendica\Core\Logger\LoggerManager::class => [
'substitutions' => [
\Friendica\Core\Logger\Factory\LoggerFactory::class => \Friendica\Core\Logger\Factory\LegacyLoggerFactory::class,
\Friendica\Core\Logger\Factory\LoggerFactory::class => \Friendica\Core\Logger\Factory\DelegatingLoggerFactory::class,
],
],
\Friendica\Core\Logger\Factory\LoggerFactory::class => [
'instanceOf' => \Friendica\Core\Logger\Factory\LegacyLoggerFactory::class,
'instanceOf' => \Friendica\Core\Logger\Factory\DelegatingLoggerFactory::class,
'call' => [
['registerFactory', ['stream', [Dice::INSTANCE => '$StreamLoggerFactory']]],
['registerFactory', ['syslog', [Dice::INSTANCE => '$SyslogLoggerFactory']]],
],
],
'$StreamLoggerFactory' => [
'instanceOf' => \Friendica\Core\Logger\Factory\StreamLoggerFactory::class,
'substitutions' => [
\Friendica\Core\Logger\Util\FileSystemUtil::class => \Friendica\Core\Logger\Util\FileSystem::class,
],
],
'$SyslogLoggerFactory' => [
'instanceOf' => \Friendica\Core\Logger\Factory\SyslogLoggerFactory::class,
],
\Friendica\Core\Logger\Type\SyslogLogger::class => [
'instanceOf' => \Friendica\Core\Logger\Factory\SyslogLogger::class,

View file

@ -0,0 +1,75 @@
<?php
// Copyright (C) 2010-2024, the Friendica project
// SPDX-FileCopyrightText: 2010-2024 the Friendica project
//
// SPDX-License-Identifier: AGPL-3.0-or-later
declare(strict_types=1);
namespace Friendica\Test\Unit\Core\Logger\Factory;
use Exception;
use Friendica\Core\Config\Capability\IManageConfigValues;
use Friendica\Core\Logger\Capability\LogChannel;
use Friendica\Core\Logger\Factory\DelegatingLoggerFactory;
use Friendica\Core\Logger\Factory\LoggerFactory;
use PHPUnit\Framework\TestCase;
use Psr\Log\LoggerInterface;
use Psr\Log\LogLevel;
use Psr\Log\NullLogger;
class DelegatingLoggerFactoryTest extends TestCase
{
public function testCreateLoggerReturnsPsrLogger(): void
{
$config = $this->createStub(IManageConfigValues::class);
$config->method('get')->willReturnMap([
['system', 'logger_config', null, 'test'],
]);
$factory = new DelegatingLoggerFactory($config);
$factory->registerFactory('test', $this->createStub(LoggerFactory::class));
$this->assertInstanceOf(
LoggerInterface::class,
$factory->createLogger(LogLevel::DEBUG, LogChannel::DEFAULT)
);
}
public function testCreateLoggerWithoutRegisteredFactoryReturnsNullLogger(): void
{
$config = $this->createStub(IManageConfigValues::class);
$config->method('get')->willReturnMap([
['system', 'logger_config', null, 'not-existing-factory'],
]);
$factory = new DelegatingLoggerFactory($config);
$this->assertInstanceOf(
NullLogger::class,
$factory->createLogger(LogLevel::DEBUG, LogChannel::DEFAULT)
);
}
public function testCreateLoggerWithExceptionThrowingFactoryReturnsNullLogger(): void
{
$config = $this->createStub(IManageConfigValues::class);
$config->method('get')->willReturnMap([
['system', 'logger_config', null, 'test'],
]);
$factory = new DelegatingLoggerFactory($config);
$brokenFactory = $this->createStub(LoggerFactory::class);
$brokenFactory->method('createLogger')->willThrowException(new Exception());
$factory->registerFactory('test', $brokenFactory);
$this->assertInstanceOf(
NullLogger::class,
$factory->createLogger(LogLevel::DEBUG, LogChannel::DEFAULT)
);
}
}

View file

@ -1,36 +0,0 @@
<?php
// Copyright (C) 2010-2024, the Friendica project
// SPDX-FileCopyrightText: 2010-2024 the Friendica project
//
// SPDX-License-Identifier: AGPL-3.0-or-later
declare(strict_types=1);
namespace Friendica\Test\Unit\Core\Logger\Factory;
use Friendica\Core\Config\Capability\IManageConfigValues;
use Friendica\Core\Hooks\Capability\ICanCreateInstances;
use Friendica\Core\Logger\Capability\LogChannel;
use Friendica\Core\Logger\Factory\LegacyLoggerFactory;
use Friendica\Util\Profiler;
use PHPUnit\Framework\TestCase;
use Psr\Log\LoggerInterface;
use Psr\Log\LogLevel;
class LegacyLoggerFactoryTest extends TestCase
{
public function testCreateLoggerReturnsPsrLogger(): void
{
$factory = new LegacyLoggerFactory(
$this->createStub(ICanCreateInstances::class),
$this->createStub(IManageConfigValues::class),
$this->createStub(Profiler::class),
);
$this->assertInstanceOf(
LoggerInterface::class,
$factory->createLogger(LogLevel::DEBUG, LogChannel::DEFAULT)
);
}
}

View file

@ -0,0 +1,81 @@
<?php
// Copyright (C) 2010-2024, the Friendica project
// SPDX-FileCopyrightText: 2010-2024 the Friendica project
//
// SPDX-License-Identifier: AGPL-3.0-or-later
declare(strict_types=1);
namespace Friendica\Test\Unit\Core\Logger\Factory;
use Friendica\Core\Config\Capability\IManageConfigValues;
use Friendica\Core\Logger\Capability\IHaveCallIntrospections;
use Friendica\Core\Logger\Capability\LogChannel;
use Friendica\Core\Logger\Exception\LoggerArgumentException;
use Friendica\Core\Logger\Exception\LogLevelException;
use Friendica\Core\Logger\Factory\StreamLoggerFactory;
use Friendica\Core\Logger\Util\FileSystemUtil;
use PHPUnit\Framework\TestCase;
use Psr\Log\LoggerInterface;
use Psr\Log\LogLevel;
class StreamLoggerFactoryTest extends TestCase
{
public function testCreateLoggerReturnsPsrLogger(): void
{
$config = $this->createStub(IManageConfigValues::class);
$config->method('get')->willReturnMap([
['system', 'logfile', null, dirname(__DIR__, 4) . '/datasets/log/empty.friendica.log.txt'],
]);
$factory = new StreamLoggerFactory(
$config,
$this->createStub(IHaveCallIntrospections::class),
$this->createStub(FileSystemUtil::class),
);
$this->assertInstanceOf(
LoggerInterface::class,
$factory->createLogger(LogLevel::DEBUG, LogChannel::DEFAULT)
);
}
public function testCreateLoggerWithInvalidLogfileThrowsException(): void
{
$config = $this->createStub(IManageConfigValues::class);
$config->method('get')->willReturnMap([
['system', 'logfile', null, dirname(__DIR__, 1) . '/not-existing-logfile.txt'],
]);
$factory = new StreamLoggerFactory(
$config,
$this->createStub(IHaveCallIntrospections::class),
$this->createStub(FileSystemUtil::class),
);
$this->expectException(LoggerArgumentException::class);
$this->expectExceptionMessage('tests/Unit/Core/Logger/not-existing-logfile.txt" is not a valid logfile.');
$factory->createLogger(LogLevel::DEBUG, LogChannel::DEFAULT);
}
public function testCreateLoggerWithInvalidLoglevelThrowsException(): void
{
$config = $this->createStub(IManageConfigValues::class);
$config->method('get')->willReturnMap([
['system', 'logfile', null, dirname(__DIR__, 4) . '/datasets/log/empty.friendica.log.txt'],
]);
$factory = new StreamLoggerFactory(
$config,
$this->createStub(IHaveCallIntrospections::class),
$this->createStub(FileSystemUtil::class),
);
$this->expectException(LogLevelException::class);
$this->expectExceptionMessage('The log level "unsupported-loglevel" is not supported by "Friendica\Core\Logger\Type\StreamLogger".');
$factory->createLogger('unsupported-loglevel', LogChannel::DEFAULT);
}
}

View file

@ -0,0 +1,61 @@
<?php
// Copyright (C) 2010-2024, the Friendica project
// SPDX-FileCopyrightText: 2010-2024 the Friendica project
//
// SPDX-License-Identifier: AGPL-3.0-or-later
declare(strict_types=1);
namespace Friendica\Test\Unit\Core\Logger\Factory;
use Friendica\Core\Config\Capability\IManageConfigValues;
use Friendica\Core\Logger\Capability\IHaveCallIntrospections;
use Friendica\Core\Logger\Capability\LogChannel;
use Friendica\Core\Logger\Exception\LogLevelException;
use Friendica\Core\Logger\Factory\SyslogLoggerFactory;
use Friendica\Core\Logger\Type\SyslogLogger;
use PHPUnit\Framework\TestCase;
use Psr\Log\LoggerInterface;
use Psr\Log\LogLevel;
class SyslogLoggerFactoryTest extends TestCase
{
public function testCreateLoggerReturnsPsrLogger(): void
{
$config = $this->createStub(IManageConfigValues::class);
$config->method('get')->willReturnMap([
['system', 'syslog_flags', null, SyslogLogger::DEFAULT_FLAGS],
['system', 'syslog_facility', null, SyslogLogger::DEFAULT_FACILITY],
]);
$factory = new SyslogLoggerFactory(
$config,
$this->createStub(IHaveCallIntrospections::class),
);
$this->assertInstanceOf(
LoggerInterface::class,
$factory->createLogger(LogLevel::DEBUG, LogChannel::DEFAULT)
);
}
public function testCreateLoggerWithInvalidLoglevelThrowsException(): void
{
$config = $this->createStub(IManageConfigValues::class);
$config->method('get')->willReturnMap([
['system', 'syslog_flags', null, SyslogLogger::DEFAULT_FLAGS],
['system', 'syslog_facility', null, SyslogLogger::DEFAULT_FACILITY],
]);
$factory = new SyslogLoggerFactory(
$config,
$this->createStub(IHaveCallIntrospections::class),
);
$this->expectException(LogLevelException::class);
$this->expectExceptionMessage('The log level "unsupported-loglevel" is not supported by "Friendica\Core\Logger\Type\SyslogLogger".');
$factory->createLogger('unsupported-loglevel', LogChannel::DEFAULT);
}
}

View file

@ -61,7 +61,7 @@
{{if $nav.network}}
<li class="nav-segment">
<a accesskey="n" class="nav-menu {{$sel.network}}" href="{{$nav.network.0}}"
data-toggle="tooltip" aria-label="{{$nav.network.3}}" title="{{$nav.network.3}}"><i
data-toggle="tooltip" data-viewport="#topbar-first" aria-label="{{$nav.network.3}}" title="{{$nav.network.3}}"><i
class="fa fa-lg fa-th fa-fw" aria-hidden="true"></i><span id="net-update"
class="nav-network-badge badge nav-notification"></span></a>
</li>
@ -70,14 +70,14 @@
{{if $nav.channel}}
<li class="nav-segment">
<a accesskey="l" class="nav-menu {{$sel.channel}}" href="{{$nav.channel.0}}"
data-toggle="tooltip" aria-label="{{$nav.channel.3}}" title="{{$nav.channel.3}}"><i
data-toggle="tooltip" data-viewport="#topbar-first" aria-label="{{$nav.channel.3}}" title="{{$nav.channel.3}}"><i
class="fa fa-lg fa-newspaper-o fa-fw" aria-hidden="true"></i></a>
</li>
{{/if}}
{{if $nav.home}}
<li class="nav-segment">
<a accesskey="p" class="nav-menu {{$sel.home}}" href="{{$nav.home.0}}" data-toggle="tooltip"
<a accesskey="p" class="nav-menu {{$sel.home}}" href="{{$nav.home.0}}" data-toggle="tooltip" data-viewport="#topbar-first"
aria-label="{{$nav.home.3}}" title="{{$nav.home.3}}"><i class="fa fa-lg fa-home fa-fw"
aria-hidden="true"></i><span id="home-update"
class="nav-home-badge badge nav-notification"></span></a>
@ -87,14 +87,14 @@
{{if $nav.community}}
<li class="nav-segment">
<a accesskey="c" class="nav-menu {{$sel.community}}" href="{{$nav.community.0}}"
data-toggle="tooltip" aria-label="{{$nav.community.3}}" title="{{$nav.community.3}}"><i
data-toggle="tooltip" data-viewport="#topbar-first" aria-label="{{$nav.community.3}}" title="{{$nav.community.3}}"><i
class="fa fa-lg fa-bullseye fa-fw" aria-hidden="true"></i></a>
</li>
{{/if}}
{{if $nav.messages}}
<li class="nav-segment hidden-xs">
<a accesskey="m" id="nav-messages-link" href="{{$nav.messages.0}}" data-toggle="tooltip"
<a accesskey="m" id="nav-messages-link" href="{{$nav.messages.0}}" data-toggle="tooltip" data-viewport="#topbar-first"
aria-label="{{$nav.messages.1}}" title="{{$nav.messages.1}}"
class="nav-menu {{$sel.messages}}"><i class="fa fa-envelope fa-lg fa-fw"
aria-hidden="true"></i><span id="mail-update"
@ -104,7 +104,7 @@
{{if $nav.calendar}}
<li class="nav-segment hidden-xs">
<a accesskey="e" id="nav-calendar-link" href="{{$nav.calendar.0}}" data-toggle="tooltip"
<a accesskey="e" id="nav-calendar-link" href="{{$nav.calendar.0}}" data-toggle="tooltip" data-viewport="#topbar-first"
aria-label="{{$nav.calendar.1}}" title="{{$nav.calendar.1}}" class="nav-menu"><i
class="fa fa-lg fa-calendar fa-fw"></i></a>
</li>
@ -112,7 +112,7 @@
{{if $nav.contacts}}
<li class="nav-segment hidden-xs">
<a accesskey="k" id="nav-contacts-link" href="{{$nav.contacts.0}}" data-toggle="tooltip"
<a accesskey="k" id="nav-contacts-link" href="{{$nav.contacts.0}}" data-toggle="tooltip" data-viewport="#topbar-first"
aria-label="{{$nav.contacts.1}}" title="{{$nav.contacts.1}}"
class="nav-menu {{$sel.contacts}} {{$nav.contacts.2}}"><i
class="fa fa-users fa-lg fa-fw"></i></a>
@ -503,7 +503,7 @@
<form class="navbar-form" role="search" method="get" action="{{$nav.search.0}}">
<div class="form-group form-group-search">
<input id="nav-search-input-field-mobile" class="form-control form-search" type="text" name="q"
data-toggle="tooltip" title="{{$search_hint}}" placeholder="{{$nav.search.1}}">
data-toggle="tooltip" data-viewport="#topbar-first" title="{{$search_hint}}" placeholder="{{$nav.search.1}}">
<button class="btn btn-default btn-sm form-button-search" type="submit">{{$nav.search.1}}</button>
</div>
</form>