Merge branch 'develop' into run-phpstan-in-ci-pipeline

This commit is contained in:
Art4 2024-11-16 18:59:55 +00:00
commit f75fc9a2fb
561 changed files with 64963 additions and 61342 deletions

View file

@ -63,7 +63,7 @@ class Index extends BaseAdmin
'$function' => 'addons',
'$addons' => $addons,
'$pcount' => count($addons),
'$noplugshint' => DI::l10n()->t('There are currently no addons available on your node. You can find the official addon repository at %1$s and might find other interesting addons in the open addon registry at %2$s', 'https://github.com/friendica/friendica-addons', 'http://addons.friendi.ca'),
'$noplugshint' => DI::l10n()->t('There are currently no addons available on your node. You can find the official addon repository at %1$s.', 'https://git.friendi.ca/friendica/friendica-addons'),
'$form_security_token' => self::getFormSecurityToken('admin_addons'),
]);
}

View file

@ -8,6 +8,7 @@
namespace Friendica\Module\Admin;
use Friendica\App;
use Friendica\Content\ContactSelector;
use Friendica\Core\Protocol;
use Friendica\Core\Renderer;
use Friendica\Database\DBA;
@ -36,6 +37,7 @@ class Federation extends BaseAdmin
'foundkey' => ['name' => 'Foundkey', 'color' => '#609926'], // Some random color from the repository
'funkwhale' => ['name' => 'Funkwhale', 'color' => '#4082B4'], // From the homepage
'gancio' => ['name' => 'Gancio', 'color' => '#7253ed'], // Fontcolor from the page
'glitchsoc' => ['name' => 'Mastodon Glitch Edition', 'color' => '#82dcb9'], // Color from their site
'gnusocial' => ['name' => 'GNU Social/Statusnet', 'color' => '#a22430'], // dark red from the logo
'gotosocial' => ['name' => 'GoToSocial', 'color' => '#df8958'], // Some color from their mascot
'hometown' => ['name' => 'Hometown', 'color' => '#1f70c1'], // Color from the Patreon page
@ -128,6 +130,10 @@ class Federation extends BaseAdmin
$platform = 'nomad';
} elseif(stristr($platform, 'pleroma')) {
$platform = 'pleroma';
} elseif(stristr($platform, 'glitchsoc')) {
$platform = 'glitchsoc';
} elseif(stristr($platform, 'iceshrimp.net')) {
$platform = 'iceshrimp';
} elseif(stristr($platform, 'statusnet')) {
$platform = 'gnusocial';
} elseif(stristr($platform, 'nextcloud')) {
@ -176,6 +182,7 @@ class Federation extends BaseAdmin
}
$gserver['platform'] = $systems[$platform]['name'];
$gserver['svg'] = ContactSelector::networkToSVG($gserver['network'], null, $platform, DI::userSession()->getLocalUserId());
$gserver['totallbl'] = DI::l10n()->tt('%2$s total system' , '%2$s total systems' , $gserver['total'], number_format($gserver['total']));
$gserver['monthlbl'] = DI::l10n()->tt('%2$s active user last month' , '%2$s active users last month' , $gserver['month'] ?? 0, number_format($gserver['month'] ?? 0));
$gserver['halfyearlbl'] = DI::l10n()->tt('%2$s active user last six months' , '%2$s active users last six months' , $gserver['halfyear'] ?? 0, number_format($gserver['halfyear'] ?? 0));

View file

