1
0
Fork 0

Merge remote-tracking branch 'upstream/develop' into api

This commit is contained in:
Michael 2023-01-22 19:11:21 +00:00
commit b2d7c4ec43
83 changed files with 1458 additions and 936 deletions

View file

@ -69,8 +69,6 @@ if (!DI::mode()->has(App\Mode::MAINTENANCEDISABLED)) {
return; return;
} }
DI::baseUrl()->saveByURL(DI::config()->get('system', 'url'));
$spawn = array_key_exists('s', $options) || array_key_exists('spawn', $options); $spawn = array_key_exists('s', $options) || array_key_exists('spawn', $options);
if ($spawn) { if ($spawn) {

14
composer.lock generated
View file

@ -666,6 +666,7 @@
"x509", "x509",
"x690" "x690"
], ],
"abandoned": true,
"time": "2021-12-11T12:41:06+00:00" "time": "2021-12-11T12:41:06+00:00"
}, },
{ {
@ -1244,16 +1245,16 @@
}, },
{ {
"name": "level-2/dice", "name": "level-2/dice",
"version": "4.0.3", "version": "4.0.4",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/Level-2/Dice.git", "url": "https://github.com/Level-2/Dice.git",
"reference": "3e9a8548398c01e2527110c916a93f6efa17ac9c" "reference": "e04c98d96bcc932a917b2b7e7944887e4839056a"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/Level-2/Dice/zipball/3e9a8548398c01e2527110c916a93f6efa17ac9c", "url": "https://api.github.com/repos/Level-2/Dice/zipball/e04c98d96bcc932a917b2b7e7944887e4839056a",
"reference": "3e9a8548398c01e2527110c916a93f6efa17ac9c", "reference": "e04c98d96bcc932a917b2b7e7944887e4839056a",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -1263,6 +1264,9 @@
"phpunit/phpunit": "^6.5" "phpunit/phpunit": "^6.5"
}, },
"type": "library", "type": "library",
"extra": {
"patches_applied": []
},
"autoload": { "autoload": {
"psr-4": { "psr-4": {
"Dice\\": "./" "Dice\\": "./"
@ -1286,7 +1290,7 @@
"di", "di",
"ioc" "ioc"
], ],
"time": "2021-04-20T14:06:06+00:00" "time": "2022-03-28T21:20:23+00:00"
}, },
{ {
"name": "lightopenid/lightopenid", "name": "lightopenid/lightopenid",

View file

@ -36,9 +36,11 @@ return [
'sitename' => 'Friendica Social Network', 'sitename' => 'Friendica Social Network',
'register_policy' => \Friendica\Module\Register::OPEN, 'register_policy' => \Friendica\Module\Register::OPEN,
'register_text' => '', 'register_text' => '',
'hostname' => 'friendica.local',
], ],
'system' => [ 'system' => [
'default_timezone' => 'UTC', 'default_timezone' => 'UTC',
'language' => 'en', 'language' => 'en',
'url' => 'https://friendica.local',
], ],
]; ];

View file

@ -1,6 +1,6 @@
-- ------------------------------------------ -- ------------------------------------------
-- Friendica 2023.03-dev (Giant Rhubarb) -- Friendica 2023.03-dev (Giant Rhubarb)
-- DB_UPDATE_VERSION 1511 -- DB_UPDATE_VERSION 1512
-- ------------------------------------------ -- ------------------------------------------

View file

@ -40,5 +40,7 @@ return [
'language' => 'en', 'language' => 'en',
'basepath' => '/vagrant', 'basepath' => '/vagrant',
'ssl_policy' => \Friendica\App\BaseURL::SSL_POLICY_SELFSIGN, 'ssl_policy' => \Friendica\App\BaseURL::SSL_POLICY_SELFSIGN,
'url' => 'https://192.168.56.10',
'urlpath' => '',
], ],
]; ];

View file

@ -540,25 +540,6 @@ class App
return Core\Theme::getStylesheetPath($this->getCurrentTheme()); return Core\Theme::getStylesheetPath($this->getCurrentTheme());
} }
/**
* Sets the base url for use in cmdline programs which don't have
* $_SERVER variables
*/
public function checkURL()
{
$url = $this->config->get('system', 'url');
// if the url isn't set or the stored url is radically different
// than the currently visited url, store the current value accordingly.
// "Radically different" ignores common variations such as http vs https
// and www.example.com vs example.com.
// We will only change the url to an ip address if there is no existing setting
if (empty($url) || (!Util\Strings::compareLink($url, $this->baseURL->get())) && (!preg_match("/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/", $this->baseURL->getHostname()))) {
$this->config->set('system', 'url', $this->baseURL->get());
}
}
/** /**
* Frontend App script * Frontend App script
* *
@ -657,7 +638,6 @@ class App
if ($this->mode->isInstall() && $moduleName !== 'install') { if ($this->mode->isInstall() && $moduleName !== 'install') {
$this->baseURL->redirect('install'); $this->baseURL->redirect('install');
} else { } else {
$this->checkURL();
Core\Update::check($this->getBasePath(), false); Core\Update::check($this->getBasePath(), false);
Core\Addon::loadAddons(); Core\Addon::loadAddons();
Core\Hook::loadHooks(); Core\Hook::loadHooks();

View file

@ -259,107 +259,16 @@ class BaseURL
{ {
$this->config = $config; $this->config = $config;
$this->server = $server; $this->server = $server;
$this->determineSchema();
$this->checkConfig();
}
/**
* Check the current config during loading
*/
public function checkConfig()
{
$this->hostname = $this->config->get('config', 'hostname'); $this->hostname = $this->config->get('config', 'hostname');
$this->urlPath = $this->config->get('system', 'urlpath'); $this->urlPath = $this->config->get('system', 'urlpath') ?? '';
$this->sslPolicy = $this->config->get('system', 'ssl_policy'); $this->sslPolicy = $this->config->get('system', 'ssl_policy') ?? static::DEFAULT_SSL_SCHEME;
$this->url = $this->config->get('system', 'url'); $this->url = $this->config->get('system', 'url');
if (empty($this->hostname)) { if (empty($this->hostname) || empty($this->url)) {
$this->determineHostname(); throw new \Exception('Invalid config - Missing system.url or config.hostname');
if (!empty($this->hostname)) {
$this->config->set('config', 'hostname', $this->hostname);
}
} }
if (!isset($this->urlPath)) { $this->determineSchema();
$this->determineURLPath();
$this->config->set('system', 'urlpath', $this->urlPath);
}
if (!isset($this->sslPolicy)) {
if ($this->scheme == 'https') {
$this->sslPolicy = self::SSL_POLICY_FULL;
} else {
$this->sslPolicy = self::DEFAULT_SSL_SCHEME;
}
$this->config->set('system', 'ssl_policy', $this->sslPolicy);
}
if (empty($this->url)) {
$this->determineBaseUrl();
if (!empty($this->url)) {
$this->config->set('system', 'url', $this->url);
}
}
}
/**
* Determines the hostname of this node if not set already
*/
private function determineHostname()
{
$this->hostname = '';
if (!empty($this->server['SERVER_NAME'])) {
$this->hostname = $this->server['SERVER_NAME'];
if (!empty($this->server['SERVER_PORT']) && $this->server['SERVER_PORT'] != 80 && $this->server['SERVER_PORT'] != 443) {
$this->hostname .= ':' . $this->server['SERVER_PORT'];
}
}
}
/**
* Figure out if we are running at the top of a domain or in a sub-directory
*/
private function determineURLPath()
{
$this->urlPath = '';
/*
* The automatic path detection in this function is currently deactivated,
* see issue https://github.com/friendica/friendica/issues/6679
*
* The problem is that the function seems to be confused with some url.
* These then confuses the detection which changes the url path.
*/
/* Relative script path to the web server root
* Not all of those $_SERVER properties can be present, so we do by inverse priority order
*/
$relative_script_path =
($this->server['REDIRECT_URL'] ?? '') ?:
($this->server['REDIRECT_URI'] ?? '') ?:
($this->server['REDIRECT_SCRIPT_URL'] ?? '') ?:
($this->server['SCRIPT_URL'] ?? '') ?:
$this->server['REQUEST_URI'] ?? '';
/* $relative_script_path gives /relative/path/to/friendica/module/parameter
* QUERY_STRING gives pagename=module/parameter
*
* To get /relative/path/to/friendica we perform dirname() for as many levels as there are slashes in the QUERY_STRING
*/
if (!empty($relative_script_path)) {
// Module
if (!empty($this->server['QUERY_STRING'])) {
$this->urlPath = trim(dirname($relative_script_path, substr_count(trim($this->server['QUERY_STRING'], '/'), '/') + 1), '/');
} else {
// Root page
$this->urlPath = trim($relative_script_path, '/');
}
}
} }
/** /**

View file

@ -74,7 +74,7 @@ class Request
public function __construct(IManageConfigValues $config, array $server = []) public function __construct(IManageConfigValues $config, array $server = [])
{ {
$this->remoteAddress = $this->determineRemoteAddress($config, $server); $this->remoteAddress = $this->determineRemoteAddress($config, $server);
$this->requestId = $server[static::DEFAULT_REQUEST_ID_HEADER] ?? System::createGUID(8); $this->requestId = $server[static::DEFAULT_REQUEST_ID_HEADER] ?? System::createGUID(8, false);
} }
/** /**

View file

@ -316,7 +316,7 @@ class OEmbed
if ($stopoembed == true) { if ($stopoembed == true) {
return preg_replace("/\[embed\](.+?)\[\/embed\]/is", "<!-- oembed $1 --><i>" . DI::l10n()->t('Embedding disabled') . " : $1</i><!-- /oembed $1 -->", $text); return preg_replace("/\[embed\](.+?)\[\/embed\]/is", "<!-- oembed $1 --><i>" . DI::l10n()->t('Embedding disabled') . " : $1</i><!-- /oembed $1 -->", $text);
} }
return preg_replace_callback("/\[embed\](.+?)\[\/embed\]/is", ['self', 'replaceCallback'], $text); return preg_replace_callback("/\[embed\](.+?)\[\/embed\]/is", [self::class, 'replaceCallback'], $text);
} }
/** /**

View file

@ -218,8 +218,8 @@ class Smilies
return $text; return $text;
} }
$text = preg_replace_callback('/<(pre)>(.*?)<\/pre>/ism', 'self::encode', $text); $text = preg_replace_callback('/<(pre)>(.*?)<\/pre>/ism', [self::class, 'encode'], $text);
$text = preg_replace_callback('/<(code)>(.*?)<\/code>/ism', 'self::encode', $text); $text = preg_replace_callback('/<(code)>(.*?)<\/code>/ism', [self::class, 'encode'], $text);
if ($no_images) { if ($no_images) {
$cleaned = ['texts' => [], 'icons' => []]; $cleaned = ['texts' => [], 'icons' => []];
@ -233,11 +233,11 @@ class Smilies
$smilies = $cleaned; $smilies = $cleaned;
} }
$text = preg_replace_callback('/&lt;(3+)/', 'self::heartReplaceCallback', $text); $text = preg_replace_callback('/&lt;(3+)/', [self::class, 'heartReplaceCallback'], $text);
$text = self::strOrigReplace($smilies['texts'], $smilies['icons'], $text); $text = self::strOrigReplace($smilies['texts'], $smilies['icons'], $text);
$text = preg_replace_callback('/<(code)>(.*?)<\/code>/ism', 'self::decode', $text); $text = preg_replace_callback('/<(code)>(.*?)<\/code>/ism', [self::class, 'decode'], $text);
$text = preg_replace_callback('/<(pre)>(.*?)<\/pre>/ism', 'self::decode', $text); $text = preg_replace_callback('/<(pre)>(.*?)<\/pre>/ism', [self::class, 'decode'], $text);
return $text; return $text;
} }

View file

@ -1415,8 +1415,8 @@ class BBCode
public static function cleanPictureLinks(string $text): string public static function cleanPictureLinks(string $text): string
{ {
DI::profiler()->startRecording('rendering'); DI::profiler()->startRecording('rendering');
$return = preg_replace_callback("&\[url=([^\[\]]*)\]\[img=(.*)\](.*)\[\/img\]\[\/url\]&Usi", 'self::cleanPictureLinksCallback', $text); $return = preg_replace_callback("&\[url=([^\[\]]*)\]\[img=(.*)\](.*)\[\/img\]\[\/url\]&Usi", [self::class, 'cleanPictureLinksCallback'], $text);
$return = preg_replace_callback("&\[url=([^\[\]]*)\]\[img\](.*)\[\/img\]\[\/url\]&Usi", 'self::cleanPictureLinksCallback', $return); $return = preg_replace_callback("&\[url=([^\[\]]*)\]\[img\](.*)\[\/img\]\[\/url\]&Usi", [self::class, 'cleanPictureLinksCallback'], $return);
DI::profiler()->stopRecording(); DI::profiler()->stopRecording();
return $return; return $return;
} }
@ -1450,7 +1450,7 @@ class BBCode
{ {
DI::profiler()->startRecording('rendering'); DI::profiler()->startRecording('rendering');
$regexp = "/([@!])\[url\=([^\[\]]*)\].*?\[\/url\]/ism"; $regexp = "/([@!])\[url\=([^\[\]]*)\].*?\[\/url\]/ism";
$body = preg_replace_callback($regexp, ['self', 'mentionCallback'], $body); $body = preg_replace_callback($regexp, [self::class, 'mentionCallback'], $body);
DI::profiler()->stopRecording(); DI::profiler()->stopRecording();
return $body; return $body;
} }
@ -2002,12 +2002,12 @@ class BBCode
if (!$for_plaintext) { if (!$for_plaintext) {
if (in_array($simple_html, [self::OSTATUS, self::MASTODON_API, self::TWITTER_API, self::ACTIVITYPUB])) { if (in_array($simple_html, [self::OSTATUS, self::MASTODON_API, self::TWITTER_API, self::ACTIVITYPUB])) {
$text = preg_replace_callback("/\[url\](.*?)\[\/url\]/ism", 'self::convertUrlForActivityPubCallback', $text); $text = preg_replace_callback("/\[url\](.*?)\[\/url\]/ism", [self::class, 'convertUrlForActivityPubCallback'], $text);
$text = preg_replace_callback("/\[url\=(.*?)\](.*?)\[\/url\]/ism", 'self::convertUrlForActivityPubCallback', $text); $text = preg_replace_callback("/\[url\=(.*?)\](.*?)\[\/url\]/ism", [self::class, 'convertUrlForActivityPubCallback'], $text);
} }
} else { } else {
$text = preg_replace("(\[url\](.*?)\[\/url\])ism", " $1 ", $text); $text = preg_replace("(\[url\](.*?)\[\/url\])ism", " $1 ", $text);
$text = preg_replace_callback("&\[url=([^\[\]]*)\]\[img\](.*)\[\/img\]\[\/url\]&Usi", 'self::removePictureLinksCallback', $text); $text = preg_replace_callback("&\[url=([^\[\]]*)\]\[img\](.*)\[\/img\]\[\/url\]&Usi", [self::class, 'removePictureLinksCallback'], $text);
} }
// Bookmarks in red - will be converted to bookmarks in friendica // Bookmarks in red - will be converted to bookmarks in friendica
@ -2017,7 +2017,7 @@ class BBCode
"[bookmark=$1]$2[/bookmark]", $text); "[bookmark=$1]$2[/bookmark]", $text);
if (in_array($simple_html, [self::OSTATUS, self::TWITTER])) { if (in_array($simple_html, [self::OSTATUS, self::TWITTER])) {
$text = preg_replace_callback("/([^#@!])\[url\=([^\]]*)\](.*?)\[\/url\]/ism", "self::expandLinksCallback", $text); $text = preg_replace_callback("/([^#@!])\[url\=([^\]]*)\](.*?)\[\/url\]/ism", [self::class, 'expandLinksCallback'], $text);
//$text = preg_replace("/[^#@!]\[url\=([^\]]*)\](.*?)\[\/url\]/ism", ' $2 [url]$1[/url]', $text); //$text = preg_replace("/[^#@!]\[url\=([^\]]*)\](.*?)\[\/url\]/ism", ' $2 [url]$1[/url]', $text);
$text = preg_replace("/\[bookmark\=([^\]]*)\](.*?)\[\/bookmark\]/ism", ' $2 [url]$1[/url]', $text); $text = preg_replace("/\[bookmark\=([^\]]*)\](.*?)\[\/bookmark\]/ism", ' $2 [url]$1[/url]', $text);
} }
@ -2327,7 +2327,7 @@ class BBCode
$url_search_string = "^\[\]"; $url_search_string = "^\[\]";
$text = preg_replace_callback( $text = preg_replace_callback(
"/([@!])\[(.*?)\]\(([$url_search_string]*?)\)/ism", "/([@!])\[(.*?)\]\(([$url_search_string]*?)\)/ism",
['self', 'bbCodeMention2DiasporaCallback'], [self::class, 'bbCodeMention2DiasporaCallback'],
$text $text
); );
} }

View file

@ -1032,7 +1032,7 @@ class HTML
// the quotes, e.g.: // the quotes, e.g.:
// //
// concat("'foo'", '"', "bar") // concat("'foo'", '"', "bar")
return 'concat(' . implode(', \'"\', ', array_map(['self', 'xpathQuote'], explode('"', $value))) . ')'; return 'concat(' . implode(', \'"\', ', array_map([self::class, 'xpathQuote'], explode('"', $value))) . ')';
} }
/** /**

View file

@ -144,7 +144,7 @@ class TagCloud
$x ++; $x ++;
} }
usort($tags, 'self::tagsSort'); usort($tags, [self::class, 'tagsSort']);
$range = max(0.01, $max - $min) * 1.0001; $range = max(0.01, $max - $min) * 1.0001;
for ($x = 0; $x < count($tags); $x ++) { for ($x = 0; $x < count($tags); $x ++) {

View file

@ -214,6 +214,17 @@ class ConfigFileTransformer
case "NULL": case "NULL":
return "null"; return "null";
case "object": case "object":
if (method_exists($value, '__toString')) {
return sprintf('\'%s\'', $value);
} elseif ($value instanceof \Serializable) {
try {
return $value->serialize();
} catch (\Exception $e) {
throw new \InvalidArgumentException(sprintf('Cannot serialize %s.', gettype($value)), $e);
}
} else {
throw new \InvalidArgumentException(sprintf('%s is an object without stringify.', gettype($value)));
}
case "resource": case "resource":
case "resource (closed)": case "resource (closed)":
throw new \InvalidArgumentException(sprintf('%s in configs are not supported yet.', gettype($value))); throw new \InvalidArgumentException(sprintf('%s in configs are not supported yet.', gettype($value)));

View file

@ -0,0 +1,29 @@
<?php
/**
* @copyright Copyright (C) 2010-2023, the Friendica project
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
namespace Friendica\Core\Hooks\Capabilities;
/**
* All classes, implementing this interface are valid Strategies for Hook calls
*/
interface IAmAStrategy
{
}

View file

@ -0,0 +1,81 @@
<?php
/**
* @copyright Copyright (C) 2010-2023, the Friendica project
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
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 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
*
* @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 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
*
* @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 The fully-qualified name of the given class or interface which will get returned
* @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"
*
* @throws HookInstanceException In case the class cannot get created
*/
public function getInstance(string $class, string $name, array $arguments = []): object;
}

View file

