X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=src%2FProtocol%2FActivityPub%2FTransmitter.php;h=a39a4c502a6c453834119e04e2cbb95c4f830146;hb=8720561e49d2d5889fa4f4fd611efc790258ad1c;hp=d17e269edf9d516bf30c0db82546c1d8221d071f;hpb=0c4f1eadb87a6bbd1e2ae082a9f4289e5223330b;p=friendica.git diff --git a/src/Protocol/ActivityPub/Transmitter.php b/src/Protocol/ActivityPub/Transmitter.php index d17e269edf..a39a4c502a 100644 --- a/src/Protocol/ActivityPub/Transmitter.php +++ b/src/Protocol/ActivityPub/Transmitter.php @@ -288,6 +288,69 @@ class Transmitter return $data; } + /** + * Public posts for the given owner + * + * @param array $owner Owner array + * @param integer $page Page number + * + * @return array of posts + * @throws \Friendica\Network\HTTPException\InternalServerErrorException + * @throws \ImagickException + */ + public static function getFeatured($owner, $page = null) + { + $condition = ["`uri-id` IN (SELECT `uri-id` FROM `collection-view` WHERE `cid` = ? AND `type` = ?)", + Contact::getIdForURL($owner['url'], 0, false), Post\Collection::FEATURED]; + + $condition = DBA::mergeConditions($condition, + ['uid' => $owner['uid'], + 'author-id' => Contact::getIdForURL($owner['url'], 0, false), + 'private' => [Item::PUBLIC, Item::UNLISTED], + 'gravity' => [GRAVITY_PARENT, GRAVITY_COMMENT], + 'network' => Protocol::FEDERATED, + 'parent-network' => Protocol::FEDERATED, + 'origin' => true, + 'deleted' => false, + 'visible' => true]); + + $count = Post::count($condition); + + $data = ['@context' => ActivityPub::CONTEXT]; + $data['id'] = DI::baseUrl() . '/featured/' . $owner['nickname']; + $data['type'] = 'OrderedCollection'; + $data['totalItems'] = $count; + + if (empty($page)) { + $data['first'] = DI::baseUrl() . '/featured/' . $owner['nickname'] . '?page=1'; + } else { + $data['type'] = 'OrderedCollectionPage'; + $list = []; + + $items = Post::select(['id'], $condition, ['limit' => [($page - 1) * 20, 20], 'order' => ['created' => true]]); + while ($item = Post::fetch($items)) { + $activity = self::createActivityFromItem($item['id'], true); + $activity['type'] = $activity['type'] == 'Update' ? 'Create' : $activity['type']; + + // Only list "Create" activity objects here, no reshares + if (!empty($activity['object']) && ($activity['type'] == 'Create')) { + $list[] = $activity['object']; + } + } + DBA::close($items); + + if (!empty($list)) { + $data['next'] = DI::baseUrl() . '/featured/' . $owner['nickname'] . '?page=' . ($page + 1); + } + + $data['partOf'] = DI::baseUrl() . '/featured/' . $owner['nickname']; + + $data['orderedItems'] = $list; + } + + return $data; + } + /** * Return the service array containing information the used software and it's url * @@ -328,8 +391,9 @@ class Transmitter if ($uid != 0) { $data['following'] = DI::baseUrl() . '/following/' . $owner['nick']; $data['followers'] = DI::baseUrl() . '/followers/' . $owner['nick']; - $data['inbox'] = DI::baseUrl() . '/inbox/' . $owner['nick']; - $data['outbox'] = DI::baseUrl() . '/outbox/' . $owner['nick']; + $data['inbox'] = DI::baseUrl() . '/inbox/' . $owner['nick']; + $data['outbox'] = DI::baseUrl() . '/outbox/' . $owner['nick']; + $data['featured'] = DI::baseUrl() . '/featured/' . $owner['nick']; } else { $data['inbox'] = DI::baseUrl() . '/friendica/inbox'; } @@ -427,12 +491,13 @@ class Transmitter * Returns an array with permissions of the thread parent of the given item array * * @param array $item + * @param bool $is_forum_thread * * @return array with permissions * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \ImagickException */ - public static function fetchPermissionBlockFromThreadParent($item) + private static function fetchPermissionBlockFromThreadParent(array $item, bool $is_forum_thread) { if (empty($item['thr-parent-id'])) { return []; @@ -462,7 +527,9 @@ class Transmitter $type = [Tag::TO => 'to', Tag::CC => 'cc', Tag::BTO => 'bto', Tag::BCC => 'bcc']; foreach (Tag::getByURIId($item['thr-parent-id'], [Tag::TO, Tag::CC, Tag::BTO, Tag::BCC]) as $receiver) { if (!empty($parent_profile['followers']) && $receiver['url'] == $parent_profile['followers'] && !empty($item_profile['followers'])) { - $permissions[$type[$receiver['type']]][] = $item_profile['followers']; + if (!$is_forum_thread) { + $permissions[$type[$receiver['type']]][] = $item_profile['followers']; + } } elseif (!in_array($receiver['url'], $exclude)) { $permissions[$type[$receiver['type']]][] = $receiver['url']; } @@ -523,6 +590,14 @@ class Transmitter $always_bcc = true; } + $parent = Post::selectFirst(['causer-link', 'post-reason'], ['id' => $item['parent']]); + if (($parent['post-reason'] == Item::PR_ANNOUNCEMENT) && !empty($parent['causer-link'])) { + $profile = APContact::getByURL($parent['causer-link'], false); + $is_forum_thread = isset($profile['type']) && $profile['type'] == 'Group'; + } else { + $is_forum_thread = false; + } + if (self::isAnnounce($item) || DI::config()->get('debug', 'total_ap_delivery') || self::isAPPost($last_id)) { // Will be activated in a later step $networks = Protocol::FEDERATED; @@ -553,7 +628,7 @@ class Transmitter $data['cc'][] = $announce['actor']['url']; } - $data = array_merge($data, self::fetchPermissionBlockFromThreadParent($item)); + $data = array_merge($data, self::fetchPermissionBlockFromThreadParent($item, $is_forum_thread)); // Check if the item is completely public or unlisted if ($item['private'] == Item::PUBLIC) { @@ -619,7 +694,7 @@ class Transmitter } if (!empty($item['parent'])) { - $parents = Post::select(['id', 'author-link', 'owner-link', 'gravity', 'uri'], ['parent' => $item['parent']]); + $parents = Post::select(['id', 'author-link', 'owner-link', 'gravity', 'uri'], ['parent' => $item['parent']], ['order' => ['id']]); while ($parent = Post::fetch($parents)) { if ($parent['gravity'] == GRAVITY_PARENT) { $profile = APContact::getByURL($parent['owner-link'], false); @@ -633,11 +708,11 @@ class Transmitter $data['to'][] = $profile['url']; } else { $data['cc'][] = $profile['url']; - if (($item['private'] != Item::PRIVATE) && !empty($actor_profile['followers'])) { + if (($item['private'] != Item::PRIVATE) && !empty($actor_profile['followers'])&& !$is_forum_thread) { $data['cc'][] = $actor_profile['followers']; } } - } elseif (!$exclusive) { + } elseif (!$exclusive && !$is_forum_thread) { // Public thread parent post always are directed to the followers. if ($item['private'] != Item::PRIVATE) { $data['cc'][] = $actor_profile['followers']; @@ -1456,10 +1531,28 @@ class Transmitter return []; } + // We are treating posts differently when they are directed to a community. + // This is done to better support Lemmy. Most of the changes should work with other systems as well. + // But to not risk compatibility issues we currently perform the changes only for communities. + if ($item['gravity'] == GRAVITY_PARENT) { + $isCommunityPost = !empty(Tag::getByURIId($item['uri-id'], [Tag::EXCLUSIVE_MENTION])); + $links = Post\Media::getByURIId($item['uri-id'], [Post\Media::HTML]); + if ($isCommunityPost && (count($links) == 1)) { + $link = $links[0]['url']; + } + } else { + $isCommunityPost = false; + } + if ($item['event-type'] == 'event') { $type = 'Event'; } elseif (!empty($item['title'])) { - $type = 'Article'; + if (!$isCommunityPost || empty($link)) { + $type = 'Article'; + } else { + // "Page" is used by Lemmy for posts that contain an external link + $type = 'Page'; + } } else { $type = 'Note'; } @@ -1491,7 +1584,7 @@ class Transmitter $data['updated'] = DateTimeFormat::utc($item['edited'] . '+00:00', DateTimeFormat::ATOM); } - $data['url'] = $item['plink']; + $data['url'] = $link ?? $item['plink']; $data['attributedTo'] = $item['author-link']; $data['sensitive'] = self::isSensitive($item['uri-id']); $data['context'] = self::fetchContextURLForItem($item); @@ -1528,6 +1621,19 @@ class Transmitter if ($type == 'Event') { $data = array_merge($data, self::createEvent($item)); } else { + if ($isCommunityPost) { + // For community posts we remove the visible "!user@domain.tld". + // This improves the look at systems like Lemmy. + // Also in the future we should control the community delivery via other methods. + $body = preg_replace("/!\[url\=[^\[\]]*\][^\[\]]*\[\/url\]/ism", '', $body); + } + + if ($type == 'Page') { + // When we transmit "Page" posts we have to remove the attachment. + // The attachment contains the link that we already transmit in the "url" field. + $body = preg_replace("/\s*\[attachment .*?\].*?\[\/attachment\]\s*/ism", '', $body); + } + $body = BBCode::setMentionsToNicknames($body); $data['content'] = BBCode::convertForUriId($item['uri-id'], $body, BBCode::ACTIVITYPUB);