Merge branch 'develop' into mastodon-status-post-with-title

This commit is contained in:
Hank Grabowski
2023-02-18 10:30:57 -05:00
23 changed files with 291 additions and 212 deletions

View File

@@ -979,6 +979,11 @@ class Conversation
$condition['author-hidden'] = false;
}
if ($this->config->get('system', 'emoji_activities')) {
$emojis = $this->getEmojis($uriids);
$condition = DBA::mergeConditions($condition, ["(`gravity` != ? OR `origin`)", ItemModel::GRAVITY_ACTIVITY]);
}
$condition = DBA::mergeConditions($condition,
["`uid` IN (0, ?) AND (NOT `vid` IN (?, ?, ?) OR `vid` IS NULL)", $uid, Verb::getID(Activity::FOLLOW), Verb::getID(Activity::VIEW), Verb::getID(Activity::READ)]);
@@ -1081,6 +1086,8 @@ class Conversation
}
foreach ($items as $key => $row) {
$items[$key]['emojis'] = $emojis[$key] ?? [];
$always_display = in_array($mode, [self::MODE_CONTACTS, self::MODE_CONTACT_POSTS]);
$items[$key]['user-blocked-author'] = !$always_display && in_array($row['author-id'], $blocks);
@@ -1102,6 +1109,53 @@ class Conversation
return $items;
}
/**
* Fetch emoji reaction from the conversation
*
* @param array $uriids
* @return array
*/
private function getEmojis(array $uriids): array
{
$activity_emoji = [
Activity::LIKE => '👍',
Activity::DISLIKE => '👎',
Activity::ATTEND => '✔️',
Activity::ATTENDMAYBE => '❓',
Activity::ATTENDNO => '❌',
Activity::ANNOUNCE => '♻',
Activity::VIEW => '📺',
];
$index_list = array_values($activity_emoji);
$verbs = array_merge(array_keys($activity_emoji), [Activity::EMOJIREACT]);
$condition = DBA::mergeConditions(['parent-uri-id' => $uriids, 'gravity' => ItemModel::GRAVITY_ACTIVITY, 'verb' => $verbs], ["NOT `deleted`"]);
$separator = chr(255) . chr(255) . chr(255);
$sql = "SELECT `thr-parent-id`, `body`, `verb`, COUNT(*) AS `total`, GROUP_CONCAT(REPLACE(`author-name`, '" . $separator . "', ' ') SEPARATOR '". $separator ."' LIMIT 50) AS `title` FROM `post-view` WHERE " . array_shift($condition) . " GROUP BY `thr-parent-id`, `verb`, `body`";
$emojis = [];
$rows = DBA::p($sql, $condition);
while ($row = DBA::fetch($rows)) {
$row['verb'] = $row['body'] ? Activity::EMOJIREACT : $row['verb'];
$emoji = $row['body'] ?: $activity_emoji[$row['verb']];
if (!isset($index_list[$emoji])) {
$index_list[] = $emoji;
}
$index = array_search($emoji, $index_list);
$emojis[$row['thr-parent-id']][$index]['emoji'] = $emoji;
$emojis[$row['thr-parent-id']][$index]['verb'] = $row['verb'];
$emojis[$row['thr-parent-id']][$index]['total'] = $emojis[$row['thr-parent-id']][$emoji]['total'] ?? 0 + $row['total'];
$emojis[$row['thr-parent-id']][$index]['title'] = array_unique(array_merge($emojis[$row['thr-parent-id']][$emoji]['title'] ?? [], explode($separator, $row['title'])));
}
DBA::close($rows);
return $emojis;
}
/**
* Plucks the children of the given parent from a given item list.
*

View File

@@ -166,7 +166,7 @@ class System
$load = System::currentLoad();
if ($load) {
if (intval($load) > $maxsysload) {
$this->logger->warning('system load for process too high.', ['load' => $load, 'process' => 'backend', 'maxsysload' => $maxsysload]);
$this->logger->notice('system load for process too high.', ['load' => $load, 'process' => 'backend', 'maxsysload' => $maxsysload]);
return true;
}
}

View File

@@ -141,7 +141,7 @@ class Worker
if (DI::lock()->acquire(self::LOCK_WORKER, 0)) {
// Count active workers and compare them with a maximum value that depends on the load
if (self::tooMuchWorkers()) {
Logger::notice('Active worker limit reached, quitting.');
Logger::info('Active worker limit reached, quitting.');
DI::lock()->release(self::LOCK_WORKER);
return;
}
@@ -188,7 +188,7 @@ class Worker
{
// Count active workers and compare them with a maximum value that depends on the load
if (self::tooMuchWorkers()) {
Logger::notice('Active worker limit reached, quitting.');
Logger::info('Active worker limit reached, quitting.');
return false;
}
@@ -511,7 +511,7 @@ class Worker
while ($load = System::getLoadAvg($processes_cooldown != 0)) {
if (($load_cooldown > 0) && ($load['average1'] > $load_cooldown)) {
if (!$sleeping) {
Logger::notice('Load induced pre execution cooldown.', ['max' => $load_cooldown, 'load' => $load, 'called-by' => System::callstack(1)]);
Logger::info('Load induced pre execution cooldown.', ['max' => $load_cooldown, 'load' => $load, 'called-by' => System::callstack(1)]);
$sleeping = true;
}
sleep(1);
@@ -519,7 +519,7 @@ class Worker
}
if (($processes_cooldown > 0) && ($load['scheduled'] > $processes_cooldown)) {
if (!$sleeping) {
Logger::notice('Process induced pre execution cooldown.', ['max' => $processes_cooldown, 'load' => $load, 'called-by' => System::callstack(1)]);
Logger::info('Process induced pre execution cooldown.', ['max' => $processes_cooldown, 'load' => $load, 'called-by' => System::callstack(1)]);
$sleeping = true;
}
sleep(1);
@@ -529,7 +529,7 @@ class Worker
}
if ($sleeping) {
Logger::notice('Cooldown ended.', ['max-load' => $load_cooldown, 'max-processes' => $processes_cooldown, 'load' => $load, 'called-by' => System::callstack(1)]);
Logger::info('Cooldown ended.', ['max-load' => $load_cooldown, 'max-processes' => $processes_cooldown, 'load' => $load, 'called-by' => System::callstack(1)]);
}
}
@@ -814,7 +814,7 @@ class Worker
}
}
Logger::notice('Load: ' . $load . '/' . $maxsysload . ' - processes: ' . $deferred . '/' . $active . '/' . $waiting_processes . $processlist . ' - maximum: ' . $queues . '/' . $maxqueues);
Logger::info('Load: ' . $load . '/' . $maxsysload . ' - processes: ' . $deferred . '/' . $active . '/' . $waiting_processes . $processlist . ' - maximum: ' . $queues . '/' . $maxqueues);
// Are there fewer workers running as possible? Then fork a new one.
if (!DI::config()->get('system', 'worker_dont_fork', false) && ($queues > ($active + 1)) && self::entriesExists() && !self::systemLimitReached()) {

View File

@@ -382,14 +382,6 @@ abstract class DI
return self::$dice->create(Factory\Api\Mastodon\Error::class);
}
/**
* @return Factory\Api\Mastodon\FollowRequest
*/
public static function mstdnFollowRequest()
{
return self::$dice->create(Factory\Api\Mastodon\FollowRequest::class);
}
/**
* @return Factory\Api\Mastodon\Poll
*/