@ -0,0 +1,30 @@
<?php
/**
* @copyright Copyright (C) 2010-2023, the Friendica project
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
namespace Friendica\Core\Hooks\Exceptions;
class HookInstanceException extends \RuntimeException
{
public function __construct($message = "", \Throwable $previous = null)
{
parent::__construct($message, 500, $previous);
}
}

View file

@ -0,0 +1,30 @@
<?php
/**
* @copyright Copyright (C) 2010-2023, the Friendica project
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
namespace Friendica\Core\Hooks\Exceptions;
class HookRegisterArgumentException extends \RuntimeException
{
public function __construct($message = "", \Throwable $previous = null)
{
parent::__construct($message, 500, $previous);
}
}

View file

@ -0,0 +1,104 @@
<?php
/**
* @copyright Copyright (C) 2010-2023, the Friendica project
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
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 substitution 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;
}
}

View file

@ -0,0 +1,32 @@
<?php
/**
* @copyright Copyright (C) 2010-2023, the Friendica project
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
namespace Friendica\Core\Logger\Exception;
use Throwable;
class LoggerInvalidException extends \RuntimeException
{
public function __construct($message = "", Throwable $previous = null)
{
parent::__construct($message, 500, $previous);
}
}

View file

@ -22,16 +22,11 @@
namespace Friendica\Core\Logger\Factory; namespace Friendica\Core\Logger\Factory;
use Friendica\Core\Config\Capability\IManageConfigValues; use Friendica\Core\Config\Capability\IManageConfigValues;
use Friendica\Core; use Friendica\Core\Hooks\Capabilities\ICanManageInstances;
use Friendica\Core\Logger\Capabilities\IHaveCallIntrospections;
use Friendica\Core\Logger\Exception\LogLevelException; 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\ProfilerLogger;
use Friendica\Core\Logger\Type\StreamLogger; use Friendica\Core\Logger\Type\StreamLogger;
use Friendica\Core\Logger\Type\SyslogLogger; use Friendica\Core\Logger\Type\SyslogLogger;
use Friendica\Util\Profiler;
use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface;
use Psr\Log\LogLevel; use Psr\Log\LogLevel;
use Psr\Log\NullLogger; use Psr\Log\NullLogger;
@ -44,115 +39,55 @@ class Logger
const DEV_CHANNEL = 'dev'; const DEV_CHANNEL = 'dev';
/** @var string The log-channel (app, worker, ...) */ /** @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 $this->instanceManager
if ($includeAddon) { ->registerStrategy(LoggerInterface::class, 'syslog', SyslogLogger::class)
Core\Addon::loadAddons(); ->registerStrategy(LoggerInterface::class, 'stream', StreamLogger::class, isset($logfile) ? [$logfile] : null);
Core\Hook::loadHooks();
if ($this->config->get('system', 'profiling') ?? false) {
$this->instanceManager->registerDecorator(LoggerInterface::class, ProfilerLogger::class);
} }
} }
/** /**
* Creates a new PSR-3 compliant logger instances * Creates a new PSR-3 compliant logger instances
* *
* @param Database $database The Friendica Database instance * @param string|null $loglevel (optional) A given loglevel in case the loglevel in the config isn't applicable
* @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
* *
* @return LoggerInterface The PSR-3 compliant logger instance * @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))) { if (empty($this->config->get('system', 'debugging') ?? false)) {
$logger = new NullLogger(); return new NullLogger();
$database->setLogger($logger);
return $logger;
} }
$minLevel = $minLevel ?? $config->get('system', 'loglevel'); $loglevel = $loglevel ?? static::mapLegacyConfigDebugLevel($this->config->get('system', 'loglevel'));
$loglevel = self::mapLegacyConfigDebugLevel((string)$minLevel); $name = $this->config->get('system', 'logger_config') ?? 'stream';
$name = $config->get('system', 'logger_config', 'stream');
switch ($name) {
case 'syslog':
try { try {
$logger = new SyslogLogger($this->channel, $introspection, $loglevel, $config->get('system', 'syslog_flags', SyslogLogger::DEFAULT_FLAGS), $config->get('system', 'syslog_facility', SyslogLogger::DEFAULT_FACILITY)); /** @var LoggerInterface */
return $this->instanceManager->getInstance(LoggerInterface::class, $name, [$this->channel, $loglevel]);
} catch (LogLevelException $exception) { } catch (LogLevelException $exception) {
// If there's a wrong config value for loglevel, try again with standard // If there's a wrong config value for loglevel, try again with standard
$logger = $this->create($database, $config, $profiler, $fileSystem, $introspection, LogLevel::NOTICE); $logger = $this->create(LogLevel::NOTICE);
$logger->warning('Invalid loglevel set in config.', ['loglevel' => $loglevel]); $logger->warning('Invalid loglevel set in config.', ['loglevel' => $loglevel]);
return $logger;
} catch (\Throwable $e) { } catch (\Throwable $e) {
// No logger ... // No logger ...
$logger = new NullLogger(); return 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 * 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 * @return LoggerInterface The PSR-3 compliant logger instance
* @throws \Exception * @throws \Exception
*/ */
public static function createDev(IManageConfigValues $config, Profiler $profiler, FileSystem $fileSystem, IHaveCallIntrospections $introspection) public function createDev()
{ {
$debugging = $config->get('system', 'debugging'); $debugging = $this->config->get('system', 'debugging');
$stream = $config->get('system', 'dlogfile'); $stream = $this->config->get('system', 'dlogfile');
$developerIp = $config->get('system', 'dlogip'); $developerIp = $this->config->get('system', 'dlogip');
if ((!isset($developerIp) || !$debugging) && if ((!isset($developerIp) || !$debugging) &&
(!is_file($stream) || is_writable($stream))) { (!is_file($stream) || is_writable($stream))) {
return new NullLogger(); return new NullLogger();
} }
$name = $config->get('system', 'logger_config', 'stream'); $name = $this->config->get('system', 'logger_config') ?? 'stream';
switch ($name) { /** @var LoggerInterface */
return $this->instanceManager->getInstance(LoggerInterface::class, $name, [self::DEV_CHANNEL, LogLevel::DEBUG, $stream]);
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;
} }
/** /**

View file

@ -21,8 +21,8 @@
namespace Friendica\Core\Logger\Type; namespace Friendica\Core\Logger\Type;
use Friendica\Core\Logger\Capabilities\IHaveCallIntrospections;
use Friendica\Core\Logger\Exception\LoggerException; use Friendica\Core\Logger\Exception\LoggerException;
use Friendica\Core\Logger\Util\Introspection;
use Friendica\Util\Strings; use Friendica\Util\Strings;
use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface;
use Psr\Log\LogLevel; use Psr\Log\LogLevel;
@ -46,7 +46,7 @@ abstract class AbstractLogger implements LoggerInterface
/** /**
* The Introspection for the current call * The Introspection for the current call
* @var Introspection * @var IHaveCallIntrospections
*/ */
protected $introspection; protected $introspection;
@ -69,11 +69,11 @@ abstract class AbstractLogger implements LoggerInterface
/** /**
* @param string $channel The output channel * @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 * @throws LoggerException
*/ */
public function __construct(string $channel, Introspection $introspection) public function __construct(string $channel, IHaveCallIntrospections $introspection)
{ {
$this->channel = $channel; $this->channel = $channel;
$this->introspection = $introspection; $this->introspection = $introspection;

View file

@ -21,18 +21,20 @@
namespace Friendica\Core\Logger\Type; 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\LoggerArgumentException;
use Friendica\Core\Logger\Exception\LoggerException; use Friendica\Core\Logger\Exception\LoggerException;
use Friendica\Core\Logger\Exception\LogLevelException; use Friendica\Core\Logger\Exception\LogLevelException;
use Friendica\Util\DateTimeFormat; use Friendica\Util\DateTimeFormat;
use Friendica\Util\FileSystem; use Friendica\Util\FileSystem;
use Friendica\Core\Logger\Util\Introspection;
use Psr\Log\LogLevel; use Psr\Log\LogLevel;
/** /**
* A Logger instance for logging into a stream (file, stdout, stderr) * 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 * The minimum loglevel at which this logger will be triggered
@ -80,16 +82,20 @@ class StreamLogger extends AbstractLogger
/** /**
* {@inheritdoc} * {@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 * @param string $level The minimum loglevel at which this logger will be triggered
* *
* @throws LoggerArgumentException * @throws LoggerArgumentException
* @throws LogLevelException * @throws LogLevelException
*/ */
public function __construct($channel, $stream, 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; $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); parent::__construct($channel, $introspection);
if (is_resource($stream)) { if (is_resource($stream)) {

View file

@ -21,16 +21,18 @@
namespace Friendica\Core\Logger\Type; 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\LoggerException;
use Friendica\Core\Logger\Exception\LogLevelException; use Friendica\Core\Logger\Exception\LogLevelException;
use Friendica\Core\Logger\Util\Introspection;
use Psr\Log\LogLevel; use Psr\Log\LogLevel;
/** /**
* A Logger instance for syslogging (fast, but simple) * A Logger instance for syslogging (fast, but simple)
* @see http://php.net/manual/en/function.syslog.php * @see http://php.net/manual/en/function.syslog.php
*/ */
class SyslogLogger extends AbstractLogger class SyslogLogger extends AbstractLogger implements IAmAStrategy
{ {
const IDENT = 'Friendica'; const IDENT = 'Friendica';
@ -100,17 +102,16 @@ class SyslogLogger extends AbstractLogger
/** /**
* {@inheritdoc} * {@inheritdoc}
* @param string $level The minimum loglevel at which this logger will be triggered * @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 LogLevelException
* @throws LoggerException * @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, IHaveCallIntrospections $introspection, string $level = LogLevel::NOTICE)
{ {
parent::__construct($channel, $introspection); 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->logLevel = $this->mapLevelToPriority($level);
$this->introspection->addClasses([self::class]); $this->introspection->addClasses([self::class]);
} }

View file

@ -527,7 +527,7 @@ class DBA
public static function buildTableString(array $tables): string public static function buildTableString(array $tables): string
{ {
// Quote each entry // Quote each entry
return implode(',', array_map(['self', 'quoteIdentifier'], $tables)); return implode(',', array_map([self::class, 'quoteIdentifier'], $tables));
} }
/** /**
@ -717,7 +717,7 @@ class DBA
{ {
$groupby_string = ''; $groupby_string = '';
if (!empty($params['group_by'])) { if (!empty($params['group_by'])) {
$groupby_string = " GROUP BY " . implode(', ', array_map(['self', 'quoteIdentifier'], $params['group_by'])); $groupby_string = " GROUP BY " . implode(', ', array_map([self::class, 'quoteIdentifier'], $params['group_by']));
} }
$order_string = ''; $order_string = '';

View file

@ -783,7 +783,7 @@ class DBStructure
} }
if (!DBA::exists('verb', ['id' => 0])) { if (!DBA::exists('verb', ['id' => 0])) {
DBA::insert('verb', ['name' => '']); DBA::insert('verb', ['name' => ''], Database::INSERT_IGNORE);
$lastid = DBA::lastInsertId(); $lastid = DBA::lastInsertId();
if ($lastid != 0) { if ($lastid != 0) {
DBA::update('verb', ['id' => 0], ['id' => $lastid]); DBA::update('verb', ['id' => 0], ['id' => $lastid]);
@ -819,7 +819,7 @@ class DBStructure
} }
if (self::existsTable('contact') && !DBA::exists('contact', ['id' => 0])) { if (self::existsTable('contact') && !DBA::exists('contact', ['id' => 0])) {
DBA::insert('contact', ['nurl' => '']); DBA::insert('contact', ['nurl' => ''], Database::INSERT_IGNORE);
$lastid = DBA::lastInsertId(); $lastid = DBA::lastInsertId();
if ($lastid != 0) { if ($lastid != 0) {
DBA::update('contact', ['id' => 0], ['id' => $lastid]); DBA::update('contact', ['id' => 0], ['id' => $lastid]);
@ -834,7 +834,7 @@ class DBStructure
} }
if (self::existsTable('tag') && !DBA::exists('tag', ['id' => 0])) { if (self::existsTable('tag') && !DBA::exists('tag', ['id' => 0])) {
DBA::insert('tag', ['name' => '']); DBA::insert('tag', ['name' => ''], Database::INSERT_IGNORE);
$lastid = DBA::lastInsertId(); $lastid = DBA::lastInsertId();
if ($lastid != 0) { if ($lastid != 0) {
DBA::update('tag', ['id' => 0], ['id' => $lastid]); DBA::update('tag', ['id' => 0], ['id' => $lastid]);
@ -850,7 +850,7 @@ class DBStructure
if (self::existsTable('permissionset')) { if (self::existsTable('permissionset')) {
if (!DBA::exists('permissionset', ['id' => 0])) { if (!DBA::exists('permissionset', ['id' => 0])) {
DBA::insert('permissionset', ['allow_cid' => '', 'allow_gid' => '', 'deny_cid' => '', 'deny_gid' => '']); DBA::insert('permissionset', ['allow_cid' => '', 'allow_gid' => '', 'deny_cid' => '', 'deny_gid' => ''], Database::INSERT_IGNORE);
$lastid = DBA::lastInsertId(); $lastid = DBA::lastInsertId();
if ($lastid != 0) { if ($lastid != 0) {
DBA::update('permissionset', ['id' => 0], ['id' => $lastid]); DBA::update('permissionset', ['id' => 0], ['id' => $lastid]);
@ -878,7 +878,7 @@ class DBStructure
} }
$fields = ['id' => $set['psid'], 'uid' => $set['uid'], 'allow_cid' => $permission, $fields = ['id' => $set['psid'], 'uid' => $set['uid'], 'allow_cid' => $permission,
'allow_gid' => '', 'deny_cid' => '', 'deny_gid' => '']; 'allow_gid' => '', 'deny_cid' => '', 'deny_gid' => ''];
DBA::insert('permissionset', $fields); DBA::insert('permissionset', $fields, Database::INSERT_IGNORE);
} }
DBA::close($sets); DBA::close($sets);
} }

View file

@ -36,7 +36,6 @@ use PDO;
use PDOException; use PDOException;
use PDOStatement; use PDOStatement;
use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface;
use Psr\Log\NullLogger;
/** /**
* This class is for the low level database stuff that does driver specific things. * This class is for the low level database stuff that does driver specific things.
@ -81,16 +80,14 @@ class Database
/** @var ViewDefinition */ /** @var ViewDefinition */
protected $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 // We are storing these values for being able to perform a reconnect
$this->config = $config; $this->config = $config;
$this->profiler = $profiler; $this->profiler = $profiler;
$this->dbaDefinition = $dbaDefinition; $this->dbaDefinition = $dbaDefinition;
$this->viewDefinition = $viewDefinition; $this->viewDefinition = $viewDefinition;
$this->logger = $logger;
// Temporary NullLogger until we can fetch the logger class from the config
$this->logger = new NullLogger();
$this->connect(); $this->connect();
} }
@ -196,21 +193,6 @@ class Database
$this->testmode = $test; $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 * Sets the profiler for DBA
* *

View file

@ -87,6 +87,10 @@ class DbaDefinition
$data[$field] = mb_substr($data[$field], 0, $result[1]); $data[$field] = mb_substr($data[$field], 0, $result[1]);
} elseif (is_string($data[$field]) && preg_match("/binary\((\d*)\)/", $definition[$table]['fields'][$field]['type'], $result)) { } elseif (is_string($data[$field]) && preg_match("/binary\((\d*)\)/", $definition[$table]['fields'][$field]['type'], $result)) {
$data[$field] = substr($data[$field], 0, $result[1]); $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]; $fields[$field] = $data[$field];
} }

View file

@ -243,15 +243,13 @@ class Contact
* @throws \Exception * @throws \Exception
* @todo Let's get rid of boolean type of $old_fields * @todo Let's get rid of boolean type of $old_fields
*/ */
public static function update(array $fields, array $condition, $old_fields = []) public static function update(array $fields, array $condition, $old_fields = []): bool
{ {
$fields = DI::dbaDefinition()->truncateFieldsForTable('contact', $fields);
$ret = DBA::update('contact', $fields, $condition, $old_fields);
// Apply changes to the "user-contact" table on dedicated fields // Apply changes to the "user-contact" table on dedicated fields
Contact\User::updateByContactUpdate($fields, $condition); Contact\User::updateByContactUpdate($fields, $condition);
return $ret; $fields = DI::dbaDefinition()->truncateFieldsForTable('contact', $fields);
return DBA::update('contact', $fields, $condition, $old_fields);
} }
/** /**
@ -2970,7 +2968,7 @@ class Contact
} }
// check if we already have a contact // check if we already have a contact
$condition = ['uid' => $uid, 'nurl' => Strings::normaliseLink($ret['url'])]; $condition = ['uid' => $uid, 'nurl' => Strings::normaliseLink($ret['url']), 'deleted' => false];
$contact = DBA::selectFirst('contact', ['id', 'rel', 'url', 'pending', 'hub-verify'], $condition); $contact = DBA::selectFirst('contact', ['id', 'rel', 'url', 'pending', 'hub-verify'], $condition);
$protocol = self::getProtocol($ret['url'], $ret['network']); $protocol = self::getProtocol($ret['url'], $ret['network']);
@ -3293,7 +3291,7 @@ class Contact
if ($contact['rel'] == self::SHARING || in_array($contact['network'], [Protocol::FEED, Protocol::MAIL])) { if ($contact['rel'] == self::SHARING || in_array($contact['network'], [Protocol::FEED, Protocol::MAIL])) {
self::remove($contact['id']); self::remove($contact['id']);
} else { } else {
self::update(['rel' => self::FOLLOWER], ['id' => $contact['id']]); self::update(['rel' => self::FOLLOWER, 'pending' => false], ['id' => $contact['id']]);
} }
Worker::add(Worker::PRIORITY_LOW, 'ContactDiscoveryForUser', $contact['uid']); Worker::add(Worker::PRIORITY_LOW, 'ContactDiscoveryForUser', $contact['uid']);

View file

@ -198,7 +198,7 @@ class Event
public static function sortByDate(array $event_list): array public static function sortByDate(array $event_list): array
{ {
usort($event_list, ['self', 'compareDatesCallback']); usort($event_list, [self::class, 'compareDatesCallback']);
return $event_list; return $event_list;
} }

View file

@ -455,22 +455,26 @@ class GServer
* Set failed server status * Set failed server status
* *
* @param string $url * @param string $url
* @return void
*/ */
public static function setFailureByUrl(string $url) public static function setFailureByUrl(string $url)
{ {
$gserver = DBA::selectFirst('gserver', [], ['nurl' => Strings::normaliseLink($url)]); $nurl = Strings::normaliseLink($url);
$gserver = DBA::selectFirst('gserver', [], ['nurl' => $nurl]);
if (DBA::isResult($gserver)) { if (DBA::isResult($gserver)) {
$next_update = self::getNextUpdateDate(false, $gserver['created'], $gserver['last_contact']); $next_update = self::getNextUpdateDate(false, $gserver['created'], $gserver['last_contact']);
self::update(['url' => $url, 'failed' => true, 'blocked' => Network::isUrlBlocked($url), 'last_failure' => DateTimeFormat::utcNow(), self::update(['url' => $url, 'failed' => true, 'blocked' => Network::isUrlBlocked($url), 'last_failure' => DateTimeFormat::utcNow(),
'next_contact' => $next_update, 'network' => Protocol::PHANTOM, 'detection-method' => null], 'next_contact' => $next_update, 'network' => Protocol::PHANTOM, 'detection-method' => null],
['nurl' => Strings::normaliseLink($url)]); ['nurl' => $nurl]);
Logger::info('Set failed status for existing server', ['url' => $url]); Logger::info('Set failed status for existing server', ['url' => $url]);
if (self::isDefunct($gserver)) { if (self::isDefunct($gserver)) {
self::archiveContacts($gserver['id']); self::archiveContacts($gserver['id']);
} }
return; return;
} }
self::insert(['url' => $url, 'nurl' => Strings::normaliseLink($url),
self::insert(['url' => $url, 'nurl' => $nurl,
'network' => Protocol::PHANTOM, 'created' => DateTimeFormat::utcNow(), 'network' => Protocol::PHANTOM, 'created' => DateTimeFormat::utcNow(),
'failed' => true, 'last_failure' => DateTimeFormat::utcNow()]); 'failed' => true, 'last_failure' => DateTimeFormat::utcNow()]);
Logger::info('Set failed status for new server', ['url' => $url]); Logger::info('Set failed status for new server', ['url' => $url]);
@ -556,7 +560,7 @@ class GServer
// If the URL missmatches, then we mark the old entry as failure // If the URL missmatches, then we mark the old entry as failure
if (!Strings::compareLink($url, $original_url)) { if (!Strings::compareLink($url, $original_url)) {
self::setFailureByUrl($original_url); self::setFailureByUrl($original_url);
if (!self::getID($url, true)) { if (!self::getID($url, true) && !Network::isUrlBlocked($url)) {
self::detect($url, $network, $only_nodeinfo); self::detect($url, $network, $only_nodeinfo);
} }
return false; return false;
@ -577,7 +581,7 @@ class GServer
(((parse_url($url, PHP_URL_HOST) != parse_url($valid_url, PHP_URL_HOST)) || (parse_url($url, PHP_URL_PATH) != parse_url($valid_url, PHP_URL_PATH))) && empty(parse_url($valid_url, PHP_URL_PATH)))) { (((parse_url($url, PHP_URL_HOST) != parse_url($valid_url, PHP_URL_HOST)) || (parse_url($url, PHP_URL_PATH) != parse_url($valid_url, PHP_URL_PATH))) && empty(parse_url($valid_url, PHP_URL_PATH)))) {
Logger::debug('Found redirect. Mark old entry as failure', ['old' => $url, 'new' => $valid_url]); Logger::debug('Found redirect. Mark old entry as failure', ['old' => $url, 'new' => $valid_url]);
self::setFailureByUrl($url); self::setFailureByUrl($url);
if (!self::getID($valid_url, true)) { if (!self::getID($valid_url, true) && !Network::isUrlBlocked($valid_url)) {
self::detect($valid_url, $network, $only_nodeinfo); self::detect($valid_url, $network, $only_nodeinfo);
} }
return false; return false;
@ -591,7 +595,7 @@ class GServer
$valid_url = (string)Uri::fromParts($parts); $valid_url = (string)Uri::fromParts($parts);
self::setFailureByUrl($url); self::setFailureByUrl($url);
if (!self::getID($valid_url, true)) { if (!self::getID($valid_url, true) && !Network::isUrlBlocked($valid_url)) {
self::detect($valid_url, $network, $only_nodeinfo); self::detect($valid_url, $network, $only_nodeinfo);
} }
return false; return false;

View file

@ -55,17 +55,17 @@ class Nodeinfo
$userStats = User::getStatistics(); $userStats = User::getStatistics();
$config->set('nodeinfo', 'total_users', $userStats['total_users']); DI::keyValue()->set('nodeinfo_total_users', $userStats['total_users']);
$config->set('nodeinfo', 'active_users_halfyear', $userStats['active_users_halfyear']); DI::keyValue()->set('nodeinfo_active_users_halfyear', $userStats['active_users_halfyear']);
$config->set('nodeinfo', 'active_users_monthly', $userStats['active_users_monthly']); DI::keyValue()->set('nodeinfo_active_users_monthly', $userStats['active_users_monthly']);
$config->set('nodeinfo', 'active_users_weekly', $userStats['active_users_weekly']); DI::keyValue()->set('nodeinfo_active_users_weekly', $userStats['active_users_weekly']);
$logger->info('user statistics', $userStats); $logger->info('user statistics', $userStats);
$posts = DBA::count('post-thread', ["`uri-id` IN (SELECT `uri-id` FROM `post-user` WHERE NOT `deleted` AND `origin`)"]); $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]); $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); DI::keyValue()->set('nodeinfo_local_posts', $posts);
$config->set('nodeinfo', 'local_comments', $comments); DI::keyValue()->set('nodeinfo_local_comments', $comments);
$logger->info('User actitivy', ['posts' => $posts, 'comments' => $comments]); $logger->info('User actitivy', ['posts' => $posts, 'comments' => $comments]);
} }
@ -83,14 +83,14 @@ class Nodeinfo
$usage->users = new \stdClass; $usage->users = new \stdClass;
if (!empty($config->get('system', 'nodeinfo'))) { if (!empty($config->get('system', 'nodeinfo'))) {
$usage->users->total = intval($config->get('nodeinfo', 'total_users')); $usage->users->total = intval(DI::keyValue()->get('nodeinfo_total_users'));
$usage->users->activeHalfyear = intval($config->get('nodeinfo', 'active_users_halfyear')); $usage->users->activeHalfyear = intval(DI::keyValue()->get('nodeinfo_active_users_halfyear'));
$usage->users->activeMonth = intval($config->get('nodeinfo', 'active_users_monthly')); $usage->users->activeMonth = intval(DI::keyValue()->get('nodeinfo_active_users_monthly'));
$usage->localPosts = intval($config->get('nodeinfo', 'local_posts')); $usage->localPosts = intval(DI::keyValue()->get('nodeinfo_local_posts'));
$usage->localComments = intval($config->get('nodeinfo', 'local_comments')); $usage->localComments = intval(DI::keyValue()->get('nodeinfo_local_comments'));
if ($version2) { if ($version2) {
$usage->users->activeWeek = intval($config->get('nodeinfo', 'active_users_weekly')); $usage->users->activeWeek = intval(DI::keyValue()->get('nodeinfo_active_users_weekly'));
} }
} }

View file

@ -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. * 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 * From the manual: "Using the PASSWORD_BCRYPT as the algorithm, will result in the password parameter being
@ -770,13 +770,13 @@ class User
*/ */
public static function getPasswordRegExp(string $delimiter = null): string public static function getPasswordRegExp(string $delimiter = null): string
{ {
$allowed_characters = '!"#$%&\'()*+,-./;<=>?@[\]^_`{|}~'; $allowed_characters = ':!"#$%&\'()*+,-./;<=>?@[\]^_`{|}~';
if ($delimiter) { if ($delimiter) {
$allowed_characters = preg_quote($allowed_characters, $delimiter); $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}' : '+') . '$';
} }
/** /**
@ -804,7 +804,7 @@ class User
} }
if (!preg_match('/' . self::getPasswordRegExp('/') . '/', $password)) { 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)); return self::updatePasswordHashed($uid, self::hashPassword($password));

View file

@ -239,9 +239,6 @@ class Profile extends BaseModule
'$baseurl' => $this->baseUrl->get(true), '$baseurl' => $this->baseUrl->get(true),
]); ]);
$contact['blocked'] = Contact\User::isBlocked($contact['id'], DI::userSession()->getLocalUserId());
$contact['readonly'] = Contact\User::isIgnored($contact['id'], DI::userSession()->getLocalUserId());
switch ($localRelationship->rel) { switch ($localRelationship->rel) {
case Contact::FRIEND: $relation_text = $this->t('You are mutual friends with %s', $contact['name']); break; case Contact::FRIEND: $relation_text = $this->t('You are mutual friends with %s', $contact['name']); break;
case Contact::FOLLOWER: $relation_text = $this->t('You are sharing with %s', $contact['name']); break; case Contact::FOLLOWER: $relation_text = $this->t('You are sharing with %s', $contact['name']); break;
@ -361,16 +358,13 @@ class Profile extends BaseModule
'$last_update' => $last_update, '$last_update' => $last_update,
'$udnow' => $this->t('Update now'), '$udnow' => $this->t('Update now'),
'$contact_id' => $contact['id'], '$contact_id' => $contact['id'],
'$block_text' => ($contact['blocked'] ? $this->t('Unblock') : $this->t('Block')), '$pending' => $localRelationship->pending ? $this->t('Awaiting connection acknowledge') : '',
'$ignore_text' => ($contact['readonly'] ? $this->t('Unignore') : $this->t('Ignore')), '$blocked' => $localRelationship->blocked ? $this->t('Currently blocked') : '',
'$insecure' => (in_array($contact['network'], [Protocol::ACTIVITYPUB, Protocol::DFRN, Protocol::MAIL, Protocol::DIASPORA]) ? '' : $insecure), '$ignored' => $localRelationship->ignored ? $this->t('Currently ignored') : '',
'$info' => $localRelationship->info, '$collapsed' => $localRelationship->collapsed ? $this->t('Currently collapsed') : '',
'$cinfo' => ['info', '', $localRelationship->info, ''],
'$blocked' => ($contact['blocked'] ? $this->t('Currently blocked') : ''),
'$ignored' => ($contact['readonly'] ? $this->t('Currently ignored') : ''),
'$collapsed' => (Contact\User::isCollapsed($contact['id'], DI::userSession()->getLocalUserId()) ? $this->t('Currently collapsed') : ''),
'$archived' => ($contact['archive'] ? $this->t('Currently archived') : ''), '$archived' => ($contact['archive'] ? $this->t('Currently archived') : ''),
'$pending' => ($contact['pending'] ? $this->t('Awaiting connection acknowledge') : ''), '$insecure' => (in_array($contact['network'], [Protocol::ACTIVITYPUB, Protocol::DFRN, Protocol::MAIL, Protocol::DIASPORA]) ? '' : $insecure),
'$cinfo' => ['info', '', $localRelationship->info, ''],
'$hidden' => ['hidden', $this->t('Hide this contact from others'), $localRelationship->hidden, $this->t('Replies/likes to your public posts <strong>may</strong> still be visible')], '$hidden' => ['hidden', $this->t('Hide this contact from others'), $localRelationship->hidden, $this->t('Replies/likes to your public posts <strong>may</strong> still be visible')],
'$notify_new_posts' => ['notify_new_posts', $this->t('Notification for new posts'), ($localRelationship->notifyNewPosts), $this->t('Send a notification of every new post of this contact')], '$notify_new_posts' => ['notify_new_posts', $this->t('Notification for new posts'), ($localRelationship->notifyNewPosts), $this->t('Send a notification of every new post of this contact')],
'$fetch_further_information' => $fetch_further_information, '$fetch_further_information' => $fetch_further_information,

View file

@ -36,7 +36,7 @@ class Maintenance extends BaseModule
{ {
protected function content(array $request = []): string 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://') || if ((substr(Strings::normaliseLink($reason), 0, 7) === 'http://') ||
(substr(Strings::normaliseLink($reason), 0, 8) === 'https://')) { (substr(Strings::normaliseLink($reason), 0, 8) === 'https://')) {

View file

@ -61,7 +61,10 @@ class Token extends BaseApi
} }
if (empty($request['client_id']) && substr($authorization, 0, 6) == 'Basic ') { 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) { if (count($datapair) == 2) {
$request['client_id'] = $datapair[0]; $request['client_id'] = $datapair[0];
$request['client_secret'] = $datapair[1]; $request['client_secret'] = $datapair[1];

View file

@ -98,7 +98,7 @@ class PasswordTooLong extends \Friendica\BaseModule
'$return_url' => $request['return_url'] ?? '', '$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_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"'], '$password_confirm' => ['password_confirm', $this->l10n->t('Confirm:'), '', '', 'required', 'autocomplete="off"'],
]); ]);

View file

@ -549,7 +549,7 @@ class Account extends BaseSettings
$notify_type = DI::pConfig()->get(DI::userSession()->getLocalUserId(), 'system', 'notify_type'); $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.') : ''); . (PASSWORD_DEFAULT === PASSWORD_BCRYPT ? ' ' . DI::l10n()->t('Password length is limited to 72 characters.') : '');
$tpl = Renderer::getMarkupTemplate('settings/account.tpl'); $tpl = Renderer::getMarkupTemplate('settings/account.tpl');

View file

@ -25,6 +25,7 @@ use Friendica\App;
use Friendica\BaseModule; use Friendica\BaseModule;
use Friendica\Core\Addon; use Friendica\Core\Addon;
use Friendica\Core\Config\Capability\IManageConfigValues; use Friendica\Core\Config\Capability\IManageConfigValues;
use Friendica\Core\KeyValueStorage\Capabilities\IManageKeyValuePairs;
use Friendica\Core\L10n; use Friendica\Core\L10n;
use Friendica\Core\System; use Friendica\Core\System;
use Friendica\Network\HTTPException\NotFoundException; use Friendica\Network\HTTPException\NotFoundException;
@ -35,13 +36,15 @@ class Statistics extends BaseModule
{ {
/** @var IManageConfigValues */ /** @var IManageConfigValues */
protected $config; protected $config;
/** @var IManageKeyValuePairs */
protected $keyValue;
public function __construct(L10n $l10n, App\BaseURL $baseUrl, App\Arguments $args, LoggerInterface $logger, Profiler $profiler, IManageConfigValues $config, Response $response, array $server, array $parameters = []) 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); 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")) { if (!$this->config->get("system", "nodeinfo")) {
throw new NotFoundException(); throw new NotFoundException();
} }
@ -72,10 +75,10 @@ class Statistics extends BaseModule
'network' => App::PLATFORM, 'network' => App::PLATFORM,
'version' => App::VERSION . '-' . DB_UPDATE_VERSION, 'version' => App::VERSION . '-' . DB_UPDATE_VERSION,
'registrations_open' => $registration_open, 'registrations_open' => $registration_open,
'total_users' => $this->config->get('nodeinfo', 'total_users'), 'total_users' => $this->keyValue->get('nodeinfo_total_users'),
'active_users_halfyear' => $this->config->get('nodeinfo', 'active_users_halfyear'), 'active_users_halfyear' => $this->keyValue->get('nodeinfo_active_users_halfyear'),
'active_users_monthly' => $this->config->get('nodeinfo', 'active_users_monthly'), 'active_users_monthly' => $this->keyValue->get('nodeinfo_active_users_monthly'),
'local_posts' => $this->config->get('nodeinfo', 'local_posts'), 'local_posts' => $this->keyValue->get('nodeinfo_local_posts'),
'services' => $services, 'services' => $services,
], $services); ], $services);

