use Friendica\DI;
use Friendica\Model\Contact;
use Friendica\Model\Item;
-use Friendica\Model\Photo;
use Friendica\Model\Post as PostModel;
use Friendica\Model\Tag;
use Friendica\Model\User;
use Friendica\Protocol\Activity;
use Friendica\Util\Crypto;
use Friendica\Util\DateTimeFormat;
-use Friendica\Util\Proxy;
use Friendica\Util\Strings;
use Friendica\Util\Temporal;
+use GuzzleHttp\Psr7\Uri;
use InvalidArgumentException;
/**
}
$this->writable = $this->getDataValue('writable') || $this->getDataValue('self');
- $author = ['uid' => 0, 'id' => $this->getDataValue('author-id'),
+ $author = [
+ 'uid' => 0,
+ 'id' => $this->getDataValue('author-id'),
'network' => $this->getDataValue('author-network'),
- 'url' => $this->getDataValue('author-link')];
+ 'url' => $this->getDataValue('author-link'),
+ 'alias' => $this->getDataValue('author-alias')
+ ];
$this->redirect_url = Contact::magicLinkByContact($author);
if (!$this->isToplevel()) {
$this->threaded = true;
/**
* Get data in a form usable by a conversation template
*
- * @param array $conv_responses conversation responses
- * @param string $formSecurityToken A security Token to avoid CSF attacks
- * @param integer $thread_level default = 1
+ * @param array $conv_responses conversation responses
+ * @param string $formSecurityToken A security Token to avoid CSF attacks
+ * @param integer $thread_level default = 1
+ * @param array $thread_parent Array of parent guid and parent author names
*
* @return mixed The data requested on success, false on failure
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
* @throws \ImagickException
*/
- public function getTemplateData(array $conv_responses, string $formSecurityToken, int $thread_level = 1)
+ public function getTemplateData(array $conv_responses, string $formSecurityToken, int $thread_level = 1, array $thread_parent = [])
{
$item = $this->getData();
$edited = false;
$lock = ($item['private'] == Item::PRIVATE) ? $privacy : false;
$connector = !in_array($item['network'], Protocol::NATIVE_SUPPORT) ? DI::l10n()->t('Connector Message') : false;
- $shareable = in_array($conv->getProfileOwner(), [0, DI::userSession()->getLocalUserId()]) && $item['private'] != Item::PRIVATE;
- $announceable = $shareable && in_array($item['network'], [Protocol::ACTIVITYPUB, Protocol::DFRN, Protocol::DIASPORA, Protocol::TWITTER]);
+ $shareable = in_array($conv->getProfileOwner(), [0, DI::userSession()->getLocalUserId()]) && $item['private'] != Item::PRIVATE;
+ $announceable = $shareable && in_array($item['network'], [Protocol::ACTIVITYPUB, Protocol::DFRN, Protocol::DIASPORA, Protocol::TWITTER, Protocol::TUMBLR, Protocol::BLUESKY]);
+ $commentable = ($item['network'] != Protocol::TUMBLR);
// On Diaspora only toplevel posts can be reshared
if ($announceable && ($item['network'] == Protocol::DIASPORA) && ($item['gravity'] != Item::GRAVITY_PARENT)) {
$pinned = DI::l10n()->t('Pinned item');
}
- // Showing the one or the other text, depending upon if we can only hide it or really delete it.
- $delete = $origin ? DI::l10n()->t('Delete globally') : DI::l10n()->t('Remove locally');
-
- $drop = false;
- $block = false;
- $ignore = false;
+ $drop = false;
+ $block = false;
+ $ignore = false;
+ $collapse = false;
+ $report = false;
+ $ignoreServer = false;
if (DI::userSession()->getLocalUserId()) {
$drop = [
'dropping' => $dropping,
'pagedrop' => $item['pagedrop'],
'select' => DI::l10n()->t('Select'),
- 'delete' => $delete,
+ 'label' => $origin ? DI::l10n()->t('Delete globally') : DI::l10n()->t('Remove locally'),
];
}
if (!$item['self'] && DI::userSession()->getLocalUserId()) {
$block = [
'blocking' => true,
- 'block' => DI::l10n()->t('Block %s', $item['author-name']),
+ 'label' => DI::l10n()->t('Block %s', $item['author-name']),
'author_id' => $item['author-id'],
];
$ignore = [
'ignoring' => true,
- 'ignore' => DI::l10n()->t('Ignore %s', $item['author-name']),
+ 'label' => DI::l10n()->t('Ignore %s', $item['author-name']),
'author_id' => $item['author-id'],
];
+ $collapse = [
+ 'collapsing' => true,
+ 'label' => DI::l10n()->t('Collapse %s', $item['author-name']),
+ 'author_id' => $item['author-id'],
+ ];
+ $report = [
+ 'label' => DI::l10n()->t('Report post'),
+ 'href' => 'moderation/report/create?' . http_build_query(['cid' => $item['author-id'], 'uri-ids' => [$item['uri-id']]]),
+ ];
+ $authorBaseUri = new Uri($item['author-baseurl'] ?? '');
+ if ($authorBaseUri->getHost() && !DI::baseUrl()->isLocalUrl($authorBaseUri)) {
+ $ignoreServer = [
+ 'label' => DI::l10n()->t("Ignore %s server", $authorBaseUri->getHost()),
+ ];
+ }
}
$filer = DI::userSession()->getLocalUserId() ? DI::l10n()->t('Save to folder') : false;
}
if (DI::userSession()->isAuthenticated()) {
- $author = ['uid' => 0, 'id' => $item['author-id'],
- 'network' => $item['author-network'], 'url' => $item['author-link']];
+ $author = [
+ 'uid' => 0,
+ 'id' => $item['author-id'],
+ 'network' => $item['author-network'],
+ 'url' => $item['author-link'],
+ 'alias' => $item['author-alias'],
+ ];
$profile_link = Contact::magicLinkByContact($author);
} else {
$profile_link = $item['author-link'];
$location_html = $locate['html'] ?: Strings::escapeHtml($locate['location'] ?: $locate['coord'] ?: '');
// process action responses - e.g. like/dislike/attend/agree/whatever
- $response_verbs = ['like', 'dislike', 'announce'];
+ $response_verbs = ['like', 'dislike', 'announce', 'comment'];
$isevent = false;
$attend = [];
}
}
+ $emojis = $this->getEmojis($item);
+
+ $verbs = [
+ 'like' => Activity::LIKE,
+ 'dislike' => Activity::DISLIKE,
+ 'announce' => Activity::ANNOUNCE,
+ 'comment' => Activity::POST,
+ 'attendyes' => Activity::ATTEND,
+ 'attendno' => Activity::ATTENDNO,
+ 'attendmaybe' => Activity::ATTENDMAYBE,
+ ];
+ $reactions = $emojis;
$responses = [];
foreach ($response_verbs as $value => $verb) {
$responses[$verb] = [
'self' => $conv_responses[$verb][$item['uri-id']]['self'] ?? 0,
- 'output' => !empty($conv_responses[$verb][$item['uri-id']]) ? DI::conversation()->formatActivity($conv_responses[$verb][$item['uri-id']]['links'], $verb, $item['uri-id']) : '',
+ 'output' => !empty($conv_responses[$verb][$item['uri-id']]) ? DI::conversation()->formatActivity($conv_responses[$verb][$item['uri-id']]['links'], $verb, $item['uri-id'], $verbs[$verb], $emojis) : '',
+ 'total' => $emojis[$verbs[$verb]]['total'] ?? '',
+ 'title' => $emojis[$verbs[$verb]]['title'] ?? '',
];
+ unset($reactions[$verbs[$verb]]);
}
+ unset($emojis[Activity::POST]);
+
/*
* We should avoid doing this all the time, but it depends on the conversation mode
* And the conv mode may change when we change the conv, or it changes its mode
}
if ($conv->isWritable()) {
- $buttons['like'] = [DI::l10n()->t("I like this \x28toggle\x29") , DI::l10n()->t('Like')];
+ $buttons['like'] = [DI::l10n()->t("I like this \x28toggle\x29"), DI::l10n()->t('Like')];
$buttons['dislike'] = [DI::l10n()->t("I don't like this \x28toggle\x29"), DI::l10n()->t('Dislike')];
if ($shareable) {
$buttons['share'] = [DI::l10n()->t('Quote share this'), DI::l10n()->t('Quote Share')];
}
}
- $comment_html = $this->getCommentBox($indent);
+ if ($commentable) {
+ $comment_html = $this->getCommentBox($indent);
+ } else {
+ $comment_html = '';
+ }
if (strcmp(DateTimeFormat::utc($item['created']), DateTimeFormat::utc('now - 12 hours')) > 0) {
$shiny = 'shiny';
$title = '';
}
- if (DI::pConfig()->get(DI::userSession()->getLocalUserId(), 'system', 'hide_dislike')) {
+ $hide_dislike = DI::pConfig()->get(DI::userSession()->getLocalUserId(), 'system', 'hide_dislike');
+ if ($hide_dislike) {
$buttons['dislike'] = false;
}
// Fetching of Diaspora posts doesn't always work. There are issues with reshares and possibly comments
if (!DI::userSession()->getLocalUserId() && ($item['network'] != Protocol::DIASPORA) && !empty(DI::session()->get('remote_comment'))) {
- $remote_comment = [DI::l10n()->t('Comment this item on your system'), DI::l10n()->t('Remote comment'),
- str_replace('{uri}', urlencode($item['uri']), DI::session()->get('remote_comment'))];
+ $remote_comment = [
+ DI::l10n()->t('Comment this item on your system'), DI::l10n()->t('Remote comment'),
+ str_replace('{uri}', urlencode($item['uri']), DI::session()->get('remote_comment'))
+ ];
// Ensure to either display the remote comment or the local activities
$buttons = [];
$browsershare = null;
}
+ $parent_guid = $thread_parent[$item['thr-parent-id']]['guid'] ?? '';
+ $parent_username = $thread_parent[$item['thr-parent-id']]['name'] ?? '';
+ $parent_unknown = $parent_username ? '' : DI::l10n()->t('Unknown parent');
+
$tmp_item = [
+ 'parentguid' => $parent_guid,
+ 'inreplyto' => DI::l10n()->t('in reply to %s', $parent_username),
+ 'isunknown' => $parent_unknown,
+ 'isunknown_label' => DI::l10n()->t('Parent is probably private or not federated.'),
'template' => $this->getTemplate(),
'type' => implode('', array_slice(explode('/', $item['verb']), -1)),
'comment_firstcollapsed' => false,
'drop' => $drop,
'block' => $block,
'ignore_author' => $ignore,
+ 'collapse' => $collapse,
+ 'report' => $report,
+ 'ignore_server' => $ignoreServer,
'vote' => $buttons,
'like_html' => $responses['like']['output'],
'dislike_html' => $responses['dislike']['output'],
- 'emojis' => $this->getEmojis($item),
+ 'hide_dislike' => $hide_dislike,
+ 'emojis' => $emojis,
+ 'quoteshares' => $this->getQuoteShares($item['quoteshares']),
+ 'reactions' => $reactions,
'responses' => $responses,
+ 'legacy_activities' => DI::config()->get('system', 'legacy_activities'),
'switchcomment' => DI::l10n()->t('Comment'),
'reply_label' => DI::l10n()->t('Reply to %s', $profile_name),
'comment_html' => $comment_html,
'wait' => DI::l10n()->t('Please wait'),
'thread_level' => $thread_level,
'edited' => $edited,
+ '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']),
$children = $this->getChildren();
$nb_children = count($children);
if ($nb_children > 0) {
+ $thread_parent[$item['uri-id']] = ['guid' => $item['guid'], 'name' => $item['author-name']];
foreach ($children as $child) {
- $result['children'][] = $child->getTemplateData($conv_responses, $formSecurityToken, $thread_level + 1);
+ $thread_parent[$child->getDataValue('uri-id')] = ['guid' => $child->getDataValue('guid'), 'name' => $child->getDataValue('author-name')];
+ $result['children'][] = $child->getTemplateData($conv_responses, $formSecurityToken, $thread_level + 1, $thread_parent);
}
// Collapse
$emojis = [];
foreach ($item['emojis'] as $index => $element) {
+ $key = $element['verb'];
$actors = implode(', ', $element['title']);
switch ($element['verb']) {
case Activity::ANNOUNCE:
$icon = ['fa' => 'fa-times', 'icon' => 'icon-remove'];
break;
+ case Activity::POST:
+ $title = DI::l10n()->t('Commented by: %s', $actors);
+ $icon = ['fa' => 'fa-commenting', 'icon' => 'icon-commenting'];
+ break;
+
default:
$title = DI::l10n()->t('Reacted with %s by: %s', $element['emoji'], $actors);
$icon = [];
+ $key = $element['emoji'];
break;
- break;
}
- $emojis[$index] = ['emoji' => $element['emoji'], 'total' => $element['total'], 'title' => $title, 'icon' => $icon];
+ $emojis[$key] = ['emoji' => $element['emoji'], 'total' => $element['total'], 'title' => $title, 'icon' => $icon];
}
- ksort($emojis);
return $emojis;
}
+ /**
+ * Fetch quote shares
+ *
+ * @param array $quoteshares
+ * @return array
+ */
+ private function getQuoteShares($quoteshares)
+ {
+ if (empty($quoteshares)) {
+ return [];
+ }
+
+ return ['total' => $quoteshares['total'], 'title' => DI::l10n()->t('Quote shared by: %s', implode(', ', $quoteshares['title']))];
+ }
+
/**
* @return integer
*/
if ($item->getDataValue('network') === Protocol::MAIL && DI::userSession()->getLocalUserId() != $item->getDataValue('uid')) {
Logger::warning('Post object does not belong to local user', ['post' => $item, 'local_user' => DI::userSession()->getLocalUserId()]);
return false;
- } elseif (DI::activity()->match($item->getDataValue('verb'), Activity::LIKE) ||
- DI::activity()->match($item->getDataValue('verb'), Activity::DISLIKE)) {
+ } elseif (
+ DI::activity()->match($item->getDataValue('verb'), Activity::LIKE) ||
+ DI::activity()->match($item->getDataValue('verb'), Activity::DISLIKE)
+ ) {
Logger::warning('Post objects is a like/dislike', ['post' => $item]);
return false;
}
if ($conv) {
// This will allow us to comment on wall-to-wall items owned by our friends
- // and community forums even if somebody else wrote the post.
+ // and community groups even if somebody else wrote the post.
// bug #517 - this fixes for conversation owner
if ($conv->getMode() == 'profile' && $conv->getProfileOwner() == DI::userSession()->getLocalUserId()) {
return true;
}
$profile = Contact::getByURL($term['url'], false, ['addr', 'contact-type']);
- if (!empty($profile['addr']) && (($profile['contact-type'] ?? Contact::TYPE_UNKNOWN) != Contact::TYPE_COMMUNITY) &&
- ($profile['addr'] != $owner['addr']) && !strstr($text, $profile['addr'])) {
+ if (
+ !empty($profile['addr']) && (($profile['contact-type'] ?? Contact::TYPE_UNKNOWN) != Contact::TYPE_COMMUNITY) &&
+ ($profile['addr'] != $owner['addr']) && !strstr($text, $profile['addr'])
+ ) {
$text .= '@' . $profile['addr'] . ' ';
}
}
'$edbold' => DI::l10n()->t('Bold'),
'$editalic' => DI::l10n()->t('Italic'),
'$eduline' => DI::l10n()->t('Underline'),
+ '$contentwarn' => DI::l10n()->t('Content Warning'),
'$edquote' => DI::l10n()->t('Quote'),
+ '$edemojis' => DI::l10n()->t('Add emojis'),
'$edcode' => DI::l10n()->t('Code'),
'$edimg' => DI::l10n()->t('Image'),
'$edurl' => DI::l10n()->t('Link'),
'$prompttext' => DI::l10n()->t('Please enter a image/video/audio/webpage URL:'),
'$preview' => DI::l10n()->t('Preview'),
'$indent' => $indent,
- '$rand_num' => Crypto::randomDigits(12),
+ '$rand_num' => Crypto::randomDigits(12)
]);
}
'id' => $this->getDataValue('owner-id'),
'network' => $this->getDataValue('owner-network'),
'url' => $this->getDataValue('owner-link'),
+ 'alias' => $this->getDataValue('owner-alias'),
];
$this->owner_url = Contact::magicLinkByContact($owner);
}