diff --git a/src/Content/Text/BBCode.php b/src/Content/Text/BBCode.php index c2b54821aa..38719e046c 100644 --- a/src/Content/Text/BBCode.php +++ b/src/Content/Text/BBCode.php @@ -1052,9 +1052,12 @@ class BBCode extends BaseObject $text = ($is_quote_share? '
' : '') . '

' . html_entity_decode('♲ ', ENT_QUOTES, 'UTF-8') . ' ' . $author_contact['addr'] . ':

' . "\n" . $content; break; case 7: // statusnet/GNU Social - case 9: // ActivityPub $text = ($is_quote_share? '
' : '') . '

' . html_entity_decode('♲ ', ENT_QUOTES, 'UTF-8') . ' @' . $author_contact['addr'] . ': ' . $content . '

' . "\n"; break; + case 9: // ActivityPub + $author = '@' . $author_contact['addr'] . ':'; + $text = '
' . html_entity_decode('♲', ENT_QUOTES, 'UTF-8') . ' ' . $author . '
' . $content . '
' . "\n"; + break; default: // Transforms quoted tweets in rich attachments to avoid nested tweets if (stripos(Strings::normaliseLink($attributes['link']), 'http://twitter.com/') === 0 && OEmbed::isAllowedURL($attributes['link'])) { diff --git a/src/Module/Objects.php b/src/Module/Objects.php index 5538be1888..df57636926 100644 --- a/src/Module/Objects.php +++ b/src/Module/Objects.php @@ -42,7 +42,14 @@ class Objects extends BaseModule } } - $data = ActivityPub\Transmitter::createObjectFromItemID($item['id']); + $activity = ActivityPub\Transmitter::createActivityFromItem($item['id'], true); + // Only display "Create" activity objects here, no reshares or anything else + if (!is_array($activity['object']) || ($activity['type'] != 'Create')) { + throw new \Friendica\Network\HTTPException\NotFoundException(); + } + + $data = ['@context' => ActivityPub::CONTEXT]; + $data = array_merge($data, $activity['object']); header('Content-Type: application/activity+json'); echo json_encode($data); diff --git a/src/Protocol/ActivityPub/Transmitter.php b/src/Protocol/ActivityPub/Transmitter.php index fa8e4bf46f..720fa09d7f 100644 --- a/src/Protocol/ActivityPub/Transmitter.php +++ b/src/Protocol/ActivityPub/Transmitter.php @@ -176,9 +176,11 @@ class Transmitter $items = Item::select(['id'], $condition, ['limit' => [($page - 1) * 20, 20], 'order' => ['created' => true]]); while ($item = Item::fetch($items)) { - $object = self::createObjectFromItemID($item['id']); - unset($object['@context']); - $list[] = $object; + $activity = self::createActivityFromItem($item['id'], true); + // Only list "Create" activity objects here, no reshares + if (is_array($activity['object']) && ($activity['type'] == 'Create')) { + $list[] = $activity['object']; + } } if (!empty($list)) { @@ -379,6 +381,15 @@ class Transmitter $terms = Term::tagArrayFromItemId($item['id'], [Term::MENTION, Term::IMPLICIT_MENTION]); + // Directly mention the original author upon a quoted reshare. + // Else just ensure that the original author receives the reshare. + $announce = self::getAnnounceObject($item); + if (!empty($announce['comment'])) { + $data['to'][] = $announce['actor']['url']; + } elseif (!empty($announce)) { + $data['cc'][] = $announce['actor']['url']; + } + if (!$item['private']) { $data = array_merge($data, self::fetchPermissionBlockFromConversation($item)); @@ -757,8 +768,8 @@ class Transmitter // Only check for a reshare, if it is a real reshare and no quoted reshare if (strpos($item['body'], "[share") === 0) { - $announce = api_share_as_retweet($item); - $reshared = !empty($announce['plink']); + $announce = self::getAnnounceObject($item); + $reshared = !empty($announce); } if ($reshared) { @@ -1004,6 +1015,13 @@ class Transmitter $tags[] = ['type' => 'Mention', 'href' => $term['url'], 'name' => $mention]; } } + + $announce = self::getAnnounceObject($item); + // Mention the original author upon commented reshares + if (!empty($announce['comment'])) { + $tags[] = ['type' => 'Mention', 'href' => $announce['actor']['url'], 'name' => '@' . $announce['actor']['addr']]; + } + return $tags; } @@ -1371,21 +1389,21 @@ class Transmitter private static function createAnnounce($item, $data) { $orig_body = $item['body']; - $announce = api_share_as_retweet($item); - if (empty($announce['plink'])) { + $announce = self::getAnnounceObject($item); + if (empty($announce)) { $data['type'] = 'Create'; $data['object'] = self::createNote($item); return $data; } // Fetch the original id of the object - $activity = ActivityPub::fetchContent($announce['plink'], $item['uid']); + $activity = ActivityPub::fetchContent($announce['id'], $item['uid']); if (!empty($activity)) { $ldactivity = JsonLD::compact($activity); $id = JsonLD::fetchElement($ldactivity, '@id'); $type = str_replace('as:', '', JsonLD::fetchElement($ldactivity, '@type')); if (!empty($id)) { - if (empty($announce['share-pre-body'])) { + if (empty($announce['comment'])) { // Pure announce, without a quote $data['type'] = 'Announce'; $data['object'] = $id; @@ -1394,7 +1412,7 @@ class Transmitter // Quote $data['type'] = 'Create'; - $item['body'] = trim($announce['share-pre-body']) . "\n" . $id; + $item['body'] = $announce['comment'] . "\n" . $id; $data['object'] = self::createNote($item); /// @todo Finally descide how to implement this in AP. This is a possible way: @@ -1411,6 +1429,30 @@ class Transmitter return $data; } + /** + * Return announce related data if the item is an annunce + * + * @param array $item + * + * @return array + */ + public static function getAnnounceObject($item) + { + $announce = api_share_as_retweet($item); + if (empty($announce['plink'])) { + return []; + } + + /// @ToDo Check if the announced item is an AP object + + $profile = APContact::getByURL($announce['author-link'], false); + if (empty($profile)) { + return []; + } + + return ['id' => $announce['plink'], 'actor' => $profile, 'comment' => trim($announce['share-pre-body'])]; + } + /** * Creates an activity id for a given contact id *