mirror of
https://git.sekbaer.de/Friendica/friendica.git
synced 2025-06-06 15:24:27 +02:00
Merge branch 'develop' into phpstan-level-3
This commit is contained in:
commit
d6b072477d
29 changed files with 763 additions and 165 deletions
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
73
src/Core/Logger/Factory/DelegatingLoggerFactory.php
Normal file
73
src/Core/Logger/Factory/DelegatingLoggerFactory.php
Normal 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;
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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');
|
||||
|
|
76
src/Core/Logger/Factory/StreamLoggerFactory.php
Normal file
76
src/Core/Logger/Factory/StreamLoggerFactory.php
Normal 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()
|
||||
);
|
||||
}
|
||||
}
|
|
@ -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'));
|
||||
|
|
66
src/Core/Logger/Factory/SyslogLoggerFactory.php
Normal file
66
src/Core/Logger/Factory/SyslogLoggerFactory.php
Normal 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
|
||||
);
|
||||
}
|
||||
}
|
|
@ -208,7 +208,7 @@ class ErrorHandler
|
|||
*/
|
||||
private function handleException(Throwable $e): void
|
||||
{
|
||||
$level = LogLevel::ERROR;
|
||||
$level = LogLevel::CRITICAL;
|
||||
foreach ($this->uncaughtExceptionLevelMap as $class => $candidate) {
|
||||
if ($e instanceof $class) {
|
||||
$level = $candidate;
|
||||
|
|
|
@ -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));
|
||||
|
|
40
src/Core/Logger/Util/FileSystemUtil.php
Normal file
40
src/Core/Logger/Util/FileSystemUtil.php
Normal 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);
|
||||
}
|
|
@ -1094,9 +1094,9 @@ class Item
|
|||
}
|
||||
|
||||
if ($update_commented) {
|
||||
$fields = ['commented' => DateTimeFormat::utcNow(), 'changed' => DateTimeFormat::utcNow()];
|
||||
$fields = ['commented' => $posted_item['received'], 'changed' => $posted_item['received']];
|
||||
} else {
|
||||
$fields = ['changed' => DateTimeFormat::utcNow()];
|
||||
$fields = ['changed' => $posted_item['received']];
|
||||
}
|
||||
|
||||
Post::update($fields, ['uri-id' => $posted_item['parent-uri-id'], 'uid' => $posted_item['uid']]);
|
||||
|
|
|
@ -205,13 +205,25 @@ final class ItemHelper
|
|||
$item['file'] = trim($item['file'] ?? '');
|
||||
|
||||
// Items cannot be stored before they happen ...
|
||||
if ($item['created'] > DateTimeFormat::utcNow()) {
|
||||
$item['created'] = DateTimeFormat::utcNow();
|
||||
if ($item['received'] > DateTimeFormat::utcNow()) {
|
||||
$item['received'] = DateTimeFormat::utcNow();
|
||||
}
|
||||
|
||||
if ($item['created'] > $item['received']) {
|
||||
$item['created'] = $item['received'];
|
||||
}
|
||||
|
||||
// We haven't invented time travel by now.
|
||||
if ($item['edited'] > DateTimeFormat::utcNow()) {
|
||||
$item['edited'] = DateTimeFormat::utcNow();
|
||||
if ($item['edited'] > $item['received'] ) {
|
||||
$item['edited'] = $item['received'] ;
|
||||
}
|
||||
|
||||
if ($item['changed'] > $item['received'] ) {
|
||||
$item['changed'] = $item['received'] ;
|
||||
}
|
||||
|
||||
if ($item['commented'] > $item['received'] ) {
|
||||
$item['commented'] = $item['received'] ;
|
||||
}
|
||||
|
||||
$item['plink'] = ($item['plink'] ?? '') ?: $this->baseUrl . '/display/' . urlencode($item['guid']);
|
||||
|
|
|
@ -130,6 +130,7 @@ class Photo extends BaseApi
|
|||
|
||||
$photo = MPhoto::getPhoto($photoid, $scale, self::getCurrentUserID());
|
||||
if ($photo === false) {
|
||||
$this->logger->notice('Photo was not loaded', ['parameters' => $this->parameters, 'id' => $photoid]);
|
||||
throw new HTTPException\NotFoundException(DI::l10n()->t('The Photo with id %s is not available.', $photoid));
|
||||
}
|
||||
}
|
||||
|
@ -137,6 +138,7 @@ class Photo extends BaseApi
|
|||
$fetch = microtime(true) - $stamp;
|
||||
|
||||
if ($photo === false) {
|
||||
$this->logger->notice('Photo was not loaded', ['parameters' => $this->parameters]);
|
||||
throw new HTTPException\NotFoundException();
|
||||
}
|
||||
|
||||
|
@ -151,6 +153,7 @@ class Photo extends BaseApi
|
|||
$mimetype = $photo['type'];
|
||||
}
|
||||
if (empty($imgdata) && empty($photo['blurhash'])) {
|
||||
$this->logger->notice('Image data was not loaded', ['parameters' => $this->parameters, 'class' => $photo['backend-class'], 'ref' => $photo['backend-ref']]);
|
||||
throw new HTTPException\NotFoundException();
|
||||
}
|
||||
|
||||
|
@ -317,7 +320,11 @@ class Photo extends BaseApi
|
|||
$photo = MPhoto::selectFirst([], ['scale' => $scale, 'uid' => $contact['uid'], 'profile' => 1]);
|
||||
if (!empty($photo)) {
|
||||
return $photo;
|
||||
} else {
|
||||
$this->logger->notice('Profile photo was not loaded', ['scale' => $scale, 'uid' => $contact['uid']]);
|
||||
}
|
||||
} else {
|
||||
$this->logger->notice('Local Contact was not found', ['url' => $contact['nurl']]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -333,6 +340,7 @@ class Photo extends BaseApi
|
|||
if (!empty($photo)) {
|
||||
return $photo;
|
||||
} else {
|
||||
$this->logger->notice('Photo was not loaded', ['resource-id' => $resourceid]);
|
||||
$url = $contact['avatar'];
|
||||
}
|
||||
} else {
|
||||
|
@ -340,6 +348,8 @@ class Photo extends BaseApi
|
|||
}
|
||||
} elseif (!empty($contact['avatar'])) {
|
||||
$url = $contact['avatar'];
|
||||
} else {
|
||||
$url = '';
|
||||
}
|
||||
|
||||
// If it is a local link, we save resources by just redirecting to it.
|
||||
|
@ -381,8 +391,6 @@ class Photo extends BaseApi
|
|||
}
|
||||
}
|
||||
|
||||
$url = '';
|
||||
|
||||
if (empty($mimetext) && !empty($contact['blurhash'])) {
|
||||
$image = new Image('', image_type_to_mime_type(IMAGETYPE_WEBP));
|
||||
$image->getFromBlurHash($contact['blurhash'], $customsize, $customsize);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -117,7 +117,7 @@ class DateTimeFormat
|
|||
$tz_to = 'UTC';
|
||||
}
|
||||
|
||||
if (($s === '') || (!is_string($s))) {
|
||||
if ($s === '') {
|
||||
$s = 'now';
|
||||
}
|
||||
|
||||
|
@ -135,7 +135,8 @@ class DateTimeFormat
|
|||
}
|
||||
|
||||
try {
|
||||
$d = new DateTime($s, $from_obj);
|
||||
$d = DateTime::createFromFormat('U', $s, $from_obj)
|
||||
?: new DateTime($s, $from_obj);
|
||||
} catch (Exception $e) {
|
||||
try {
|
||||
$d = new DateTime(self::fix($s), $from_obj);
|
||||
|
@ -176,6 +177,7 @@ class DateTimeFormat
|
|||
$pregPatterns = [
|
||||
['#(\w+), (\d+ \w+ \d+) (\d+:\d+:\d+) (.+)#', '$2 $3 $4'],
|
||||
['#(\d+:\d+) (\w+), (\w+) (\d+), (\d+)#', '$1 $2 $3 $4 $5'],
|
||||
['#\[[^\]]*\]#', ''], // 2025-03-07T08:54:14.341+01:00[Europe/Berlin]
|
||||
];
|
||||
|
||||
foreach ($pregPatterns as $pattern) {
|
||||
|
|
|
@ -121,6 +121,9 @@ class Cron
|
|||
|
||||
Worker::add(Worker::PRIORITY_LOW, 'UpdateAllSuggestions');
|
||||
|
||||
// add missing public contacts and account-user entries
|
||||
Worker::add(Worker::PRIORITY_LOW, 'FixContacts');
|
||||
|
||||
if (DI::config()->get('system', 'optimize_tables')) {
|
||||
Worker::add(Worker::PRIORITY_LOW, 'OptimizeTables');
|
||||
}
|
||||
|
|
51
src/Worker/FixContacts.php
Normal file
51
src/Worker/FixContacts.php
Normal file
|
@ -0,0 +1,51 @@
|
|||
<?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\Worker;
|
||||
|
||||
use Friendica\Database\DBA;
|
||||
use Friendica\DI;
|
||||
use Friendica\Model\Contact;
|
||||
|
||||
/**
|
||||
* add missing public contacts and account-user entries
|
||||
*/
|
||||
class FixContacts
|
||||
{
|
||||
public static function execute()
|
||||
{
|
||||
$added = 0;
|
||||
DI::logger()->info('Add missing public contacts');
|
||||
$contacts = DBA::p("SELECT `contact`.`id` FROM `contact` LEFT JOIN `contact` AS `pcontact` ON `contact`.`uri-id` = `pcontact`.`uri-id` WHERE `pcontact`.`id` IS NULL");
|
||||
while ($contact = DBA::fetch($contacts)) {
|
||||
Contact::selectAccountUserById($contact['id'], ['id']);
|
||||
$added++;
|
||||
}
|
||||
DBA::close($contacts);
|
||||
|
||||
if ($added == 0) {
|
||||
DI::logger()->info('No public contacts have been added');
|
||||
} else {
|
||||
DI::logger()->info('Missing public contacts have been added', ['added' => $added]);
|
||||
}
|
||||
|
||||
$added = 0;
|
||||
DI::logger()->info('Add missing account-user entries');
|
||||
$contacts = DBA::p("SELECT `contact`.`id`, `contact`.`uid`, `contact`.`uri-id`, `contact`.`url` FROM `contact` LEFT JOIN `account-user` ON `contact`.`id` = `account-user`.`id` WHERE `contact`.`id` > ? AND `account-user`.`id` IS NULL", 0);
|
||||
while ($contact = DBA::fetch($contacts)) {
|
||||
Contact::setAccountUser($contact['id'], $contact['uid'], $contact['uri-id'], $contact['url']);
|
||||
$added++;
|
||||
}
|
||||
DBA::close($contacts);
|
||||
|
||||
if ($added == 0) {
|
||||
DI::logger()->info('No account-user entries have been added');
|
||||
} else {
|
||||
DI::logger()->info('Missing account-user entries have been added', ['added' => $added]);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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)
|
||||
);
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
);
|
||||
}
|
||||
}
|
81
tests/Unit/Core/Logger/Factory/StreamLoggerFactoryTest.php
Normal file
81
tests/Unit/Core/Logger/Factory/StreamLoggerFactoryTest.php
Normal 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);
|
||||
}
|
||||
}
|
61
tests/Unit/Core/Logger/Factory/SyslogLoggerFactoryTest.php
Normal file
61
tests/Unit/Core/Logger/Factory/SyslogLoggerFactoryTest.php
Normal 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);
|
||||
}
|
||||
}
|
|
@ -16,39 +16,39 @@ class DateTimeFormatTest extends MockedTestCase
|
|||
{
|
||||
return [
|
||||
'validNormal' => [
|
||||
'input' => '1990-10',
|
||||
'input' => '1990-10',
|
||||
'assert' => true,
|
||||
],
|
||||
'validOneCharMonth' => [
|
||||
'input' => '1990-1',
|
||||
'input' => '1990-1',
|
||||
'assert' => true,
|
||||
],
|
||||
'validTwoCharMonth' => [
|
||||
'input' => '1990-01',
|
||||
'input' => '1990-01',
|
||||
'assert' => true,
|
||||
],
|
||||
'invalidFormat' => [
|
||||
'input' => '199-11',
|
||||
'input' => '199-11',
|
||||
'assert' => false,
|
||||
],
|
||||
'invalidFormat2' => [
|
||||
'input' => '1990-15',
|
||||
'input' => '1990-15',
|
||||
'assert' => false,
|
||||
],
|
||||
'invalidFormat3' => [
|
||||
'input' => '99-101',
|
||||
'input' => '99-101',
|
||||
'assert' => false,
|
||||
],
|
||||
'invalidFormat4' => [
|
||||
'input' => '11-1990',
|
||||
'input' => '11-1990',
|
||||
'assert' => false,
|
||||
],
|
||||
'invalidFuture' => [
|
||||
'input' => '3030-12',
|
||||
'input' => '3030-12',
|
||||
'assert' => false,
|
||||
],
|
||||
'invalidYear' => [
|
||||
'input' => '-100-10',
|
||||
'input' => '-100-10',
|
||||
'assert' => false,
|
||||
],
|
||||
];
|
||||
|
@ -79,51 +79,55 @@ class DateTimeFormatTest extends MockedTestCase
|
|||
return [
|
||||
'Mo, 19 Sep 2022 14:51:00 +0200' => [
|
||||
'expectedDate' => '2022-09-19T14:51:00+02:00',
|
||||
'dateString' => 'Mo, 19 Sep 2022 14:51:00 +0200',
|
||||
'dateString' => 'Mo, 19 Sep 2022 14:51:00 +0200',
|
||||
],
|
||||
'2020-11-21T12:00:13.745339ZZ' => [
|
||||
'expectedDate' => '2020-11-21T12:00:13+00:00',
|
||||
'dateString' => '2020-11-21T12:00:13.745339ZZ',
|
||||
'dateString' => '2020-11-21T12:00:13.745339ZZ',
|
||||
],
|
||||
'2016-09-09T13:32:00ZZ' => [
|
||||
'expectedDate' => '2016-09-09T13:32:00+00:00',
|
||||
'dateString' => '2016-09-09T13:32:00ZZ',
|
||||
'dateString' => '2016-09-09T13:32:00ZZ',
|
||||
],
|
||||
'Sun, 10/03/2021 - 12:41' => [
|
||||
'expectedDate' => '2021-10-03T12:41:00+00:00',
|
||||
'dateString' => 'Sun, 10/03/2021 - 12:41',
|
||||
'dateString' => 'Sun, 10/03/2021 - 12:41',
|
||||
],
|
||||
'4:30 PM, Sep 13, 2022' => [
|
||||
'expectedDate' => '2022-09-13T16:30:00+00:00',
|
||||
'dateString' => '4:30 PM, Sep 13, 2022',
|
||||
'dateString' => '4:30 PM, Sep 13, 2022',
|
||||
],
|
||||
'August 27, 2022 - 21:00' => [
|
||||
'expectedDate' => '2022-08-27T21:00:00+00:00',
|
||||
'dateString' => 'August 27, 2022 - 21:00',
|
||||
'dateString' => 'August 27, 2022 - 21:00',
|
||||
],
|
||||
'2021-09-19T14:06:03+00:00' => [
|
||||
'expectedDate' => '2021-09-19T14:06:03+00:00',
|
||||
'dateString' => '2021-09-19T14:06:03+00:00',
|
||||
'dateString' => '2021-09-19T14:06:03+00:00',
|
||||
],
|
||||
'Eastern Time timezone' => [
|
||||
'expectedDate' => '2022-09-30T00:00:00-05:00',
|
||||
'dateString' => 'September 30, 2022, 12:00 a.m. ET',
|
||||
'dateString' => 'September 30, 2022, 12:00 a.m. ET',
|
||||
],
|
||||
'German date time string' => [
|
||||
'expectedDate' => '2022-10-05T16:34:00+02:00',
|
||||
'dateString' => '05 Okt 2022 16:34:00 +0200',
|
||||
'dateString' => '05 Okt 2022 16:34:00 +0200',
|
||||
],
|
||||
'(Coordinated Universal Time)' => [
|
||||
'expectedDate' => '2022-12-30T14:29:10+00:00',
|
||||
'dateString' => 'Fri Dec 30 2022 14:29:10 GMT+0000 (Coordinated Universal Time)',
|
||||
'dateString' => 'Fri Dec 30 2022 14:29:10 GMT+0000 (Coordinated Universal Time)',
|
||||
],
|
||||
'Double HTML encode' => [
|
||||
'expectedDate' => '2015-05-22T08:48:00+12:00',
|
||||
'dateString' => '2015-05-22T08:48:00&#43;12:00'
|
||||
'dateString' => '2015-05-22T08:48:00&#43;12:00'
|
||||
],
|
||||
'2023-04-02\T17:22:42+05:30' => [
|
||||
'expectedDate' => '2023-04-02T17:22:42+05:30',
|
||||
'dateString' => '2023-04-02\T17:22:42+05:30'
|
||||
'dateString' => '2023-04-02\T17:22:42+05:30'
|
||||
],
|
||||
'2025-03-07T08:54:14.341+01:00[Europe/Berlin]' => [
|
||||
'expectedDate' => '2025-03-07T08:54:14+01:00',
|
||||
'dateString' => '2025-03-07T08:54:14.341+01:00[Europe/Berlin]'
|
||||
],
|
||||
];
|
||||
}
|
||||
|
@ -151,9 +155,87 @@ class DateTimeFormatTest extends MockedTestCase
|
|||
*/
|
||||
public function testConvertRelative()
|
||||
{
|
||||
$now = DateTimeFormat::utcNow('U');
|
||||
$now = DateTimeFormat::utcNow('U');
|
||||
$date = DateTimeFormat::utc('now - 3 days', 'U');
|
||||
|
||||
$this->assertEquals(259200, $now - $date);
|
||||
}
|
||||
|
||||
public function dataConvert()
|
||||
{
|
||||
return [
|
||||
'unix timestamp' => [
|
||||
'expected' => '2025-03-12 16:18:27',
|
||||
's' => '1741796307',
|
||||
],
|
||||
'ATOM' => [
|
||||
'expected' => '2022-06-02 15:58:35',
|
||||
's' => '2022-06-02T16:58:35+01:00',
|
||||
],
|
||||
'COOKIE' => [
|
||||
'expected' => '2022-06-02 14:58:35',
|
||||
's' => 'Thursday, 02-Jun-2022 16:58:35 Africa/Cairo',
|
||||
],
|
||||
'ISO 8601/RFC 3339' => [
|
||||
'expected' => '2022-06-02 13:58:35',
|
||||
's' => '2022-06-02T16:58:35+0300',
|
||||
],
|
||||
'RFC 822/RFC 1036' => [
|
||||
'expected' => '2022-06-02 12:58:35',
|
||||
's' => 'Thu, 02 Jun 22 16:58:35 +0400',
|
||||
],
|
||||
'RFC 850' => [
|
||||
'expected' => '2022-06-02 11:58:35',
|
||||
's' => 'Thursday, 02-Jun-22 16:58:35 Indian/Kerguelen',
|
||||
],
|
||||
'RFC 1123/RFC 2822/RSS' => [
|
||||
'expected' => '2022-06-02 10:58:35',
|
||||
's' => 'Thu, 02 Jun 2022 16:58:35 +0600',
|
||||
],
|
||||
'RFC 3339/W3C' => [
|
||||
'expected' => '2025-03-07 01:54:14',
|
||||
's' => '2025-03-07T08:54:14+07:00',
|
||||
],
|
||||
'RFC 3339 extended' => [
|
||||
'expected' => '2025-03-07 00:54:14',
|
||||
's' => '2025-03-07T08:54:14.341+08:00',
|
||||
],
|
||||
'RFC 7231' => [
|
||||
'expected' => '2022-06-02 07:58:35',
|
||||
's' => 'Thu, 02 Jun 2022 16:58:35 Asia/Tokyo',
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider dataConvert
|
||||
*/
|
||||
public function testConvert($expected, string $s = 'now', string $tz_to = 'UTC', string $tz_from = 'UTC', string $format = DateTimeFormat::MYSQL)
|
||||
{
|
||||
$this->assertSame($expected, DateTimeFormat::convert($s, $tz_to, $tz_from, $format));
|
||||
}
|
||||
|
||||
public function dataConvertNow()
|
||||
{
|
||||
return [
|
||||
'now missing' => [
|
||||
],
|
||||
'now empty' => [
|
||||
's' => '',
|
||||
],
|
||||
'now now' => [
|
||||
's' => 'now',
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider dataConvertNow
|
||||
*/
|
||||
public function testConvertNow(string $s = 'now', string $tz_to = 'UTC', string $tz_from = 'UTC', string $format = DateTimeFormat::MYSQL)
|
||||
{
|
||||
$this->assertSame(date(DateTimeFormat::MYSQL), DateTimeFormat::convert($s, $tz_to, $tz_from, $format));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue