From 6ecc9c4cba30b22a5104f693010493aea8541fa0 Mon Sep 17 00:00:00 2001 From: Hypolite Petovan Date: Sat, 12 Aug 2023 10:11:10 +0200 Subject: [PATCH] Implement ignored server block in conversations - Add server ignore status in contact profile page - Add new reason in DisplayNotFound exception page --- src/Content/Conversation.php | 65 +++++++++++++------- src/DI.php | 9 +++ src/Model/Item.php | 4 +- src/Model/Post.php | 10 ++- src/Model/Post/UserNotification.php | 11 +++- src/Module/Contact/Profile.php | 20 ++++-- src/Module/Conversation/Community.php | 2 +- src/Module/Special/DisplayNotFound.php | 1 + src/User/Settings/Repository/UserGServer.php | 14 ++++- view/theme/frio/templates/contact_edit.tpl | 1 + 10 files changed, 96 insertions(+), 41 deletions(-) diff --git a/src/Content/Conversation.php b/src/Content/Conversation.php index caaaf21d11..151a2bfc7e 100644 --- a/src/Content/Conversation.php +++ b/src/Content/Conversation.php @@ -45,6 +45,8 @@ use Friendica\Network\HTTPException\InternalServerErrorException; use Friendica\Object\Post as PostObject; use Friendica\Object\Thread; use Friendica\Protocol\Activity; +use Friendica\User\Settings\Entity\UserGServer; +use Friendica\User\Settings\Repository; use Friendica\Util\Crypto; use Friendica\Util\DateTimeFormat; use Friendica\Util\Profiler; @@ -90,22 +92,25 @@ class Conversation private $mode; /** @var IHandleUserSessions */ private $session; + /** @var Repository\UserGServer */ + private $userGServer; - public function __construct(LoggerInterface $logger, Profiler $profiler, Activity $activity, L10n $l10n, Item $item, Arguments $args, BaseURL $baseURL, IManageConfigValues $config, IManagePersonalConfigValues $pConfig, App\Page $page, App\Mode $mode, App $app, IHandleUserSessions $session) + public function __construct(Repository\UserGServer $userGServer, LoggerInterface $logger, Profiler $profiler, Activity $activity, L10n $l10n, Item $item, Arguments $args, BaseURL $baseURL, IManageConfigValues $config, IManagePersonalConfigValues $pConfig, App\Page $page, App\Mode $mode, App $app, IHandleUserSessions $session) { - $this->activity = $activity; - $this->item = $item; - $this->config = $config; - $this->mode = $mode; - $this->baseURL = $baseURL; - $this->profiler = $profiler; - $this->logger = $logger; - $this->l10n = $l10n; - $this->args = $args; - $this->pConfig = $pConfig; - $this->page = $page; - $this->app = $app; - $this->session = $session; + $this->activity = $activity; + $this->item = $item; + $this->config = $config; + $this->mode = $mode; + $this->baseURL = $baseURL; + $this->profiler = $profiler; + $this->logger = $logger; + $this->l10n = $l10n; + $this->args = $args; + $this->pConfig = $pConfig; + $this->page = $page; + $this->app = $app; + $this->session = $session; + $this->userGServer = $userGServer; } /** @@ -459,8 +464,14 @@ class Conversation $live_update_div = ''; + $userGservers = $this->userGServer->listIgnoredByUser($this->session->getLocalUserId()); + + $ignoredGsids = array_map(function (UserGServer $userGServer) { + return $userGServer->gsid; + }, $userGservers->getArrayCopy()); + if ($mode === self::MODE_NETWORK) { - $items = $this->addChildren($items, false, $order, $uid, $mode); + $items = $this->addChildren($items, false, $order, $uid, $mode, $ignoredGsids); if (!$update) { /* * The special div is needed for liveUpdate to kick in for this page. @@ -486,7 +497,7 @@ class Conversation . "'; \r\n"; } } elseif ($mode === self::MODE_PROFILE) { - $items = $this->addChildren($items, false, $order, $uid, $mode); + $items = $this->addChildren($items, false, $order, $uid, $mode, $ignoredGsids); if (!$update) { $tab = !empty($_GET['tab']) ? trim($_GET['tab']) : 'posts'; @@ -511,7 +522,7 @@ class Conversation . "; var netargs = '?f='; \r\n"; } } elseif ($mode === self::MODE_DISPLAY) { - $items = $this->addChildren($items, false, $order, $uid, $mode); + $items = $this->addChildren($items, false, $order, $uid, $mode, $ignoredGsids); if (!$update) { $live_update_div = '
' . "\r\n" @@ -519,7 +530,7 @@ class Conversation . ""; } } elseif ($mode === self::MODE_COMMUNITY) { - $items = $this->addChildren($items, true, $order, $uid, $mode); + $items = $this->addChildren($items, true, $order, $uid, $mode, $ignoredGsids); if (!$update) { $live_update_div = '
' . "\r\n" @@ -530,7 +541,7 @@ class Conversation . "'; \r\n"; } } elseif ($mode === self::MODE_CONTACTS) { - $items = $this->addChildren($items, false, $order, $uid, $mode); + $items = $this->addChildren($items, false, $order, $uid, $mode, $ignoredGsids); if (!$update) { $live_update_div = '
' . "\r\n" @@ -812,13 +823,14 @@ class Conversation * * @param array $parents Parent items * @param bool $block_authors - * @param bool $order + * @param string $order Either "received" or "commented" * @param int $uid - * @param string $mode + * @param string $mode One of self::MODE_* + * @param array $ignoredGsids List of ids of servers ignored by the user * @return array items with parents and comments - * @throws \Friendica\Network\HTTPException\InternalServerErrorException + * @throws InternalServerErrorException */ - private function addChildren(array $parents, bool $block_authors, string $order, int $uid, string $mode): array + private function addChildren(array $parents, bool $block_authors, string $order, int $uid, string $mode, array $ignoredGsids = []): array { $this->profiler->startRecording('rendering'); if (count($parents) > 1) { @@ -900,6 +912,13 @@ class Conversation continue; } + if (in_array($row['author-gsid'], $ignoredGsids) + || in_array($row['owner-gsid'], $ignoredGsids) + || in_array($row['causer-gsid'], $ignoredGsids) + ) { + continue; + } + if (($mode != self::MODE_CONTACTS) && !$row['origin']) { $row['featured'] = false; } diff --git a/src/DI.php b/src/DI.php index 34cf1c68d5..2d6eb6ede4 100644 --- a/src/DI.php +++ b/src/DI.php @@ -671,6 +671,15 @@ abstract class DI return self::$dice->create(Security\Authentication::class); } + // + // "User" namespace instances + // + + public static function userGServer(): User\Settings\Repository\UserGServer + { + return self::$dice->create(User\Settings\Repository\UserGServer::class); + } + // // "Util" namespace instances // diff --git a/src/Model/Item.php b/src/Model/Item.php index a2304056d3..cf039da3ab 100644 --- a/src/Model/Item.php +++ b/src/Model/Item.php @@ -96,8 +96,8 @@ class Item 'content-warning', 'location', 'coord', 'app', 'rendered-hash', 'rendered-html', 'object', 'quote-uri', 'quote-uri-id', 'allow_cid', 'allow_gid', 'deny_cid', 'deny_gid', 'mention', 'global', 'author-id', 'author-link', 'author-alias', 'author-name', 'author-avatar', 'author-network', 'author-updated', 'author-gsid', 'author-addr', 'author-uri-id', - 'owner-id', 'owner-link', 'owner-alias', 'owner-name', 'owner-avatar', 'owner-network', 'owner-contact-type', 'owner-updated', - 'causer-id', 'causer-link', 'causer-alias', 'causer-name', 'causer-avatar', 'causer-contact-type', 'causer-network', + 'owner-id', 'owner-link', 'owner-alias', 'owner-name', 'owner-avatar', 'owner-network', 'owner-contact-type', 'owner-updated', 'owner-gsid', + 'causer-id', 'causer-link', 'causer-alias', 'causer-name', 'causer-avatar', 'causer-contact-type', 'causer-network', 'causer-gsid', 'contact-id', 'contact-uid', 'contact-link', 'contact-name', 'contact-avatar', 'writable', 'self', 'cid', 'alias', 'event-created', 'event-edited', 'event-start', 'event-finish', diff --git a/src/Model/Post.php b/src/Model/Post.php index 770ab08317..6f855867f6 100644 --- a/src/Model/Post.php +++ b/src/Model/Post.php @@ -453,12 +453,10 @@ class Post AND (NOT `causer-blocked` OR `causer-id` = ? OR `causer-id` IS NULL) AND NOT `contact-blocked` AND ((NOT `contact-readonly` AND NOT `contact-pending` AND (`contact-rel` IN (?, ?))) OR `self` OR `contact-uid` = ?) - AND NOT `" . $view . "`.`uri-id` IN (SELECT `uri-id` FROM `post-user` WHERE `uid` = ? AND `hidden`) - AND NOT `author-id` IN (SELECT `cid` FROM `user-contact` WHERE `uid` = ? AND `blocked` AND `cid` = `author-id`) - AND NOT `owner-id` IN (SELECT `cid` FROM `user-contact` WHERE `uid` = ? AND `blocked` AND `cid` = `owner-id`) - AND NOT `author-id` IN (SELECT `cid` FROM `user-contact` WHERE `uid` = ? AND `ignored` AND `cid` = `author-id`) - AND NOT `owner-id` IN (SELECT `cid` FROM `user-contact` WHERE `uid` = ? AND `ignored` AND `cid` = `owner-id`)", - 0, Contact::SHARING, Contact::FRIEND, 0, $uid, $uid, $uid, $uid, $uid]); + AND NOT EXISTS(SELECT `uri-id` FROM `post-user` WHERE `uid` = ? AND `uri-id` = " . DBA::quoteIdentifier($view) . ".`uri-id` AND `hidden`) + AND NOT EXISTS(SELECT `cid` FROM `user-contact` WHERE `uid` = ? AND `cid` IN (`author-id`, `owner-id`) AND (`blocked` OR `ignored`)) + AND NOT EXISTS(SELECT `gsid` FROM `user-gserver` WHERE `uid` = ? AND `gsid` IN (`author-gsid`, `owner-gsid`, `causer-gsid`) AND `ignored`)", + 0, Contact::SHARING, Contact::FRIEND, 0, $uid, $uid, $uid]); $select_string = implode(', ', array_map([DBA::class, 'quoteIdentifier'], $selected)); diff --git a/src/Model/Post/UserNotification.php b/src/Model/Post/UserNotification.php index 012a49dbf5..726e82d7e0 100644 --- a/src/Model/Post/UserNotification.php +++ b/src/Model/Post/UserNotification.php @@ -133,14 +133,14 @@ class UserNotification public static function setNotification(int $uri_id, int $uid) { $fields = ['id', 'uri-id', 'parent-uri-id', 'uid', 'body', 'parent', 'gravity', 'vid', 'gravity', - 'contact-id', 'author-id', 'owner-id', 'causer-id', + 'contact-id', 'author-id', 'author-gsid', 'owner-id', 'owner-gsid', 'causer-id', 'causer-gsid', 'private', 'thr-parent', 'thr-parent-id', 'parent-uri-id', 'parent-uri', 'verb']; $item = Post::selectFirst($fields, ['uri-id' => $uri_id, 'uid' => $uid, 'origin' => false]); if (!DBA::isResult($item)) { return; } - $parent = Post::selectFirstPost(['author-id', 'owner-id', 'causer-id'], ['uri-id' => $item['parent-uri-id']]); + $parent = Post::selectFirstPost(['author-id', 'author-gsid', 'owner-id', 'owner-gsid', 'causer-id', 'causer-gsid',], ['uri-id' => $item['parent-uri-id']]); if (!DBA::isResult($parent)) { return; } @@ -195,6 +195,13 @@ class UserNotification } } + foreach (array_unique([$parent['author-gsid'], $parent['owner-gsid'], $parent['causer-gsid'], $item['author-gsid'], $item['owner-gsid'], $item['causer-gsid']]) as $gsid) { + if ($gsid && DI::userGServer()->isIgnoredByUser($uid, $gsid)) { + Logger::debug('Server is ignored by user', ['uid' => $uid, 'gsid' => $gsid, 'uri-id' => $item['uri-id']]); + return; + } + } + $user = User::getById($uid, ['account-type', 'account_removed', 'account_expired']); if (in_array($user['account-type'], [User::ACCOUNT_TYPE_COMMUNITY, User::ACCOUNT_TYPE_RELAY])) { return; diff --git a/src/Module/Contact/Profile.php b/src/Module/Contact/Profile.php index 11e3990439..399198062b 100644 --- a/src/Module/Contact/Profile.php +++ b/src/Module/Contact/Profile.php @@ -23,8 +23,7 @@ namespace Friendica\Module\Contact; use Friendica\App; use Friendica\BaseModule; -use Friendica\Contact\LocalRelationship\Entity; -use Friendica\Contact\LocalRelationship\Repository; +use Friendica\Contact\LocalRelationship; use Friendica\Content\ContactSelector; use Friendica\Content\Nav; use Friendica\Content\Text\BBCode; @@ -43,6 +42,7 @@ use Friendica\Module; use Friendica\Module\Response; use Friendica\Navigation\SystemMessages; use Friendica\Network\HTTPException; +use Friendica\User\Settings; use Friendica\Util\DateTimeFormat; use Friendica\Util\Profiler; use Psr\Log\LoggerInterface; @@ -64,8 +64,10 @@ class Profile extends BaseModule private $systemMessages; /** @var Database */ private $db; + /** @var Settings\Repository\UserGServer */ + private $userGServer; - public function __construct(Database $db, SystemMessages $systemMessages, IHandleUserSessions $session, L10n $l10n, Repository\LocalRelationship $localRelationship, App\BaseURL $baseUrl, App\Arguments $args, LoggerInterface $logger, Profiler $profiler, Response $response, App\Page $page, IManageConfigValues $config, array $server, array $parameters = []) + public function __construct(Settings\Repository\UserGServer $userGServer, Database $db, SystemMessages $systemMessages, IHandleUserSessions $session, L10n $l10n, LocalRelationship\Repository\LocalRelationship $localRelationship, App\BaseURL $baseUrl, App\Arguments $args, LoggerInterface $logger, Profiler $profiler, Response $response, App\Page $page, IManageConfigValues $config, array $server, array $parameters = []) { parent::__construct($l10n, $baseUrl, $args, $logger, $profiler, $response, $server, $parameters); @@ -75,6 +77,7 @@ class Profile extends BaseModule $this->session = $session; $this->systemMessages = $systemMessages; $this->db = $db; + $this->userGServer = $userGServer; } protected function post(array $request = []) @@ -264,6 +267,11 @@ class Profile extends BaseModule $insecure = $this->t('Private communications are not available for this contact.'); + $serverIgnored = + $this->userGServer->isIgnoredByUser($this->session->getLocalUserId(), $contact['gsid']) ? + $this->t('This contact is on a server you ignored.') + : ''; + $last_update = (($contact['last-update'] <= DBA::NULL_DATETIME) ? $this->t('Never') : DateTimeFormat::local($contact['last-update'], 'D, j M Y, g:i A')); if ($contact['last-update'] > DBA::NULL_DATETIME) { @@ -368,6 +376,8 @@ class Profile extends BaseModule '$collapsed' => $localRelationship->collapsed ? $this->t('Currently collapsed') : '', '$archived' => ($contact['archive'] ? $this->t('Currently archived') : ''), '$insecure' => (in_array($contact['network'], [Protocol::ACTIVITYPUB, Protocol::DFRN, Protocol::MAIL, Protocol::DIASPORA]) ? '' : $insecure), + '$serverIgnored' => $serverIgnored, + '$manageServers' => $this->t('Manage remote servers'), '$cinfo' => ['info', '', $localRelationship->info, ''], '$hidden' => ['hidden', $this->t('Hide this contact from others'), $localRelationship->hidden, $this->t('Replies/likes to your public posts may 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')], @@ -418,11 +428,11 @@ class Profile extends BaseModule * This includes actions like e.g. 'block', 'hide', 'delete' and others * * @param array $contact Public contact row - * @param Entity\LocalRelationship $localRelationship + * @param LocalRelationship\Entity\LocalRelationship $localRelationship * @return array with contact related actions * @throws HTTPException\InternalServerErrorException */ - private function getContactActions(array $contact, Entity\LocalRelationship $localRelationship): array + private function getContactActions(array $contact, LocalRelationship\Entity\LocalRelationship $localRelationship): array { $poll_enabled = in_array($contact['network'], [Protocol::ACTIVITYPUB, Protocol::DFRN, Protocol::OSTATUS, Protocol::FEED, Protocol::MAIL]); $contact_actions = []; diff --git a/src/Module/Conversation/Community.php b/src/Module/Conversation/Community.php index 7525ba1c16..3c3bbb8a83 100644 --- a/src/Module/Conversation/Community.php +++ b/src/Module/Conversation/Community.php @@ -356,7 +356,7 @@ class Community extends BaseModule } } - $r = Post::selectThreadForUser(0, ['uri-id', 'commented', 'author-link'], $condition, $params); + $r = Post::selectThreadForUser(DI::userSession()->getLocalUserId() ?: 0, ['uri-id', 'commented', 'author-link'], $condition, $params); $items = Post::toArray($r); if (empty($items)) { diff --git a/src/Module/Special/DisplayNotFound.php b/src/Module/Special/DisplayNotFound.php index 009c3241f9..293f40aa06 100644 --- a/src/Module/Special/DisplayNotFound.php +++ b/src/Module/Special/DisplayNotFound.php @@ -36,6 +36,7 @@ class DisplayNotFound extends \Friendica\BaseModule $this->t('The top-level post was deleted.'), $this->t('This node has blocked the top-level author or the author of the shared post.'), $this->t('You have ignored or blocked the top-level author or the author of the shared post.'), + $this->t("You have ignored the top-level author's server or the shared post author's server."), ]; $tpl = Renderer::getMarkupTemplate('special/displaynotfound.tpl'); diff --git a/src/User/Settings/Repository/UserGServer.php b/src/User/Settings/Repository/UserGServer.php index d7a0b3c27b..baf70095ce 100644 --- a/src/User/Settings/Repository/UserGServer.php +++ b/src/User/Settings/Repository/UserGServer.php @@ -102,6 +102,11 @@ class UserGServer extends \Friendica\BaseRepository return $this->count(['uid' => $uid]); } + public function isIgnoredByUser(int $uid, int $gsid): bool + { + return $this->exists(['uid' => $uid, 'gsid' => $gsid, 'ignored' => 1]); + } + /** * @param Entity\UserGServer $userGServer * @return bool @@ -132,15 +137,20 @@ class UserGServer extends \Friendica\BaseRepository * @return Collection\UserGServers * @throws Exception */ - protected function _select(array $condition, array $params = []): BaseCollection + protected function _select(array $condition, array $params = [], bool $hydrate = true): BaseCollection { $rows = $this->db->selectToArray(static::$table_name, [], $condition, $params); $Entities = new Collection\UserGServers(); foreach ($rows as $fields) { - $Entities[] = $this->factory->createFromTableRow($fields, $this->gserverRepository->selectOneById($fields['gsid'])); + $Entities[] = $this->factory->createFromTableRow($fields, $hydrate ? $this->gserverRepository->selectOneById($fields['gsid']) : null); } return $Entities; } + + public function listIgnoredByUser(int $uid): Collection\UserGServers + { + return $this->_select(['uid' => $uid, 'ignored' => 1], [], false); + } } diff --git a/view/theme/frio/templates/contact_edit.tpl b/view/theme/frio/templates/contact_edit.tpl index 6b17da17f1..56459df718 100644 --- a/view/theme/frio/templates/contact_edit.tpl +++ b/view/theme/frio/templates/contact_edit.tpl @@ -61,6 +61,7 @@ {{if $ignored}}
  • {{$ignored}}
  • {{/if}} {{if $collapsed}}
  • {{$collapsed}}
  • {{/if}} {{if $archived}}
  • {{$archived}}
  • {{/if}} + {{if $serverIgnored}}
  • {{$serverIgnored}} {{$manageServers}}
  • {{/if}} {{* End of contact-edit-status-wrapper *}} -- 2.39.5