X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=src%2FContent%2FConversation.php;h=6edef06fc65c56b0b4b7d49a00c753b21b351277;hb=ddd2c72be8e7245389f97d74dd847f5a20410936;hp=710422ee762cc162e411b8dd496a4c8e751fb2c3;hpb=fd055193ac47948c4245453fe4e0f01c9f9ed7eb;p=friendica.git diff --git a/src/Content/Conversation.php b/src/Content/Conversation.php index 710422ee76..6edef06fc6 100644 --- a/src/Content/Conversation.php +++ b/src/Content/Conversation.php @@ -1,6 +1,6 @@ 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; } /** @@ -244,19 +251,21 @@ class Conversation /** * Format the activity text for an item/photo/video * - * @param array $links = array of pre-linked names of actors - * @param string $verb = one of 'like, 'dislike', 'attendyes', 'attendno', 'attendmaybe' - * @param int $id = item id + * @param array $links array of pre-linked names of actors + * @param string $verb one of 'like, 'dislike', 'attendyes', 'attendno', 'attendmaybe' + * @param int $id item id + * @param string $activity Activity URI + * @param array $emojis Array with emoji reactions * @return string formatted text * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ - public function formatActivity(array $links, string $verb, int $id): string + public function formatActivity(array $links, string $verb, int $id, string $activity, array $emojis): string { $this->profiler->startRecording('rendering'); $expanded = ''; $phrase = $this->getLikerPhrase($verb, $links); - $total = count($links); + $total = max(count($links), $emojis[$activity]['total'] ?? 0); if ($total > 1) { $spanatts = "class=\"btn btn-link fakelink\" onclick=\"openClose('{$verb}list-$id');\""; @@ -459,8 +468,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. @@ -482,11 +497,13 @@ class Conversation . (!empty($_GET['cmin']) ? '&cmin=' . rawurlencode($_GET['cmin']) : '') . (!empty($_GET['cmax']) ? '&cmax=' . rawurlencode($_GET['cmax']) : '') . (!empty($_GET['file']) ? '&file=' . rawurlencode($_GET['file']) : '') - + . (!empty($_GET['channel']) ? '&channel=' . rawurlencode($_GET['channel']) : '') + . (!empty($_GET['no_sharer']) ? '&no_sharer=' . rawurlencode($_GET['no_sharer']) : '') + . (!empty($_GET['accounttype']) ? '&accounttype=' . rawurlencode($_GET['accounttype']) : '') . "'; \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,15 +528,26 @@ 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" . ""; } + } elseif ($mode === self::MODE_CHANNEL) { + $items = $this->addChildren($items, true, $order, $uid, $mode, $ignoredGsids); + + if (!$update) { + $live_update_div = '
' . "\r\n" + . "\r\n"; + } } 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 +558,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" @@ -541,7 +569,7 @@ class Conversation $live_update_div = '' . "\r\n"; } - $page_dropping = $this->session->getLocalUserId() && $this->session->getLocalUserId() == $uid && $mode != self::MODE_SEARCH; + $page_dropping = $this->session->getLocalUserId() && $this->pConfig->get($this->session->getLocalUserId(), 'system', 'show_page_drop', true) && ($this->session->getLocalUserId() == $uid && $mode != self::MODE_SEARCH); if (!$update) { $_SESSION['return_path'] = $this->args->getQueryString(); @@ -609,7 +637,7 @@ class Conversation unset($conv_responses['dislike']); } - if (in_array($mode, [self::MODE_COMMUNITY, self::MODE_CONTACTS, self::MODE_PROFILE])) { + if (in_array($mode, [self::MODE_CHANNEL, 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); @@ -628,10 +656,6 @@ class Conversation * But for now, this array respects the old style, just in case */ foreach ($items as $item) { - if (in_array($item['author-id'], $this->getBlocklist())) { - continue; - } - // Can we put this after the visibility check? $this->builtinActivityPuller($item, $conv_responses); @@ -666,29 +690,6 @@ class Conversation return $threads; } - private function getBlocklist(): array - { - if (!$this->session->getLocalUserId()) { - return []; - } - - $str_blocked = str_replace(["\n", "\r"], ",", $this->pConfig->get($this->session->getLocalUserId(), 'system', 'blocked') ?? ''); - if (empty($str_blocked)) { - return []; - } - - $blocklist = []; - - foreach (explode(',', $str_blocked) as $entry) { - $cid = Contact::getIdForURL(trim($entry), 0, false); - if (!empty($cid)) { - $blocklist[] = $cid; - } - } - - return $blocklist; - } - /** * Adds some information (Causer, post reason, direction) to the fetched post row. * @@ -743,7 +744,12 @@ class Conversation $row['direction'] = ['direction' => 6, 'title' => $this->l10n->t('You are following %s.', $row['causer-name'] ?: $row['author-name'])]; break; case ItemModel::PR_TAG: - $row['direction'] = ['direction' => 4, 'title' => $this->l10n->t('You subscribed to one or more tags in this post.')]; + $tags = Category::getArrayByURIId($row['uri-id'], $row['uid'], Category::SUBCRIPTION); + if (!empty($tags)) { + $row['direction'] = ['direction' => 4, 'title' => $this->l10n->t('You subscribed to %s.', implode(', ', $tags))]; + } else { + $row['direction'] = ['direction' => 4, 'title' => $this->l10n->t('You subscribed to one or more tags in this post.')]; + } break; case ItemModel::PR_ANNOUNCEMENT: if (!empty($row['causer-id']) && $this->pConfig->get($this->session->getLocalUserId(), 'system', 'display_resharer')) { @@ -812,13 +818,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) { @@ -857,14 +864,17 @@ class Conversation $condition['author-hidden'] = false; } - if ($this->config->get('system', 'emoji_activities')) { - $emojis = $this->getEmojis($uriids); + $emojis = $this->getEmojis($uriids); + $quoteshares = $this->getQuoteShares($uriids); + $counts = $this->getCounts($uriids); + + if (!$this->config->get('system', 'legacy_activities')) { $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)] + ["`uid` IN (0, ?) AND (NOT `verb` IN (?, ?, ?) OR `verb` IS NULL)", $uid, Activity::FOLLOW, Activity::VIEW, Activity::READ] ); $condition = DBA::mergeConditions($condition, ["(`uid` != ? OR `private` != ?)", 0, ItemModel::PRIVATE]); @@ -900,6 +910,14 @@ 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; } @@ -972,7 +990,9 @@ class Conversation } foreach ($items as $key => $row) { - $items[$key]['emojis'] = $emojis[$key] ?? []; + $items[$key]['emojis'] = $emojis[$key] ?? []; + $items[$key]['counts'] = $counts[$key] ?? 0; + $items[$key]['quoteshares'] = $quoteshares[$key] ?? []; $always_display = in_array($mode, [self::MODE_CONTACTS, self::MODE_CONTACT_POSTS]); @@ -984,7 +1004,7 @@ class Conversation $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($mode, [self::MODE_CHANNEL, 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]); @@ -1005,6 +1025,16 @@ class Conversation */ private function getEmojis(array $uriids): array { + $emojis = []; + + foreach (Post\Counts::get(['parent-uri-id' => $uriids]) as $count) { + $emojis[$count['uri-id']][$count['reaction']]['emoji'] = $count['reaction']; + $emojis[$count['uri-id']][$count['reaction']]['verb'] = Verb::getByID($count['vid']); + $emojis[$count['uri-id']][$count['reaction']]['total'] = $count['count']; + $emojis[$count['uri-id']][$count['reaction']]['title'] = []; + } + + // @todo The following code should be removed, once that we display activity authors on demand $activity_emoji = [ Activity::LIKE => '👍', Activity::DISLIKE => '👎', @@ -1013,37 +1043,74 @@ class Conversation Activity::ATTENDNO => '❌', Activity::ANNOUNCE => '♻', Activity::VIEW => '📺', + Activity::READ => '📖', ]; - $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`"]); + $verbs = array_merge(array_keys($activity_emoji), [Activity::EMOJIREACT, Activity::POST]); + $condition = DBA::mergeConditions(['parent-uri-id' => $uriids, 'gravity' => [ItemModel::GRAVITY_ACTIVITY, ItemModel::GRAVITY_COMMENT], '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 = []; + $sql = "SELECT `parent-uri-id`, `thr-parent-id`, `body`, `verb`, `gravity`, GROUP_CONCAT(REPLACE(`author-name`, '" . $separator . "', ' ') SEPARATOR '" . $separator . "' LIMIT 50) AS `title` FROM `post-view` WHERE " . array_shift($condition) . " GROUP BY `parent-uri-id`, `thr-parent-id`, `verb`, `body`, `gravity`"; $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; + if ($row['gravity'] == ItemModel::GRAVITY_ACTIVITY) { + $emoji = $row['body'] ?: $activity_emoji[$row['verb']]; + } else { + $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']][$index]['total'] ?? 0) + $row['total']; - $emojis[$row['thr-parent-id']][$index]['title'] = array_unique(array_merge($emojis[$row['thr-parent-id']][$index]['title'] ?? [], explode($separator, $row['title']))); + if (isset($emojis[$row['thr-parent-id']][$emoji]['title'])) { + $emojis[$row['thr-parent-id']][$emoji]['title'] = array_unique(array_merge($emojis[$row['thr-parent-id']][$emoji]['title'] ?? [], explode($separator, $row['title']))); + } } DBA::close($rows); return $emojis; } + /** + * Fetch comment counts from the conversation + * + * @param array $uriids + * @return array + */ + private function getCounts(array $uriids): array + { + $counts = []; + + foreach (Post\Counts::get(['parent-uri-id' => $uriids, 'verb' => Activity::POST]) as $count) { + $counts[$count['parent-uri-id']] = ($counts[$count['parent-uri-id']] ?? 0) + $count['count']; + } + + return $counts; + } + + /** + * Fetch quote shares from the conversation + * + * @param array $uriids + * @return array + */ + private function getQuoteShares(array $uriids): array + { + $condition = DBA::mergeConditions(['quote-uri-id' => $uriids], ["NOT `quote-uri-id` IS NULL"]); + $separator = chr(255) . chr(255) . chr(255); + + $sql = "SELECT `quote-uri-id`, COUNT(*) AS `total`, GROUP_CONCAT(REPLACE(`name`, '" . $separator . "', ' ') SEPARATOR '" . $separator . "' LIMIT 50) AS `title` FROM `post-content` INNER JOIN `post` ON `post`.`uri-id` = `post-content`.`uri-id` INNER JOIN `contact` ON `post`.`author-id` = `contact`.`id` WHERE " . array_shift($condition) . " GROUP BY `quote-uri-id`"; + + $quotes = []; + + $rows = DBA::p($sql, $condition); + while ($row = DBA::fetch($rows)) { + $quotes[$row['quote-uri-id']]['total'] = $row['total']; + $quotes[$row['quote-uri-id']]['title'] = array_unique(explode($separator, $row['title'])); + } + DBA::close($rows); + + return $quotes; + } + /** * Plucks the children of the given parent from a given item list. * @@ -1199,16 +1266,10 @@ class Conversation return $parents; } - $blocklist = $this->getBlocklist(); - $item_array = []; // Dedupes the item list on the uri to prevent infinite loops foreach ($item_list as $item) { - if (in_array($item['author-id'], $blocklist)) { - continue; - } - $item_array[$item['uri-id']] = $item; } @@ -1223,6 +1284,8 @@ class Conversation usort($parents, [$this, 'sortThrFeaturedReceived']); } elseif (stristr($order, 'pinned_commented')) { usort($parents, [$this, 'sortThrFeaturedCommented']); + } elseif (stristr($order, 'pinned_created')) { + usort($parents, [$this, 'sortThrFeaturedCreated']); } elseif (stristr($order, 'received')) { usort($parents, [$this, 'sortThrReceived']); } elseif (stristr($order, 'commented')) { @@ -1300,6 +1363,24 @@ class Conversation return strcmp($b['commented'], $a['commented']); } + /** + * usort() callback to sort item arrays by featured and the created key + * + * @param array $a + * @param array $b + * @return int + */ + private function sortThrFeaturedCreated(array $a, array $b): int + { + if ($b['featured'] && !$a['featured']) { + return 1; + } elseif (!$b['featured'] && $a['featured']) { + return -1; + } + + return strcmp($b['created'], $a['created']); + } + /** * usort() callback to sort item arrays by the received key * @@ -1377,10 +1458,6 @@ class Conversation continue; } - if (in_array($item['author-id'], $this->getBlocklist())) { - continue; - } - // prevent private email from leaking. if ($item['network'] === Protocol::MAIL && $this->session->getLocalUserId() != $item['uid']) { continue; @@ -1462,6 +1539,7 @@ class Conversation 'received' => $item['received'], 'created_date' => $item['created'], 'uriid' => $item['uri-id'], + 'author_gsid' => $item['author-gsid'], 'network' => $item['network'], 'network_name' => ContactSelector::networkToName($item['author-network'], $item['author-link'], $item['network'], $item['author-gsid']), 'network_icon' => ContactSelector::networkToIcon($item['network'], $item['author-link'], $item['author-gsid']),