View file

@ -614,7 +614,7 @@ class Notify extends BaseRepository
$emailBuilder->setHeader('Message-ID', $message_id); $emailBuilder->setHeader('Message-ID', $message_id);
$log_msg = "No previous notification found for this parent:\n" . $log_msg = "No previous notification found for this parent:\n" .
" parent: ${params['parent']}\n" . " uid : ${params['uid']}\n"; " parent: {$params['parent']}\n" . " uid : {$params['uid']}\n";
$this->logger->info($log_msg); $this->logger->info($log_msg);
} else { } else {
// If not, just "follow" the thread. // If not, just "follow" the thread.

View file

@ -69,6 +69,10 @@ class HttpClient implements ICanSendHttpRequests
$this->logger->debug('Request start.', ['url' => $url, 'method' => $method]); $this->logger->debug('Request start.', ['url' => $url, 'method' => $method]);
$host = parse_url($url, PHP_URL_HOST); $host = parse_url($url, PHP_URL_HOST);
if (empty($host)) {
throw new \InvalidArgumentException('Unable to retrieve the host in URL: ' . $url);
}
if(!filter_var($host, FILTER_VALIDATE_IP) && !@dns_get_record($host . '.', DNS_A + DNS_AAAA) && !gethostbyname($host)) { if(!filter_var($host, FILTER_VALIDATE_IP) && !@dns_get_record($host . '.', DNS_A + DNS_AAAA) && !gethostbyname($host)) {
$this->logger->debug('URL cannot be resolved.', ['url' => $url, 'callstack' => System::callstack(20)]); $this->logger->debug('URL cannot be resolved.', ['url' => $url, 'callstack' => System::callstack(20)]);
$this->profiler->stopRecording(); $this->profiler->stopRecording();

View file

@ -54,6 +54,8 @@ class Card extends BaseDataTransferObject
protected $image; protected $image;
/** @var string */ /** @var string */
protected $blurhash; protected $blurhash;
/** @var array */
protected $history;
/** /**
* Creates a card record from an attachment array. * Creates a card record from an attachment array.

View file

@ -25,7 +25,6 @@ use Friendica\BaseDataTransferObject;
use Friendica\Core\Config\Capability\IManageConfigValues; use Friendica\Core\Config\Capability\IManageConfigValues;
use Friendica\Core\Protocol; use Friendica\Core\Protocol;
use Friendica\Database\Database; use Friendica\Database\Database;
use Friendica\Database\DBA;
use Friendica\DI; use Friendica\DI;
/** /**
@ -45,9 +44,9 @@ class Stats extends BaseDataTransferObject
public function __construct(IManageConfigValues $config, Database $database) public function __construct(IManageConfigValues $config, Database $database)
{ {
if (!empty($config->get('system', 'nodeinfo'))) { if (!empty($config->get('system', 'nodeinfo'))) {
$this->user_count = intval($config->get('nodeinfo', 'total_users')); $this->user_count = intval(DI::keyValue()->get('nodeinfo_total_users'));
$this->status_count = $config->get('nodeinfo', 'local_posts') + $config->get('nodeinfo', 'local_comments'); $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`", Protocol::DFRN, Protocol::ACTIVITYPUB]); $this->domain_count = $database->count('gserver', ["`network` in (?, ?) AND NOT `failed` AND NOT `blocked`", Protocol::DFRN, Protocol::ACTIVITYPUB]);
} }
} }
} }

View file

@ -1661,7 +1661,7 @@ class Transmitter
* *
* } elseif (($type == 'Article') && empty($data['summary'])) { * } elseif (($type == 'Article') && empty($data['summary'])) {
* $regexp = "/[@!]\[url\=([^\[\]]*)\].*?\[\/url\]/ism"; * $regexp = "/[@!]\[url\=([^\[\]]*)\].*?\[\/url\]/ism";
* $summary = preg_replace_callback($regexp, ['self', 'mentionAddrCallback'], $body); * $summary = preg_replace_callback($regexp, [self::class, 'mentionAddrCallback'], $body);
* $data['summary'] = BBCode::toPlaintext(Plaintext::shorten(self::removePictures($summary), 1000)); * $data['summary'] = BBCode::toPlaintext(Plaintext::shorten(self::removePictures($summary), 1000));
* } * }
*/ */

View file

@ -646,7 +646,7 @@ class ParseUrl
$arr_tags = str_getcsv($string); $arr_tags = str_getcsv($string);
if (count($arr_tags)) { if (count($arr_tags)) {
// add the # sign to every tag // add the # sign to every tag
array_walk($arr_tags, ['self', 'arrAddHashes']); array_walk($arr_tags, [self::class, 'arrAddHashes']);
return $arr_tags; return $arr_tags;
} }

View file

@ -141,7 +141,7 @@ class Proxy
{ {
$html = str_replace(Strings::normaliseLink(DI::baseUrl()) . '/', DI::baseUrl() . '/', $html); $html = str_replace(Strings::normaliseLink(DI::baseUrl()) . '/', DI::baseUrl() . '/', $html);
return preg_replace_callback('/(<img [^>]*src *= *["\'])([^"\']+)(["\'][^>]*>)/siU', 'self::replaceUrl', $html); return preg_replace_callback('/(<img [^>]*src *= *["\'])([^"\']+)(["\'][^>]*>)/siU', [self::class, 'replaceUrl'], $html);
} }
/** /**

View file

@ -57,7 +57,7 @@ class UpdateServerPeers
$total = 0; $total = 0;
$added = 0; $added = 0;
foreach ($peers as $peer) { foreach ($peers as $peer) {
if (Network::isUrlBlocked('http://' . $peer)) { if (Network::isUrlBlocked('https://' . $peer)) {
// Ignore blocked systems as soon as possible in the loop to avoid being slowed down by tar pits // Ignore blocked systems as soon as possible in the loop to avoid being slowed down by tar pits
continue; continue;
} }

View file

@ -55,7 +55,7 @@
use Friendica\Database\DBA; use Friendica\Database\DBA;
if (!defined('DB_UPDATE_VERSION')) { if (!defined('DB_UPDATE_VERSION')) {
define('DB_UPDATE_VERSION', 1511); define('DB_UPDATE_VERSION', 1512);
} }
return [ return [

View file

@ -37,6 +37,8 @@ use Dice\Dice;
use Friendica\App; use Friendica\App;
use Friendica\Core\Cache; use Friendica\Core\Cache;
use Friendica\Core\Config; use Friendica\Core\Config;
use Friendica\Core\Hooks\Capabilities\ICanManageInstances;
use Friendica\Core\Hooks\Model\InstanceManager;
use Friendica\Core\PConfig; use Friendica\Core\PConfig;
use Friendica\Core\L10n; use Friendica\Core\L10n;
use Friendica\Core\Lock; use Friendica\Core\Lock;
@ -76,6 +78,12 @@ return [
$_SERVER $_SERVER
] ]
], ],
ICanManageInstances::class => [
'instanceOf' => InstanceManager::class,
'constructParams' => [
[Dice::INSTANCE => Dice::SELF],
],
],
Config\Util\ConfigFileManager::class => [ Config\Util\ConfigFileManager::class => [
'instanceOf' => Config\Factory\Config::class, 'instanceOf' => Config\Factory\Config::class,
'call' => [ 'call' => [

View file

@ -30,6 +30,7 @@ use Friendica\Database\Definition\ViewDefinition;
use Friendica\Test\DatabaseTestTrait; use Friendica\Test\DatabaseTestTrait;
use Friendica\Test\Util\Database\StaticDatabase; use Friendica\Test\Util\Database\StaticDatabase;
use Friendica\Util\Profiler; use Friendica\Util\Profiler;
use Psr\Log\NullLogger;
trait CreateDatabaseTrait 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); $database->setTestmode(true);
return $database; return $database;

View file

@ -0,0 +1,60 @@
<?php
/**
* @copyright Copyright (C) 2010-2023, the Friendica project
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
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;
}
}

View file

@ -0,0 +1,59 @@
<?php
/**
* @copyright Copyright (C) 2010-2023, the Friendica project
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
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();
}
}

View file

@ -0,0 +1,33 @@
<?php
/**
* @copyright Copyright (C) 2010-2023, the Friendica project
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
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;
}

View file

@ -0,0 +1,35 @@
<?php
/**
* @copyright Copyright (C) 2010-2023, the Friendica project
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
namespace Friendica\Test\Util;
class SerializableObjectDouble implements \Serializable
{
public function serialize()
{
return '\'serialized\'';
}
public function unserialize($data)
{
return '\'unserialized\'';
}
}

View file

@ -0,0 +1,11 @@
<?php
use Friendica\Test\Util\SerializableObjectDouble;
use ParagonIE\HiddenString\HiddenString;
return [
'object' => [
'toString' => new HiddenString('test'),
'serializable' => new SerializableObjectDouble(),
],
];

View file

@ -25,7 +25,6 @@ use Dice\Dice;
use Friendica\App; use Friendica\App;
use Friendica\Core\Cache\Capability\ICanCache; use Friendica\Core\Cache\Capability\ICanCache;
use Friendica\Core\Cache\Capability\ICanCacheInMemory; use Friendica\Core\Cache\Capability\ICanCacheInMemory;
use Friendica\Core\Config\Model\Config;
use Friendica\Core\Config\ValueObject\Cache; use Friendica\Core\Config\ValueObject\Cache;
use Friendica\Core\Config\Capability\IManageConfigValues; use Friendica\Core\Config\Capability\IManageConfigValues;
use Friendica\Core\Lock\Capability\ICanLock; use Friendica\Core\Lock\Capability\ICanLock;
@ -33,7 +32,6 @@ use Friendica\Database\Database;
use Friendica\Test\Util\VFSTrait; use Friendica\Test\Util\VFSTrait;
use Friendica\Util\BasePath; use Friendica\Util\BasePath;
use Friendica\Core\Config\Util\ConfigFileManager; use Friendica\Core\Config\Util\ConfigFileManager;
use Friendica\Util\Profiler;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface;
@ -53,7 +51,18 @@ class DependencyCheckTest extends TestCase
$this->setUpVfsDir(); $this->setUpVfsDir();
$this->dice = (new Dice()) $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() public function testLogger()
{ {
/** @var LoggerInterface $logger */ /** @var LoggerInterface $logger */
$logger = $this->dice->create(LoggerInterface::class, ['test']); $logger = $this->dice->create(LoggerInterface::class, [['$channel' => 'test']]);
self::assertInstanceOf(LoggerInterface::class, $logger); self::assertInstanceOf(LoggerInterface::class, $logger);
} }
@ -154,7 +163,7 @@ class DependencyCheckTest extends TestCase
$config->set('system', 'dlogfile', $this->root->url() . '/friendica.log'); $config->set('system', 'dlogfile', $this->root->url() . '/friendica.log');
/** @var LoggerInterface $logger */ /** @var LoggerInterface $logger */
$logger = $this->dice->create('$devLogger', ['dev']); $logger = $this->dice->create('$devLogger', [['$channel' => 'dev']]);
self::assertInstanceOf(LoggerInterface::class, $logger); self::assertInstanceOf(LoggerInterface::class, $logger);
} }
@ -164,6 +173,7 @@ class DependencyCheckTest extends TestCase
/** @var ICanCache $cache */ /** @var ICanCache $cache */
$cache = $this->dice->create(ICanCache::class); $cache = $this->dice->create(ICanCache::class);
self::assertInstanceOf(ICanCache::class, $cache); self::assertInstanceOf(ICanCache::class, $cache);
} }

View file

@ -62,7 +62,7 @@ class DatabaseCacheTest extends CacheTest
$dbaDefinition = (new DbaDefinition($configCache->get('system', 'basepath')))->load(); $dbaDefinition = (new DbaDefinition($configCache->get('system', 'basepath')))->load();
$viewDefinition = (new ViewDefinition($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); $this->cache = new Cache\Type\DatabaseCache('database', $dba);
return $this->cache; return $this->cache;

View file

@ -23,6 +23,9 @@ namespace Friendica\Test\src\Core\Config\Util;
use Friendica\Core\Config\Util\ConfigFileTransformer; use Friendica\Core\Config\Util\ConfigFileTransformer;
use Friendica\Test\MockedTest; use Friendica\Test\MockedTest;
use Friendica\Test\Util\SerializableObjectDouble;
use ParagonIE\HiddenString\HiddenString;
use function PHPUnit\Framework\assertEquals;
class ConfigFileTransformerTest extends MockedTest class ConfigFileTransformerTest extends MockedTest
{ {
@ -45,9 +48,34 @@ class ConfigFileTransformerTest extends MockedTest
'configFile' => (dirname(__DIR__, 4) . '/datasets/config/transformer/object.node.config.php'), 'configFile' => (dirname(__DIR__, 4) . '/datasets/config/transformer/object.node.config.php'),
'assertException' => true, 'assertException' => true,
], ],
'ressource_invalid' => [ 'resource' => [
'configFile' => (dirname(__DIR__, 4) . '/datasets/config/transformer/ressource.node.config.php'), 'configFile' => (dirname(__DIR__, 4) . '/datasets/config/transformer/ressource.node.config.php'),
'assertException' => true, 'assertException' => false,
'assertion' => <<<EOF
<?php
return [
'ressource' => [
'ressources_not_allowed' => '',
],
];
EOF,
],
'object_valid' => [
'configFile' => (dirname(__DIR__, 4) . '/datasets/config/transformer/object_valid.node.config.php'),
'assertException' => false,
'assertion' => <<<EOF
<?php
return [
'object' => [
'toString' => 'test',
'serializable' => 'serialized',
],
];
EOF,
], ],
'test_types' => [ 'test_types' => [
'configFile' => (dirname(__DIR__, 4) . '/datasets/config/transformer/types.node.config.php'), 'configFile' => (dirname(__DIR__, 4) . '/datasets/config/transformer/types.node.config.php'),
@ -63,7 +91,7 @@ class ConfigFileTransformerTest extends MockedTest
* *
* @dataProvider dataTests * @dataProvider dataTests
*/ */
public function testConfigFile(string $configFile, bool $assertException = false) public function testConfigFile(string $configFile, bool $assertException = false, $assertion = null)
{ {
$dataArray = include $configFile; $dataArray = include $configFile;
@ -73,6 +101,10 @@ class ConfigFileTransformerTest extends MockedTest
$newConfig = ConfigFileTransformer::encode($dataArray); $newConfig = ConfigFileTransformer::encode($dataArray);
if (empty($assertion)) {
self::assertEquals(file_get_contents($configFile), $newConfig); self::assertEquals(file_get_contents($configFile), $newConfig);
} else {
self::assertEquals($assertion, $newConfig);
}
} }
} }

View file

@ -0,0 +1,258 @@
<?php
/**
* @copyright Copyright (C) 2010-2023, the Friendica project
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
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());
}
}

View file

@ -21,6 +21,7 @@
namespace Friendica\Test\src\Core\Logger; namespace Friendica\Test\src\Core\Logger;
use Friendica\Core\Config\Capability\IManageConfigValues;
use Friendica\Test\MockedTest; use Friendica\Test\MockedTest;
use Friendica\Core\Logger\Util\Introspection; use Friendica\Core\Logger\Util\Introspection;
use Mockery\MockInterface; use Mockery\MockInterface;
@ -41,6 +42,10 @@ abstract class AbstractLoggerTest extends MockedTest
* @var Introspection|MockInterface * @var Introspection|MockInterface
*/ */
protected $introspection; protected $introspection;
/**
* @var IManageConfigValues|MockInterface
*/
protected $config;
/** /**
* Returns the content of the current logger instance * Returns the content of the current logger instance
@ -68,6 +73,8 @@ abstract class AbstractLoggerTest extends MockedTest
'line' => self::LINE, 'line' => self::LINE,
'function' => self::FUNC 'function' => self::FUNC
]); ]);
$this->config = \Mockery::mock(IManageConfigValues::class);
} }
public function assertLogline($string) public function assertLogline($string)

View file

@ -62,7 +62,9 @@ class StreamLoggerTest extends AbstractLoggerTest
$this->logfile = vfsStream::newFile('friendica.log') $this->logfile = vfsStream::newFile('friendica.log')
->at($this->root); ->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; return $logger;
} }
@ -75,43 +77,6 @@ class StreamLoggerTest extends AbstractLoggerTest
return $this->logfile->getContent(); 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 * Test when a file isn't set
*/ */
@ -120,7 +85,9 @@ class StreamLoggerTest extends AbstractLoggerTest
$this->expectException(LoggerArgumentException::class); $this->expectException(LoggerArgumentException::class);
$this->expectExceptionMessage("Missing stream URL."); $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'); $logger->emergency('not working');
} }
@ -130,13 +97,14 @@ class StreamLoggerTest extends AbstractLoggerTest
*/ */
public function testWrongUrl() public function testWrongUrl()
{ {
$this->expectException(LoggerException::class); $this->expectException(LoggerArgumentException::class);
$this->expectExceptionMessage("Cannot create stream.");
$logfile = vfsStream::newFile('friendica.log') $logfile = vfsStream::newFile('friendica.log')
->at($this->root)->chmod(0); ->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'); $logger->emergency('not working');
} }
@ -164,7 +132,9 @@ class StreamLoggerTest extends AbstractLoggerTest
$this->expectException(LogLevelException::class); $this->expectException(LogLevelException::class);
$this->expectExceptionMessageMatches("/The level \".*\" is not valid./"); $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') $logfile = vfsStream::newFile('friendica.log')
->at($this->root); ->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'); $logger->log('NOPE', 'a test');
} }
@ -191,7 +163,9 @@ class StreamLoggerTest extends AbstractLoggerTest
$this->expectException(LoggerArgumentException::class); $this->expectException(LoggerArgumentException::class);
$this->expectExceptionMessage("A stream must either be a resource or a string."); $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()); 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'); $logger->info('Test');
} }

View file

