diff --git a/mod/item.php b/mod/item.php index c1740c274f..13ffe75683 100644 --- a/mod/item.php +++ b/mod/item.php @@ -29,6 +29,7 @@ */ use Friendica\App; +use Friendica\Content\Conversation; use Friendica\Content\Text\BBCode; use Friendica\Core\Hook; use Friendica\Core\Logger; @@ -274,7 +275,7 @@ function item_process(array $post, array $request, bool $preview, string $return $post['body'] = BBCode::removeSharedData(Item::setHashtags($post['body'])); $post['writable'] = true; - $o = DI::conversation()->create([$post], 'search', false, true); + $o = DI::conversation()->create([$post], Conversation::MODE_SEARCH, false, true); System::jsonExit(['preview' => $o]); } diff --git a/mod/notes.php b/mod/notes.php index 00a74eecad..360441471f 100644 --- a/mod/notes.php +++ b/mod/notes.php @@ -20,6 +20,7 @@ */ use Friendica\App; +use Friendica\Content\Conversation; use Friendica\Content\Nav; use Friendica\Content\Pager; use Friendica\Database\DBA; @@ -84,7 +85,7 @@ function notes_content(App $a, bool $update = false) $count = count($notes); - $o .= DI::conversation()->create($notes, 'notes', $update); + $o .= DI::conversation()->create($notes, Conversation::MODE_NOTES, $update); } $o .= $pager->renderMinimal($count); diff --git a/src/Content/Conversation.php b/src/Content/Conversation.php index f391bbb4ac..c5e854b1d9 100644 --- a/src/Content/Conversation.php +++ b/src/Content/Conversation.php @@ -53,6 +53,16 @@ use Psr\Log\LoggerInterface; class Conversation { + const MODE_COMMUNITY = 'community'; + const MODE_CONTACTS = 'contacts'; + const MODE_CONTACT_POSTS = 'contact-posts'; + const MODE_DISPLAY = 'display'; + const MODE_FILED = 'filed'; + const MODE_NETWORK = 'network'; + const MODE_NOTES = 'notes'; + const MODE_SEARCH = 'search'; + const MODE_PROFILE = 'profile'; + /** @var Activity */ private $activity; /** @var L10n */ @@ -444,7 +454,7 @@ class Conversation $previewing = (($preview) ? ' preview ' : ''); - if ($mode === 'network') { + if ($mode === self::MODE_NETWORK) { $items = $this->addChildren($items, false, $order, $uid, $mode); if (!$update) { /* @@ -470,7 +480,7 @@ class Conversation . "'; \r\n"; } - } elseif ($mode === 'profile') { + } elseif ($mode === self::MODE_PROFILE) { $items = $this->addChildren($items, false, $order, $uid, $mode); if (!$update) { @@ -487,7 +497,7 @@ class Conversation . "; var netargs = '?f='; \r\n"; } } - } elseif ($mode === 'notes') { + } elseif ($mode === self::MODE_NOTES) { $items = $this->addChildren($items, false, $order, $this->session->getLocalUserId(), $mode); if (!$update) { @@ -495,7 +505,7 @@ class Conversation . "\r\n"; } - } elseif ($mode === 'display') { + } elseif ($mode === self::MODE_DISPLAY) { $items = $this->addChildren($items, false, $order, $uid, $mode); if (!$update) { @@ -503,7 +513,7 @@ class Conversation . ""; } - } elseif ($mode === 'community') { + } elseif ($mode === self::MODE_COMMUNITY) { $items = $this->addChildren($items, true, $order, $uid, $mode); if (!$update) { @@ -514,7 +524,7 @@ class Conversation . (!empty($_GET['accounttype']) ? '&accounttype=' . rawurlencode($_GET['accounttype']) : '') . "'; \r\n"; } - } elseif ($mode === 'contacts') { + } elseif ($mode === self::MODE_CONTACTS) { $items = $this->addChildren($items, false, $order, $uid, $mode); if (!$update) { @@ -522,11 +532,11 @@ class Conversation . "\r\n"; } - } elseif ($mode === 'search') { + } elseif ($mode === self::MODE_SEARCH) { $live_update_div = '
' . "\r\n"; } - $page_dropping = $this->session->getLocalUserId() && $this->session->getLocalUserId() == $uid && $mode != 'search'; + $page_dropping = $this->session->getLocalUserId() && $this->session->getLocalUserId() == $uid && $mode != self::MODE_SEARCH; if (!$update) { $_SESSION['return_path'] = $this->args->getQueryString(); @@ -558,7 +568,7 @@ class Conversation $formSecurityToken = BaseModule::getFormSecurityToken('contact_action'); if (!empty($items)) { - if (in_array($mode, ['community', 'contacts', 'profile'])) { + if (in_array($mode, [self::MODE_COMMUNITY, self::MODE_CONTACTS, self::MODE_PROFILE])) { $writable = true; } else { $writable = $items[0]['writable'] || ($items[0]['uid'] == 0) && in_array($items[0]['network'], Protocol::FEDERATED); @@ -568,7 +578,7 @@ class Conversation $writable = false; } - if (in_array($mode, ['filed', 'search', 'contact-posts'])) { + if (in_array($mode, [self::MODE_FILED, self::MODE_SEARCH, self::MODE_CONTACT_POSTS])) { /* * "New Item View" on network page or search page results @@ -621,7 +631,7 @@ class Conversation $location_html = $locate['html'] ?: Strings::escapeHtml($locate['location'] ?: $locate['coord'] ?: ''); $this->item->localize($item); - if ($mode === 'filed') { + if ($mode === self::MODE_FILED) { $dropping = true; } else { $dropping = false; @@ -972,6 +982,11 @@ class Conversation $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)]); + $condition = DBA::mergeConditions($condition, + ["`visible` AND NOT `deleted` AND NOT `author-blocked` AND NOT `owner-blocked` + AND ((NOT `contact-pending` AND (`contact-rel` IN (?, ?))) OR `self` OR `contact-uid` = ?)", + Contact::SHARING, Contact::FRIEND, 0]); + $thread_parents = Post::select(['uri-id', 'causer-id'], $condition, ['order' => ['uri-id' => false, 'uid']]); $thr_parent = []; @@ -983,17 +998,18 @@ class Conversation $params = ['order' => ['uri-id' => true, 'uid' => true]]; - $thread_items = Post::selectForUser($uid, array_merge(ItemModel::DISPLAY_FIELDLIST, ['featured', 'contact-uid', 'gravity', 'post-type', 'post-reason']), $condition, $params); + $thread_items = Post::select(array_merge(ItemModel::DISPLAY_FIELDLIST, ['featured', 'contact-uid', 'gravity', 'post-type', 'post-reason']), $condition, $params); $items = []; $quote_uri_ids = []; + $authors = []; while ($row = Post::fetch($thread_items)) { if (!empty($items[$row['uri-id']]) && ($row['uid'] == 0)) { continue; } - if (($mode != 'contacts') && !$row['origin']) { + if (($mode != self::MODE_CONTACTS) && !$row['origin']) { $row['featured'] = false; } @@ -1006,6 +1022,9 @@ class Conversation } } + $authors[] = $row['author-id']; + $authors[] = $row['owner-id']; + if (in_array($row['gravity'], [ItemModel::GRAVITY_PARENT, ItemModel::GRAVITY_COMMENT])) { $quote_uri_ids[$row['uri-id']] = [ 'uri-id' => $row['uri-id'], @@ -1033,10 +1052,50 @@ class Conversation $row['thr-parent'] = $quote_uri_ids[$quote['quote-uri-id']]['uri']; $row['thr-parent-id'] = $quote_uri_ids[$quote['quote-uri-id']]['uri-id']; + $authors[] = $row['author-id']; + $authors[] = $row['owner-id']; + $items[$row['uri-id']] = $this->addRowInformation($row, [], []); } DBA::close($quotes); + $authors = array_unique($authors); + + $blocks = []; + $ignores = []; + $collapses = []; + if (!empty($authors)) { + $usercontacts = DBA::select('user-contact', ['cid', 'blocked', 'ignored', 'collapsed'], ['uid' => $uid, 'cid' => $authors]); + while ($usercontact = DBA::fetch($usercontacts)) { + if ($usercontact['blocked']) { + $blocks[] = $usercontact['cid']; + } + if ($usercontact['ignored']) { + $ignores[] = $usercontact['cid']; + } + if ($usercontact['collapsed']) { + $collapses[] = $usercontact['cid']; + } + } + DBA::close($usercontacts); + } + + foreach ($items as $key => $row) { + $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); + $items[$key]['user-ignored-author'] = !$always_display && in_array($row['author-id'], $ignores); + $items[$key]['user-blocked-owner'] = !$always_display && in_array($row['owner-id'], $blocks); + $items[$key]['user-ignored-owner'] = !$always_display && in_array($row['owner-id'], $ignores); + $items[$key]['user-collapsed-author'] = !$always_display && in_array($row['author-id'], $collapses); + $items[$key]['user-collapsed-owner'] = !$always_display && in_array($row['owner-id'], $collapses); + + if (in_array($mode, [self::MODE_COMMUNITY, self::MODE_NETWORK]) && + (in_array($row['author-id'], $blocks) || in_array($row['owner-id'], $blocks) || in_array($row['author-id'], $ignores) || in_array($row['owner-id'], $ignores))) { + unset($items[$key]); + } + } + $items = $this->convSort($items, $order); $this->profiler->stopRecording(); diff --git a/src/Model/Contact.php b/src/Model/Contact.php index e30e695420..a16d55976c 100644 --- a/src/Model/Contact.php +++ b/src/Model/Contact.php @@ -23,6 +23,7 @@ namespace Friendica\Model; use Friendica\Contact\Avatar; use Friendica\Contact\Introduction\Exception\IntroductionNotFoundException; +use Friendica\Content\Conversation; use Friendica\Content\Pager; use Friendica\Content\Text\HTML; use Friendica\Core\Hook; @@ -1609,7 +1610,7 @@ class Contact } } - $o .= DI::conversation()->create($items, 'contacts', $update, false, 'pinned_commented', DI::userSession()->getLocalUserId()); + $o .= DI::conversation()->create($items, Conversation::MODE_CONTACTS, $update, false, 'pinned_commented', DI::userSession()->getLocalUserId()); } else { $fields = array_merge(Item::DISPLAY_FIELDLIST, ['featured']); $items = Post::toArray(Post::selectForUser(DI::userSession()->getLocalUserId(), $fields, $condition, $params)); @@ -1624,7 +1625,7 @@ class Contact } } - $o .= DI::conversation()->create($items, 'contact-posts', $update); + $o .= DI::conversation()->create($items, Conversation::MODE_CONTACT_POSTS, $update); } if (!$update) { diff --git a/src/Model/Item.php b/src/Model/Item.php index 4eafd28475..05ff10273c 100644 --- a/src/Model/Item.php +++ b/src/Model/Item.php @@ -623,10 +623,6 @@ class Item return false; } - if (!empty($item['uid']) && !self::isAllowedByUser($item, $item['uid'])) { - return false; - } - if ($item['verb'] == Activity::FOLLOW) { if (!$item['origin'] && ($item['author-id'] == Contact::getPublicIdByUserId($item['uid']))) { // Our own follow request can be relayed to us. We don't store it to avoid notification chaos. @@ -988,13 +984,6 @@ class Item return 0; } - // If the thread originated from this node, we check the permission against the thread starter - $condition = ['uri-id' => $toplevel_parent['uri-id'], 'wall' => true]; - $localTopLevelParent = Post::selectFirst(['uid'], $condition); - if (!empty($localTopLevelParent['uid']) && !self::isAllowedByUser($item, $localTopLevelParent['uid'])) { - return 0; - } - $parent_id = $toplevel_parent['id']; $item['parent-uri'] = $toplevel_parent['uri']; $item['parent-uri-id'] = $toplevel_parent['uri-id']; @@ -3065,7 +3054,11 @@ class Item // Compile eventual content filter reasons $filter_reasons = []; if (!$is_preview && DI::userSession()->getPublicContactId() != $item['author-id']) { - if (Contact\User::isCollapsed($item['author-id'], $item['uid'])) { + if (!empty($item['user-blocked-author']) || !empty($item['user-blocked-owner'])) { + $filter_reasons[] = DI::l10n()->t('%s is blocked', $item['author-name']); + } elseif (!empty($item['user-ignored-author']) || !empty($item['user-ignored-owner'])) { + $filter_reasons[] = DI::l10n()->t('%s is ignored', $item['author-name']); + } elseif (!empty($item['user-collapsed-author']) || !empty($item['user-collapsed-owner'])) { $filter_reasons[] = DI::l10n()->t('Content from %s is collapsed', $item['author-name']); } @@ -3706,53 +3699,6 @@ class Item return 0; } - /** - * Check a prospective item array against user-level permissions - * - * @param array $item Expected keys: uri, gravity, and - * author-link if is author-id is set, - * owner-link if is owner-id is set, - * causer-link if is causer-id is set. - * @param int $user_id Local user ID - * @return bool - * @throws \Exception - */ - protected static function isAllowedByUser(array $item, int $user_id): bool - { - if (!empty($item['author-id']) && Contact\User::isBlocked($item['author-id'], $user_id)) { - Logger::notice('Author is blocked by user', ['author-link' => $item['author-link'], 'uid' => $user_id, 'item-uri' => $item['uri']]); - return false; - } - - if (!empty($item['owner-id']) && Contact\User::isBlocked($item['owner-id'], $user_id)) { - Logger::notice('Owner is blocked by user', ['owner-link' => $item['owner-link'], 'uid' => $user_id, 'item-uri' => $item['uri']]); - return false; - } - - // The causer is set during a thread completion, for example because of a reshare. It countains the responsible actor. - if (!empty($item['causer-id']) && Contact\User::isBlocked($item['causer-id'], $user_id)) { - Logger::notice('Causer is blocked by user', ['causer-link' => $item['causer-link'] ?? $item['causer-id'], 'uid' => $user_id, 'item-uri' => $item['uri']]); - return false; - } - - if (!empty($item['author-id']) && Contact\User::isIgnored($item['author-id'], $user_id)) { - Logger::notice('Author is ignored by user', ['author-link' => $item['author-link'], 'uid' => $user_id, 'item-uri' => $item['uri']]); - return false; - } - - if (!empty($item['owner-id']) && Contact\User::isIgnored($item['owner-id'], $user_id)) { - Logger::notice('Owner is ignored by user', ['owner-link' => $item['owner-link'], 'uid' => $user_id, 'item-uri' => $item['uri']]); - return false; - } - - if (!empty($item['causer-id']) && Contact\User::isIgnored($item['causer-id'], $user_id)) { - Logger::notice('Causer is ignored by user', ['causer-link' => $item['causer-link'] ?? $item['causer-id'], 'uid' => $user_id, 'item-uri' => $item['uri']]); - return false; - } - - return true; - } - /** * Fetch the uri-id of a quote * diff --git a/src/Module/Conversation/Community.php b/src/Module/Conversation/Community.php index 63cde443ae..818943733a 100644 --- a/src/Module/Conversation/Community.php +++ b/src/Module/Conversation/Community.php @@ -24,6 +24,7 @@ namespace Friendica\Module\Conversation; use Friendica\BaseModule; use Friendica\Content\BoundariesPager; +use Friendica\Content\Conversation; use Friendica\Content\Feature; use Friendica\Content\Nav; use Friendica\Content\Text\HTML; @@ -156,7 +157,7 @@ class Community extends BaseModule return $o; } - $o .= DI::conversation()->create($items, 'community', false, false, 'commented', DI::userSession()->getLocalUserId()); + $o .= DI::conversation()->create($items, Conversation::MODE_COMMUNITY, false, false, 'commented', DI::userSession()->getLocalUserId()); $pager = new BoundariesPager( DI::l10n(), diff --git a/src/Module/Conversation/Network.php b/src/Module/Conversation/Network.php index 6670e7bb86..84d08ff9c2 100644 --- a/src/Module/Conversation/Network.php +++ b/src/Module/Conversation/Network.php @@ -23,6 +23,7 @@ namespace Friendica\Module\Conversation; use Friendica\BaseModule; use Friendica\Content\BoundariesPager; +use Friendica\Content\Conversation; use Friendica\Content\ForumManager; use Friendica\Content\Nav; use Friendica\Content\Widget; @@ -200,7 +201,7 @@ class Network extends BaseModule $ordering = '`commented`'; } - $o .= DI::conversation()->create($items, 'network', false, false, $ordering, DI::userSession()->getLocalUserId()); + $o .= DI::conversation()->create($items, Conversation::MODE_NETWORK, false, false, $ordering, DI::userSession()->getLocalUserId()); if (DI::pConfig()->get(DI::userSession()->getLocalUserId(), 'system', 'infinite_scroll')) { $o .= HTML::scrollLoader(); diff --git a/src/Module/Item/Display.php b/src/Module/Item/Display.php index ad2ed6850e..a97c9db830 100644 --- a/src/Module/Item/Display.php +++ b/src/Module/Item/Display.php @@ -278,7 +278,7 @@ class Display extends BaseModule $output .= $this->conversation->statusEditor([], 0, true); } - $output .= $this->conversation->create([$item], 'display', $updateUid, false, 'commented', $itemUid); + $output .= $this->conversation->create([$item], Conversation::MODE_DISPLAY, $updateUid, false, 'commented', $itemUid); return $output; } diff --git a/src/Module/Profile/Conversations.php b/src/Module/Profile/Conversations.php index 322cdc80eb..715bf45d3d 100644 --- a/src/Module/Profile/Conversations.php +++ b/src/Module/Profile/Conversations.php @@ -240,7 +240,7 @@ class Conversations extends BaseProfile $items = array_merge($items, $pinned); } - $o .= $this->conversation->create($items, 'profile', false, false, 'pinned_received', $profile['uid']); + $o .= $this->conversation->create($items, Conversation::MODE_PROFILE, false, false, 'pinned_received', $profile['uid']); $o .= $pager->renderMinimal(count($items)); diff --git a/src/Module/Search/Filed.php b/src/Module/Search/Filed.php index 90a3c53f79..4661a58664 100644 --- a/src/Module/Search/Filed.php +++ b/src/Module/Search/Filed.php @@ -21,6 +21,7 @@ namespace Friendica\Module\Search; +use Friendica\Content\Conversation; use Friendica\Content\Nav; use Friendica\Content\Pager; use Friendica\Content\Text\HTML; @@ -98,7 +99,7 @@ class Filed extends BaseSearch $items = Post::toArray(Post::selectForUser(DI::userSession()->getLocalUserId(), Item::DISPLAY_FIELDLIST, $item_condition, $item_params)); - $o .= DI::conversation()->create($items, 'filed', false, false, '', DI::userSession()->getLocalUserId()); + $o .= DI::conversation()->create($items, Conversation::MODE_FILED, false, false, '', DI::userSession()->getLocalUserId()); if (DI::pConfig()->get(DI::userSession()->getLocalUserId(), 'system', 'infinite_scroll')) { $o .= HTML::scrollLoader(); diff --git a/src/Module/Search/Index.php b/src/Module/Search/Index.php index cd35d803a6..d1cd5f40d3 100644 --- a/src/Module/Search/Index.php +++ b/src/Module/Search/Index.php @@ -22,6 +22,7 @@ namespace Friendica\Module\Search; use Friendica\App; +use Friendica\Content\Conversation; use Friendica\Content\Nav; use Friendica\Content\Pager; use Friendica\Content\Text\HTML; @@ -212,7 +213,7 @@ class Index extends BaseSearch Logger::info('Start Conversation.', ['q' => $search]); - $o .= DI::conversation()->create($items, 'search', false, false, 'commented', DI::userSession()->getLocalUserId()); + $o .= DI::conversation()->create($items, Conversation::MODE_SEARCH, false, false, 'commented', DI::userSession()->getLocalUserId()); if (DI::pConfig()->get(DI::userSession()->getLocalUserId(), 'system', 'infinite_scroll')) { $o .= HTML::scrollLoader(); diff --git a/src/Module/Update/Community.php b/src/Module/Update/Community.php index 5b8e479fbf..1ac241e55a 100644 --- a/src/Module/Update/Community.php +++ b/src/Module/Update/Community.php @@ -22,6 +22,7 @@ namespace Friendica\Module\Update; +use Friendica\Content\Conversation; use Friendica\Core\System; use Friendica\DI; use Friendica\Module\Conversation\Community as CommunityModule; @@ -39,7 +40,7 @@ class Community extends CommunityModule $o = ''; if (!empty($request['force'])) { - $o = DI::conversation()->create(self::getItems(), 'community', true, false, 'commented', DI::userSession()->getLocalUserId()); + $o = DI::conversation()->create(self::getItems(), Conversation::MODE_COMMUNITY, true, false, 'commented', DI::userSession()->getLocalUserId()); } System::htmlUpdateExit($o); diff --git a/src/Module/Update/Network.php b/src/Module/Update/Network.php index 2119631565..052ae040f0 100644 --- a/src/Module/Update/Network.php +++ b/src/Module/Update/Network.php @@ -21,6 +21,7 @@ namespace Friendica\Module\Update; +use Friendica\Content\Conversation; use Friendica\Core\System; use Friendica\DI; use Friendica\Model\Item; @@ -78,7 +79,7 @@ class Network extends NetworkModule $ordering = '`commented`'; } - $o = DI::conversation()->create($items, 'network', $profile_uid, false, $ordering, DI::userSession()->getLocalUserId()); + $o = DI::conversation()->create($items, Conversation::MODE_NETWORK, $profile_uid, false, $ordering, DI::userSession()->getLocalUserId()); System::htmlUpdateExit($o); } diff --git a/src/Module/Update/Profile.php b/src/Module/Update/Profile.php index 80d3b51891..53406e195f 100644 --- a/src/Module/Update/Profile.php +++ b/src/Module/Update/Profile.php @@ -22,6 +22,7 @@ namespace Friendica\Module\Update; use Friendica\BaseModule; +use Friendica\Content\Conversation; use Friendica\Core\System; use Friendica\Database\DBA; use Friendica\DI; @@ -115,7 +116,7 @@ class Profile extends BaseModule } } - $o .= DI::conversation()->create($items, 'profile', $a->getProfileOwner(), false, 'received', $a->getProfileOwner()); + $o .= DI::conversation()->create($items, Conversation::MODE_PROFILE, $a->getProfileOwner(), false, 'received', $a->getProfileOwner()); System::htmlUpdateExit($o); }