View File

@@ -1,61 +0,0 @@
<?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\Factory\Api\Mastodon;
use Friendica\App\BaseURL;
use Friendica\BaseFactory;
use Friendica\Contact\Introduction\Entity\Introduction;
use Friendica\Database\DBA;
use Friendica\Model\APContact;
use Friendica\Model\Contact;
use Friendica\Network\HTTPException;
use ImagickException;
use Psr\Log\LoggerInterface;
class FollowRequest extends BaseFactory
{
/** @var BaseURL */
private $baseUrl;
public function __construct(LoggerInterface $logger, BaseURL $baseURL)
{
parent::__construct($logger);
$this->baseUrl = $baseURL;
}
/**
* @param Introduction $introduction
* @return \Friendica\Object\Api\Mastodon\FollowRequest
* @throws ImagickException|HTTPException\InternalServerErrorException
*/
public function createFromIntroduction(Introduction $introduction): \Friendica\Object\Api\Mastodon\FollowRequest
{
$account = DBA::selectFirst('account-user-view', [], ['id' => $introduction->cid, 'uid' => [0, $introduction->uid]]);
if (empty($account)) {
$this->logger->warning('Wrong introduction data', ['Introduction' => $introduction]);
throw new HTTPException\InternalServerErrorException('Wrong introduction data');
}
return new \Friendica\Object\Api\Mastodon\FollowRequest($this->baseUrl, $introduction->id, $account);
}
}

