if ($pager->getStart() == 0) {
$cdata = Contact::getPublicAndUserContactID($cid, local_user());
if (!empty($cdata['public'])) {
- $condition = ["`uri-id` IN (SELECT `uri-id` FROM `collection-view` WHERE `cid` = ?)", $cdata['public']];
+ $condition = ["`uri-id` IN (SELECT `uri-id` FROM `collection-view` WHERE `cid` = ? AND `type` = ?)",
+ $cdata['public'], Post\Collection::FEATURED];
$pinned = Post::toArray(Post::selectForUser(local_user(), $fields, $condition, $params));
$items = array_merge($pinned, $items);
}
--- /dev/null
+<?php
+/**
+ * @copyright Copyright (C) 2010-2022, the Friendica project
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace Friendica\Module\ActivityPub;
+
+use Friendica\BaseModule;
+use Friendica\Model\User;
+use Friendica\Protocol\ActivityPub;
+
+/**
+ * ActivityPub featured posts
+ */
+class Featured extends BaseModule
+{
+ protected function rawContent(array $request = [])
+ {
+ if (empty($this->parameters['nickname'])) {
+ throw new \Friendica\Network\HTTPException\NotFoundException();
+ }
+
+ $owner = User::getOwnerDataByNick($this->parameters['nickname']);
+ if (empty($owner)) {
+ throw new \Friendica\Network\HTTPException\NotFoundException();
+ }
+
+ $page = $_REQUEST['page'] ?? null;
+
+ $outbox = ActivityPub\Transmitter::getFeatured($owner, $page);
+ header('Content-Type: application/activity+json');
+ echo json_encode($outbox);
+ exit();
+ }
+}
'diaspora' => 'https://diasporafoundation.org/ns/',
'litepub' => 'http://litepub.social/ns#',
'toot' => 'http://joinmastodon.org/ns#',
+ 'featured' => [
+ "@id" => "toot:featured",
+ "@type" => "@id",
+ ],
'schema' => 'http://schema.org#',
'manuallyApprovesFollowers' => 'as:manuallyApprovesFollowers',
'sensitive' => 'as:sensitive', 'Hashtag' => 'as:Hashtag',
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
*
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';
}
'/dirfind' => [Module\Search\Directory::class, [R::GET]],
'/directory' => [Module\Directory::class, [R::GET]],
- '/events/json' => [Module\Events\Json::class, [R::GET]],
+ '/events/json' => [Module\Events\Json::class, [R::GET]],
+
+ '/featured/{nickname}' => [Module\ActivityPub\Featured::class, [R::GET]],
'/feed' => [
'/{nickname}' => [Module\Feed::class, [R::GET]],