@ -64,23 +64,19 @@ class Summary extends BaseAdmin
// Check if github.com/friendica/stable/VERSION is higher then
// the local version of Friendica. Check is opt-in, source may be stable or develop branch
if (DI::config()->get('system', 'check_new_version_url', 'none') != 'none') {
$gitversion = DI::keyValue()->get('git_friendica_version') ?? '';
if (version_compare(App::VERSION, $gitversion) < 0) {
$warningtext[] = DI::l10n()->t('There is a new version of Friendica available for download. Your current version is %1$s, upstream version is %2$s', App::VERSION, $gitversion);
}
if (Update::isAvailable()) {
$warningtext[] = DI::l10n()->t('There is a new version of Friendica available for download. Your current version is %1$s, upstream version is %2$s', App::VERSION, Update::getAvailableVersion());
}
if (DI::config()->get('system', 'dbupdate', DBStructure::UPDATE_NOT_CHECKED) == DBStructure::UPDATE_NOT_CHECKED) {
if (DBStructure::getUpdateStatus() == DBStructure::UPDATE_NOT_CHECKED) {
DBStructure::performUpdate();
}
if (DI::config()->get('system', 'dbupdate') == DBStructure::UPDATE_FAILED) {
if (DBStructure::getUpdateStatus() == DBStructure::UPDATE_FAILED) {
$warningtext[] = DI::l10n()->t('The database update failed. Please run "php bin/console.php dbstructure update" from the command line and have a look at the errors that might appear.');
}
if (DI::config()->get('system', 'update') == Update::FAILED) {
if (Update::getStatus() == Update::FAILED) {
$warningtext[] = DI::l10n()->t('The last update failed. Please run "php bin/console.php dbstructure update" from the command line and have a look at the errors that might appear. (Some of the errors are possibly inside the logfile.)');
}
@ -160,9 +156,6 @@ class Summary extends BaseAdmin
// We can do better, but this is a quick queue status
$queues = ['label' => DI::l10n()->t('Message queues'), 'deferred' => $deferred, 'workerq' => $workerqueue];
$variables = DBA::toArray(DBA::p('SHOW variables LIKE "max_allowed_packet"'));
$max_allowed_packet = $variables ? $variables[0]['Value'] : 0;
$server_settings = [
'label' => DI::l10n()->t('Server Settings'),
'php' => [
@ -173,7 +166,7 @@ class Summary extends BaseAdmin
'memory_limit' => ini_get('memory_limit')
],
'mysql' => [
'max_allowed_packet' => $max_allowed_packet
'max_allowed_packet' => DBA::getVariable('max_allowed_packet'),
]
];

View file

@ -7,10 +7,8 @@
namespace Friendica\Module\Api\Mastodon\Accounts;
use Friendica\Core\System;
use Friendica\DI;
use Friendica\Model\Contact;
use Friendica\Model\User;
use Friendica\Module\BaseApi;
/**
@ -29,15 +27,6 @@ class Block extends BaseApi
Contact\User::setBlocked($this->parameters['id'], $uid, true);
$ucid = Contact::getUserContactId($this->parameters['id'], $uid);
if ($ucid) {
$contact = Contact::getById($ucid);
if (!empty($contact)) {
// Mastodon-expected behavior: relationship is severed on block
Contact::terminateFriendship($contact);
}
}
$this->jsonExit(DI::mstdnRelationship()->createFromContactId($this->parameters['id'], $uid)->toArray());
}
}

View file

@ -59,28 +59,34 @@ class Apps extends BaseApi
$this->logAndJsonError(422, $this->errorFactory->UnprocessableEntity($this->t('Missing parameters')));
}
$client_id = bin2hex(random_bytes(32));
$client_secret = bin2hex(random_bytes(32));
$fields = ['client_id' => $client_id, 'client_secret' => $client_secret, 'name' => $request['client_name'], 'redirect_uri' => $request['redirect_uris']];
$fields = ['name' => $request['client_name'], 'redirect_uri' => $request['redirect_uris']];
if (!empty($request['scopes'])) {
$fields['scopes'] = $request['scopes'];
}
$fields['read'] = (stripos($request['scopes'], self::SCOPE_READ) !== false);
$fields['write'] = (stripos($request['scopes'], self::SCOPE_WRITE) !== false);
$fields['follow'] = (stripos($request['scopes'], self::SCOPE_FOLLOW) !== false);
$fields['push'] = (stripos($request['scopes'], self::SCOPE_PUSH) !== false);
if (!empty($request['website'])) {
$fields['website'] = $request['website'];
}
$application = DBA::selectFirst('application', ['id'], $fields);
if (!empty($application['id'])) {
$this->logger->debug('Found existing application', ['request' => $request, 'id' => $application['id']]);
$this->jsonExit(DI::mstdnApplication()->createFromApplicationId($application['id'])->toArray());
}
$fields['read'] = (stripos($request['scopes'], self::SCOPE_READ) !== false);
$fields['write'] = (stripos($request['scopes'], self::SCOPE_WRITE) !== false);
$fields['follow'] = (stripos($request['scopes'], self::SCOPE_FOLLOW) !== false);
$fields['push'] = (stripos($request['scopes'], self::SCOPE_PUSH) !== false);
$fields['client_id'] = bin2hex(random_bytes(32));
$fields['client_secret'] = bin2hex(random_bytes(32));
if (!DBA::insert('application', $fields)) {
$this->logAndJsonError(500, $this->errorFactory->InternalError());
}
$this->logger->debug('Create new application', ['request' => $request, 'id' => DBA::lastInsertId()]);
$this->jsonExit(DI::mstdnApplication()->createFromApplicationId(DBA::lastInsertId())->toArray());
}
}

View file

@ -42,38 +42,37 @@ class Media extends BaseApi
$type = Post\Media::getType($request['file']['type']);
if (in_array($type, [Post\Media::IMAGE, Post\Media::UNKNOWN])) {
if (in_array($type, [Post\Media::IMAGE, Post\Media::UNKNOWN, Post\Media::APPLICATION])) {
$media = Photo::upload($uid, $request['file'], '', null, null, '', '', $request['description']);
if (empty($media)) {
$this->logAndJsonError(422, $this->errorFactory->UnprocessableEntity());
if (!empty($media)) {
Logger::info('Uploaded photo', ['media' => $media]);
$this->jsonExit(DI::mstdnAttachment()->createFromPhoto($media['id']));
} elseif ($type == Post\Media::IMAGE) {
$this->jsonExit(DI::mstdnAttachment()->createFromPhoto($media['id']));
}
Logger::info('Uploaded photo', ['media' => $media]);
$this->jsonExit(DI::mstdnAttachment()->createFromPhoto($media['id']));
} else {
$tempFileName = $request['file']['tmp_name'];
$fileName = basename($request['file']['name']);
$fileSize = intval($request['file']['size']);
$maxFileSize = Strings::getBytesFromShorthand(DI::config()->get('system', 'maxfilesize'));
if ($fileSize <= 0) {
Logger::notice('Filesize is invalid', ['size' => $fileSize, 'request' => $request]);
@unlink($tempFileName);
$this->logAndJsonError(422, $this->errorFactory->UnprocessableEntity());
}
if ($maxFileSize && $fileSize > $maxFileSize) {
Logger::notice('Filesize is too large', ['size' => $fileSize, 'max' => $maxFileSize, 'request' => $request]);
@unlink($tempFileName);
$this->logAndJsonError(422, $this->errorFactory->UnprocessableEntity());
}
$id = Attach::storeFile($tempFileName, self::getCurrentUserID(), $fileName, $request['file']['type'], '<' . Contact::getPublicIdByUserId(self::getCurrentUserID()) . '>');
@unlink($tempFileName);
Logger::info('Uploaded media', ['id' => $id]);
$this->jsonExit(DI::mstdnAttachment()->createFromAttach($id));
}
$tempFileName = $request['file']['tmp_name'];
$fileName = basename($request['file']['name']);
$fileSize = intval($request['file']['size']);
$maxFileSize = Strings::getBytesFromShorthand(DI::config()->get('system', 'maxfilesize'));
if ($fileSize <= 0) {
Logger::notice('Filesize is invalid', ['size' => $fileSize, 'request' => $request]);
@unlink($tempFileName);
$this->logAndJsonError(422, $this->errorFactory->UnprocessableEntity());
}
if ($maxFileSize && $fileSize > $maxFileSize) {
Logger::notice('Filesize is too large', ['size' => $fileSize, 'max' => $maxFileSize, 'request' => $request]);
@unlink($tempFileName);
$this->logAndJsonError(422, $this->errorFactory->UnprocessableEntity());
}
$id = Attach::storeFile($tempFileName, self::getCurrentUserID(), $fileName, $request['file']['type'], '<' . Contact::getPublicIdByUserId(self::getCurrentUserID()) . '>');
@unlink($tempFileName);
Logger::info('Uploaded media', ['id' => $id]);
$this->jsonExit(DI::mstdnAttachment()->createFromAttach($id));
}
public function put(array $request = [])

View file

@ -66,7 +66,7 @@ class Context extends BaseApi
if (!empty($uid) && !$request['show_all']) {
$condition = DBA::mergeConditions(
$condition,
["NOT `author-id` IN (SELECT `cid` FROM `user-contact` WHERE `uid` = ? AND (`blocked` OR `ignored`))", $uid]
["NOT `author-id` IN (SELECT `cid` FROM `user-contact` WHERE `uid` = ? AND (`blocked` OR `ignored` OR `is-blocked`))", $uid]
);
}

View file

@ -55,7 +55,7 @@ class Direct extends BaseApi
if (!empty($uid)) {
$condition = DBA::mergeConditions(
$condition,
["NOT `parent-author-id` IN (SELECT `cid` FROM `user-contact` WHERE `uid` = ? AND (`blocked` OR `ignored`) AND `cid` = `parent-author-id`)", $uid]
["NOT `parent-author-id` IN (SELECT `cid` FROM `user-contact` WHERE `uid` = ? AND (`blocked` OR `ignored` OR `is-blocked`) AND `cid` = `parent-author-id`)", $uid]
);
}

View file

@ -66,6 +66,8 @@ class Home extends BaseApi
$condition = DBA::mergeConditions($condition, ['gravity' => Item::GRAVITY_PARENT]);
}
$condition = DBA::mergeConditions($condition, ["NOT EXISTS(SELECT `cid` FROM `user-contact` WHERE `uid` = ? AND `cid` IN (`parent-owner-id`, `parent-author-id`) AND (`blocked` OR `ignored` OR `is-blocked` OR `channel-only`))", $uid]);
$items = Post::selectTimelineForUser($uid, ['uri-id'], $condition, $params);
$display_quotes = self::appSupportsQuotes();

View file

@ -93,7 +93,7 @@ class Tag extends BaseApi
if (!empty($uid)) {
$condition = DBA::mergeConditions(
$condition,
["NOT `author-id` IN (SELECT `cid` FROM `user-contact` WHERE `uid` = ? AND (`blocked` OR `ignored`) AND `cid` = `author-id`)", $uid]
["NOT `author-id` IN (SELECT `cid` FROM `user-contact` WHERE `uid` = ? AND (`blocked` OR `ignored` OR `is-blocked`) AND `cid` = `author-id`)", $uid]
);
}

View file

@ -617,7 +617,7 @@ class Contact extends BaseModule
'account_type' => Model\Contact::getAccountType($contact['contact-type']),
'sparkle' => $sparkle,
'itemurl' => ($contact['addr'] ?? '') ?: $contact['url'],
'network' => ContactSelector::networkToName($contact['network'], $contact['url'], $contact['protocol'], $contact['gsid']),
'network' => ContactSelector::networkToName($contact['network'], $contact['protocol'], $contact['gsid']),
];
}
}

View file

@ -56,11 +56,15 @@ class Follow extends BaseModule
throw new ForbiddenException($this->t('Access denied.'));
}
if (isset($request['cancel']) || empty($request['url'])) {
$this->baseUrl->redirect('contact');
if (!empty($request['follow-url'])) {
$this->baseUrl->redirect('contact/follow?binurl=' . bin2hex($request['follow-url']));
}
$url = Probe::cleanURI($request['url']);
$url = $this->getUrl($request);
if (isset($request['cancel']) || empty($url)) {
$this->baseUrl->redirect('contact');
}
$this->process($url);
}
@ -77,7 +81,7 @@ class Follow extends BaseModule
$uid = $this->session->getLocalUserId();
// uri is used by the /authorize_interaction Mastodon route
$url = Probe::cleanURI(trim($request['uri'] ?? $request['url'] ?? ''));
$url = $this->getUrl($request);
// Issue 6874: Allow remote following from Peertube
if (strpos($url, 'acct:') === 0) {
@ -182,7 +186,7 @@ class Follow extends BaseModule
protected function process(string $url)
{
$returnPath = 'contact/follow?url=' . urlencode($url);
$returnPath = 'contact/follow?binurl=' . bin2hex($url);
$result = Contact::createFromProbeForUser($this->session->getLocalUserId(), $url);
@ -227,4 +231,14 @@ class Follow extends BaseModule
return;
}
}
private function getUrl(array $request): string
{
if (!empty($request['binurl']) && Strings::isHex($request['binurl'])) {
$url = hex2bin($request['binurl']);
} else {
$url = $request['url'] ?? '';
}
return Probe::cleanURI($url);
}
}

View file

@ -297,7 +297,7 @@ class Profile extends BaseModule
$poll_enabled = in_array($contact['network'], [Protocol::DFRN, Protocol::FEED, Protocol::MAIL]);
$nettype = $this->t('Network type: %s', ContactSelector::networkToName($contact['network'], $contact['url'], $contact['protocol'], $contact['gsid']));
$nettype = $this->t('Network type: %s', ContactSelector::networkToName($contact['network'], $contact['protocol'], $contact['gsid']));
// tabs
$tab_str = Module\Contact::getTabsHTML($contact, Module\Contact::TAB_PROFILE);
@ -356,6 +356,11 @@ class Profile extends BaseModule
$contact_actions = $this->getContactActions($contact, $localRelationship);
if (Contact\User::isIsBlocked($contact['id'], $this->session->getLocalUserId())) {
$relation_text = $this->t('%s has blocked you', $contact['name'] ?: $contact['nick']);
unset($contact_actions['follow']);
}
if ($localRelationship->rel !== Contact::NOTHING) {
$lbl_info1 = $this->t('Contact Information / Notes');
$contact_settings_label = $this->t('Contact Settings');
@ -477,7 +482,7 @@ class Profile extends BaseModule
} else {
$contact_actions['follow'] = [
'label' => $this->t('Follow'),
'url' => 'contact/follow?url=' . urlencode($contact['url']) . '&auto=1',
'url' => 'contact/follow?binurl=' . bin2hex($contact['url']) . '&auto=1',
'title' => '',
'sel' => '',
'id' => 'follow',

View file

@ -87,7 +87,7 @@ class Install extends BaseModule
// so we may not have a css at all. Here we set a static css file for the install procedure pages
Renderer::$theme['stylesheet'] = $this->baseUrl . '/view/install/style.css';
$this->currentWizardStep = ($_POST['pass'] ?? '') ?: self::SYSTEM_CHECK;
$this->currentWizardStep = ($_REQUEST['pass'] ?? '') ?: self::SYSTEM_CHECK;
}
protected function post(array $request = [])
@ -164,6 +164,7 @@ class Install extends BaseModule
break;
}
DI::baseUrl()->redirect('install?pass=' . $this->currentWizardStep);
}
protected function content(array $request = []): string

View file

@ -96,7 +96,7 @@ class Add extends BaseModeration
array_walk($gservers, function (array &$gserver) {
$gserver['domain'] = (new Uri($gserver['url']))->getHost();
$gserver['network_icon'] = ContactSelector::networkToIcon($gserver['network']);
$gserver['network_svg'] = ContactSelector::networkToSVG($gserver['network']);
$gserver['network_name'] = ContactSelector::networkToName($gserver['network']);
});

View file

@ -76,7 +76,7 @@ class Source extends BaseModeration
'urllbl' => $this->t('URL'),
'mentionlbl' => $this->t('Mention'),
'implicitlbl' => $this->t('Implicit Mention'),
'error' => $this->t('Error'),
'error' => $this->tt('Error','Errors', 1),
'notfound' => $this->t('Item not found'),
'nosource' => $this->t('No source recorded'),
'noconfig' => !$this->config->get('debug', 'store_source') ? $this->t('Please make sure the <code>debug.store_source</code> config key is set in <code>config/local.config.php</code> for future items to have sources.') : '',

View file

@ -156,7 +156,8 @@ class Introductions extends BaseNotifications
$header .= ' <' . $Introduction->getAddr() . '>';
}
$header .= ' (' . ContactSelector::networkToName($Introduction->getNetwork(), $Introduction->getUrl()) . ')';
$gsid = ContactSelector::getServerIdForProfile($Introduction->getUrl());
$header .= ' (' . ContactSelector::networkToName($Introduction->getNetwork(), '', $gsid) . ')';
if ($Introduction->getNetwork() != Protocol::DIASPORA) {
$discard = $this->t('Discard');
@ -191,7 +192,7 @@ class Introductions extends BaseNotifications
'$addr' => $Introduction->getAddr(),
'$lbl_knowyou' => $lbl_knowyou,
'$lbl_network' => $this->t('Network:'),
'$network' => ContactSelector::networkToName($Introduction->getNetwork(), $Introduction->getUrl()),
'$network' => ContactSelector::networkToName($Introduction->getNetwork(), '', $gsid),
'$knowyou' => $knowyou,
'$approve' => $this->t('Approve'),
'$note' => $Introduction->getNote(),

View file

@ -36,17 +36,18 @@ class Authorize extends BaseApi
], $request);
if ($request['response_type'] != 'code') {
Logger::warning('Unsupported or missing response type', ['request' => $_REQUEST]);
Logger::warning('Unsupported or missing response type', ['request' => $request]);
$this->logAndJsonError(422, $this->errorFactory->UnprocessableEntity($this->t('Unsupported or missing response type')));
}
if (empty($request['client_id']) || empty($request['redirect_uri'])) {
Logger::warning('Incomplete request data', ['request' => $_REQUEST]);
Logger::warning('Incomplete request data', ['request' => $request]);
$this->logAndJsonError(422, $this->errorFactory->UnprocessableEntity($this->t('Incomplete request data')));
}
$application = OAuth::getApplication($request['client_id'], $request['client_secret'], $request['redirect_uri']);
if (empty($application)) {
Logger::warning('An application could not be fetched.', ['request' => $request]);
$this->logAndJsonError(422, $this->errorFactory->UnprocessableEntity());
}

View file

@ -9,10 +9,14 @@ namespace Friendica\Module;
use DOMDocument;
use DOMElement;
use Friendica\App;
use Friendica\BaseModule;
use Friendica\Core\System;
use Friendica\DI;
use Friendica\Core\Config\Capability\IManageConfigValues;
use Friendica\Core\L10n;
use Friendica\Util\BasePath;
use Friendica\Util\Profiler;
use Friendica\Util\XML;
use Psr\Log\LoggerInterface;
/**
* Prints the opensearch description document
@ -20,22 +24,37 @@ use Friendica\Util\XML;
*/
class OpenSearch extends BaseModule
{
/** @var IManageConfigValues */
private $config;
/** @var App\baseUrl */
protected $baseUrl;
/** @var string */
private $basePath;
public function __construct(BasePath $basePath, IManageConfigValues $config, L10n $l10n, App\baseUrl $baseUrl, App\Arguments $args, LoggerInterface $logger, Profiler $profiler, Response $response, array $server, array $parameters = [])
{
parent::__construct($l10n, $baseUrl, $args, $logger, $profiler, $response, $server, $parameters);
$this->config = $config;
$this->basePath = $basePath->getPath();
$this->baseUrl = $baseUrl;
}
/**
* @throws \Exception
*/
protected function rawContent(array $request = [])
{
$hostname = DI::baseUrl()->getHost();
$baseUrl = (string)DI::baseUrl();
/** @var DOMDocument $xml */
XML::fromArray([
'OpenSearchDescription' => [
'@attributes' => [
'xmlns' => 'http://a9.com/-/spec/opensearch/1.1',
'xmlns' => 'http://a9.com/-/spec/opensearch/1.1/',
],
'ShortName' => "Friendica $hostname",
'Description' => "Search in Friendica $hostname",
'ShortName' => $this->baseUrl->getHost(),
'Description' => $this->l10n->t('Search in Friendica %s', $this->baseUrl->getHost()),
'Contact' => 'https://github.com/friendica/friendica/issues',
'InputEncoding' => 'UTF-8',
'OutputEncoding' => 'UTF-8',
@ -46,29 +65,41 @@ class OpenSearch extends BaseModule
/** @var DOMElement $parent */
$parent = $xml->getElementsByTagName('OpenSearchDescription')[0];
XML::addElement($xml, $parent, 'Image',
"$baseUrl/images/friendica-16.png", [
if (file_exists($this->basePath . '/favicon.ico')) {
$shortcut_icon = '/favicon.ico';
} else {
$shortcut_icon = $this->config->get('system', 'shortcut_icon');
}
if (!empty($shortcut_icon)) {
$imagedata = getimagesize($this->baseUrl . $shortcut_icon);
}
if (!empty($imagedata)) {
XML::addElement($xml, $parent, 'Image', $this->baseUrl . $shortcut_icon, [
'width' => $imagedata[0],
'height' => $imagedata[1],
'type' => $imagedata['mime'],
]);
} else {
XML::addElement($xml, $parent, 'Image',
$this->baseUrl . '/images/friendica-16.png', [
'height' => 16,
'width' => 16,
'type' => 'image/png',
]);
XML::addElement($xml, $parent, 'Image',
"$baseUrl/images/friendica-64.png", [
'height' => 64,
'width' => 64,
'type' => 'image/png',
]);
}
XML::addElement($xml, $parent, 'Url', '', [
'type' => 'text/html',
'template' => "$baseUrl/search?search={searchTerms}",
'method' => 'get',
'template' => $this->baseUrl . '/search?q={searchTerms}',
]);
XML::addElement($xml, $parent, 'Url', '', [
'type' => 'application/opensearchdescription+xml',
'rel' => 'self',
'template' => "$baseUrl/opensearch",
'template' => $this->baseUrl . '/opensearch',
]);
$this->httpExit($xml->saveXML(), Response::TYPE_XML, 'application/opensearchdescription+xml');

View file

@ -225,7 +225,7 @@ class Conversations extends BaseProfile
$items = array_merge($items, $pinned);
}
$o .= $this->conversation->render($items, Conversation::MODE_PROFILE, false, false, 'pinned_received', $profile['uid']);
$o .= $this->conversation->render($items, Conversation::MODE_PROFILE, false, false, 'pinned_received', $this->session->getLocalUserId());
$o .= $pager->renderMinimal(count($items));

View file

@ -8,6 +8,7 @@
namespace Friendica\Module\Settings;
use Friendica\App;
use Friendica\Content\ContactSelector;
use Friendica\Content\Conversation\Collection\Timelines;
use Friendica\Content\Text\BBCode;
use Friendica\Content\Conversation\Factory\Channel as ChannelFactory;
@ -80,23 +81,26 @@ class Display extends BaseSettings
$user = User::getById($uid);
$theme = trim($request['theme']);
$mobile_theme = trim($request['mobile_theme'] ?? '');
$enable_smile = (bool)$request['enable_smile'];
$enable = (array)$request['enable'];
$bookmark = (array)$request['bookmark'];
$channel_languages = (array)$request['channel_languages'];
$first_day_of_week = (bool)$request['first_day_of_week'];
$calendar_default_view = trim($request['calendar_default_view']);
$infinite_scroll = (bool)$request['infinite_scroll'];
$enable_smart_threading = (bool)$request['enable_smart_threading'];
$enable_dislike = (bool)$request['enable_dislike'];
$display_resharer = (bool)$request['display_resharer'];
$stay_local = (bool)$request['stay_local'];
$show_page_drop = (bool)$request['show_page_drop'];
$display_eventlist = (bool)$request['display_eventlist'];
$preview_mode = (int)$request['preview_mode'];
$browser_update = (int)$request['browser_update'];
$theme = trim($request['theme']);
$mobile_theme = trim($request['mobile_theme'] ?? '');
$enable_smile = (bool)$request['enable_smile'];
$enable = (array)$request['enable'];
$bookmark = (array)$request['bookmark'];
$channel_languages = (array)$request['channel_languages'];
$first_day_of_week = (int)$request['first_day_of_week'];
$calendar_default_view = trim($request['calendar_default_view']);
$infinite_scroll = (bool)$request['infinite_scroll'];
$enable_smart_threading = (bool)$request['enable_smart_threading'];
$enable_dislike = (bool)$request['enable_dislike'];
$display_resharer = (bool)$request['display_resharer'];
$stay_local = (bool)$request['stay_local'];
$hide_empty_descriptions = (bool)$request['hide_empty_descriptions'];
$hide_custom_emojis = (bool)$request['hide_custom_emojis'];
$platform_icon_style = (int)$request['platform_icon_style'];
$show_page_drop = (bool)$request['show_page_drop'];
$display_eventlist = (bool)$request['display_eventlist'];
$preview_mode = (int)$request['preview_mode'];
$browser_update = (int)$request['browser_update'];
if ($browser_update != -1) {
$browser_update = $browser_update * 1000;
if ($browser_update < 10000) {
@ -135,25 +139,29 @@ class Display extends BaseSettings
$this->pConfig->set($uid, 'system', 'mobile_theme', $mobile_theme);
}
$this->pConfig->set($uid, 'system', 'itemspage_network' , $itemspage_network);
$this->pConfig->set($uid, 'system', 'itemspage_network', $itemspage_network);
$this->pConfig->set($uid, 'system', 'itemspage_mobile_network', $itemspage_mobile_network);
$this->pConfig->set($uid, 'system', 'update_interval' , $browser_update);
$this->pConfig->set($uid, 'system', 'no_smilies' , !$enable_smile);
$this->pConfig->set($uid, 'system', 'infinite_scroll' , $infinite_scroll);
$this->pConfig->set($uid, 'system', 'no_smart_threading' , !$enable_smart_threading);
$this->pConfig->set($uid, 'system', 'hide_dislike' , !$enable_dislike);
$this->pConfig->set($uid, 'system', 'display_resharer' , $display_resharer);
$this->pConfig->set($uid, 'system', 'stay_local' , $stay_local);
$this->pConfig->set($uid, 'system', 'show_page_drop' , $show_page_drop);
$this->pConfig->set($uid, 'system', 'display_eventlist' , $display_eventlist);
$this->pConfig->set($uid, 'system', 'preview_mode' , $preview_mode);
$this->pConfig->set($uid, 'system', 'update_interval', $browser_update);
$this->pConfig->set($uid, 'system', 'no_smilies', !$enable_smile);
$this->pConfig->set($uid, 'system', 'infinite_scroll', $infinite_scroll);
$this->pConfig->set($uid, 'system', 'no_smart_threading', !$enable_smart_threading);
$this->pConfig->set($uid, 'system', 'hide_dislike', !$enable_dislike);
$this->pConfig->set($uid, 'system', 'display_resharer', $display_resharer);
$this->pConfig->set($uid, 'system', 'stay_local', $stay_local);
$this->pConfig->set($uid, 'system', 'show_page_drop', $show_page_drop);
$this->pConfig->set($uid, 'system', 'display_eventlist', $display_eventlist);
$this->pConfig->set($uid, 'system', 'preview_mode', $preview_mode);
$this->pConfig->set($uid, 'system', 'network_timelines' , $network_timelines);
$this->pConfig->set($uid, 'system', 'enabled_timelines' , $enabled_timelines);
$this->pConfig->set($uid, 'channel', 'languages' , $channel_languages);
$this->pConfig->set($uid, 'system', 'network_timelines', $network_timelines);
$this->pConfig->set($uid, 'system', 'enabled_timelines', $enabled_timelines);
$this->pConfig->set($uid, 'channel', 'languages', $channel_languages);
$this->pConfig->set($uid, 'calendar', 'first_day_of_week' , $first_day_of_week);
$this->pConfig->set($uid, 'calendar', 'default_view' , $calendar_default_view);
$this->pConfig->set($uid, 'accessibility', 'hide_empty_descriptions', $hide_empty_descriptions);
$this->pConfig->set($uid, 'accessibility', 'hide_custom_emojis', $hide_custom_emojis);
$this->pConfig->set($uid, 'accessibility', 'platform_icon_style', $platform_icon_style);
$this->pConfig->set($uid, 'calendar', 'first_day_of_week', $first_day_of_week);
$this->pConfig->set($uid, 'calendar', 'default_view', $calendar_default_view);
if (in_array($theme, Theme::getAllowedList())) {
if ($theme == $user['theme']) {
@ -241,6 +249,17 @@ class Display extends BaseSettings
$show_page_drop = $this->pConfig->get($uid, 'system', 'show_page_drop', true);
$display_eventlist = $this->pConfig->get($uid, 'system', 'display_eventlist', true);
$hide_empty_descriptions = $this->pConfig->get($uid, 'accessibility', 'hide_empty_descriptions', false);
$hide_custom_emojis = $this->pConfig->get($uid, 'accessibility', 'hide_custom_emojis', false);
$platform_icon_style = $this->pConfig->get($uid, 'accessibility', 'platform_icon_style', ContactSelector::SVG_COLOR_BLACK);
$platform_icon_styles = [
ContactSelector::SVG_DISABLED => $this->t('Disabled'),
ContactSelector::SVG_COLOR_BLACK => $this->t('Color/Black'),
ContactSelector::SVG_BLACK => $this->t('Black'),
ContactSelector::SVG_COLOR_WHITE => $this->t('Color/White'),
ContactSelector::SVG_WHITE => $this->t('White'),
];
$preview_mode = $this->pConfig->get($uid, 'system', 'preview_mode', BBCode::PREVIEW_LARGE);
$preview_modes = [
BBCode::PREVIEW_NONE => $this->t('No preview'),
@ -308,18 +327,21 @@ class Display extends BaseSettings
'$mobile_theme' => ['mobile_theme', $this->t('Mobile Theme:'), $mobile_theme_selected, '', $mobile_themes, false],
'$theme_config' => $theme_config,
'$itemspage_network' => ['itemspage_network' , $this->t('Number of items to display per page:'), $itemspage_network, $this->t('Maximum of 100 items')],
'$itemspage_network' => ['itemspage_network', $this->t('Number of items to display per page:'), $itemspage_network, $this->t('Maximum of 100 items')],
'$itemspage_mobile_network' => ['itemspage_mobile_network', $this->t('Number of items to display per page when viewed from mobile device:'), $itemspage_mobile_network, $this->t('Maximum of 100 items')],
'$ajaxint' => ['browser_update' , $this->t('Update browser every xx seconds'), $browser_update, $this->t('Minimum of 10 seconds. Enter -1 to disable it.')],
'$enable_smile' => ['enable_smile' , $this->t('Display emoticons'), $enable_smile, $this->t('When enabled, emoticons are replaced with matching symbols.')],
'$infinite_scroll' => ['infinite_scroll' , $this->t('Infinite scroll'), $infinite_scroll, $this->t('Automatic fetch new items when reaching the page end.')],
'$enable_smart_threading' => ['enable_smart_threading' , $this->t('Enable Smart Threading'), $enable_smart_threading, $this->t('Enable the automatic suppression of extraneous thread indentation.')],
'$enable_dislike' => ['enable_dislike' , $this->t('Display the Dislike feature'), $enable_dislike, $this->t('Display the Dislike button and dislike reactions on posts and comments.')],
'$display_resharer' => ['display_resharer' , $this->t('Display the resharer'), $display_resharer, $this->t('Display the first resharer as icon and text on a reshared item.')],
'$stay_local' => ['stay_local' , $this->t('Stay local'), $stay_local, $this->t("Don't go to a remote system when following a contact link.")],
'$show_page_drop' => ['show_page_drop' , $this->t('Show the post deletion checkbox'), $show_page_drop, $this->t("Display the checkbox for the post deletion on the network page.")],
'$display_eventlist' => ['display_eventlist' , $this->t('DIsplay the event list'), $display_eventlist, $this->t("Display the birthday reminder and event list on the network page.")],
'$preview_mode' => ['preview_mode' , $this->t('Link preview mode'), $preview_mode, $this->t('Appearance of the link preview that is added to each post with a link.'), $preview_modes, false],
'$ajaxint' => ['browser_update', $this->t('Update browser every xx seconds'), $browser_update, $this->t('Minimum of 10 seconds. Enter -1 to disable it.')],
'$enable_smile' => ['enable_smile', $this->t('Display emoticons'), $enable_smile, $this->t('When enabled, emoticons are replaced with matching symbols.')],
'$infinite_scroll' => ['infinite_scroll', $this->t('Infinite scroll'), $infinite_scroll, $this->t('Automatic fetch new items when reaching the page end.')],
'$enable_smart_threading' => ['enable_smart_threading', $this->t('Enable Smart Threading'), $enable_smart_threading, $this->t('Enable the automatic suppression of extraneous thread indentation.')],
'$enable_dislike' => ['enable_dislike', $this->t('Display the Dislike feature'), $enable_dislike, $this->t('Display the Dislike button and dislike reactions on posts and comments.')],
'$display_resharer' => ['display_resharer', $this->t('Display the resharer'), $display_resharer, $this->t('Display the first resharer as icon and text on a reshared item.')],
'$stay_local' => ['stay_local', $this->t('Stay local'), $stay_local, $this->t("Don't go to a remote system when following a contact link.")],
'$show_page_drop' => ['show_page_drop', $this->t('Show the post deletion checkbox'), $show_page_drop, $this->t("Display the checkbox for the post deletion on the network page.")],
'$display_eventlist' => ['display_eventlist', $this->t('DIsplay the event list'), $display_eventlist, $this->t("Display the birthday reminder and event list on the network page.")],
'$preview_mode' => ['preview_mode', $this->t('Link preview mode'), $preview_mode, $this->t('Appearance of the link preview that is added to each post with a link.'), $preview_modes, false],
'$hide_empty_descriptions' => ['hide_empty_descriptions', $this->t('Hide pictures with empty alternative text'), $hide_empty_descriptions, $this->t("Don't display pictures that are missing the alternative text.")],
'$hide_custom_emojis' => ['hide_custom_emojis', $this->t('Hide custom emojis'), $hide_custom_emojis, $this->t("Don't display custom emojis.")],
'$platform_icon_style' => ['platform_icon_style', $this->t('Platform icons style'), $platform_icon_style, $this->t('Style of the platform icons'), $platform_icon_styles, false],
'$timeline_label' => $this->t('Label'),
'$timeline_descriptiom' => $this->t('Description'),
@ -330,7 +352,7 @@ class Display extends BaseSettings
'$channel_languages' => ['channel_languages[]', $this->t('Channel languages:'), $channel_languages, $this->t('Select all languages that you want to see in your channels.'), $languages, 'multiple'],
'$first_day_of_week' => ['first_day_of_week' , $this->t('Beginning of week:') , $first_day_of_week , '', $weekdays , false],
'$first_day_of_week' => ['first_day_of_week', $this->t('Beginning of week:'), $first_day_of_week, '', $weekdays, false],
'$calendar_default_view' => ['calendar_default_view', $this->t('Default calendar view:'), $calendar_default_view, '', $calendarViews, false],
]);
}

View file

@ -77,7 +77,8 @@ class AppSpecific extends BaseSettings
$this->baseUrl->redirect('settings/2fa/app_specific?t=' . self::getFormSecurityToken('settings_2fa_password'));
} else {
$this->appSpecificPassword = AppSpecificPassword::generateForUser($this->session->getLocalUserId(), $request['description'] ?? '');
$this->systemMessages->addInfo($this->t('New app-specific password generated.'));
$this->systemMessages->addInfo($this->t('New app-specific password generated: %s', $this->appSpecificPassword['plaintext_password']));
$this->baseUrl->redirect('settings/2fa/app_specific?t=' . self::getFormSecurityToken('settings_2fa_password'));
}
break;

View file

@ -14,8 +14,11 @@ use Friendica\Core\Config\Capability\IManageConfigValues;
use Friendica\Core\KeyValueStorage\Capability\IManageKeyValuePairs;
use Friendica\Core\L10n;
use Friendica\Core\Protocol;
use Friendica\Core\Update;
use Friendica\Core\Worker;
use Friendica\Database\Database;
use Friendica\Database\DBA;
use Friendica\Database\DBStructure;
use Friendica\Model\Register;
use Friendica\Moderation\Entity\Report;
use Friendica\Util\DateTimeFormat;
@ -23,6 +26,10 @@ use Friendica\Util\Profiler;
use Psr\Log\LoggerInterface;
use Friendica\Network\HTTPException;
/**
* Returns statistics of the current node for administration use
* Like for monitoring
*/
class Stats extends BaseModule
{
/** @var IManageConfigValues */
@ -129,7 +136,25 @@ class Stats extends BaseModule
],
'open' => $this->dba->count('report', ['status' => Report::STATUS_OPEN]),
'closed' => $this->dba->count('report', ['status' => Report::STATUS_CLOSED]),
]
],
'update' => [
'available' => Update::isAvailable(),
'available_version' => Update::getAvailableVersion(),
'status' => Update::getStatus(),
'db_status' => DBStructure::getUpdateStatus(),
],
'server' => [
'version' => App::VERSION,
'php' => [
'version' => phpversion(),
'upload_max_filesize' => ini_get('upload_max_filesize'),
'post_max_size' => ini_get('post_max_size'),
'memory_limit' => ini_get('memory_limit'),
],
'database' => [
'max_allowed_packet' => DBA::getVariable('max_allowed_packet'),
],
],
];
if (Addon::isEnabled('bluesky')) {

View file

@ -33,14 +33,14 @@ class Xrd extends BaseModule
}
$uri = urldecode(trim($_GET['uri']));
$mode = self::getAcceptedContentType($_SERVER['HTTP_ACCEPT'] ?? '', Response::TYPE_JSON);
$mode = self::getAcceptedContentType($_SERVER['HTTP_ACCEPT'] ?? '', Response::TYPE_XML);
} else {
if (empty($_GET['resource'])) {
throw new BadRequestException();
}
$uri = urldecode(trim($_GET['resource']));
$mode = self::getAcceptedContentType($_SERVER['HTTP_ACCEPT'] ?? '', Response::TYPE_XML);
$mode = self::getAcceptedContentType($_SERVER['HTTP_ACCEPT'] ?? '', Response::TYPE_JSON);
}
if (Network::isValidHttpUrl($uri)) {