From 8a7e9417268fa28131ecbab41294bcb6be8b77dd Mon Sep 17 00:00:00 2001 From: Maxence Lange Date: Fri, 7 Apr 2023 11:08:28 -0100 Subject: [PATCH] basic implementation of collections Signed-off-by: Maxence Lange --- lib/Controller/ActivityPubController.php | 25 ++++-- lib/Db/FollowsRequest.php | 2 + lib/Model/ActivityPub/OrderedCollection.php | 85 ++++++--------------- lib/Service/FollowService.php | 27 +++++-- lib/Service/StreamService.php | 46 ++++++++--- 5 files changed, 102 insertions(+), 83 deletions(-) diff --git a/lib/Controller/ActivityPubController.php b/lib/Controller/ActivityPubController.php index 65370503..498a6261 100644 --- a/lib/Controller/ActivityPubController.php +++ b/lib/Controller/ActivityPubController.php @@ -278,7 +278,17 @@ class ActivityPubController extends Controller { * @return Response */ public function outbox(string $username): Response { - return $this->success([$username]); +// if (!$this->checkSourceActivityStreams()) { +// return $this->socialPubController->outbox($username); +// } + + try { + $actor = $this->cacheActorService->getFromLocalAccount($username); + + return $this->directSuccess($this->streamService->getOutboxCollection($actor)); + } catch (Exception $e) { + return $this->fail($e); + } } @@ -301,11 +311,8 @@ class ActivityPubController extends Controller { try { $actor = $this->cacheActorService->getFromLocalAccount($username); - $followers = $this->followService->getFollowersCollection($actor); -// $followers->setTopLevel(true); - - return $this->directSuccess($followers); + return $this->directSuccess($this->followService->getFollowersCollection($actor)); } catch (Exception $e) { return $this->fail($e); } @@ -329,7 +336,13 @@ class ActivityPubController extends Controller { return $this->socialPubController->following($username); } - return $this->success([$username]); + try { + $actor = $this->cacheActorService->getFromLocalAccount($username); + + return $this->directSuccess($this->followService->getFollowingCollection($actor)); + } catch (Exception $e) { + return $this->fail($e); + } } diff --git a/lib/Db/FollowsRequest.php b/lib/Db/FollowsRequest.php index 920fe44b..ea58d86a 100644 --- a/lib/Db/FollowsRequest.php +++ b/lib/Db/FollowsRequest.php @@ -223,6 +223,8 @@ class FollowsRequest extends FollowsRequestBuilder { $this->leftJoinDetails($qb, 'id', 'ca'); $qb->orderBy('f.creation', 'desc'); + // TODO: pagination + return $this->getFollowsFromRequest($qb); } diff --git a/lib/Model/ActivityPub/OrderedCollection.php b/lib/Model/ActivityPub/OrderedCollection.php index 8343f87d..39be0a65 100644 --- a/lib/Model/ActivityPub/OrderedCollection.php +++ b/lib/Model/ActivityPub/OrderedCollection.php @@ -2,7 +2,6 @@ declare(strict_types=1); - /** * Nextcloud - Social Support * @@ -28,103 +27,69 @@ declare(strict_types=1); * */ - namespace OCA\Social\Model\ActivityPub; use JsonSerializable; -/** - * Class OrderedCollection - * - * @package OCA\Social\Model\ActivityPub - */ class OrderedCollection extends ACore implements JsonSerializable { public const TYPE = 'OrderedCollection'; - private int $totalItems = 0; - private string $first = ''; + private string $last = ''; - /** - * Activity constructor. - * - * @param ACore $parent - */ public function __construct($parent = null) { parent::__construct($parent); $this->setType(self::TYPE); } - - /** - * @return int - */ public function getTotalItems(): int { return $this->totalItems; } - /** - * @param int $totalItems - * - * @return OrderedCollection - */ - public function setTotalItems(int $totalItems): OrderedCollection { + public function setTotalItems(int $totalItems): self { $this->totalItems = $totalItems; return $this; } - - /** - * @return string - */ public function getFirst(): string { return $this->first; } - /** - * @param string $first - * - * @return OrderedCollection - */ - public function setFirst(string $first): OrderedCollection { + public function setFirst(string $first): self { $this->first = $first; return $this; } - - - - - - - //"id": "https://pub.pontapreta.net/users/admin/following", - //"type": "OrderedCollection", - //"totalItems": 1, - //"first": "https://pub.pontapreta.net/users/admin/following?page=1" - - - /** - * @param array $data - */ - public function import(array $data) { - parent::import($data); + public function getLast(): string { + return $this->last; } + public function setLast(string $last): self { + $this->last = $last; + + return $this; + } + + public function import(array $data): self { + parent::import($data); + + return $this; + } - /** - * @return array - */ public function jsonSerialize(): array { - return array_merge( - parent::jsonSerialize(), - [ - 'totalItems' => $this->getTotalItems(), - 'first' => $this->getFirst() - ] + return array_filter( + array_merge( + parent::jsonSerialize(), + [ + 'totalItems' => $this->getTotalItems(), + 'first' => $this->getFirst(), + 'last' => $this->getLast() + ] + ) ); } } diff --git a/lib/Service/FollowService.php b/lib/Service/FollowService.php index cab69ab0..56c1d864 100644 --- a/lib/Service/FollowService.php +++ b/lib/Service/FollowService.php @@ -56,18 +56,19 @@ use OCA\Social\Tools\Exceptions\RequestResultNotJsonException; use OCA\Social\Tools\Exceptions\RequestResultSizeException; use OCA\Social\Tools\Exceptions\RequestServerException; use OCA\Social\Tools\Traits\TArrayTools; +use OCP\IURLGenerator; use Psr\Log\LoggerInterface; class FollowService { use TArrayTools; + private IURLGenerator $urlGenerator; private FollowsRequest $followsRequest; private ActivityService $activityService; private CacheActorService $cacheActorService; private ConfigService $configService; private LoggerInterface $logger; - private ?Person $viewer = null; @@ -81,12 +82,14 @@ class FollowService { * @param LoggerInterface $logger */ public function __construct( + IURLGenerator $urlGenerator, FollowsRequest $followsRequest, ActivityService $activityService, CacheActorService $cacheActorService, ConfigService $configService, LoggerInterface $logger ) { + $this->urlGenerator = $urlGenerator; $this->followsRequest = $followsRequest; $this->activityService = $activityService; $this->cacheActorService = $cacheActorService; @@ -250,8 +253,14 @@ class FollowService { public function getFollowersCollection(Person $actor): OrderedCollection { $collection = new OrderedCollection(); $collection->setId($actor->getFollowers()); - $collection->setTotalItems(20); - $collection->setFirst('...'); + $collection->setTotalItems($this->getInt('followers', $actor->getDetails('count'))); + + $first = $this->urlGenerator->linkToRouteAbsolute( + 'social.ActivityPub.followers', + ['username' => $actor->getPreferredUsername()] + ) + . '?page=1'; + $collection->setFirst($first); return $collection; } @@ -276,9 +285,15 @@ class FollowService { */ public function getFollowingCollection(Person $actor): OrderedCollection { $collection = new OrderedCollection(); -// $collection->setId($actor->getFollowers()); -// $collection->setTotalItems(20); -// $collection->setFirst('...'); + $collection->setId($actor->getFollowing()); + $collection->setTotalItems($this->getInt('following', $actor->getDetails('count'))); + + $first = $this->urlGenerator->linkToRouteAbsolute( + 'social.ActivityPub.following', + ['username' => $actor->getPreferredUsername()] + ) + . '?page=1'; + $collection->setFirst($first); return $collection; } diff --git a/lib/Service/StreamService.php b/lib/Service/StreamService.php index f619f132..4788df46 100644 --- a/lib/Service/StreamService.php +++ b/lib/Service/StreamService.php @@ -42,6 +42,7 @@ use OCA\Social\Exceptions\UnauthorizedFediverseException; use OCA\Social\Model\ActivityPub\ACore; use OCA\Social\Model\ActivityPub\Actor\Person; use OCA\Social\Model\ActivityPub\Object\Note; +use OCA\Social\Model\ActivityPub\OrderedCollection; use OCA\Social\Model\ActivityPub\Stream; use OCA\Social\Model\Client\Options\ProbeOptions; use OCA\Social\Model\InstancePath; @@ -52,8 +53,13 @@ use OCA\Social\Tools\Exceptions\RequestNetworkException; use OCA\Social\Tools\Exceptions\RequestResultNotJsonException; use OCA\Social\Tools\Exceptions\RequestResultSizeException; use OCA\Social\Tools\Exceptions\RequestServerException; +use OCA\Social\Tools\Traits\TArrayTools; +use OCP\IURLGenerator; class StreamService { + use TArrayTools; + + private IUrlGenerator $urlGenerator; private StreamRequest $streamRequest; private ActivityService $activityService; private CacheActorService $cacheActorService; @@ -61,20 +67,14 @@ class StreamService { private const ANCESTOR_LIMIT = 5; - /** - * NoteService constructor. - * - * @param StreamRequest $streamRequest - * @param ActivityService $activityService - * @param CacheActorService $cacheActorService - * @param ConfigService $configService - */ public function __construct( + IUrlGenerator $urlGenerator, StreamRequest $streamRequest, ActivityService $activityService, CacheActorService $cacheActorService, ConfigService $configService ) { + $this->urlGenerator = $urlGenerator; $this->streamRequest = $streamRequest; $this->activityService = $activityService; $this->cacheActorService = $cacheActorService; @@ -282,8 +282,6 @@ class StreamService { } - - /** * @param Note $note * @param string $replyTo @@ -403,7 +401,11 @@ class StreamService { * @throws StreamNotFoundException * @throws DateTimeException */ - public function getRepliesByParentId(string $id, int $since = 0, int $limit = 5, bool $asViewer = false + public function getRepliesByParentId( + string $id, + int $since = 0, + int $limit = 5, + bool $asViewer = false ): array { return $this->streamRequest->getRepliesByParentId($id, $since, $limit, $asViewer); } @@ -563,4 +565,26 @@ class StreamService { return $this->cacheActorService->getFromId($note->getAttributedTo()); } + + + /** + * @param Person $actor + * + * @return OrderedCollection + */ + public function getOutboxCollection(Person $actor): OrderedCollection { + $collection = new OrderedCollection(); + $collection->setId($actor->getOutbox()); + $collection->setTotalItems($this->getInt('post', $actor->getDetails('count'))); + + $link = $this->urlGenerator->linkToRouteAbsolute( + 'social.ActivityPub.outbox', + ['username' => $actor->getPreferredUsername()] + ); + + $collection->setFirst($link . '?page=1'); + $collection->setLast($link . '?page=1&min_id=0'); + + return $collection; + } }