]> git.mxchange.org Git - friendica.git/blobdiff - src/Content/Conversation.php
Merge pull request #12986 from annando/exception
[friendica.git] / src / Content / Conversation.php
index c5e854b1d9ece6a02f55ab98e9238aec0ef4022b..458a0a690f19fe97ed5a481723cc4d9b2340e0fd 100644 (file)
@@ -41,6 +41,7 @@ use Friendica\Model\Post;
 use Friendica\Model\Tag;
 use Friendica\Model\User;
 use Friendica\Model\Verb;
+use Friendica\Network\HTTPException\InternalServerErrorException;
 use Friendica\Object\Post as PostObject;
 use Friendica\Object\Thread;
 use Friendica\Protocol\Activity;
@@ -193,6 +194,52 @@ class Conversation
                }
        }
 
+       /**
+        * Returns the liker phrase based on a list of likers
+        *
+        * @param string $verb   the activity verb
+        * @param array  $likers a list of likers
+        *
+        * @return string the liker phrase
+        *
+        * @throws InternalServerErrorException in case either the verb is invalid or the list of likers is empty
+        */
+       private function getLikerPhrase(string $verb, array $likers): string
+       {
+               $total = count($likers);
+
+               if ($total === 0) {
+                       throw new InternalServerErrorException(sprintf('There has to be at least one Liker for verb "%s"', $verb));
+               } else if ($total === 1) {
+                       $likerString = $likers[0];
+               } else {
+                       if ($total < $this->config->get('system', 'max_likers')) {
+                               $likerString = implode(', ', array_slice($likers, 0, -1));
+                               $likerString .= ' ' . $this->l10n->t('and') . ' ' . $likers[count($likers) - 1];
+                       } else {
+                               $likerString = implode(', ', array_slice($likers, 0, $this->config->get('system', 'max_likers') - 1));
+                               $likerString .= ' ' . $this->l10n->t('and %d other people', $total - $this->config->get('system', 'max_likers'));
+                       }
+               }
+
+               switch ($verb) {
+                       case 'like':
+                               return $this->l10n->tt('%2$s likes this.', '%2$s like this.', $total, $likerString);
+                       case 'dislike':
+                               return $this->l10n->tt('%2$s doesn\'t like this.', '%2$s don\'t like this.', $total, $likerString);
+                       case 'attendyes':
+                               return $this->l10n->tt('%2$s attends.', '%2$s attend.', $total, $likerString);
+                       case 'attendno':
+                               return $this->l10n->tt('%2$s doesn\'t attend.', '%2$s don\'t attend.', $total, $likerString);
+                       case 'attendmaybe':
+                               return $this->l10n->tt('%2$s attends maybe.', '%2$s attend maybe.', $total, $likerString);
+                       case 'announce':
+                               return $this->l10n->tt('%2$s reshared this.', '%2$s reshared this.', $total, $likerString);
+                       default:
+                               throw new InternalServerErrorException(sprintf('Unknown verb "%s"', $verb));
+               }
+       }
+
        /**
         * Format the activity text for an item/photo/video
         *
@@ -205,87 +252,48 @@ class Conversation
        public function formatActivity(array $links, string $verb, int $id): string
        {
                $this->profiler->startRecording('rendering');
-               $o        = '';
                $expanded = '';
-               $phrase   = '';
 
-               $total = count($links);
-               if ($total == 1) {
-                       $likers = $links[0];
+               $phrase = $this->getLikerPhrase($verb, $links);
+               $total  = count($links);
 
-                       // Phrase if there is only one liker. In other cases it will be uses for the expanded
-                       // list which show all likers
-                       switch ($verb) {
-                               case 'like':
-                                       $phrase = $this->l10n->t('%s likes this.', $likers);
-                                       break;
-                               case 'dislike':
-                                       $phrase = $this->l10n->t('%s doesn\'t like this.', $likers);
-                                       break;
-                               case 'attendyes':
-                                       $phrase = $this->l10n->t('%s attends.', $likers);
-                                       break;
-                               case 'attendno':
-                                       $phrase = $this->l10n->t('%s doesn\'t attend.', $likers);
-                                       break;
-                               case 'attendmaybe':
-                                       $phrase = $this->l10n->t('%s attends maybe.', $likers);
-                                       break;
-                               case 'announce':
-                                       $phrase = $this->l10n->t('%s reshared this.', $likers);
-                                       break;
-                       }
-               } elseif ($total > 1) {
-                       if ($total < $this->config->get('system', 'max_likers')) {
-                               $likers = implode(', ', array_slice($links, 0, -1));
-                               $likers .= ' ' . $this->l10n->t('and') . ' ' . $links[count($links) - 1];
-                       } else {
-                               $likers = implode(', ', array_slice($links, 0, $this->config->get('system', 'max_likers') - 1));
-                               $likers .= ' ' . $this->l10n->t('and %d other people', $total - $this->config->get('system', 'max_likers'));
-                       }
+               if ($total > 1) {
+                       $spanatts  = "class=\"btn btn-link fakelink\" onclick=\"openClose('{$verb}list-$id');\"";
+                       $explikers = $phrase;
 
-                       $spanatts = "class=\"btn btn-link fakelink\" onclick=\"openClose('{$verb}list-$id');\"";
-
-                       $explikers = '';
                        switch ($verb) {
                                case 'like':
-                                       $phrase    = $this->l10n->t('<button type="button" %1$s>%2$d people</button> like this', $spanatts, $total);
-                                       $explikers = $this->l10n->t('%s like this.', $likers);
+                                       $phrase = $this->l10n->tt('<button type="button" %2$s>%1$d person</button> likes this', '<button type="button" %2$s>%1$d people</button> like this', $total, $spanatts);
                                        break;
                                case 'dislike':
-                                       $phrase    = $this->l10n->t('<button type="button" %1$s>%2$d people</button> don\'t like this', $spanatts, $total);
-                                       $explikers = $this->l10n->t('%s don\'t like this.', $likers);
+                                       $phrase = $this->l10n->tt('<button type="button" %2$s>%1$d person</button> doesn\'t like this', '<button type="button" %2$s>%1$d peiple</button> don\'t like this', $total, $spanatts);
                                        break;
                                case 'attendyes':
-                                       $phrase    = $this->l10n->t('<button type="button" %1$s>%2$d people</button> attend', $spanatts, $total);
-                                       $explikers = $this->l10n->t('%s attend.', $likers);
+                                       $phrase = $this->l10n->tt('<button type="button" %2$s>%1$d person</button> attends', '<button type="button" %2$s>%1$d people</button> attend', $total, $spanatts);
                                        break;
                                case 'attendno':
-                                       $phrase    = $this->l10n->t('<button type="button" %1$s>%2$d people</button> don\'t attend', $spanatts, $total);
-                                       $explikers = $this->l10n->t('%s don\'t attend.', $likers);
+                                       $phrase = $this->l10n->tt('<button type="button" %2$s>%1$d person</button> doesn\'t attend','<button type="button" %2$s>%1$d people</button> don\'t attend', $total, $spanatts);
                                        break;
                                case 'attendmaybe':
-                                       $phrase    = $this->l10n->t('<button type="button" %1$s>%2$d people</button> attend maybe', $spanatts, $total);
-                                       $explikers = $this->l10n->t('%s attend maybe.', $likers);
+                                       $phrase = $this->l10n->tt('<button type="button" %2$s>%1$d person</button> attends maybe', '<button type="button" %2$s>%1$d people</button> attend maybe', $total, $spanatts);
                                        break;
                                case 'announce':
-                                       $phrase    = $this->l10n->t('<button type="button" %1$s>%2$d people</button> reshared this', $spanatts, $total);
-                                       $explikers = $this->l10n->t('%s reshared this.', $likers);
+                                       $phrase = $this->l10n->tt('<button type="button" %2$s>%1$d person</button> reshared this', '<button type="button" %2$s>%1$d people</button> reshared this', $total, $spanatts);
                                        break;
                        }
 
                        $expanded .= "\t" . '<p class="wall-item-' . $verb . '-expanded" id="' . $verb . 'list-' . $id . '" style="display: none;" >' . $explikers . '</p>';
                }
 
-               $o .= Renderer::replaceMacros(Renderer::getMarkupTemplate('voting_fakelink.tpl'), [
+               $output = Renderer::replaceMacros(Renderer::getMarkupTemplate('voting_fakelink.tpl'), [
                        '$phrase' => $phrase,
                        '$type'   => $verb,
                        '$id'     => $id
                ]);
-               $o .= $expanded;
+               $output .= $expanded;
 
                $this->profiler->stopRecording();
-               return $o;
+               return $output;
        }
 
        public function statusEditor(array $x = [], int $notes_cid = 0, bool $popup = false): string
@@ -314,7 +322,7 @@ class Conversation
                $tpl = Renderer::getMarkupTemplate('jot-header.tpl');
                $this->page['htmlhead'] .= Renderer::replaceMacros($tpl, [
                        '$newpost'   => 'true',
-                       '$baseurl'   => $this->baseURL->get(true),
+                       '$baseurl'   => $this->baseURL,
                        '$geotag'    => $geotag,
                        '$nickname'  => $x['nickname'],
                        '$ispublic'  => $this->l10n->t('Visible to <strong>everybody</strong>'),
@@ -385,7 +393,7 @@ class Conversation
                        '$posttype'     => $notes_cid ? ItemModel::PT_PERSONAL_NOTE : ItemModel::PT_ARTICLE,
                        '$content'      => $x['content'] ?? '',
                        '$post_id'      => $x['post_id'] ?? '',
-                       '$baseurl'      => $this->baseURL->get(true),
+                       '$baseurl'      => $this->baseURL,
                        '$defloc'       => $x['default_location'],
                        '$visitor'      => $x['visitor'],
                        '$pvisit'       => $notes_cid ? 'none' : $x['visitor'],
@@ -446,8 +454,6 @@ class Conversation
                $this->page->registerStylesheet(Theme::getPathForFile('js/friendica-tagsinput/friendica-tagsinput.css'));
                $this->page->registerStylesheet(Theme::getPathForFile('js/friendica-tagsinput/friendica-tagsinput-typeahead.css'));
 
-               $ssl_state = (bool)$this->session->getLocalUserId();
-
                $live_update_div = '';
 
                $blocklist = $this->getBlocklist();
@@ -784,7 +790,7 @@ class Conversation
                }
 
                $o = Renderer::replaceMacros($page_template, [
-                       '$baseurl'     => $this->baseURL->get($ssl_state),
+                       '$baseurl'     => $this->baseURL,
                        '$return_path' => $this->args->getQueryString(),
                        '$live_update' => $live_update_div,
                        '$remove'      => $this->l10n->t('remove'),
@@ -979,9 +985,16 @@ 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)]);
 
+               $condition = DBA::mergeConditions($condition, ["(`uid` != ? OR `private` != ?)", 0, ItemModel::PRIVATE]);
+
                $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` = ?)",
@@ -1081,6 +1094,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 +1117,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']][$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'])));
+               }
+               DBA::close($rows);
+
+               return $emojis;
+       }
+
        /**
         * Plucks the children of the given parent from a given item list.
         *
@@ -1308,7 +1370,7 @@ class Conversation
                        }
                }
 
-               /// @TODO: Stop recusrsively adding all children back to the top level (!!!)
+               /// @TODO: Stop recursively adding all children back to the top level (!!!)
                /// However, this apparently ensures responses (likes, attendance) display (?!)
                foreach ($parents as $parent) {
                        if (count($parent['children'])) {