View File

@@ -169,7 +169,7 @@ class APContact
$cachekey = 'apcontact:' . ItemURI::getIdByURI($url);
$result = DI::cache()->get($cachekey);
if (!is_null($result)) {
Logger::notice('Multiple requests for the address', ['url' => $url, 'update' => $update, 'callstack' => System::callstack(20), 'result' => $result]);
Logger::info('Multiple requests for the address', ['url' => $url, 'update' => $update, 'callstack' => System::callstack(20), 'result' => $result]);
if (!empty($fetched_contact)) {
return $fetched_contact;
}

View File

@@ -105,8 +105,10 @@ class FollowRequests extends BaseApi
foreach ($introductions as $key => $introduction) {
try {
self::setBoundaries($introduction->id);
$return[] = DI::mstdnFollowRequest()->createFromIntroduction($introduction);
} catch (HTTPException\InternalServerErrorException $exception) {
$return[] = DI::mstdnAccount()->createFromContactId($introduction->cid, $introduction->uid);
} catch (HTTPException\InternalServerErrorException
| HTTPException\NotFoundException
| \ImagickException $exception) {
DI::intro()->delete($introduction);
unset($introductions[$key]);
}

View File

@@ -80,7 +80,7 @@ class Notify extends BaseModule
$msg = Diaspora::decodeRaw($postdata, '', true);
if (!is_array($msg)) {
// We have to fail silently to be able to hand it over to the salmon parser
$this->logger->warning('Diaspora::decodeRaw() has failed for some reason.');
$this->logger->warning('Diaspora::decodeRaw() has failed for some reason.', ['post-data' => $postdata]);
return false;
}

View File

@@ -282,7 +282,7 @@ class Notification extends BaseRepository
'parent-uri-id' => $itemUriId,
];
$this->logger->notice('deleteForItem', ['conditionTarget' => $conditionTarget, 'conditionParent' => $conditionParent]);
$this->logger->info('deleteForItem', ['conditionTarget' => $conditionTarget, 'conditionParent' => $conditionParent]);
return
$this->db->delete(self::$table_name, $conditionTarget)

View File

@@ -83,7 +83,7 @@ class HttpClient extends BaseFactory
ResponseInterface $response,
UriInterface $uri
) use ($logger) {
$logger->notice('Curl redirect.', ['url' => $request->getUri(), 'to' => $uri, 'method' => $request->getMethod()]);
$logger->info('Curl redirect.', ['url' => $request->getUri(), 'to' => $uri, 'method' => $request->getMethod()]);
};
$userAgent = App::PLATFORM . " '" .

View File