@ -39,6 +39,10 @@ class SyslogLoggerTest extends AbstractLoggerTest
parent::setUp(); parent::setUp();
$this->introspection->shouldReceive('addClasses')->with([SyslogLogger::class]); $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) 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; return $this->logger;
} }
@ -68,7 +72,7 @@ class SyslogLoggerTest extends AbstractLoggerTest
$this->expectException(LogLevelException::class); $this->expectException(LogLevelException::class);
$this->expectExceptionMessageMatches("/The level \".*\" is not valid./"); $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->expectException(LogLevelException::class);
$this->expectExceptionMessageMatches("/The level \".*\" is not valid./"); $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'); $logger->log('NOPE', 'a test');
} }
@ -90,7 +94,7 @@ class SyslogLoggerTest extends AbstractLoggerTest
*/ */
public function testClose() public function testClose()
{ {
$logger = new SyslogLoggerWrapper('test', $this->introspection); $logger = new SyslogLoggerWrapper('test', $this->config, $this->introspection);
$logger->emergency('test'); $logger->emergency('test');
$logger->close(); $logger->close();
// Reopened itself // Reopened itself

View file

@ -21,6 +21,7 @@
namespace Friendica\Test\src\Core\Logger; namespace Friendica\Test\src\Core\Logger;
use Friendica\Core\Config\Capability\IManageConfigValues;
use Friendica\Core\Logger\Type\SyslogLogger; use Friendica\Core\Logger\Type\SyslogLogger;
use Friendica\Core\Logger\Util\Introspection; use Friendica\Core\Logger\Util\Introspection;
use Psr\Log\LogLevel; use Psr\Log\LogLevel;
@ -32,9 +33,9 @@ class SyslogLoggerWrapper extends SyslogLogger
{ {
private $content; 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 = ''; $this->content = '';
} }

View file

@ -200,47 +200,6 @@ class BaseURLTest extends MockedTest
]; ];
} }
/**
* Test the default config determination
* @dataProvider dataDefault
*/
public function testCheck($server, $input, $assert)
{
$configMock = \Mockery::mock(IManageConfigValues::class);
$configMock->shouldReceive('get')->with('config', 'hostname')->andReturn($input['hostname']);
$configMock->shouldReceive('get')->with('system', 'urlpath')->andReturn($input['urlPath']);
$configMock->shouldReceive('get')->with('system', 'ssl_policy')->andReturn($input['sslPolicy']);
$configMock->shouldReceive('get')->with('system', 'url')->andReturn($input['url']);
// If we don't have an urlPath as an input, we assert it, we will save it to the DB for the next time
if (!isset($input['urlPath']) && isset($assert['urlPath'])) {
$configMock->shouldReceive('set')->with('system', 'urlpath', $assert['urlPath'])->once();
}
// If we don't have the ssl_policy as an input, we assert it, we will save it to the DB for the next time
if (!isset($input['sslPolicy']) && isset($assert['sslPolicy'])) {
$configMock->shouldReceive('set')->with('system', 'ssl_policy', $assert['sslPolicy'])->once();
}
// If we don't have the hostname as an input, we assert it, we will save it to the DB for the next time
if (empty($input['hostname']) && !empty($assert['hostname'])) {
$configMock->shouldReceive('set')->with('config', 'hostname', $assert['hostname'])->once();
}
// If we don't have an URL at first, but we assert it, we will save it to the DB for the next time
if (empty($input['url']) && !empty($assert['url'])) {
$configMock->shouldReceive('set')->with('system', 'url', $assert['url'])->once();
}
$baseUrl = new BaseURL($configMock, $server);
self::assertEquals($assert['hostname'], $baseUrl->getHostname());
self::assertEquals($assert['urlPath'], $baseUrl->getUrlPath());
self::assertEquals($assert['sslPolicy'], $baseUrl->getSSLPolicy());
self::assertEquals($assert['scheme'], $baseUrl->getScheme());
self::assertEquals($assert['url'], $baseUrl->get());
}
public function dataSave() public function dataSave()
{ {
return [ return [

View file

@ -1227,3 +1227,20 @@ function update_1510()
} }
return Update::SUCCESS; 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');
}

View file

@ -8,7 +8,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: 2023.03-dev\n" "Project-Id-Version: 2023.03-dev\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2023-01-14 21:19+0000\n" "POT-Creation-Date: 2023-01-21 09:22-0500\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n" "Language-Team: LANGUAGE <LL@li.org>\n"
@ -49,7 +49,7 @@ msgstr ""
#: src/Module/Attach.php:55 src/Module/BaseApi.php:95 #: src/Module/Attach.php:55 src/Module/BaseApi.php:95
#: src/Module/BaseNotifications.php:98 src/Module/BaseSettings.php:52 #: 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/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/Advanced.php:60 src/Module/Contact/Follow.php:86
#: src/Module/Contact/Follow.php:159 src/Module/Contact/MatchInterests.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 #: src/Module/Contact/Suggestions.php:54 src/Module/Contact/Unfollow.php:66
@ -302,7 +302,7 @@ msgstr ""
#: mod/photos.php:819 mod/photos.php:1097 mod/photos.php:1138 #: mod/photos.php:819 mod/photos.php:1097 mod/photos.php:1138
#: mod/photos.php:1194 mod/photos.php:1268 #: mod/photos.php:1194 mod/photos.php:1268
#: src/Module/Calendar/Event/Form.php:250 src/Module/Contact/Advanced.php:132 #: src/Module/Calendar/Event/Form.php:250 src/Module/Contact/Advanced.php:132
#: src/Module/Contact/Profile.php:343 #: src/Module/Contact/Profile.php:340
#: src/Module/Debug/ActivityPubConversion.php:140 #: src/Module/Debug/ActivityPubConversion.php:140
#: src/Module/Debug/Babel.php:313 src/Module/Debug/Localtime.php:64 #: src/Module/Debug/Babel.php:313 src/Module/Debug/Localtime.php:64
#: src/Module/Debug/Probe.php:54 src/Module/Debug/WebFinger.php:51 #: src/Module/Debug/Probe.php:54 src/Module/Debug/WebFinger.php:51
@ -385,7 +385,7 @@ msgstr ""
#: mod/photos.php:67 mod/photos.php:132 mod/photos.php:577 #: mod/photos.php:67 mod/photos.php:132 mod/photos.php:577
#: src/Model/Event.php:514 src/Model/Profile.php:234 #: 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/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/Common.php:62 src/Module/Profile/Common.php:71
#: src/Module/Profile/Contacts.php:64 src/Module/Profile/Contacts.php:72 #: src/Module/Profile/Contacts.php:64 src/Module/Profile/Contacts.php:72
@ -649,11 +649,11 @@ msgstr ""
msgid "Map" msgid "Map"
msgstr "" msgstr ""
#: src/App.php:472 #: src/App.php:470
msgid "No system theme config value set." msgid "No system theme config value set."
msgstr "" msgstr ""
#: src/App.php:594 #: src/App.php:592
msgid "Apologies but the website is unavailable at the moment." msgid "Apologies but the website is unavailable at the moment."
msgstr "" msgstr ""
@ -1544,36 +1544,36 @@ msgstr ""
msgid "Follow Thread" msgid "Follow Thread"
msgstr "" msgstr ""
#: src/Content/Item.php:420 src/Model/Contact.php:1206 #: src/Content/Item.php:420 src/Model/Contact.php:1204
msgid "View Status" msgid "View Status"
msgstr "" msgstr ""
#: src/Content/Item.php:421 src/Content/Item.php:440 src/Model/Contact.php:1150 #: src/Content/Item.php:421 src/Content/Item.php:440 src/Model/Contact.php:1148
#: src/Model/Contact.php:1198 src/Model/Contact.php:1207 #: src/Model/Contact.php:1196 src/Model/Contact.php:1205
#: src/Module/Directory.php:157 src/Module/Settings/Profile/Index.php:234 #: src/Module/Directory.php:157 src/Module/Settings/Profile/Index.php:234
msgid "View Profile" msgid "View Profile"
msgstr "" msgstr ""
#: src/Content/Item.php:422 src/Model/Contact.php:1208 #: src/Content/Item.php:422 src/Model/Contact.php:1206
msgid "View Photos" msgid "View Photos"
msgstr "" msgstr ""
#: src/Content/Item.php:423 src/Model/Contact.php:1199 #: src/Content/Item.php:423 src/Model/Contact.php:1197
#: src/Model/Contact.php:1209 #: src/Model/Contact.php:1207
msgid "Network Posts" msgid "Network Posts"
msgstr "" msgstr ""
#: src/Content/Item.php:424 src/Model/Contact.php:1200 #: src/Content/Item.php:424 src/Model/Contact.php:1198
#: src/Model/Contact.php:1210 #: src/Model/Contact.php:1208
msgid "View Contact" msgid "View Contact"
msgstr "" msgstr ""
#: src/Content/Item.php:425 src/Model/Contact.php:1211 #: src/Content/Item.php:425 src/Model/Contact.php:1209
msgid "Send PM" msgid "Send PM"
msgstr "" msgstr ""
#: src/Content/Item.php:426 src/Module/Contact.php:440 #: src/Content/Item.php:426 src/Module/Contact.php:440
#: src/Module/Contact/Profile.php:364 src/Module/Contact/Profile.php:484 #: src/Module/Contact/Profile.php:478
#: src/Module/Moderation/Blocklist/Contact.php:116 #: src/Module/Moderation/Blocklist/Contact.php:116
#: src/Module/Moderation/Users/Active.php:137 #: src/Module/Moderation/Users/Active.php:137
#: src/Module/Moderation/Users/Index.php:152 #: src/Module/Moderation/Users/Index.php:152
@ -1581,7 +1581,7 @@ msgid "Block"
msgstr "" msgstr ""
#: src/Content/Item.php:427 src/Module/Contact.php:441 #: src/Content/Item.php:427 src/Module/Contact.php:441
#: src/Module/Contact/Profile.php:365 src/Module/Contact/Profile.php:492 #: src/Module/Contact/Profile.php:486
#: src/Module/Notifications/Introductions.php:134 #: src/Module/Notifications/Introductions.php:134
#: src/Module/Notifications/Introductions.php:206 #: src/Module/Notifications/Introductions.php:206
#: src/Module/Notifications/Notification.php:89 #: src/Module/Notifications/Notification.php:89
@ -1589,7 +1589,7 @@ msgid "Ignore"
msgstr "" msgstr ""
#: src/Content/Item.php:428 src/Module/Contact.php:442 #: src/Content/Item.php:428 src/Module/Contact.php:442
#: src/Module/Contact/Profile.php:500 #: src/Module/Contact/Profile.php:494
msgid "Collapse" msgid "Collapse"
msgstr "" msgstr ""
@ -1598,7 +1598,7 @@ msgid "Languages"
msgstr "" msgstr ""
#: src/Content/Item.php:437 src/Content/Widget.php:80 #: src/Content/Item.php:437 src/Content/Widget.php:80
#: src/Model/Contact.php:1201 src/Model/Contact.php:1212 #: src/Model/Contact.php:1199 src/Model/Contact.php:1210
#: src/Module/Contact/Follow.php:166 view/theme/vier/theme.php:196 #: src/Module/Contact/Follow.php:166 view/theme/vier/theme.php:196
msgid "Connect/Follow" msgid "Connect/Follow"
msgstr "" msgstr ""
@ -1651,7 +1651,7 @@ msgstr ""
#: src/Content/Nav.php:230 src/Module/BaseProfile.php:49 #: src/Content/Nav.php:230 src/Module/BaseProfile.php:49
#: src/Module/BaseSettings.php:100 src/Module/Contact.php:476 #: src/Module/BaseSettings.php:100 src/Module/Contact.php:476
#: src/Module/Contact/Profile.php:399 src/Module/Profile/Profile.php:268 #: src/Module/Contact/Profile.php:393 src/Module/Profile/Profile.php:268
#: src/Module/Welcome.php:57 view/theme/frio/theme.php:230 #: src/Module/Welcome.php:57 view/theme/frio/theme.php:230
msgid "Profile" msgid "Profile"
msgstr "" msgstr ""
@ -1877,9 +1877,9 @@ msgstr ""
#: src/Content/Nav.php:335 src/Module/BaseModeration.php:127 #: src/Content/Nav.php:335 src/Module/BaseModeration.php:127
#: src/Module/Moderation/Blocklist/Contact.php:110 #: src/Module/Moderation/Blocklist/Contact.php:110
#: src/Module/Moderation/Blocklist/Server/Add.php:119 #: src/Module/Moderation/Blocklist/Server/Add.php:121
#: src/Module/Moderation/Blocklist/Server/Import.php:115 #: src/Module/Moderation/Blocklist/Server/Import.php:118
#: src/Module/Moderation/Blocklist/Server/Index.php:92 #: src/Module/Moderation/Blocklist/Server/Index.php:95
#: src/Module/Moderation/Item/Delete.php:61 #: src/Module/Moderation/Item/Delete.php:61
#: src/Module/Moderation/Summary.php:76 #: src/Module/Moderation/Summary.php:76
#: src/Module/Moderation/Users/Active.php:133 #: src/Module/Moderation/Users/Active.php:133
@ -1970,7 +1970,7 @@ msgid "The end"
msgstr "" msgstr ""
#: src/Content/Text/HTML.php:884 src/Content/Widget/VCard.php:109 #: src/Content/Text/HTML.php:884 src/Content/Widget/VCard.php:109
#: src/Model/Profile.php:463 src/Module/Contact/Profile.php:444 #: src/Model/Profile.php:463 src/Module/Contact/Profile.php:438
msgid "Follow" msgid "Follow"
msgstr "" msgstr ""
@ -2097,7 +2097,7 @@ msgstr ""
msgid "Organisations" msgid "Organisations"
msgstr "" msgstr ""
#: src/Content/Widget.php:523 src/Model/Contact.php:1658 #: src/Content/Widget.php:523 src/Model/Contact.php:1656
msgid "News" msgid "News"
msgstr "" msgstr ""
@ -2156,18 +2156,18 @@ msgid "More Trending Tags"
msgstr "" msgstr ""
#: src/Content/Widget/VCard.php:102 src/Model/Profile.php:378 #: src/Content/Widget/VCard.php:102 src/Model/Profile.php:378
#: src/Module/Contact/Profile.php:388 src/Module/Profile/Profile.php:199 #: src/Module/Contact/Profile.php:382 src/Module/Profile/Profile.php:199
msgid "XMPP:" msgid "XMPP:"
msgstr "" msgstr ""
#: src/Content/Widget/VCard.php:103 src/Model/Profile.php:379 #: src/Content/Widget/VCard.php:103 src/Model/Profile.php:379
#: src/Module/Contact/Profile.php:390 src/Module/Profile/Profile.php:203 #: src/Module/Contact/Profile.php:384 src/Module/Profile/Profile.php:203
msgid "Matrix:" msgid "Matrix:"
msgstr "" msgstr ""
#: src/Content/Widget/VCard.php:104 src/Model/Event.php:82 #: src/Content/Widget/VCard.php:104 src/Model/Event.php:82
#: src/Model/Event.php:109 src/Model/Event.php:473 src/Model/Event.php:958 #: src/Model/Event.php:109 src/Model/Event.php:473 src/Model/Event.php:958
#: src/Model/Profile.php:373 src/Module/Contact/Profile.php:386 #: src/Model/Profile.php:373 src/Module/Contact/Profile.php:380
#: src/Module/Directory.php:147 src/Module/Notifications/Introductions.php:187 #: src/Module/Directory.php:147 src/Module/Notifications/Introductions.php:187
#: src/Module/Profile/Profile.php:221 #: src/Module/Profile/Profile.php:221
msgid "Location:" msgid "Location:"
@ -2178,9 +2178,9 @@ msgstr ""
msgid "Network:" msgid "Network:"
msgstr "" msgstr ""
#: src/Content/Widget/VCard.php:111 src/Model/Contact.php:1202 #: src/Content/Widget/VCard.php:111 src/Model/Contact.php:1200
#: src/Model/Contact.php:1213 src/Model/Profile.php:465 #: src/Model/Contact.php:1211 src/Model/Profile.php:465
#: src/Module/Contact/Profile.php:436 #: src/Module/Contact/Profile.php:430
msgid "Unfollow" msgid "Unfollow"
msgstr "" msgstr ""
@ -2882,82 +2882,82 @@ msgstr ""
msgid "Legacy module file not found: %s" msgid "Legacy module file not found: %s"
msgstr "" msgstr ""
#: src/Model/Contact.php:1219 src/Module/Moderation/Users/Pending.php:102 #: src/Model/Contact.php:1217 src/Module/Moderation/Users/Pending.php:102
#: src/Module/Notifications/Introductions.php:132 #: src/Module/Notifications/Introductions.php:132
#: src/Module/Notifications/Introductions.php:204 #: src/Module/Notifications/Introductions.php:204
msgid "Approve" msgid "Approve"
msgstr "" msgstr ""
#: src/Model/Contact.php:1654 #: src/Model/Contact.php:1652
msgid "Organisation" msgid "Organisation"
msgstr "" msgstr ""
#: src/Model/Contact.php:1662 #: src/Model/Contact.php:1660
msgid "Forum" msgid "Forum"
msgstr "" msgstr ""
#: src/Model/Contact.php:2931 #: src/Model/Contact.php:2929
msgid "Disallowed profile URL." msgid "Disallowed profile URL."
msgstr "" msgstr ""
#: src/Model/Contact.php:2936 src/Module/Friendica.php:83 #: src/Model/Contact.php:2934 src/Module/Friendica.php:83
msgid "Blocked domain" msgid "Blocked domain"
msgstr "" msgstr ""
#: src/Model/Contact.php:2941 #: src/Model/Contact.php:2939
msgid "Connect URL missing." msgid "Connect URL missing."
msgstr "" msgstr ""
#: src/Model/Contact.php:2950 #: src/Model/Contact.php:2948
msgid "" msgid ""
"The contact could not be added. Please check the relevant network " "The contact could not be added. Please check the relevant network "
"credentials in your Settings -> Social Networks page." "credentials in your Settings -> Social Networks page."
msgstr "" msgstr ""
#: src/Model/Contact.php:2968 #: src/Model/Contact.php:2966
#, php-format #, php-format
msgid "Expected network %s does not match actual network %s" msgid "Expected network %s does not match actual network %s"
msgstr "" msgstr ""
#: src/Model/Contact.php:2985 #: src/Model/Contact.php:2983
msgid "The profile address specified does not provide adequate information." msgid "The profile address specified does not provide adequate information."
msgstr "" msgstr ""
#: src/Model/Contact.php:2987 #: src/Model/Contact.php:2985
msgid "No compatible communication protocols or feeds were discovered." msgid "No compatible communication protocols or feeds were discovered."
msgstr "" msgstr ""
#: src/Model/Contact.php:2990 #: src/Model/Contact.php:2988
msgid "An author or name was not found." msgid "An author or name was not found."
msgstr "" msgstr ""
#: src/Model/Contact.php:2993 #: src/Model/Contact.php:2991
msgid "No browser URL could be matched to this address." msgid "No browser URL could be matched to this address."
msgstr "" msgstr ""
#: src/Model/Contact.php:2996 #: src/Model/Contact.php:2994
msgid "" msgid ""
"Unable to match @-style Identity Address with a known protocol or email " "Unable to match @-style Identity Address with a known protocol or email "
"contact." "contact."
msgstr "" msgstr ""
#: src/Model/Contact.php:2997 #: src/Model/Contact.php:2995
msgid "Use mailto: in front of address to force email check." msgid "Use mailto: in front of address to force email check."
msgstr "" msgstr ""
#: src/Model/Contact.php:3003 #: src/Model/Contact.php:3001
msgid "" msgid ""
"The profile address specified belongs to a network which has been disabled " "The profile address specified belongs to a network which has been disabled "
"on this site." "on this site."
msgstr "" msgstr ""
#: src/Model/Contact.php:3008 #: src/Model/Contact.php:3006
msgid "" msgid ""
"Limited profile. This person will be unable to receive direct/personal " "Limited profile. This person will be unable to receive direct/personal "
"notifications from you." "notifications from you."
msgstr "" msgstr ""
#: src/Model/Contact.php:3073 #: src/Model/Contact.php:3071
msgid "Unable to retrieve contact information." msgid "Unable to retrieve contact information."
msgstr "" msgstr ""
@ -3206,7 +3206,7 @@ msgstr ""
msgid "Homepage:" msgid "Homepage:"
msgstr "" msgstr ""
#: src/Model/Profile.php:377 src/Module/Contact/Profile.php:392 #: src/Model/Profile.php:377 src/Module/Contact/Profile.php:386
#: src/Module/Notifications/Introductions.php:189 #: src/Module/Notifications/Introductions.php:189
msgid "About:" msgid "About:"
msgstr "" msgstr ""
@ -3296,7 +3296,7 @@ msgstr ""
msgid "Title/Description:" msgid "Title/Description:"
msgstr "" 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 #: src/Module/Moderation/Summary.php:77
msgid "Summary" msgid "Summary"
msgstr "" msgstr ""
@ -3368,8 +3368,7 @@ msgid "The password length is limited to 72 characters."
msgstr "" msgstr ""
#: src/Model/User.php:807 #: src/Model/User.php:807
msgid "" msgid "The password can't contain white spaces nor accentuated letters"
"The password can't contain accentuated letters, white spaces or colons (:)"
msgstr "" msgstr ""
#: src/Model/User.php:1002 #: 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/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/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/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/Admin/Themes/Index.php:111 src/Module/Admin/Tos.php:77
#: src/Module/Moderation/Users/Create.php:61 #: src/Module/Moderation/Users/Create.php:61
#: src/Module/Moderation/Users/Pending.php:96 #: src/Module/Moderation/Users/Pending.php:96
@ -4918,7 +4917,7 @@ msgid ""
"received." "received."
msgstr "" msgstr ""
#: src/Module/Admin/Site.php:551 src/Module/Contact/Profile.php:290 #: src/Module/Admin/Site.php:551 src/Module/Contact/Profile.php:287
#: src/Module/Settings/TwoFactor/Index.php:125 #: src/Module/Settings/TwoFactor/Index.php:125
msgid "Disabled" msgid "Disabled"
msgstr "" msgstr ""
@ -5007,12 +5006,12 @@ msgstr ""
msgid "Database (legacy)" msgid "Database (legacy)"
msgstr "" msgstr ""
#: src/Module/Admin/Summary.php:57 #: src/Module/Admin/Summary.php:55
#, php-format #, php-format
msgid "Template engine (%s) error: %s" msgid "Template engine (%s) error: %s"
msgstr "" msgstr ""
#: src/Module/Admin/Summary.php:61 #: src/Module/Admin/Summary.php:59
#, php-format #, php-format
msgid "" msgid ""
"Your DB still runs with MyISAM tables. You should change the engine type to " "Your DB still runs with MyISAM tables. You should change the engine type to "
@ -5023,7 +5022,7 @@ msgid ""
"automatic conversion.<br />" "automatic conversion.<br />"
msgstr "" msgstr ""
#: src/Module/Admin/Summary.php:66 #: src/Module/Admin/Summary.php:64
#, php-format #, php-format
msgid "" msgid ""
"Your DB still runs with InnoDB tables in the Antelope file format. You " "Your DB still runs with InnoDB tables in the Antelope file format. You "
@ -5034,7 +5033,7 @@ msgid ""
"installation for an automatic conversion.<br />" "installation for an automatic conversion.<br />"
msgstr "" msgstr ""
#: src/Module/Admin/Summary.php:76 #: src/Module/Admin/Summary.php:74
#, php-format #, php-format
msgid "" msgid ""
"Your table_definition_cache is too low (%d). This can lead to the database " "Your table_definition_cache is too low (%d). This can lead to the database "
@ -5042,39 +5041,39 @@ msgid ""
"to %d. See <a href=\"%s\">here</a> for more information.<br />" "to %d. See <a href=\"%s\">here</a> for more information.<br />"
msgstr "" msgstr ""
#: src/Module/Admin/Summary.php:86 #: src/Module/Admin/Summary.php:84
#, php-format #, php-format
msgid "" msgid ""
"There is a new version of Friendica available for download. Your current " "There is a new version of Friendica available for download. Your current "
"version is %1$s, upstream version is %2$s" "version is %1$s, upstream version is %2$s"
msgstr "" msgstr ""
#: src/Module/Admin/Summary.php:95 #: src/Module/Admin/Summary.php:93
msgid "" msgid ""
"The database update failed. Please run \"php bin/console.php dbstructure " "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 " "update\" from the command line and have a look at the errors that might "
"appear." "appear."
msgstr "" msgstr ""
#: src/Module/Admin/Summary.php:99 #: src/Module/Admin/Summary.php:97
msgid "" msgid ""
"The last update failed. Please run \"php bin/console.php dbstructure update" "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. " "\" from the command line and have a look at the errors that might appear. "
"(Some of the errors are possibly inside the logfile.)" "(Some of the errors are possibly inside the logfile.)"
msgstr "" msgstr ""
#: src/Module/Admin/Summary.php:104 #: src/Module/Admin/Summary.php:102
msgid "The worker was never executed. Please check your database structure!" msgid "The worker was never executed. Please check your database structure!"
msgstr "" msgstr ""
#: src/Module/Admin/Summary.php:106 #: src/Module/Admin/Summary.php:104
#, php-format #, php-format
msgid "" msgid ""
"The last worker execution was on %s UTC. This is older than one hour. Please " "The last worker execution was on %s UTC. This is older than one hour. Please "
"check your crontab settings." "check your crontab settings."
msgstr "" msgstr ""
#: src/Module/Admin/Summary.php:111 #: src/Module/Admin/Summary.php:109
#, php-format #, php-format
msgid "" msgid ""
"Friendica's configuration now is stored in config/local.config.php, please " "Friendica's configuration now is stored in config/local.config.php, please "
@ -5083,7 +5082,7 @@ msgid ""
"with the transition." "with the transition."
msgstr "" msgstr ""
#: src/Module/Admin/Summary.php:115 #: src/Module/Admin/Summary.php:113
#, php-format #, php-format
msgid "" msgid ""
"Friendica's configuration now is stored in config/local.config.php, please " "Friendica's configuration now is stored in config/local.config.php, please "
@ -5092,7 +5091,7 @@ msgid ""
"with the transition." "with the transition."
msgstr "" msgstr ""
#: src/Module/Admin/Summary.php:119 #: src/Module/Admin/Summary.php:117
#, php-format #, php-format
msgid "" msgid ""
"Friendica's configuration store \"%s\" isn't writable. Until then database " "Friendica's configuration store \"%s\" isn't writable. Until then database "
@ -5100,7 +5099,7 @@ msgid ""
"configuration changes won't be saved." "configuration changes won't be saved."
msgstr "" msgstr ""
#: src/Module/Admin/Summary.php:125 #: src/Module/Admin/Summary.php:123
#, php-format #, php-format
msgid "" msgid ""
"<a href=\"%s\">%s</a> is not reachable on your system. This is a severe " "<a href=\"%s\">%s</a> is not reachable on your system. This is a severe "
@ -5108,50 +5107,50 @@ msgid ""
"href=\"%s\">the installation page</a> for help." "href=\"%s\">the installation page</a> for help."
msgstr "" msgstr ""
#: src/Module/Admin/Summary.php:143 #: src/Module/Admin/Summary.php:141
#, php-format #, php-format
msgid "The logfile '%s' is not usable. No logging possible (error: '%s')" msgid "The logfile '%s' is not usable. No logging possible (error: '%s')"
msgstr "" msgstr ""
#: src/Module/Admin/Summary.php:157 #: src/Module/Admin/Summary.php:155
#, php-format #, php-format
msgid "The debug logfile '%s' is not usable. No logging possible (error: '%s')" msgid "The debug logfile '%s' is not usable. No logging possible (error: '%s')"
msgstr "" msgstr ""
#: src/Module/Admin/Summary.php:173 #: src/Module/Admin/Summary.php:171
#, php-format #, php-format
msgid "" msgid ""
"Friendica's system.basepath was updated from '%s' to '%s'. Please remove the " "Friendica's system.basepath was updated from '%s' to '%s'. Please remove the "
"system.basepath from your db to avoid differences." "system.basepath from your db to avoid differences."
msgstr "" msgstr ""
#: src/Module/Admin/Summary.php:181 #: src/Module/Admin/Summary.php:179
#, php-format #, php-format
msgid "" msgid ""
"Friendica's current system.basepath '%s' is wrong and the config file '%s' " "Friendica's current system.basepath '%s' is wrong and the config file '%s' "
"isn't used." "isn't used."
msgstr "" msgstr ""
#: src/Module/Admin/Summary.php:189 #: src/Module/Admin/Summary.php:187
#, php-format #, php-format
msgid "" msgid ""
"Friendica's current system.basepath '%s' is not equal to the config file " "Friendica's current system.basepath '%s' is not equal to the config file "
"'%s'. Please fix your configuration." "'%s'. Please fix your configuration."
msgstr "" msgstr ""
#: src/Module/Admin/Summary.php:200 #: src/Module/Admin/Summary.php:198
msgid "Message queues" msgid "Message queues"
msgstr "" msgstr ""
#: src/Module/Admin/Summary.php:206 #: src/Module/Admin/Summary.php:204
msgid "Server Settings" msgid "Server Settings"
msgstr "" msgstr ""
#: src/Module/Admin/Summary.php:224 #: src/Module/Admin/Summary.php:222
msgid "Version" msgid "Version"
msgstr "" msgstr ""
#: src/Module/Admin/Summary.php:228 #: src/Module/Admin/Summary.php:226
msgid "Active addons" msgid "Active addons"
msgstr "" msgstr ""
@ -5543,13 +5542,13 @@ msgstr ""
#: src/Module/Install.php:286 src/Module/Install.php:291 #: src/Module/Install.php:286 src/Module/Install.php:291
#: src/Module/Install.php:305 src/Module/Install.php:320 #: src/Module/Install.php:305 src/Module/Install.php:320
#: src/Module/Install.php:347 #: 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/Add.php:136
#: src/Module/Moderation/Blocklist/Server/Import.php:126 #: src/Module/Moderation/Blocklist/Server/Add.php:138
#: src/Module/Moderation/Blocklist/Server/Index.php:83 #: src/Module/Moderation/Blocklist/Server/Import.php:129
#: src/Module/Moderation/Blocklist/Server/Index.php:84 #: src/Module/Moderation/Blocklist/Server/Index.php:86
#: src/Module/Moderation/Blocklist/Server/Index.php:112 #: src/Module/Moderation/Blocklist/Server/Index.php:87
#: src/Module/Moderation/Blocklist/Server/Index.php:113 #: 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/Moderation/Item/Delete.php:67 src/Module/Register.php:148
#: src/Module/Security/TwoFactor/Verify.php:101 #: src/Module/Security/TwoFactor/Verify.php:101
#: src/Module/Settings/TwoFactor/Index.php:140 #: src/Module/Settings/TwoFactor/Index.php:140
@ -5589,15 +5588,15 @@ msgstr ""
msgid "Basic" msgid "Basic"
msgstr "" msgstr ""
#: src/Module/Calendar/Export.php:77 #: src/Module/Calendar/Export.php:94
msgid "This calendar format is not supported" msgid "This calendar format is not supported"
msgstr "" msgstr ""
#: src/Module/Calendar/Export.php:79 #: src/Module/Calendar/Export.php:96
msgid "No exportable data found" msgid "No exportable data found"
msgstr "" msgstr ""
#: src/Module/Calendar/Export.php:96 #: src/Module/Calendar/Export.php:113
msgid "calendar" msgid "calendar"
msgstr "" msgstr ""
@ -5696,20 +5695,18 @@ msgstr ""
msgid "Update" msgid "Update"
msgstr "" msgstr ""
#: src/Module/Contact.php:440 src/Module/Contact/Profile.php:364 #: src/Module/Contact.php:440 src/Module/Contact/Profile.php:478
#: src/Module/Contact/Profile.php:484
#: src/Module/Moderation/Blocklist/Contact.php:117 #: src/Module/Moderation/Blocklist/Contact.php:117
#: src/Module/Moderation/Users/Blocked.php:138 #: src/Module/Moderation/Users/Blocked.php:138
#: src/Module/Moderation/Users/Index.php:154 #: src/Module/Moderation/Users/Index.php:154
msgid "Unblock" msgid "Unblock"
msgstr "" msgstr ""
#: src/Module/Contact.php:441 src/Module/Contact/Profile.php:365 #: src/Module/Contact.php:441 src/Module/Contact/Profile.php:486
#: src/Module/Contact/Profile.php:492
msgid "Unignore" msgid "Unignore"
msgstr "" msgstr ""
#: src/Module/Contact.php:442 src/Module/Contact/Profile.php:500 #: src/Module/Contact.php:442 src/Module/Contact/Profile.php:494
msgid "Uncollapse" msgid "Uncollapse"
msgstr "" msgstr ""
@ -5761,7 +5758,7 @@ msgstr ""
msgid "Pending incoming contact request" msgid "Pending incoming contact request"
msgstr "" msgstr ""
#: src/Module/Contact.php:597 src/Module/Contact/Profile.php:350 #: src/Module/Contact.php:597 src/Module/Contact/Profile.php:347
#, php-format #, php-format
msgid "Visit %s's profile [%s]" msgid "Visit %s's profile [%s]"
msgstr "" msgstr ""
@ -5914,7 +5911,7 @@ msgstr ""
msgid "Your Identity Address:" msgid "Your Identity Address:"
msgstr "" msgstr ""
#: src/Module/Contact/Follow.php:169 src/Module/Contact/Profile.php:382 #: src/Module/Contact/Follow.php:169 src/Module/Contact/Profile.php:376
#: src/Module/Contact/Unfollow.php:129 #: src/Module/Contact/Unfollow.php:129
#: src/Module/Moderation/Blocklist/Contact.php:133 #: src/Module/Moderation/Blocklist/Contact.php:133
#: src/Module/Notifications/Introductions.php:129 #: src/Module/Notifications/Introductions.php:129
@ -5922,7 +5919,7 @@ msgstr ""
msgid "Profile URL" msgid "Profile URL"
msgstr "" msgstr ""
#: src/Module/Contact/Follow.php:170 src/Module/Contact/Profile.php:394 #: src/Module/Contact/Follow.php:170 src/Module/Contact/Profile.php:388
#: src/Module/Notifications/Introductions.php:191 #: src/Module/Notifications/Introductions.php:191
#: src/Module/Profile/Profile.php:234 #: src/Module/Profile/Profile.php:234
msgid "Tags:" msgid "Tags:"
@ -5989,220 +5986,220 @@ msgstr ""
msgid "Contact has been collapsed" msgid "Contact has been collapsed"
msgstr "" msgstr ""
#: src/Module/Contact/Profile.php:246 #: src/Module/Contact/Profile.php:243
#, php-format #, php-format
msgid "You are mutual friends with %s" msgid "You are mutual friends with %s"
msgstr "" msgstr ""
#: src/Module/Contact/Profile.php:247 #: src/Module/Contact/Profile.php:244
#, php-format #, php-format
msgid "You are sharing with %s" msgid "You are sharing with %s"
msgstr "" msgstr ""
#: src/Module/Contact/Profile.php:248 #: src/Module/Contact/Profile.php:245
#, php-format #, php-format
msgid "%s is sharing with you" msgid "%s is sharing with you"
msgstr "" msgstr ""
#: src/Module/Contact/Profile.php:264 #: src/Module/Contact/Profile.php:261
msgid "Private communications are not available for this contact." msgid "Private communications are not available for this contact."
msgstr "" msgstr ""
#: src/Module/Contact/Profile.php:266 #: src/Module/Contact/Profile.php:263
msgid "Never" msgid "Never"
msgstr "" msgstr ""
#: src/Module/Contact/Profile.php:269 #: src/Module/Contact/Profile.php:266
msgid "(Update was not successful)" msgid "(Update was not successful)"
msgstr "" msgstr ""
#: src/Module/Contact/Profile.php:269 #: src/Module/Contact/Profile.php:266
msgid "(Update was successful)" msgid "(Update was successful)"
msgstr "" msgstr ""
#: src/Module/Contact/Profile.php:271 src/Module/Contact/Profile.php:455 #: src/Module/Contact/Profile.php:268 src/Module/Contact/Profile.php:449
msgid "Suggest friends" msgid "Suggest friends"
msgstr "" msgstr ""
#: src/Module/Contact/Profile.php:275 #: src/Module/Contact/Profile.php:272
#, php-format #, php-format
msgid "Network type: %s" msgid "Network type: %s"
msgstr "" msgstr ""
#: src/Module/Contact/Profile.php:280 #: src/Module/Contact/Profile.php:277
msgid "Communications lost with this contact!" msgid "Communications lost with this contact!"
msgstr "" msgstr ""
#: src/Module/Contact/Profile.php:286 #: src/Module/Contact/Profile.php:283
msgid "Fetch further information for feeds" msgid "Fetch further information for feeds"
msgstr "" msgstr ""
#: src/Module/Contact/Profile.php:288 #: src/Module/Contact/Profile.php:285
msgid "" msgid ""
"Fetch information like preview pictures, title and teaser from the feed " "Fetch information like preview pictures, title and teaser from the feed "
"item. You can activate this if the feed doesn't contain much text. Keywords " "item. You can activate this if the feed doesn't contain much text. Keywords "
"are taken from the meta header in the feed item and are posted as hash tags." "are taken from the meta header in the feed item and are posted as hash tags."
msgstr "" msgstr ""
#: src/Module/Contact/Profile.php:291 #: src/Module/Contact/Profile.php:288
msgid "Fetch information" msgid "Fetch information"
msgstr "" msgstr ""
#: src/Module/Contact/Profile.php:292 #: src/Module/Contact/Profile.php:289
msgid "Fetch keywords" msgid "Fetch keywords"
msgstr "" msgstr ""
#: src/Module/Contact/Profile.php:293 #: src/Module/Contact/Profile.php:290
msgid "Fetch information and keywords" msgid "Fetch information and keywords"
msgstr "" msgstr ""
#: src/Module/Contact/Profile.php:303 src/Module/Contact/Profile.php:308 #: src/Module/Contact/Profile.php:300 src/Module/Contact/Profile.php:305
#: src/Module/Contact/Profile.php:313 src/Module/Contact/Profile.php:319 #: src/Module/Contact/Profile.php:310 src/Module/Contact/Profile.php:316
msgid "No mirroring" msgid "No mirroring"
msgstr "" msgstr ""
#: src/Module/Contact/Profile.php:304 src/Module/Contact/Profile.php:314 #: src/Module/Contact/Profile.php:301 src/Module/Contact/Profile.php:311
#: src/Module/Contact/Profile.php:320 #: src/Module/Contact/Profile.php:317
msgid "Mirror as my own posting" msgid "Mirror as my own posting"
msgstr "" msgstr ""
#: src/Module/Contact/Profile.php:309 src/Module/Contact/Profile.php:315 #: src/Module/Contact/Profile.php:306 src/Module/Contact/Profile.php:312
msgid "Native reshare" msgid "Native reshare"
msgstr "" msgstr ""
#: src/Module/Contact/Profile.php:332 #: src/Module/Contact/Profile.php:329
msgid "Contact Information / Notes" msgid "Contact Information / Notes"
msgstr "" msgstr ""
#: src/Module/Contact/Profile.php:333 #: src/Module/Contact/Profile.php:330
msgid "Contact Settings" msgid "Contact Settings"
msgstr "" msgstr ""
#: src/Module/Contact/Profile.php:341 #: src/Module/Contact/Profile.php:338
msgid "Contact" msgid "Contact"
msgstr "" msgstr ""
#: src/Module/Contact/Profile.php:345 #: src/Module/Contact/Profile.php:342
msgid "Their personal note" msgid "Their personal note"
msgstr "" msgstr ""
#: src/Module/Contact/Profile.php:347 #: src/Module/Contact/Profile.php:344
msgid "Edit contact notes" msgid "Edit contact notes"
msgstr "" msgstr ""
#: src/Module/Contact/Profile.php:351 #: src/Module/Contact/Profile.php:348
msgid "Block/Unblock contact" msgid "Block/Unblock contact"
msgstr "" msgstr ""
#: src/Module/Contact/Profile.php:352 #: src/Module/Contact/Profile.php:349
msgid "Ignore contact" msgid "Ignore contact"
msgstr "" msgstr ""
#: src/Module/Contact/Profile.php:353 #: src/Module/Contact/Profile.php:350
msgid "View conversations" msgid "View conversations"
msgstr "" msgstr ""
#: src/Module/Contact/Profile.php:358 #: src/Module/Contact/Profile.php:355
msgid "Last update:" msgid "Last update:"
msgstr "" msgstr ""
#: src/Module/Contact/Profile.php:360 #: src/Module/Contact/Profile.php:357
msgid "Update public posts" msgid "Update public posts"
msgstr "" msgstr ""
#: src/Module/Contact/Profile.php:362 src/Module/Contact/Profile.php:465 #: src/Module/Contact/Profile.php:359 src/Module/Contact/Profile.php:459
msgid "Update now" msgid "Update now"
msgstr "" msgstr ""
#: src/Module/Contact/Profile.php:369 #: src/Module/Contact/Profile.php:361
msgid "Currently blocked"
msgstr ""
#: src/Module/Contact/Profile.php:370
msgid "Currently ignored"
msgstr ""
#: src/Module/Contact/Profile.php:371
msgid "Currently collapsed"
msgstr ""
#: src/Module/Contact/Profile.php:372
msgid "Currently archived"
msgstr ""
#: src/Module/Contact/Profile.php:373
msgid "Awaiting connection acknowledge" msgid "Awaiting connection acknowledge"
msgstr "" msgstr ""
#: src/Module/Contact/Profile.php:374 #: src/Module/Contact/Profile.php:362
msgid "Currently blocked"
msgstr ""
#: src/Module/Contact/Profile.php:363
msgid "Currently ignored"
msgstr ""
#: src/Module/Contact/Profile.php:364
msgid "Currently collapsed"
msgstr ""
#: src/Module/Contact/Profile.php:365
msgid "Currently archived"
msgstr ""
#: src/Module/Contact/Profile.php:368
#: src/Module/Notifications/Introductions.php:192 #: src/Module/Notifications/Introductions.php:192
msgid "Hide this contact from others" msgid "Hide this contact from others"
msgstr "" msgstr ""
#: src/Module/Contact/Profile.php:374 #: src/Module/Contact/Profile.php:368
msgid "" msgid ""
"Replies/likes to your public posts <strong>may</strong> still be visible" "Replies/likes to your public posts <strong>may</strong> still be visible"
msgstr "" msgstr ""
#: src/Module/Contact/Profile.php:375 #: src/Module/Contact/Profile.php:369
msgid "Notification for new posts" msgid "Notification for new posts"
msgstr "" msgstr ""
#: src/Module/Contact/Profile.php:375 #: src/Module/Contact/Profile.php:369
msgid "Send a notification of every new post of this contact" msgid "Send a notification of every new post of this contact"
msgstr "" msgstr ""
#: src/Module/Contact/Profile.php:377 #: src/Module/Contact/Profile.php:371
msgid "Keyword Deny List" msgid "Keyword Deny List"
msgstr "" msgstr ""
#: src/Module/Contact/Profile.php:377 #: src/Module/Contact/Profile.php:371
msgid "" msgid ""
"Comma separated list of keywords that should not be converted to hashtags, " "Comma separated list of keywords that should not be converted to hashtags, "
"when \"Fetch information and keywords\" is selected" "when \"Fetch information and keywords\" is selected"
msgstr "" msgstr ""
#: src/Module/Contact/Profile.php:395 #: src/Module/Contact/Profile.php:389
#: src/Module/Settings/TwoFactor/Index.php:139 #: src/Module/Settings/TwoFactor/Index.php:139
msgid "Actions" msgid "Actions"
msgstr "" msgstr ""
#: src/Module/Contact/Profile.php:397 #: src/Module/Contact/Profile.php:391
#: src/Module/Settings/TwoFactor/Index.php:119 view/theme/frio/theme.php:229 #: src/Module/Settings/TwoFactor/Index.php:119 view/theme/frio/theme.php:229
msgid "Status" msgid "Status"
msgstr "" msgstr ""
#: src/Module/Contact/Profile.php:403 #: src/Module/Contact/Profile.php:397
msgid "Mirror postings from this contact" msgid "Mirror postings from this contact"
msgstr "" msgstr ""
#: src/Module/Contact/Profile.php:405 #: src/Module/Contact/Profile.php:399
msgid "" msgid ""
"Mark this contact as remote_self, this will cause friendica to repost new " "Mark this contact as remote_self, this will cause friendica to repost new "
"entries from this contact." "entries from this contact."
msgstr "" msgstr ""
#: src/Module/Contact/Profile.php:475 #: src/Module/Contact/Profile.php:469
msgid "Refetch contact data" msgid "Refetch contact data"
msgstr "" msgstr ""
#: src/Module/Contact/Profile.php:486 #: src/Module/Contact/Profile.php:480
msgid "Toggle Blocked status" msgid "Toggle Blocked status"
msgstr "" msgstr ""
#: src/Module/Contact/Profile.php:494 #: src/Module/Contact/Profile.php:488
msgid "Toggle Ignored status" msgid "Toggle Ignored status"
msgstr "" msgstr ""
#: src/Module/Contact/Profile.php:502 #: src/Module/Contact/Profile.php:496
msgid "Toggle Collapsed status" msgid "Toggle Collapsed status"
msgstr "" msgstr ""
#: src/Module/Contact/Profile.php:509 src/Module/Contact/Revoke.php:106 #: src/Module/Contact/Profile.php:503 src/Module/Contact/Revoke.php:106
msgid "Revoke Follow" msgid "Revoke Follow"
msgstr "" msgstr ""
#: src/Module/Contact/Profile.php:511 #: src/Module/Contact/Profile.php:505
msgid "Revoke the follow from this contact" msgid "Revoke the follow from this contact"
msgstr "" msgstr ""
@ -6725,8 +6722,8 @@ msgid "On this server the following remote servers are blocked."
msgstr "" msgstr ""
#: src/Module/Friendica.php:84 #: src/Module/Friendica.php:84
#: src/Module/Moderation/Blocklist/Server/Index.php:84 #: src/Module/Moderation/Blocklist/Server/Index.php:87
#: src/Module/Moderation/Blocklist/Server/Index.php:108 #: src/Module/Moderation/Blocklist/Server/Index.php:111
msgid "Reason for the block" msgid "Reason for the block"
msgstr "" msgstr ""
@ -7399,32 +7396,32 @@ msgid ""
msgstr "" msgstr ""
#: src/Module/Moderation/Blocklist/Contact.php:135 #: 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" msgid "Block Reason"
msgstr "" 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." msgid "Server domain pattern added to the blocklist."
msgstr "" msgstr ""
#: src/Module/Moderation/Blocklist/Server/Add.php:86 #: src/Module/Moderation/Blocklist/Server/Add.php:88
#, php-format #, php-format
msgid "%s server scheduled to be purged." msgid "%s server scheduled to be purged."
msgid_plural "%s servers scheduled to be purged." msgid_plural "%s servers scheduled to be purged."
msgstr[0] "" msgstr[0] ""
msgstr[1] "" msgstr[1] ""
#: src/Module/Moderation/Blocklist/Server/Add.php:118 #: src/Module/Moderation/Blocklist/Server/Add.php:120
#: src/Module/Moderation/Blocklist/Server/Import.php:114 #: src/Module/Moderation/Blocklist/Server/Import.php:117
msgid "← Return to the list" msgid "← Return to the list"
msgstr "" msgstr ""
#: src/Module/Moderation/Blocklist/Server/Add.php:120 #: src/Module/Moderation/Blocklist/Server/Add.php:122
msgid "Block A New Server Domain Pattern" msgid "Block A New Server Domain Pattern"
msgstr "" msgstr ""
#: src/Module/Moderation/Blocklist/Server/Add.php:121 #: src/Module/Moderation/Blocklist/Server/Add.php:123
#: src/Module/Moderation/Blocklist/Server/Index.php:96 #: src/Module/Moderation/Blocklist/Server/Index.php:99
msgid "" msgid ""
"<p>The server domain pattern syntax is case-insensitive shell wildcard, " "<p>The server domain pattern syntax is case-insensitive shell wildcard, "
"comprising the following special characters:</p>\n" "comprising the following special characters:</p>\n"
@ -7434,55 +7431,55 @@ msgid ""
"</ul>" "</ul>"
msgstr "" msgstr ""
#: src/Module/Moderation/Blocklist/Server/Add.php:126 #: src/Module/Moderation/Blocklist/Server/Add.php:128
#: src/Module/Moderation/Blocklist/Server/Index.php:104 #: src/Module/Moderation/Blocklist/Server/Index.php:107
msgid "Check pattern" msgid "Check pattern"
msgstr "" msgstr ""
#: src/Module/Moderation/Blocklist/Server/Add.php:127 #: src/Module/Moderation/Blocklist/Server/Add.php:129
msgid "Matching known servers" msgid "Matching known servers"
msgstr "" msgstr ""
#: src/Module/Moderation/Blocklist/Server/Add.php:128 #: src/Module/Moderation/Blocklist/Server/Add.php:130
msgid "Server Name" msgid "Server Name"
msgstr "" msgstr ""
#: src/Module/Moderation/Blocklist/Server/Add.php:129 #: src/Module/Moderation/Blocklist/Server/Add.php:131
msgid "Server Domain" msgid "Server Domain"
msgstr "" msgstr ""
#: src/Module/Moderation/Blocklist/Server/Add.php:130 #: src/Module/Moderation/Blocklist/Server/Add.php:132
msgid "Known Contacts" msgid "Known Contacts"
msgstr "" msgstr ""
#: src/Module/Moderation/Blocklist/Server/Add.php:131 #: src/Module/Moderation/Blocklist/Server/Add.php:133
#, php-format #, php-format
msgid "%d known server" msgid "%d known server"
msgid_plural "%d known servers" msgid_plural "%d known servers"
msgstr[0] "" msgstr[0] ""
msgstr[1] "" msgstr[1] ""
#: src/Module/Moderation/Blocklist/Server/Add.php:132 #: src/Module/Moderation/Blocklist/Server/Add.php:134
msgid "Add pattern to the blocklist" msgid "Add pattern to the blocklist"
msgstr "" msgstr ""
#: src/Module/Moderation/Blocklist/Server/Add.php:134 #: src/Module/Moderation/Blocklist/Server/Add.php:136
#: src/Module/Moderation/Blocklist/Server/Index.php:113 #: src/Module/Moderation/Blocklist/Server/Index.php:116
msgid "Server Domain Pattern" msgid "Server Domain Pattern"
msgstr "" msgstr ""
#: src/Module/Moderation/Blocklist/Server/Add.php:134 #: src/Module/Moderation/Blocklist/Server/Add.php:136
#: src/Module/Moderation/Blocklist/Server/Index.php:113 #: src/Module/Moderation/Blocklist/Server/Index.php:116
msgid "" msgid ""
"The domain pattern of the new server to add to the blocklist. Do not include " "The domain pattern of the new server to add to the blocklist. Do not include "
"the protocol." "the protocol."
msgstr "" msgstr ""
#: src/Module/Moderation/Blocklist/Server/Add.php:135 #: src/Module/Moderation/Blocklist/Server/Add.php:137
msgid "Purge server" msgid "Purge server"
msgstr "" msgstr ""
#: src/Module/Moderation/Blocklist/Server/Add.php:135 #: src/Module/Moderation/Blocklist/Server/Add.php:137
msgid "" msgid ""
"Also purges all the locally stored content authored by the known contacts " "Also purges all the locally stored content authored by the known contacts "
"registered on that server. Keeps the contacts and the server records. This " "registered on that server. Keeps the contacts and the server records. This "
@ -7494,149 +7491,149 @@ msgid_plural ""
msgstr[0] "" msgstr[0] ""
msgstr[1] "" msgstr[1] ""
#: src/Module/Moderation/Blocklist/Server/Add.php:136 #: src/Module/Moderation/Blocklist/Server/Add.php:138
msgid "Block reason" msgid "Block reason"
msgstr "" msgstr ""
#: src/Module/Moderation/Blocklist/Server/Add.php:136 #: src/Module/Moderation/Blocklist/Server/Add.php:138
msgid "" msgid ""
"The reason why you blocked this server domain pattern. This reason will be " "The reason why you blocked this server domain pattern. This reason will be "
"shown publicly in the server information page." "shown publicly in the server information page."
msgstr "" msgstr ""
#: src/Module/Moderation/Blocklist/Server/Import.php:73 #: src/Module/Moderation/Blocklist/Server/Import.php:74
#: src/Module/Moderation/Blocklist/Server/Import.php:82 #: src/Module/Moderation/Blocklist/Server/Import.php:83
msgid "Error importing pattern file" msgid "Error importing pattern file"
msgstr "" 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." msgid "Local blocklist replaced with the provided file."
msgstr "" msgstr ""
#: src/Module/Moderation/Blocklist/Server/Import.php:92 #: src/Module/Moderation/Blocklist/Server/Import.php:93
#, php-format #, php-format
msgid "%d pattern was added to the local blocklist." msgid "%d pattern was added to the local blocklist."
msgid_plural "%d patterns were added to the local blocklist." msgid_plural "%d patterns were added to the local blocklist."
msgstr[0] "" msgstr[0] ""
msgstr[1] "" 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." msgid "No pattern was added to the local blocklist."
msgstr "" msgstr ""
#: src/Module/Moderation/Blocklist/Server/Import.php:116 #: src/Module/Moderation/Blocklist/Server/Import.php:119
msgid "Import a Server Domain Pattern Blocklist" msgid "Import a Server Domain Pattern Blocklist"
msgstr "" msgstr ""
#: src/Module/Moderation/Blocklist/Server/Import.php:117 #: src/Module/Moderation/Blocklist/Server/Import.php:120
msgid "" msgid ""
"<p>This file can be downloaded from the <code>/friendica</code> path of any " "<p>This file can be downloaded from the <code>/friendica</code> path of any "
"Friendica server.</p>" "Friendica server.</p>"
msgstr "" msgstr ""
#: src/Module/Moderation/Blocklist/Server/Import.php:118 #: src/Module/Moderation/Blocklist/Server/Import.php:121
#: src/Module/Moderation/Blocklist/Server/Index.php:103 #: src/Module/Moderation/Blocklist/Server/Index.php:106
msgid "Upload file" msgid "Upload file"
msgstr "" msgstr ""
#: src/Module/Moderation/Blocklist/Server/Import.php:119 #: src/Module/Moderation/Blocklist/Server/Import.php:122
msgid "Patterns to import" msgid "Patterns to import"
msgstr "" msgstr ""
#: src/Module/Moderation/Blocklist/Server/Import.php:120 #: src/Module/Moderation/Blocklist/Server/Import.php:123
msgid "Domain Pattern" msgid "Domain Pattern"
msgstr "" msgstr ""
#: src/Module/Moderation/Blocklist/Server/Import.php:122 #: src/Module/Moderation/Blocklist/Server/Import.php:125
msgid "Import Mode" msgid "Import Mode"
msgstr "" msgstr ""
#: src/Module/Moderation/Blocklist/Server/Import.php:123 #: src/Module/Moderation/Blocklist/Server/Import.php:126
msgid "Import Patterns" msgid "Import Patterns"
msgstr "" msgstr ""
#: src/Module/Moderation/Blocklist/Server/Import.php:124 #: src/Module/Moderation/Blocklist/Server/Import.php:127
#, php-format #, php-format
msgid "%d total pattern" msgid "%d total pattern"
msgid_plural "%d total patterns" msgid_plural "%d total patterns"
msgstr[0] "" msgstr[0] ""
msgstr[1] "" msgstr[1] ""
#: src/Module/Moderation/Blocklist/Server/Import.php:126 #: src/Module/Moderation/Blocklist/Server/Import.php:129
#: src/Module/Moderation/Blocklist/Server/Index.php:112 #: src/Module/Moderation/Blocklist/Server/Index.php:115
msgid "Server domain pattern blocklist CSV file" msgid "Server domain pattern blocklist CSV file"
msgstr "" msgstr ""
#: src/Module/Moderation/Blocklist/Server/Import.php:127 #: src/Module/Moderation/Blocklist/Server/Import.php:130
msgid "Append" msgid "Append"
msgstr "" msgstr ""
#: src/Module/Moderation/Blocklist/Server/Import.php:127 #: src/Module/Moderation/Blocklist/Server/Import.php:130
msgid "" msgid ""
"Imports patterns from the file that weren't already existing in the current " "Imports patterns from the file that weren't already existing in the current "
"blocklist." "blocklist."
msgstr "" msgstr ""
#: src/Module/Moderation/Blocklist/Server/Import.php:128 #: src/Module/Moderation/Blocklist/Server/Import.php:131
msgid "Replace" msgid "Replace"
msgstr "" 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." msgid "Replaces the current blocklist by the imported patterns."
msgstr "" msgstr ""
#: src/Module/Moderation/Blocklist/Server/Index.php:83 #: src/Module/Moderation/Blocklist/Server/Index.php:86
#: src/Module/Moderation/Blocklist/Server/Index.php:107 #: src/Module/Moderation/Blocklist/Server/Index.php:110
msgid "Blocked server domain pattern" msgid "Blocked server domain pattern"
msgstr "" msgstr ""
#: src/Module/Moderation/Blocklist/Server/Index.php:85 #: src/Module/Moderation/Blocklist/Server/Index.php:88
msgid "Delete server domain pattern" msgid "Delete server domain pattern"
msgstr "" 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" msgid "Check to delete this entry from the blocklist"
msgstr "" msgstr ""
#: src/Module/Moderation/Blocklist/Server/Index.php:93 #: src/Module/Moderation/Blocklist/Server/Index.php:96
msgid "Server Domain Pattern Blocklist" msgid "Server Domain Pattern Blocklist"
msgstr "" msgstr ""
#: src/Module/Moderation/Blocklist/Server/Index.php:94 #: src/Module/Moderation/Blocklist/Server/Index.php:97
msgid "" msgid ""
"This page can be used to define a blocklist of server domain patterns from " "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 " "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." "each domain pattern you should also provide the reason why you block it."
msgstr "" msgstr ""
#: src/Module/Moderation/Blocklist/Server/Index.php:95 #: src/Module/Moderation/Blocklist/Server/Index.php:98
msgid "" msgid ""
"The list of blocked server domain patterns will be made publically available " "The list of blocked server domain patterns will be made publically available "
"on the <a href=\"/friendica\">/friendica</a> page so that your users and " "on the <a href=\"/friendica\">/friendica</a> page so that your users and "
"people investigating communication problems can find the reason easily." "people investigating communication problems can find the reason easily."
msgstr "" msgstr ""
#: src/Module/Moderation/Blocklist/Server/Index.php:101 #: src/Module/Moderation/Blocklist/Server/Index.php:104
msgid "Import server domain pattern blocklist" msgid "Import server domain pattern blocklist"
msgstr "" msgstr ""
#: src/Module/Moderation/Blocklist/Server/Index.php:102 #: src/Module/Moderation/Blocklist/Server/Index.php:105
msgid "Add new entry to the blocklist" msgid "Add new entry to the blocklist"
msgstr "" msgstr ""
#: src/Module/Moderation/Blocklist/Server/Index.php:105 #: src/Module/Moderation/Blocklist/Server/Index.php:108
msgid "Save changes to the blocklist" msgid "Save changes to the blocklist"
msgstr "" msgstr ""
#: src/Module/Moderation/Blocklist/Server/Index.php:106 #: src/Module/Moderation/Blocklist/Server/Index.php:109
msgid "Current Entries in the Blocklist" msgid "Current Entries in the Blocklist"
msgstr "" msgstr ""
#: src/Module/Moderation/Blocklist/Server/Index.php:109 #: src/Module/Moderation/Blocklist/Server/Index.php:112
msgid "Delete entry from the blocklist" msgid "Delete entry from the blocklist"
msgstr "" msgstr ""
#: src/Module/Moderation/Blocklist/Server/Index.php:110 #: src/Module/Moderation/Blocklist/Server/Index.php:113
msgid "Delete entry from the blocklist?" msgid "Delete entry from the blocklist?"
msgstr "" msgstr ""
@ -8071,7 +8068,7 @@ msgstr ""
msgid "Unsupported or missing response type" msgid "Unsupported or missing response type"
msgstr "" 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" msgid "Incomplete request data"
msgstr "" msgstr ""
@ -8082,11 +8079,11 @@ msgid ""
"close this window: %s" "close this window: %s"
msgstr "" msgstr ""
#: src/Module/OAuth/Token.php:78 #: src/Module/OAuth/Token.php:81
msgid "Invalid data or unknown client" msgid "Invalid data or unknown client"
msgstr "" msgstr ""
#: src/Module/OAuth/Token.php:97 #: src/Module/OAuth/Token.php:100
msgid "Unsupported or missing grant type" msgid "Unsupported or missing grant type"
msgstr "" msgstr ""
@ -8767,7 +8764,7 @@ msgstr ""
#: src/Module/Settings/Account.php:552 #: src/Module/Settings/Account.php:552
msgid "" msgid ""
"Allowed characters are a-z, A-Z, 0-9 and special characters except white " "Allowed characters are a-z, A-Z, 0-9 and special characters except white "
"spaces, accentuated letters and colon (:)." "spaces and accentuated letters."
msgstr "" msgstr ""
#: src/Module/Security/PasswordTooLong.php:101 #: src/Module/Security/PasswordTooLong.php:101

View file

@ -1,3 +1,4 @@
<div id="contact-edit-wrapper"> <div id="contact-edit-wrapper">
{{* Insert Tab-Nav *}} {{* Insert Tab-Nav *}}
@ -12,7 +13,7 @@
{{* This is the Action menu where contact related actions like 'ignore', 'hide' can be performed *}} {{* This is the Action menu where contact related actions like 'ignore', 'hide' can be performed *}}
<div id="contact-edit-actions"> <div id="contact-edit-actions">
<a class="btn" rel="#contact-actions-menu" href="#" id="contact-edit-actions-button">{{$contact_action_button}}</a> <button class="btn" id="contact-edit-actions-button">{{$contact_action_button}}</button>
<ul role="menu" aria-haspopup="true" id="contact-actions-menu" class="menu-popup"> <ul role="menu" aria-haspopup="true" id="contact-actions-menu" class="menu-popup">
{{if $contact_actions.follow}}<li role="menuitem"><a href="{{$contact_actions.follow.url}}" title="{{$contact_actions.follow.title}}">{{$contact_actions.follow.label}}</a></li>{{/if}} {{if $contact_actions.follow}}<li role="menuitem"><a href="{{$contact_actions.follow.url}}" title="{{$contact_actions.follow.title}}">{{$contact_actions.follow.label}}</a></li>{{/if}}
@ -23,7 +24,6 @@
<li class="divider"></li> <li class="divider"></li>
<li role="menuitem"><a href="#" title="{{$contact_actions.block.title}}" onclick="window.location.href='{{$contact_actions.block.url}}'; return false;">{{$contact_actions.block.label}}</a></li> <li role="menuitem"><a href="#" title="{{$contact_actions.block.title}}" onclick="window.location.href='{{$contact_actions.block.url}}'; return false;">{{$contact_actions.block.label}}</a></li>
<li role="menuitem"><a href="#" title="{{$contact_actions.ignore.title}}" onclick="window.location.href='{{$contact_actions.ignore.url}}'; return false;">{{$contact_actions.ignore.label}}</a></li> <li role="menuitem"><a href="#" title="{{$contact_actions.ignore.title}}" onclick="window.location.href='{{$contact_actions.ignore.url}}'; return false;">{{$contact_actions.ignore.label}}</a></li>
<li role="menuitem"><a href="#" title="{{$contact_actions.collapse.title}}" onclick="window.location.href='{{$contact_actions.collapse.url}}'; return false;">{{$contact_actions.collapse.label}}</a></li>
{{if $contact_actions.revoke_follow.url}}<li role="menuitem"><a href="{{$contact_actions.revoke_follow.url}}" title="{{$contact_actions.revoke_follow.title}}">{{$contact_actions.revoke_follow.label}}</a></li>{{/if}} {{if $contact_actions.revoke_follow.url}}<li role="menuitem"><a href="{{$contact_actions.revoke_follow.url}}" title="{{$contact_actions.revoke_follow.title}}">{{$contact_actions.revoke_follow.label}}</a></li>{{/if}}
</ul> </ul>
</div> </div>
@ -45,13 +45,12 @@
{{if $blocked && !$pending}}<li><div id="block-message">{{$blocked}}</div></li>{{/if}} {{if $blocked && !$pending}}<li><div id="block-message">{{$blocked}}</div></li>{{/if}}
{{if $pending}}<li><div id="pending-message">{{$pending}}</div></li>{{/if}} {{if $pending}}<li><div id="pending-message">{{$pending}}</div></li>{{/if}}
{{if $ignored}}<li><div id="ignore-message">{{$ignored}}</div></li>{{/if}} {{if $ignored}}<li><div id="ignore-message">{{$ignored}}</div></li>{{/if}}
{{if $collapsed}}<li><div id="collapse-message">{{$collapsed}}</div></li>{{/if}}
{{if $archived}}<li><div id="archive-message">{{$archived}}</div></li>{{/if}} {{if $archived}}<li><div id="archive-message">{{$archived}}</div></li>{{/if}}
</ul> </ul>
</div> {{* End of contact-edit-status-wrapper *}} </div> {{* End of contact-edit-status-wrapper *}}
{{* Some information about the contact from the profile *}} {{* Some information about the contact from the profile *}}
<dl><dt>{{$profileurllabel}}</dt><dd><a target="blank" href="{{$url}}">{{$profileurl}}</a></dd></dl> <dl><dt>{{$profileurllabel}}</dt><dd><a target="blank" href="{{$profileurl}}">{{$profileurl}}</a></dd></dl>
{{if $location}}<dl><dt>{{$location_label}}</dt><dd>{{$location nofilter}}</dd></dl>{{/if}} {{if $location}}<dl><dt>{{$location_label}}</dt><dd>{{$location nofilter}}</dd></dl>{{/if}}
{{if $xmpp}}<dl><dt>{{$xmpp_label}}</dt><dd>{{$xmpp}}</dd></dl>{{/if}} {{if $xmpp}}<dl><dt>{{$xmpp_label}}</dt><dd>{{$xmpp}}</dd></dl>{{/if}}
{{if $matrix}}<dl><dt>{{$matrix_label}}</dt><dd>{{$matrix}}</dd></dl>{{/if}} {{if $matrix}}<dl><dt>{{$matrix_label}}</dt><dd>{{$matrix}}</dd></dl>{{/if}}
@ -69,22 +68,21 @@
<input type="hidden" name="contact_id" value="{{$contact_id}}"> <input type="hidden" name="contact_id" value="{{$contact_id}}">
<div id="contact-edit-end"></div> <div id="contact-edit-end"></div>
{{include file="field_checkbox.tpl" field=$notify_new_posts}} {{include file="field_checkbox.tpl" field=$notify_new_posts}}
{{if $fetch_further_information}} {{if $fetch_further_information}}
{{include file="field_select.tpl" field=$fetch_further_information}} {{include file="field_select.tpl" field=$fetch_further_information}}
{{if $fetch_further_information.2 == 2 || $fetch_further_information.2 == 3}} {{include file="field_textarea.tpl" field=$ffi_keyword_denylist}} {{/if}} {{if $fetch_further_information.2 == 2 || $fetch_further_information.2 == 3}} {{include file="field_textarea.tpl" field=$ffi_keyword_denylist}} {{/if}}
{{/if}} {{/if}}
{{if $allow_remote_self}} {{if $allow_remote_self}}
{{include file="field_select.tpl" field=$remote_self}} {{include file="field_select.tpl" field=$remote_self}}
{{/if}} {{/if}}
{{include file="field_checkbox.tpl" field=$hidden}} {{include file="field_checkbox.tpl" field=$hidden}}
<div id="contact-edit-info-wrapper"> {{include file="field_textarea.tpl" field=$cinfo}}
<h4>{{$lbl_info1}}</h4>
<textarea id="contact-edit-info" rows="8" cols="60" name="info">{{$info}}</textarea>
</div>
<div id="contact-edit-info-end"></div>
{{if $reason}} {{if $reason}}
<div id="contact-info-wrapper"> <div id="contact-info-wrapper">
@ -94,9 +92,9 @@
<div id="contact-info-end"></div> <div id="contact-info-end"></div>
{{/if}} {{/if}}
</div> </div>
<input class="contact-edit-submit" type="submit" name="submit" value="{{$submit}}" /> <input class="contact-edit-submit" type="submit" name="submit" value="{{$submit}}" />
{{/if}} {{/if}}
<div class="contact-edit-submit-end clearfix"></div> <div class="contact-edit-submit-end clearfix"></div>
</form>{{* End of the form *}} </form>{{* End of the form *}}

View file

@ -69,8 +69,8 @@
<img role="presentation" id="profile-rotator" src="images/rotator.gif" alt="{{$l10n.wait}}" title="{{$l10n.wait}}" style="display: none;" /> <img role="presentation" id="profile-rotator" src="images/rotator.gif" alt="{{$l10n.wait}}" title="{{$l10n.wait}}" style="display: none;" />
</span> </span>
<span role="presentation" id="character-counter" class="grey text-info"></span> <span role="presentation" id="character-counter" class="grey text-info"></span>
<button type="button" class="btn btn-defaul btn-sm" onclick="preview_comment({{$id}});" id="comment-edit-preview-link-{{$id}}" tabindex="5"><i class="fa fa-eye"></i> {{$l10n.preview}}</button> <button type="button" class="btn btn-defaul" onclick="preview_comment({{$id}});" id="comment-edit-preview-link-{{$id}}" tabindex="5"><i class="fa fa-eye"></i> {{$l10n.preview}}</button>
<button type="submit" class="btn btn-primary btn-sm" id="comment-edit-submit-{{$id}}" name="submit" tabindex="4"><i class="fa fa-envelope"></i> {{$l10n.submit}}</button> <button type="submit" class="btn btn-primary" id="comment-edit-submit-{{$id}}" name="submit" tabindex="4"><i class="fa fa-envelope"></i> {{$l10n.submit}}</button>
</p> </p>
<div id="comment-edit-preview-{{$id}}" class="comment-edit-preview" style="display:none;"></div> <div id="comment-edit-preview-{{$id}}" class="comment-edit-preview" style="display:none;"></div>

View file

@ -367,6 +367,10 @@ btn-eventnav:hover {
aside .badge { aside .badge {
opacity: 0.7; opacity: 0.7;
} }
.forum-widget-entry .badge,
.sidebar-group-li .badge {
margin-top: 6px;
}
/* disabled elements */ /* disabled elements */
.community-content-wrapper > h3, .community-content-wrapper > h3,
@ -807,13 +811,15 @@ nav.navbar .nav > li > button:focus {
} }
#offcanvasUsermenu a { #offcanvasUsermenu a {
display: block; display: block;
margin: -10px -15px;
padding: 10px 15px;
} }
#offcanvasUsermenu li.nav-sitename { #offcanvasUsermenu li.nav-sitename {
font-weight: bold; font-weight: bold;
} }
#topbar-first .dropdown.account li#nav-sitename { #topbar-first .dropdown.account li#nav-sitename {
padding-left: 15px; padding-left: 20px;
padding-right: 15px; padding-right: 20px;
font-weight: bold; font-weight: bold;
word-break: break-word; word-break: break-word;
} }
@ -822,6 +828,10 @@ nav.navbar .nav > li > button:focus {
background-color: $nav_bg; background-color: $nav_bg;
} }
/* Nav Search */ /* Nav Search */
.menu-popup {
max-height: calc(100vh - 55px);
overflow-y: auto;
}
#topbar-first #search-box .navbar-form { #topbar-first #search-box .navbar-form {
margin: 0px; margin: 0px;
padding: 12px 12px; padding: 12px 12px;
@ -963,13 +973,15 @@ ul li .intro-wrapper button.intro-action-link {
background-color: $nav_bg; background-color: $nav_bg;
border: none; border: none;
} }
.dropdown-menu .divider {
margin: 5px 0;
}
.nav-pills .dropdown-menu li.divider, .nav-pills .dropdown-menu li.divider,
.nav-tabs .dropdown-menu li.divider, .nav-tabs .dropdown-menu li.divider,
.account .dropdown-menu li.divider, .account .dropdown-menu li.divider,
.contact-photo-wrapper .dropdown-menu li.divider { .contact-photo-wrapper .dropdown-menu li.divider {
background-color: $menu_background_hover_color; background-color: $menu_background_hover_color;
border-bottom: none; border-bottom: none;
margin: 9px 1px !important;
} }
.nav-pills .dropdown-menu li > a, .nav-pills .dropdown-menu li > a,
.nav-tabs .dropdown-menu li > a, .nav-tabs .dropdown-menu li > a,
@ -987,8 +999,6 @@ ul li .intro-wrapper button.intro-action-link {
.contact-photo-wrapper .dropdown-menu li .btn-link { .contact-photo-wrapper .dropdown-menu li .btn-link {
color: $nav_icon_color; color: $nav_icon_color;
font-weight: 400; font-weight: 400;
font-size: 13px;
padding: 4px 15px;
width: 100%; width: 100%;
text-align: left; text-align: left;
} }
@ -1044,7 +1054,6 @@ aside .widget,
position: relative; position: relative;
margin-bottom: 20px; margin-bottom: 20px;
padding: 10px; padding: 10px;
font-size: 13px;
overflow: auto; overflow: auto;
} }
aside .widget h3, aside .widget h3,
@ -1052,7 +1061,7 @@ aside .widget h3,
font-weight: bold; font-weight: bold;
font-size: 16px; font-size: 16px;
margin: 0; margin: 0;
padding-bottom: 20px; padding-bottom: 10px;
} }
aside .widget ul, aside .widget ul,
@ -1065,10 +1074,11 @@ aside .widget ul,
list-style: none; list-style: none;
} }
aside .widget li .label {
float: left;
}
aside .widget li, aside .widget li,
.nav-container .widget li { .nav-container .widget li {
padding-top: 2px;
padding-bottom: 2px;
padding-left: 20px; padding-left: 20px;
padding-right: 10px; padding-right: 10px;
} }
@ -1081,6 +1091,12 @@ aside .widget li.selected,
border-left: 3px solid $link_color !important; border-left: 3px solid $link_color !important;
padding-left: 17px; 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,
aside .widget li a:hover { aside .widget li a:hover {
color: $font_color_darker; color: $font_color_darker;
@ -1300,8 +1316,12 @@ div#sidebar-group-list {
} }
.group-edit-tool { .group-edit-tool {
padding-top: 0;
color: $font_color_darker; color: $font_color_darker;
} }
.sidebar-widget-header .group-edit-tool {
margin-top: -5px;
}
.faded-icon { .faded-icon {
color: $font_color_darker; color: $font_color_darker;
@ -1316,9 +1336,12 @@ div#sidebar-group-list {
margin-left: 20px; margin-left: 20px;
} }
aside #group-sidebar .sidebar-group-li:hover .group-edit-tool.faded-icon, aside .widget-action {
aside #saved-search-list .saved-search-li:hover .savedsearchdrop.faded-icon, padding: 5px 10px;
aside .widget:hover .widget-action.faded-icon { }
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; opacity: 0.8;
transition: all 0.25s ease-in-out; transition: all 0.25s ease-in-out;
} }
@ -1328,7 +1351,7 @@ aside .widget .widget-action.faded-icon:hover {
opacity: 1; opacity: 1;
} }
aside #group-sidebar li .group-checkbox { aside #group-sidebar li .group-checkbox {
margin: 0; margin: 6px 0 0;
} }
aside #group-sidebar li .group-edit-tool { aside #group-sidebar li .group-edit-tool {
padding-right: 10px; padding-right: 10px;
@ -1762,9 +1785,6 @@ blockquote.shared_content {
} }
/* wall items contact info */ /* wall items contact info */
.media .media-body {
font-size: 13px;
}
.media .media-body h4.media-heading { .media .media-body h4.media-heading {
font-size: 14px; font-size: 14px;
font-weight: 500; font-weight: 500;
@ -1930,6 +1950,9 @@ code > .hl-main {
margin: 10px 0; margin: 10px 0;
font-size: 13px; font-size: 13px;
} }
.wall-item-tags:empty {
margin: 0;
}
.wall-item-tags a { .wall-item-tags a {
color: $font_color_darker; color: $font_color_darker;
@ -1953,14 +1976,16 @@ code > .hl-main {
margin: 0; margin: 0;
justify-content: space-between; justify-content: space-between;
} }
.wall-item-actions .btn,
.wall-item-actions a, .wall-item-actions a,
.wall-item-actions button { .wall-item-actions button {
font-size: 13px;
color: $font_color_darker; color: $font_color_darker;
background-color: transparent;
} }
.wall-item-actions .active { .wall-item-actions .active {
font-weight: bold; font-weight: bold;
color: $link_color; color: $link_color;
box-shadow: none;
} }
.wall-item-actions-left { .wall-item-actions-left {
display: table-cell; display: table-cell;
@ -1970,17 +1995,31 @@ code > .hl-main {
display: flex; display: flex;
} }
.wall-item-actions .checkbox { .wall-item-actions .checkbox {
margin: 0; margin: 0 0 0 15px;
margin-left: 20px; }
@media screen and (max-width: 767px) {
.wall-item-actions .btn,
.wall-item-actions a,
.wall-item-actions button {
padding-right: 12px;
padding-left: 12px;
}
.wall-item-actions .checkbox {
margin-top: 8px;
}
.wall-item-actions .like-rotator {
padding-top: 8px;
}
} }
.wall-item-actions button:hover { .wall-item-actions button:hover {
color: $font_color_darker;
text-decoration: underline; text-decoration: underline;
} }
.wall-item-actions .separator { .wall-item-actions .separator {
margin: 0 0.3em; margin: 0 0.3em;
} }
.wall-item-responses {
margin-top: .3em;
}
.wall-item-responses > div > p { .wall-item-responses > div > p {
margin: 0; margin: 0;
} }
@ -2174,6 +2213,10 @@ the section element. Only after we have
moved it to the nav through js */ moved it to the nav through js */
display: none !important; display: none !important;
} }
.tabbar-wrapper__link {
padding-right: 10px;
padding-left: 10px;
}
#tabmenu, #tabmenu,
.tabbar-wrapper, .tabbar-wrapper,
.tabbar, .tabbar,
@ -2190,7 +2233,6 @@ ul.tabs {
list-style: none; list-style: none;
height: 100%; height: 100%;
padding: 0; padding: 0;
padding-top: 10px;
margin: 0; margin: 0;
} }
ul.tabs li { ul.tabs li {
@ -2203,8 +2245,9 @@ ul.tabs li {
transition: all 0.15s ease; transition: all 0.15s ease;
} }
ul.tabs li a { ul.tabs li a {
margin-left: 10px; display: block;
margin-right: 10px; padding-top: 11px;
padding-bottom: 11px;
} }
ul.tabs li:hover, ul.tabs li:hover,
ul.tabs li.active { ul.tabs li.active {
@ -2214,7 +2257,7 @@ ul.tabs li.active {
padding-top: 0; padding-top: 0;
} }
#dropdownMenuTools-xs { #dropdownMenuTools-xs {
padding: 9px 10px; padding: 9px 15px;
} }
ul.tabbar ul.tabs-extended:hover li.dropdown { ul.tabbar ul.tabs-extended:hover li.dropdown {
border-bottom: 0; border-bottom: 0;
@ -2236,6 +2279,12 @@ ul.dropdown-menu li:hover {
box-sizing: border-box; box-sizing: border-box;
} }
/* Dropdown Menu */ /* Dropdown Menu */
.dropdown-menu li .btn-link,
.dropdown-menu li a,
.tabs .dropdown-menu li a {
padding: 6px 20px;
font-size: 14px;
}
.dropdown-menu li a, .dropdown-menu li a,
.dropdown-menu li .btn-link { .dropdown-menu li .btn-link {
color: $font_color_darker; color: $font_color_darker;
@ -2493,20 +2542,18 @@ ul.viewcontact_wrapper > li {
} }
.contact-wrapper .contact-actions { .contact-wrapper .contact-actions {
display: flex; display: flex;
position: relative;
margin: -8px -8px 0 0;
} }
.contact-wrapper .contact-action-link, .contact-wrapper .contact-action-link,
.contact-wrapper .contact-action-link:hover, .contact-wrapper .contact-action-link:hover,
.textcomplete-item .contact-wrapper .contact-action-link { .textcomplete-item .contact-wrapper .contact-action-link {
padding: 0 5px;
color: $font_color_darker; color: $font_color_darker;
border: 0; border: 0;
} }
.contact-wrapper .contact-action-link { .contact-wrapper .contact-action-link {
opacity: 0.1; background-color: transparent;
transition: all 0.25s ease-in-out; opacity: 0.3;
}
ul li:hover .contact-wrapper .contact-action-link {
opacity: 0.8;
transition: all 0.25s ease-in-out; transition: all 0.25s ease-in-out;
} }
ul li:hover .contact-wrapper .contact-action-link:hover { ul li:hover .contact-wrapper .contact-action-link:hover {
@ -2912,6 +2959,10 @@ ul li:hover .contact-wrapper .contact-action-link:hover {
.section-subtitle-wrapper { .section-subtitle-wrapper {
padding: 1px 10px; padding: 1px 10px;
} }
.accordion-toggle {
width: 100%;
text-align: left;
}
details.profile-jot-net[open] summary:before, details.profile-jot-net[open] summary:before,
.panel .section-subtitle-wrapper .accordion-toggle:before { .panel .section-subtitle-wrapper .accordion-toggle:before {
font-family: ForkAwesome; font-family: ForkAwesome;
@ -2976,6 +3027,12 @@ details.profile-jot-net[open] summary:before {
margin-top: 10px; margin-top: 10px;
margin-bottom: 10px; margin-bottom: 10px;
} }
.section-subtitle-wrapper > h2 .accordion-toggle {
margin-top: -10px;
margin-bottom: -10px;
padding-top: 10px;
padding-bottom: 10px;
}
.section-subtitle-wrapper > h3 { .section-subtitle-wrapper > h3 {
font-size: 16px; font-size: 16px;

View file

@ -17,7 +17,7 @@
{{* The dropdown to change the callendar view *}} {{* The dropdown to change the callendar view *}}
<ul class="nav nav-pills"> <ul class="nav nav-pills">
<li class="dropdown pull-right"> <li class="dropdown pull-right">
<button class="btn btn-link btn-sm dropdown-toggle" type="button" id="event-calendar-views" data-toggle="dropdown" aria-expanded="false"> <button class="btn btn-link dropdown-toggle" type="button" id="event-calendar-views" data-toggle="dropdown" aria-expanded="false">
<i class="fa fa-angle-down" aria-hidden="true"></i> {{$view}} <i class="fa fa-angle-down" aria-hidden="true"></i> {{$view}}
</button> </button>
<ul class="dropdown-menu pull-right" role="menu" aria-labelledby="event-calendar-views"> <ul class="dropdown-menu pull-right" role="menu" aria-labelledby="event-calendar-views">

View file

@ -54,9 +54,9 @@
<p class="comment-edit-submit-wrapper"> <p class="comment-edit-submit-wrapper">
{{if $preview}} {{if $preview}}
<button type="button" class="btn btn-defaul btn-sm comment-edit-preview" onclick="preview_comment({{$id}});" id="comment-edit-preview-link-{{$id}}"><i class="fa fa-eye"></i> {{$preview}}</button> <button type="button" class="btn btn-defaul comment-edit-preview" onclick="preview_comment({{$id}});" id="comment-edit-preview-link-{{$id}}"><i class="fa fa-eye"></i> {{$preview}}</button>
{{/if}} {{/if}}
<button type="submit" class="btn btn-primary btn-sm comment-edit-submit" id="comment-edit-submit-{{$id}}" name="submit" data-loading-text="{{$loading}}"><i class="fa fa-envelope"></i> {{$submit}}</button> <button type="submit" class="btn btn-primary comment-edit-submit" id="comment-edit-submit-{{$id}}" name="submit" data-loading-text="{{$loading}}"><i class="fa fa-envelope"></i> {{$submit}}</button>
</p> </p>
<div class="comment-edit-end clear"></div> <div class="comment-edit-end clear"></div>

View file

@ -6,7 +6,7 @@
<ul class="tabs flex-nav" role="menu"> <ul class="tabs flex-nav" role="menu">
{{foreach $tabs as $tab}} {{foreach $tabs as $tab}}
<li id="{{$tab.id}}" role="presentation" {{if $tab.sel}} class="{{$tab.sel}}" {{/if}}> <li id="{{$tab.id}}" role="presentation" {{if $tab.sel}} class="{{$tab.sel}}" {{/if}}>
<a role="menuitem" href="{{$tab.url}}" {{if $tab.accesskey}}accesskey="{{$tab.accesskey}}" {{/if}} <a role="menuitem" class="tabbar-wrapper__link" href="{{$tab.url}}" {{if $tab.accesskey}}accesskey="{{$tab.accesskey}}" {{/if}}
{{if $tab.title}} title="{{$tab.title}}" {{/if}}> {{if $tab.title}} title="{{$tab.title}}" {{/if}}>
{{$tab.label}} {{$tab.label}}
</a> </a>
@ -37,7 +37,7 @@
{{foreach $tabs as $tab}} {{foreach $tabs as $tab}}
{{if $tab.sel}} {{if $tab.sel}}
<li id="{{$tab.id}}-xs" role="presentation" {{if $tab.sel}} class="{{$tab.sel}}" {{/if}}> <li id="{{$tab.id}}-xs" role="presentation" {{if $tab.sel}} class="{{$tab.sel}}" {{/if}}>
<a role="menuitem" href="{{$tab.url}}" {{if $tab.title}} title="{{$tab.title}}" {{/if}}> <a role="menuitem" class="tabbar-wrapper__link" href="{{$tab.url}}" {{if $tab.title}} title="{{$tab.title}}" {{/if}}>
{{$tab.label}} {{$tab.label}}
</a> </a>
</li> </li>

View file

@ -12,7 +12,7 @@
</div> </div>
{{* For very small displays we use a dropdown menu for contact relating actions *}} {{* For very small displays we use a dropdown menu for contact relating actions *}}
<button type="button" class="btn btn-link dropdown-toggle visible-xs" id="contact-photo-menu-button-{{$contact.id}}" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> <button type="button" class="btn btn-default dropdown-toggle visible-xs" id="contact-photo-menu-button-{{$contact.id}}" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
{{* use a smaller picture on very small displays (e.g. mobiles) *}} {{* use a smaller picture on very small displays (e.g. mobiles) *}}
<div class="contact-photo-image-wrapper visible-xs"> <div class="contact-photo-image-wrapper visible-xs">
<img class="contact-photo-xs media-object" src="{{$contact.thumb}}" {{$contact.sparkle}} alt="{{$contact.name}}" /> <img class="contact-photo-xs media-object" src="{{$contact.thumb}}" {{$contact.sparkle}} alt="{{$contact.name}}" />
@ -44,29 +44,29 @@
<div class="media-body"> <div class="media-body">
{{if $contact.photo_menu}} {{if $contact.photo_menu}}
{{* The contact actions like private mail, delete contact, edit contact and so on *}} {{* The contact actions like private mail, delete contact, edit contact and so on *}}
<div class="contact-actions pull-right nav-pills preferences hidden-xs"> <div class="btn-group contact-actions pull-right nav-pills preferences hidden-xs" role="group">
{{if $contact.photo_menu.pm}} {{if $contact.photo_menu.pm}}
<button type="button" class="contact-action-link btn-link" onclick="addToModal('{{$contact.photo_menu.pm.1}}'); return false;" data-toggle="tooltip" title="{{$contact.photo_menu.pm.0}}"> <button type="button" class="contact-action-link btn btn-default" onclick="addToModal('{{$contact.photo_menu.pm.1}}'); return false;" data-toggle="tooltip" title="{{$contact.photo_menu.pm.0}}">
<i class="fa fa-envelope" aria-hidden="true"></i> <i class="fa fa-envelope" aria-hidden="true"></i>
</button> </button>
{{/if}} {{/if}}
{{if $contact.photo_menu.network}} {{if $contact.photo_menu.network}}
<a class="contact-action-link btn-link" href="{{$contact.photo_menu.network.1}}" data-toggle="tooltip" title="{{$contact.photo_menu.network.0}}"> <a class="contact-action-link btn btn-default" href="{{$contact.photo_menu.network.1}}" data-toggle="tooltip" title="{{$contact.photo_menu.network.0}}">
<i class="fa fa-cloud" aria-hidden="true"></i> <i class="fa fa-cloud" aria-hidden="true"></i>
</a> </a>
{{/if}} {{/if}}
{{if $contact.photo_menu.follow}} {{if $contact.photo_menu.follow}}
<a class="contact-action-link btn-link" href="{{$contact.photo_menu.follow.1}}" data-toggle="tooltip" title="{{$contact.photo_menu.follow.0}}"> <a class="contact-action-link btn btn-default" href="{{$contact.photo_menu.follow.1}}" data-toggle="tooltip" title="{{$contact.photo_menu.follow.0}}">
<i class="fa fa-user-plus" aria-hidden="true"></i> <i class="fa fa-user-plus" aria-hidden="true"></i>
</a> </a>
{{/if}} {{/if}}
{{if $contact.photo_menu.unfollow}} {{if $contact.photo_menu.unfollow}}
<a class="contact-action-link btn-link" href="{{$contact.photo_menu.unfollow.1}}" data-toggle="tooltip" title="{{$contact.photo_menu.unfollow.0}}"> <a class="contact-action-link btn btn-default" href="{{$contact.photo_menu.unfollow.1}}" data-toggle="tooltip" title="{{$contact.photo_menu.unfollow.0}}">
<i class="fa fa-user-times" aria-hidden="true"></i> <i class="fa fa-user-times" aria-hidden="true"></i>
</a> </a>
{{/if}} {{/if}}
{{if $contact.photo_menu.hide}} {{if $contact.photo_menu.hide}}
<a class="contact-action-link btn-link" href="{{$contact.photo_menu.hide.1}}" data-toggle="tooltip" title="{{$contact.photo_menu.hide.0}}"> <a class="contact-action-link btn btn-default" href="{{$contact.photo_menu.hide.1}}" data-toggle="tooltip" title="{{$contact.photo_menu.hide.0}}">
<i class="fa fa-times" aria-hidden="true"></i> <i class="fa fa-times" aria-hidden="true"></i>
</a> </a>
{{/if}} {{/if}}
@ -76,7 +76,7 @@
{{* The button to add or remove contacts from a contact group - group edit page *}} {{* The button to add or remove contacts from a contact group - group edit page *}}
{{if $contact.change_member}} {{if $contact.change_member}}
<div class="contact-group-actions pull-right nav-pills preferences"> <div class="contact-group-actions pull-right nav-pills preferences">
<button type="button" class="contact-action-link contact-group-link btn-link" onclick="groupChangeMember({{$contact.change_member.gid}},{{$contact.change_member.cid}},'{{$contact.change_member.sec_token}}'); return true;" data-toggle="tooltip" title="{{$contact.change_member.title}}"> <button type="button" class="contact-action-link btn contact-group-link btn-default" onclick="groupChangeMember({{$contact.change_member.gid}},{{$contact.change_member.cid}},'{{$contact.change_member.sec_token}}'); return true;" data-toggle="tooltip" title="{{$contact.change_member.title}}">
{{if $contact.label == "members"}} {{if $contact.label == "members"}}
<i class="fa fa-times-circle" aria-hidden="true"></i> <i class="fa fa-times-circle" aria-hidden="true"></i>
{{elseif $contact.label == "contacts"}} {{elseif $contact.label == "contacts"}}

View file

@ -14,7 +14,7 @@
{{* This is the Action menu where contact related actions like 'ignore', 'hide' can be performed *}} {{* This is the Action menu where contact related actions like 'ignore', 'hide' can be performed *}}
<ul id="contact-edit-actions" class="nav nav-pills preferences"> <ul id="contact-edit-actions" class="nav nav-pills preferences">
<li class="dropdown pull-right"> <li class="dropdown pull-right">
<button type="button" class="btn btn-link btn-sm dropdown-toggle" id="contact-edit-actions-button" data-toggle="dropdown" aria-expanded="false"> <button type="button" class="btn btn-link dropdown-toggle" id="contact-edit-actions-button" data-toggle="dropdown" aria-expanded="false">
<i class="fa fa-angle-down" aria-hidden="true"></i>&nbsp;{{$contact_action_button}} <i class="fa fa-angle-down" aria-hidden="true"></i>&nbsp;{{$contact_action_button}}
</button> </button>

View file

@ -34,7 +34,7 @@
{{* We put the contact batch actions in a dropdown menu *}} {{* We put the contact batch actions in a dropdown menu *}}
<ul class="nav nav-pills preferences"> <ul class="nav nav-pills preferences">
<li class="dropdown pull-right"> <li class="dropdown pull-right">
<button type="button" class="btn btn-link btn-sm dropdown-toggle" id="BatchActionDropdownMenuTools" data-toggle="dropdown" aria-expanded="false"> <button type="button" class="btn btn-link dropdown-toggle" id="BatchActionDropdownMenuTools" data-toggle="dropdown" aria-expanded="false">
<i class="fa fa-angle-down"></i>&nbsp;{{$h_batch_actions}} <i class="fa fa-angle-down"></i>&nbsp;{{$h_batch_actions}}
</button> </button>
<ul class="dropdown-menu pull-right" role="menu" aria-labelledby="BatchActionDropdownMenuTools"> <ul class="dropdown-menu pull-right" role="menu" aria-labelledby="BatchActionDropdownMenuTools">

View file

@ -2,7 +2,7 @@
<h3>{{$title}}</h3> <h3>{{$title}}</h3>
</span> </span>
<div class="widget" id="group-sidebar"> <div class="widget" id="group-sidebar">
<div id="sidebar-group-header"> <div id="sidebar-group-header" class="sidebar-widget-header">
<span class="fakelink" onclick="openCloseWidget('group-sidebar', 'group-sidebar-inflated');"> <span class="fakelink" onclick="openCloseWidget('group-sidebar', 'group-sidebar-inflated');">
<h3>{{$title}}</h3> <h3>{{$title}}</h3>
</span> </span>
@ -22,7 +22,7 @@
</form> </form>
{{/if}} {{/if}}
</div> </div>
<div id="sidebar-group-list"> <div id="sidebar-group-list" class="sidebar-widget-list">
{{* The list of available groups *}} {{* The list of available groups *}}
<ul role="menu" id="sidebar-group-ul"> <ul role="menu" id="sidebar-group-ul">
{{foreach $groups as $group}} {{foreach $groups as $group}}

View file

@ -42,12 +42,12 @@
{{if $follow_link || $unfollow_link}} {{if $follow_link || $unfollow_link}}
<div id="dfrn-request-link-button"> <div id="dfrn-request-link-button">
{{if $unfollow_link}} {{if $unfollow_link}}
<a id="dfrn-request-link" class="btn btn-labeled btn-primary btn-sm" href="{{$unfollow_link}}"> <a id="dfrn-request-link" class="btn btn-labeled btn-primary" href="{{$unfollow_link}}">
<span class=""><i class="fa fa-user-times"></i></span> <span class=""><i class="fa fa-user-times"></i></span>
<span class="">{{$unfollow}}</span> <span class="">{{$unfollow}}</span>
</a> </a>
{{else}} {{else}}
<a id="dfrn-request-link" class="btn btn-labeled btn-primary btn-sm" href="{{$follow_link}}"> <a id="dfrn-request-link" class="btn btn-labeled btn-primary" href="{{$follow_link}}">
<span class=""><i class="fa fa-user-plus"></i></span> <span class=""><i class="fa fa-user-plus"></i></span>
<span class="">{{$follow}}</span> <span class="">{{$follow}}</span>
</a> </a>
@ -56,7 +56,7 @@
{{/if}} {{/if}}
{{if $subscribe_feed_link}} {{if $subscribe_feed_link}}
<div id="subscribe-feed-link-button"> <div id="subscribe-feed-link-button">
<a id="subscribe-feed-link" class="btn btn-labeled btn-primary btn-sm" href="{{$subscribe_feed_link}}"> <a id="subscribe-feed-link" class="btn btn-labeled btn-primary" href="{{$subscribe_feed_link}}">
<span class=""><i class="fa fa-rss"></i></span> <span class=""><i class="fa fa-rss"></i></span>
<span class="">{{$subscribe_feed}}</span> <span class="">{{$subscribe_feed}}</span>
</a> </a>
@ -64,7 +64,7 @@
{{/if}} {{/if}}
{{if $wallmessage_link}} {{if $wallmessage_link}}
<div id="wallmessage-link-botton"> <div id="wallmessage-link-botton">
<button type="button" id="wallmessage-link" class="btn btn-labeled btn-primary btn-sm" onclick="openWallMessage('{{$wallmessage_link}}')"> <button type="button" id="wallmessage-link" class="btn btn-labeled btn-primary" onclick="openWallMessage('{{$wallmessage_link}}')">
<span class=""><i class="fa fa-envelope"></i></span> <span class=""><i class="fa fa-envelope"></i></span>
<span class="">{{$wallmessage}}</span> <span class="">{{$wallmessage}}</span>
</button> </button>

View file

@ -5,7 +5,7 @@
<div id="profile-edit-links"> <div id="profile-edit-links">
<ul class="nav nav-pills preferences"> <ul class="nav nav-pills preferences">
<li class="dropdown pull-right"> <li class="dropdown pull-right">
<button type="button" class="btn btn-link btn-sm dropdown-toggle" id="profile-edit-links-dropdown" data-toggle="dropdown" aria-expanded="false"> <button type="button" class="btn btn-link dropdown-toggle" id="profile-edit-links-dropdown" data-toggle="dropdown" aria-expanded="false">
<i class="fa fa-angle-down" aria-hidden="true"></i>&nbsp;{{$profile_action}} <i class="fa fa-angle-down" aria-hidden="true"></i>&nbsp;{{$profile_action}}
</button> </button>
<ul class="dropdown-menu pull-right" role="menu" aria-labelledby="profile-edit-links-dropdown"> <ul class="dropdown-menu pull-right" role="menu" aria-labelledby="profile-edit-links-dropdown">

View file

@ -436,29 +436,25 @@ as the value of $top_child_total (this is done at the end of this file)
</span> </span>
</span> </span>
<div class="btn-toolbar visible-xs" role="toolbar"> <div class="btn-toolbar btn-group visible-xs" role="group">
{{* Buttons for like and dislike *}} {{* Buttons for like and dislike *}}
{{if $item.vote}} {{if $item.vote}}
<div class="btn-group" role="group">
{{if $item.vote.like}} {{if $item.vote.like}}
<button type="button" class="btn btn-sm button-likes{{if $item.responses.like.self}} active" aria-pressed="true{{/if}}" id="like-{{$item.id}}" title="{{$item.vote.like.0}}" onclick="doActivityItemAction({{$item.id}}, 'like'{{if $item.responses.like.self}}, true{{/if}});" data-toggle="button"><i class="fa fa-thumbs-up" aria-hidden="true"></i></button> <button type="button" class="btn button-likes{{if $item.responses.like.self}} active" aria-pressed="true{{/if}}" id="like-{{$item.id}}" title="{{$item.vote.like.0}}" onclick="doActivityItemAction({{$item.id}}, 'like'{{if $item.responses.like.self}}, true{{/if}});" data-toggle="button"><i class="fa fa-thumbs-up" aria-hidden="true"></i></button>
{{/if}} {{/if}}
{{if $item.vote.dislike}} {{if $item.vote.dislike}}
<button type="button" class="btn btn-sm button-likes{{if $item.responses.dislike.self}} active" aria-pressed="true{{/if}}" id="dislike-{{$item.id}}" title="{{$item.vote.dislike.0}}" onclick="doActivityItemAction({{$item.id}}, 'dislike'{{if $item.responses.dislike.self}}, true{{/if}});" data-toggle="button"><i class="fa fa-thumbs-down" aria-hidden="true"></i></button> <button type="button" class="btn button-likes{{if $item.responses.dislike.self}} active" aria-pressed="true{{/if}}" id="dislike-{{$item.id}}" title="{{$item.vote.dislike.0}}" onclick="doActivityItemAction({{$item.id}}, 'dislike'{{if $item.responses.dislike.self}}, true{{/if}});" data-toggle="button"><i class="fa fa-thumbs-down" aria-hidden="true"></i></button>
{{/if}} {{/if}}
</div>
{{/if}} {{/if}}
{{* Button to open the comment text field *}} {{* Button to open the comment text field *}}
{{if $item.comment_html}} {{if $item.comment_html}}
<div class="btn-group" role="group"> <button type="button" class="btn button-comments" id="comment-{{$item.id}}" title="{{$item.switchcomment}}" {{if $item.thread_level != 1}}onclick="openClose('item-comments-{{$item.id}}'); commentExpand({{$item.id}});" {{else}} onclick="openClose('item-comments-{{$item.id}}'); commentExpand({{$item.id}});"{{/if}}><i class="fa fa-commenting" aria-hidden="true"></i></button>
<button type="button" class="btn btn-sm button-comments" id="comment-{{$item.id}}" title="{{$item.switchcomment}}" {{if $item.thread_level != 1}}onclick="openClose('item-comments-{{$item.id}}'); commentExpand({{$item.id}});" {{else}} onclick="openClose('item-comments-{{$item.id}}'); commentExpand({{$item.id}});"{{/if}}><i class="fa fa-commenting" aria-hidden="true"></i></button>
</div>
{{/if}} {{/if}}
{{if $item.vote.announce OR $item.vote.share}} {{if $item.vote.announce OR $item.vote.share}}
<div class="share-links btn-group{{if $item.thread_level > 1}} dropup{{/if}}"> <div class="share-links btn-group{{if $item.thread_level > 1}} dropup{{/if}}" role="group">
<button type="button" class="btn btn-sm dropdown-toggle{{if $item.responses.announce.self}} active{{/if}}" data-toggle="dropdown" id="shareMenuOptions-{{$item.id}}" aria-haspopup="true" aria-expanded="false" title="{{$item.menu}}"> <button type="button" class="btn dropdown-toggle{{if $item.responses.announce.self}} active{{/if}}" data-toggle="dropdown" id="shareMenuOptions-{{$item.id}}" aria-haspopup="true" aria-expanded="false" title="{{$item.menu}}">
<i class="fa fa-share" aria-hidden="true"></i> <i class="fa fa-share" aria-hidden="true"></i>
</button> </button>
<ul class="dropdown-menu dropdown-menu-left" role="menu" aria-labelledby="shareMenuOptions-{{$item.id}}"> <ul class="dropdown-menu dropdown-menu-left" role="menu" aria-labelledby="shareMenuOptions-{{$item.id}}">
@ -487,28 +483,26 @@ as the value of $top_child_total (this is done at the end of this file)
{{/if}} {{/if}}
{{if $item.browsershare}} {{if $item.browsershare}}
<button type="button" class="btn btn-sm button-browser-share" onclick="navigator.share({url: '{{$item.plink.orig}}'})" title="{{$item.browsershare.1}}"><i class="fa fa-share-alt"></i></button> <button type="button" class="btn button-browser-share" onclick="navigator.share({url: '{{$item.plink.orig}}'})" title="{{$item.browsershare.1}}"><i class="fa fa-share-alt"></i></button>
{{/if}} {{/if}}
{{* Put additional actions in a dropdown menu *}} {{* Put additional actions in a dropdown menu *}}
<div class="btn-group" role="group">
<img id="like-rotator-{{$item.id}}" class="like-rotator" src="images/rotator.gif" alt="{{$item.wait}}" title="{{$item.wait}}" style="display: none;" /> <img id="like-rotator-{{$item.id}}" class="like-rotator" src="images/rotator.gif" alt="{{$item.wait}}" title="{{$item.wait}}" style="display: none;" />
</div> </div>
</div>
<div class="wall-item-actions-right visible-xs"> <div class="wall-item-actions-right visible-xs">
{{* Event attendance buttons *}} {{* Event attendance buttons *}}
{{if $item.isevent}} {{if $item.isevent}}
<div class="btn-group" role="group"> <div class="btn-group" role="group">
<button type="button" class="btn btn-sm btn-default button-event{{if $item.responses.attendyes.self}} active" aria-pressed="true{{/if}}" id="attendyes-{{$item.id}}" title="{{$item.attend.0}}" onclick="doActivityItemAction({{$item.id}}, 'attendyes'{{if $item.responses.attendyes.self}}, true{{/if}});"><i class="fa fa-check" aria-hidden="true"><span class="sr-only">{{$item.attend.0}}</span></i></button> <button type="button" class="btn btn-default button-event{{if $item.responses.attendyes.self}} active" aria-pressed="true{{/if}}" id="attendyes-{{$item.id}}" title="{{$item.attend.0}}" onclick="doActivityItemAction({{$item.id}}, 'attendyes'{{if $item.responses.attendyes.self}}, true{{/if}});"><i class="fa fa-check" aria-hidden="true"><span class="sr-only">{{$item.attend.0}}</span></i></button>
<button type="button" class="btn btn-sm btn-default button-event{{if $item.responses.attendno.self}} active" aria-pressed="true{{/if}}" id="attendno-{{$item.id}}" title="{{$item.attend.1}}" onclick="doActivityItemAction({{$item.id}}, 'attendno'{{if $item.responses.attendno.self}}, true{{/if}});"><i class="fa fa-times" aria-hidden="true"><span class="sr-only">{{$item.attend.1}}</span></i></button> <button type="button" class="btn btn-default button-event{{if $item.responses.attendno.self}} active" aria-pressed="true{{/if}}" id="attendno-{{$item.id}}" title="{{$item.attend.1}}" onclick="doActivityItemAction({{$item.id}}, 'attendno'{{if $item.responses.attendno.self}}, true{{/if}});"><i class="fa fa-times" aria-hidden="true"><span class="sr-only">{{$item.attend.1}}</span></i></button>
<button type="button" class="btn btn-sm btn-default button-event{{if $item.responses.attendmaybe.self}} active" aria-pressed="true{{/if}}" id="attendmaybe-{{$item.id}}" title="{{$item.attend.2}}" onclick="doActivityItemAction({{$item.id}}, 'attendmaybe'{{if $item.responses.attendmaybe.self}}, true{{/if}});"><i class="fa fa-question" aria-hidden="true"><span class="sr-only">{{$item.attend.2}}</span></i></button> <button type="button" class="btn btn-default button-event{{if $item.responses.attendmaybe.self}} active" aria-pressed="true{{/if}}" id="attendmaybe-{{$item.id}}" title="{{$item.attend.2}}" onclick="doActivityItemAction({{$item.id}}, 'attendmaybe'{{if $item.responses.attendmaybe.self}}, true{{/if}});"><i class="fa fa-question" aria-hidden="true"><span class="sr-only">{{$item.attend.2}}</span></i></button>
</div> </div>
{{/if}} {{/if}}
{{if $item.edpost || $item.tagger || $item.filer || $item.pin || $item.star || $item.follow_thread || $item.ignore || ($item.drop && $item.drop.dropping)}} {{if $item.edpost || $item.tagger || $item.filer || $item.pin || $item.star || $item.follow_thread || $item.ignore || ($item.drop && $item.drop.dropping)}}
<div class="more-links btn-group{{if $item.thread_level > 1}} dropup{{/if}}"> <div class="more-links btn-group{{if $item.thread_level > 1}} dropup{{/if}}">
<button type="button" class="btn btn-sm dropdown-toggle" data-toggle="dropdown" id="dropdownMenuOptions-{{$item.id}}" aria-haspopup="true" aria-expanded="false" title="{{$item.menu}}"><i class="fa fa-ellipsis-h" aria-hidden="true"></i></button> <button type="button" class="btn dropdown-toggle" data-toggle="dropdown" id="dropdownMenuOptions-{{$item.id}}" aria-haspopup="true" aria-expanded="false" title="{{$item.menu}}"><i class="fa fa-ellipsis-h" aria-hidden="true"></i></button>
<ul class="dropdown-menu dropdown-menu-right" role="menu" aria-labelledby="dropdownMenuOptions-{{$item.id}}"> <ul class="dropdown-menu dropdown-menu-right" role="menu" aria-labelledby="dropdownMenuOptions-{{$item.id}}">
{{if $item.edpost}} {{* edit the posting *}} {{if $item.edpost}} {{* edit the posting *}}
<li role="menuitem"> <li role="menuitem">

View file

@ -11,14 +11,14 @@
</form> </form>
{{* Directory links *}} {{* Directory links *}}
<div class="side-link" id="side-directory-link"><a href="directory">{{$nv.local_directory}}</a></div> <div class="side-link" id="side-directory-link"><a href="directory" class="side-link-link">{{$nv.local_directory}}</a></div>
<div class="side-link" id="side-directory-link"><a href="{{$nv.global_dir}}" target="extlink">{{$nv.directory}}</a></div> <div class="side-link" id="side-directory-link"><a href="{{$nv.global_dir}}" class="side-link-link" target="extlink">{{$nv.directory}}</a></div>
{{* Additional links *}} {{* Additional links *}}
<div class="side-link" id="side-match-link"><a href="contact/match">{{$nv.similar}}</a></div> <div class="side-link" id="side-match-link"><a href="contact/match" class="side-link-link">{{$nv.similar}}</a></div>
<div class="side-link" id="side-suggest-link"><a href="contact/suggestions">{{$nv.suggest}}</a></div> <div class="side-link" id="side-suggest-link"><a href="contact/suggestions" class="side-link-link">{{$nv.suggest}}</a></div>
<div class="side-link" id="side-random-profile-link"><a href="randprof" target="extlink">{{$nv.random}}</a></div> <div class="side-link" id="side-random-profile-link"><a href="randprof" class="side-link-link" target="extlink">{{$nv.random}}</a></div>
{{if $nv.inv}} {{if $nv.inv}}
<div class="side-link" id="side-invite-link"><button type="button" class="btn-link" onclick="addToModal('invite'); return false;">{{$nv.inv}}</button></div> <div class="side-link" id="side-invite-link"><button type="button" class="btn-link side-link-link" onclick="addToModal('invite'); return false;">{{$nv.inv}}</button></div>
{{/if}} {{/if}}
</div> </div>

View file

@ -36,13 +36,13 @@
<div id="profile-extra-links"> <div id="profile-extra-links">
<div id="dfrn-request-link-button"> <div id="dfrn-request-link-button">
{{if $follow_link}} {{if $follow_link}}
<a id="dfrn-request-link" class="btn btn-labeled btn-primary btn-sm" href="{{$follow_link}}""> <a id="dfrn-request-link" class="btn btn-labeled btn-primary" href="{{$follow_link}}"">
<span class=""><i class="fa fa-user-plus"></i></span> <span class=""><i class="fa fa-user-plus"></i></span>
<span class="">{{$follow}}</span> <span class="">{{$follow}}</span>
</a> </a>
{{/if}} {{/if}}
{{if $unfollow_link}} {{if $unfollow_link}}
<a id="dfrn-request-link" class="btn btn-labeled btn-primary btn-sm" href="{{$unfollow_link}}"> <a id="dfrn-request-link" class="btn btn-labeled btn-primary" href="{{$unfollow_link}}">
<span class=""><i class="fa fa-user-times"></i></span> <span class=""><i class="fa fa-user-times"></i></span>
<span class="">{{$unfollow}}</span> <span class="">{{$unfollow}}</span>
</a> </a>
@ -50,7 +50,7 @@
</div> </div>
{{if $wallmessage_link}} {{if $wallmessage_link}}
<div id="wallmessage-link-botton"> <div id="wallmessage-link-botton">
<button type="button" id="wallmessage-link" class="btn btn-labeled btn-primary btn-sm" onclick="openWallMessage('{{$wallmessage_link}}')"> <button type="button" id="wallmessage-link" class="btn btn-labeled btn-primary" onclick="openWallMessage('{{$wallmessage_link}}')">
<span class=""><i class="fa fa-envelope"></i></span> <span class=""><i class="fa fa-envelope"></i></span>
<span class="">{{$wallmessage}}</span> <span class="">{{$wallmessage}}</span>
</button> </button>

View file

@ -1,103 +0,0 @@
<div id="contact-edit-wrapper">
{{* Insert Tab-Nav *}}
{{$tab_str nofilter}}
<div id="contact-edit-nav-wrapper">
<form action="contact/{{$contact_id}}" method="post">
<div id="contact-edit-links">
<div id="contact-edit-status-wrapper">
<span id="contact-edit-contact-status">{{$contact_status}}</span>
{{* This is the Action menu where contact related actions like 'ignore', 'hide' can be performed *}}
<div id="contact-edit-actions">
<a class="btn" id="contact-edit-actions-button">{{$contact_action_button}}</a>
<ul role="menu" aria-haspopup="true" id="contact-actions-menu" class="menu-popup">
{{if $contact_actions.follow}}<li role="menuitem"><a href="{{$contact_actions.follow.url}}" title="{{$contact_actions.follow.title}}">{{$contact_actions.follow.label}}</a></li>{{/if}}
{{if $contact_actions.unfollow}}<li role="menuitem"><a href="{{$contact_actions.unfollow.url}}" title="{{$contact_actions.unfollow.title}}">{{$contact_actions.unfollow.label}}</a></li>{{/if}}
{{if $lblsuggest}}<li role="menuitem"><a href="{{$contact_actions.suggest.url}}" title="{{$contact_actions.suggest.title}}">{{$contact_actions.suggest.label}}</a></li>{{/if}}
{{if $poll_enabled}}<li role="menuitem"><a href="{{$contact_actions.update.url}}" title="{{$contact_actions.update.title}}">{{$contact_actions.update.label}}</a></li>{{/if}}
{{if $contact_actions.updateprofile}}<li role="menuitem"><a href="{{$contact_actions.updateprofile.url}}" title="{{$contact_actions.updateprofile.title}}">{{$contact_actions.updateprofile.label}}</a></li>{{/if}}
<li class="divider"></li>
<li role="menuitem"><a href="#" title="{{$contact_actions.block.title}}" onclick="window.location.href='{{$contact_actions.block.url}}'; return false;">{{$contact_actions.block.label}}</a></li>
<li role="menuitem"><a href="#" title="{{$contact_actions.ignore.title}}" onclick="window.location.href='{{$contact_actions.ignore.url}}'; return false;">{{$contact_actions.ignore.label}}</a></li>
{{if $contact_actions.revoke_follow.url}}<li role="menuitem"><a href="{{$contact_actions.revoke_follow.url}}" title="{{$contact_actions.revoke_follow.title}}">{{$contact_actions.revoke_follow.label}}</a></li>{{/if}}
</ul>
</div>
{{* Block with status information about the contact *}}
<ul>
{{if $relation_text}}<li><div id="contact-edit-rel">{{$relation_text}}</div></li>{{/if}}
{{if $poll_enabled}}
<li><div id="contact-edit-last-update-text">{{$lastupdtext}} <span id="contact-edit-last-updated">{{$last_update}}</span></div>
{{if $poll_interval}}
<span id="contact-edit-poll-text">{{$updpub}}</span> {{$poll_interval nofilter}}
{{/if}}
</li>
{{/if}}
{{if $lost_contact}}<li><div id="lost-contact-message">{{$lost_contact}}</div></li>{{/if}}
{{if $insecure}}<li><div id="insecure-message">{{$insecure}}</div></li> {{/if}}
{{if $blocked && !$pending}}<li><div id="block-message">{{$blocked}}</div></li>{{/if}}
{{if $pending}}<li><div id="pending-message">{{$pending}}</div></li>{{/if}}
{{if $ignored}}<li><div id="ignore-message">{{$ignored}}</div></li>{{/if}}
{{if $archived}}<li><div id="archive-message">{{$archived}}</div></li>{{/if}}
</ul>
</div> {{* End of contact-edit-status-wrapper *}}
{{* Some information about the contact from the profile *}}
<dl><dt>{{$profileurllabel}}</dt><dd><a target="blank" href="{{$profileurl}}">{{$profileurl}}</a></dd></dl>
{{if $location}}<dl><dt>{{$location_label}}</dt><dd>{{$location nofilter}}</dd></dl>{{/if}}
{{if $xmpp}}<dl><dt>{{$xmpp_label}}</dt><dd>{{$xmpp}}</dd></dl>{{/if}}
{{if $matrix}}<dl><dt>{{$matrix_label}}</dt><dd>{{$matrix}}</dd></dl>{{/if}}
{{if $keywords}}<dl><dt>{{$keywords_label}}</dt><dd>{{$keywords}}</dd></dl>{{/if}}
{{if $about}}<dl><dt>{{$about_label}}</dt><dd>{{$about nofilter}}</dd></dl>{{/if}}
</div>{{* End of contact-edit-links *}}
<div id="contact-edit-links-end"></div>
<hr />
{{if $contact_settings_label}}
<h4 id="contact-edit-settings-label" class="fakelink" onclick="openClose('contact-edit-settings')">{{$contact_settings_label}}</h4>
<div id="contact-edit-settings">
<input type="hidden" name="contact_id" value="{{$contact_id}}">
<div id="contact-edit-end"></div>
{{include file="field_checkbox.tpl" field=$notify_new_posts}}
{{if $fetch_further_information}}
{{include file="field_select.tpl" field=$fetch_further_information}}
{{if $fetch_further_information.2 == 2 || $fetch_further_information.2 == 3}} {{include file="field_textarea.tpl" field=$ffi_keyword_denylist}} {{/if}}
{{/if}}
{{if $allow_remote_self}}
{{include file="field_select.tpl" field=$remote_self}}
{{/if}}
{{include file="field_checkbox.tpl" field=$hidden}}
<div id="contact-edit-info-wrapper">
<h4>{{$lbl_info1}}</h4>
<textarea id="contact-edit-info" rows="8" cols="60" name="info">{{$info}}</textarea>
</div>
<div id="contact-edit-info-end"></div>
{{if $reason}}
<div id="contact-info-wrapper">
<h4>{{$lbl_info2}}</h4>
<p>{{$reason}}</p>
</div>
<div id="contact-info-end"></div>
{{/if}}
</div>
<input class="contact-edit-submit" type="submit" name="submit" value="{{$submit}}" />
{{/if}}
<div class="contact-edit-submit-end clearfix"></div>
</form>{{* End of the form *}}
</div>{{* End of contact-edit-nav-wrapper *}}
</div>