@@ -1,49 +0,0 @@
<?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\Object\Api\Mastodon;
use Friendica\App\BaseURL;
use Friendica\Collection\Api\Mastodon\Fields;
/**
* Virtual entity to separate Accounts from Follow Requests.
* In the Mastodon API they are one and the same.
*/
class FollowRequest extends Account
{
/**
* Creates a follow request entity from an introduction record.
*
* The account ID is set to the Introduction ID to allow for later interaction with follow requests.
*
* @param BaseURL $baseUrl
* @param int $introduction_id Introduction record id
* @param array $account entry of "account-user-view"
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
*/
public function __construct(BaseURL $baseUrl, int $introduction_id, array $account)
{
parent::__construct($baseUrl, $account, new Fields());
$this->id = $introduction_id;
}
}

View File

@@ -534,6 +534,7 @@ class Post
'vote' => $buttons,
'like_html' => $responses['like']['output'],
'dislike_html' => $responses['dislike']['output'],
'emojis' => $this->getEmojis($item),
'responses' => $responses,
'switchcomment' => DI::l10n()->t('Comment'),
'reply_label' => DI::l10n()->t('Reply to %s', $profile_name),
@@ -602,6 +603,70 @@ class Post
return $result;
}
/**
* Fetch emojis
*
* @param array $item
* @return array
*/
private function getEmojis(array $item): array
{
if (empty($item['emojis'])) {
return [];
}
$emojis = [];
foreach ($item['emojis'] as $index => $element) {
$actors = implode(', ', $element['title']);
switch ($element['verb']) {
case Activity::ANNOUNCE:
$title = DI::l10n()->t('Reshared by: %s', $actors);
$icon = ['fa' => 'fa-retweet', 'icon' => 'icon-retweet'];
break;
case Activity::VIEW:
$title = DI::l10n()->t('Viewed by: %s', $actors);
$icon = ['fa' => 'fa-eye', 'icon' => 'icon-eye-open'];
break;
case Activity::LIKE:
$title = DI::l10n()->t('Liked by: %s', $actors);
$icon = ['fa' => 'fa-thumbs-up', 'icon' => 'icon-thumbs-up'];
break;
case Activity::DISLIKE:
$title = DI::l10n()->t('Disliked by: %s', $actors);
$icon = ['fa' => 'fa-thumbs-down', 'icon' => 'icon-thumbs-down'];
break;
case Activity::ATTEND:
$title = DI::l10n()->t('Attended by: %s', $actors);
$icon = ['fa' => 'fa-check', 'icon' => 'icon-ok'];
break;
case Activity::ATTENDMAYBE:
$title = DI::l10n()->t('Maybe attended by: %s', $actors);
$icon = ['fa' => 'fa-question', 'icon' => 'icon-question'];
break;
case Activity::ATTENDNO:
$title = DI::l10n()->t('Not attended by: %s', $actors);
$icon = ['fa' => 'fa-times', 'icon' => 'icon-remove'];
break;
default:
$title = DI::l10n()->t('Reacted with %s by: %s', $element['emoji'], $actors);
$icon = [];
break;
break;
}
$emojis[$index] = ['emoji' => $element['emoji'], 'total' => $element['total'], 'title' => $title, 'icon' => $icon];
}
ksort($emojis);
return $emojis;
}
/**
* @return integer
*/

View File

@@ -505,7 +505,7 @@ class Processor
$recursion_depth = $activity['recursion-depth'] ?? 0;
if (!$in_background && ($recursion_depth < DI::config()->get('system', 'max_recursion_depth'))) {
Logger::notice('Parent not found. Try to refetch it.', ['parent' => $activity['reply-to-id'], 'recursion-depth' => $recursion_depth]);
Logger::info('Parent not found. Try to refetch it.', ['parent' => $activity['reply-to-id'], 'recursion-depth' => $recursion_depth]);
$result = self::fetchMissingActivity($activity['reply-to-id'], $activity, '', Receiver::COMPLETION_AUTO);
if (empty($result) && self::isActivityGone($activity['reply-to-id'])) {
Logger::notice('The activity is gone, the queue entry will be deleted', ['parent' => $activity['reply-to-id']]);
@@ -516,10 +516,10 @@ class Processor
} elseif (!empty($result)) {
$exists = Post::exists(['uri' => [$result, $activity['reply-to-id']]]);
if ($exists) {
Logger::notice('The activity has been fetched and created.', ['parent' => $result]);
Logger::info('The activity has been fetched and created.', ['parent' => $result]);
return $result;
} elseif (DI::config()->get('system', 'fetch_by_worker') || DI::config()->get('system', 'decoupled_receiver')) {
Logger::notice('The activity has been fetched and will hopefully be created later.', ['parent' => $result]);
Logger::info('The activity has been fetched and will hopefully be created later.', ['parent' => $result]);
} else {
Logger::notice('The activity exists but has not been created, the queue entry will be deleted.', ['parent' => $result]);
if (!empty($activity['entry-id'])) {
@@ -1561,11 +1561,11 @@ class Processor
}
if (($completion == Receiver::COMPLETION_RELAY) && Queue::exists($url, 'as:Create')) {
Logger::notice('Activity has already been queued.', ['url' => $url, 'object' => $activity['id']]);
Logger::info('Activity has already been queued.', ['url' => $url, 'object' => $activity['id']]);
} elseif (ActivityPub\Receiver::processActivity($ldactivity, json_encode($activity), $uid, true, false, $signer, '', $completion)) {
Logger::notice('Activity had been fetched and processed.', ['url' => $url, 'entry' => $child['entry-id'] ?? 0, 'completion' => $completion, 'object' => $activity['id']]);
Logger::info('Activity had been fetched and processed.', ['url' => $url, 'entry' => $child['entry-id'] ?? 0, 'completion' => $completion, 'object' => $activity['id']]);
} else {
Logger::notice('Activity had been fetched and will be processed later.', ['url' => $url, 'entry' => $child['entry-id'] ?? 0, 'completion' => $completion, 'object' => $activity['id']]);
Logger::info('Activity had been fetched and will be processed later.', ['url' => $url, 'entry' => $child['entry-id'] ?? 0, 'completion' => $completion, 'object' => $activity['id']]);
}
return $activity['id'];

View File

@@ -792,7 +792,7 @@ class Diaspora
*/
private static function key(WebFingerUri $uri): string
{
Logger::notice('Fetching diaspora key', ['handle' => $uri->getAddr(), 'callstack' => System::callstack(20)]);
Logger::info('Fetching diaspora key', ['handle' => $uri->getAddr(), 'callstack' => System::callstack(20)]);
try {
return DI::dsprContact()->getByAddr($uri)->pubKey;
} catch (HTTPException\NotFoundException|\InvalidArgumentException $e) {

View File

@@ -347,12 +347,13 @@ class HTTPSignature
if (!empty($gsid)) {
$insertFields['gsid'] = $gsid;
}
if (!DBA::insert('inbox-status', $insertFields, Database::INSERT_IGNORE)) {
DBA::insert('inbox-status', $insertFields, Database::INSERT_IGNORE);
$status = DBA::selectFirst('inbox-status', [], ['url' => $url]);
if (empty($status)) {
Logger::warning('Unable to insert inbox-status row', $insertFields);
return;
}
$status = DBA::selectFirst('inbox-status', [], ['url' => $url]);
}
if ($success) {

View File

@@ -69,7 +69,7 @@ class LDSignature
$dhash = self::hash(self::signableData($data));
$x = Crypto::rsaVerify($ohash . $dhash, base64_decode($data['signature']['signatureValue']), $pubkey);
Logger::notice('LD-verify', ['verified' => (int)$x, 'actor' => $profile['url']]);
Logger::info('LD-verify', ['verified' => (int)$x, 'actor' => $profile['url']]);
if (empty($x)) {
return false;