diff --git a/appinfo/routes.php b/appinfo/routes.php index 1929d455..f8cce095 100644 --- a/appinfo/routes.php +++ b/appinfo/routes.php @@ -32,7 +32,7 @@ return [ ['name' => 'Local#newPost', 'url' => '/api/v1/post', 'verb' => 'POST'], ['name' => 'Local#timeline', 'url' => '/api/v1/timeline', 'verb' => 'GET'], - ['name' => 'Local#direct', 'url' => '/api/v1/direct', 'verb' => 'PUT'] + ['name' => 'Local#direct', 'url' => '/api/v1/direct', 'verb' => 'PUT'], ['name' => 'Local#accountSearch', 'url' => '/api/v1/accounts/search', 'verb' => 'GET'], ['name' => 'Local#actorInfo', 'url' => '/api/v1/actor/info', 'verb' => 'GET'] diff --git a/lib/Db/CoreRequestBuilder.php b/lib/Db/CoreRequestBuilder.php index 71b86a4f..9f2fb8ba 100644 --- a/lib/Db/CoreRequestBuilder.php +++ b/lib/Db/CoreRequestBuilder.php @@ -31,6 +31,8 @@ namespace OCA\Social\Db; use Doctrine\DBAL\Query\QueryBuilder; +use OCA\Social\Exceptions\InvalidResourceException; +use OCA\Social\Model\ActivityPub\Person; use OCA\Social\Service\ConfigService; use OCA\Social\Service\MiscService; use OCP\DB\QueryBuilder\IQueryBuilder; @@ -224,7 +226,8 @@ class CoreRequestBuilder { /** * @param IQueryBuilder $qb - * @param string $recipient + * @param int $since + * @param int $limit */ protected function limitPaginate(IQueryBuilder &$qb, int $since = 0, int $limit = 5) { if ($since > 0) { @@ -232,7 +235,12 @@ class CoreRequestBuilder { $dt = new \DateTime(); $dt->setTimestamp($since); // TODO: Pagination should use published date, once we can properly query the db for that - $qb->andWhere($expr->lt('creation', $qb->createNamedParameter($dt, IQueryBuilder::PARAM_DATE), IQueryBuilder::PARAM_DATE)); + $qb->andWhere( + $expr->lt( + 'creation', $qb->createNamedParameter($dt, IQueryBuilder::PARAM_DATE), + IQueryBuilder::PARAM_DATE + ) + ); } $qb->setMaxResults($limit); $qb->orderBy('creation', 'desc'); @@ -273,30 +281,66 @@ class CoreRequestBuilder { $qb->andWhere($expr->like($field, $qb->createNamedParameter($value))); } -// /** -// * Left Join service to get info about the serviceId -// * -// * @param IQueryBuilder $qb -// */ -// public function leftJoinService(IQueryBuilder &$qb) { -// -// if ($qb->getType() !== QueryBuilder::SELECT) { -// return; -// } -// -// $expr = $qb->expr(); -// $pf = $this->defaultSelectAlias; -// + + /** + * @param IQueryBuilder $qb + * @param string $fieldActorId + */ + protected function leftJoinCacheActors(IQueryBuilder &$qb, string $fieldActorId) { + + if ($qb->getType() !== QueryBuilder::SELECT) { + return; + } + + $expr = $qb->expr(); + $pf = $this->defaultSelectAlias; + // /** @noinspection PhpMethodParametersCountMismatchInspection */ -// $qb->selectAlias('s.address', 'service_address') -// ->selectAlias('s.status', 'service_status') -// ->selectAlias('s.config', 'service_config') -// ->selectAlias('s.type', 'service_type') -// ->leftJoin( -// $this->defaultSelectAlias, CoreRequestBuilder::TABLE_SERVICES, 's', -// $expr->eq($pf . '.service_id', 's.id') -// ); -// } + $qb->selectAlias('ca.id', 'cacheactor_id') + ->selectAlias('ca.account', 'cacheactor_account') + ->selectAlias('ca.following', 'cacheactor_following') + ->selectAlias('ca.followers', 'cacheactor_followers') + ->selectAlias('ca.inbox', 'cacheactor_inbox') + ->selectAlias('ca.shared_inbox', 'cacheactor_shared_inbox') + ->selectAlias('ca.outbox', 'cacheactor_outbox') + ->selectAlias('ca.featured', 'cacheactor_featured') + ->selectAlias('ca.url', 'cacheactor_url') + ->selectAlias('ca.preferred_username', 'cacheactor_preferred_username') + ->selectAlias('ca.name', 'cacheactor_name') + ->selectAlias('ca.summary', 'cacheactor_summary') + ->selectAlias('ca.public_key', 'cacheactor_public_key') + ->selectAlias('ca.creation', 'cacheactor_creation') + ->leftJoin( + $this->defaultSelectAlias, CoreRequestBuilder::TABLE_CACHE_ACTORS, 'ca', + $expr->eq($pf . '.' . $fieldActorId, 'ca.id') + ); + } + + + /** + * @param array $data + * + * @return Person + * @throws InvalidResourceException + */ + protected function parseCacheActorsLeftJoin(array $data): Person { + $new = []; + + foreach ($data as $k => $v) { + if (substr($k, 0, 11) === 'cacheactor_') { + $new[substr($k, 11)] = $v; + } + } + + $actor = new Person(); + $actor->import($new); + + if ($actor->getType() !== 'Person') { + throw new InvalidResourceException(); + } + + return $actor; + } } diff --git a/lib/Db/NotesRequest.php b/lib/Db/NotesRequest.php index a17237e1..38527c33 100644 --- a/lib/Db/NotesRequest.php +++ b/lib/Db/NotesRequest.php @@ -99,14 +99,16 @@ class NotesRequest extends NotesRequestBuilder { /** - * @param string $actorId + * @param int $since + * @param int $limit * * @return array */ - public function getPublicNotes($since = 0, $limit = 5): array { + public function getPublicNotes(int $since = 0, int $limit = 5): array { $qb = $this->getNotesSelectSql(); $this->limitToRecipient($qb, ActivityService::TO_PUBLIC); $this->limitPaginate($qb, $since, $limit); + $this->leftJoinCacheActors($qb, 'attributed_to'); $notes = []; $cursor = $qb->execute(); @@ -126,6 +128,7 @@ class NotesRequest extends NotesRequestBuilder { public function getNotesForActorId(string $actorId): array { $qb = $this->getNotesSelectSql(); $this->limitToRecipient($qb, $actorId); + $this->leftJoinCacheActors($qb, 'attributed_to'); $notes = []; $cursor = $qb->execute(); diff --git a/lib/Db/NotesRequestBuilder.php b/lib/Db/NotesRequestBuilder.php index 26bfb0ad..0d1f7253 100644 --- a/lib/Db/NotesRequestBuilder.php +++ b/lib/Db/NotesRequestBuilder.php @@ -31,8 +31,8 @@ namespace OCA\Social\Db; use daita\MySmallPhpTools\Traits\TArrayTools; +use OCA\Social\Exceptions\InvalidResourceException; use OCA\Social\Model\ActivityPub\Note; -use OCA\Social\Model\Post; use OCP\DB\QueryBuilder\IQueryBuilder; class NotesRequestBuilder extends CoreRequestBuilder { @@ -118,32 +118,15 @@ class NotesRequestBuilder extends CoreRequestBuilder { ->setAttributedTo($data['attributed_to']) ->setInReplyTo($data['in_reply_to']); + try { + $actor = $this->parseCacheActorsLeftJoin($data); + $note->setCompleteDetails(true); + $note->setActor($actor); + } catch (InvalidResourceException $e) { + } + return $note; } - - /** - * @param array $data - * - * @return Post - */ - protected function parsePostsSelectSql($userId, $data): Note { - $post = new Post($userId); - - $post->setContent($data['content']); - -// $note->setId($data['id']) -// ->setTo($data['to']) -// ->setToArray(json_decode($data['to_array'], true)) -// ->setCc(json_decode($data['cc'], true)) -// ->setBcc(json_decode($data['bcc'])); -// $note->setContent($data['content']) -// ->setPublished($data['published']) -// ->setAttributedTo($data['attributed_to']) -// ->setInReplyTo($data['in_reply_to']); - - return $post; - } - } diff --git a/lib/Model/ActivityPub/ACore.php b/lib/Model/ActivityPub/ACore.php index 6189b43b..d2bf814c 100644 --- a/lib/Model/ActivityPub/ACore.php +++ b/lib/Model/ActivityPub/ACore.php @@ -109,6 +109,8 @@ abstract class ACore implements JsonSerializable { /** @var ICoreService */ private $saveAs; + /** @var bool */ + private $completeDetails = false; /** * Core constructor. @@ -685,6 +687,25 @@ abstract class ACore implements JsonSerializable { } + /** + * @return bool + */ + public function isCompleteDetails(): bool { + return $this->completeDetails; + } + + /** + * @param bool $completeDetails + * + * @return ACore + */ + public function setCompleteDetails(bool $completeDetails): ACore { + $this->completeDetails = $completeDetails; + + return $this; + } + + /** * @param array $data */ @@ -727,6 +748,9 @@ abstract class ACore implements JsonSerializable { 'actor', $this->getActor() ->getId() ); + if ($this->isCompleteDetails()) { + $this->addEntryItem('actor_info', $this->getActor()); + } } else { $this->addEntry('actor', $this->getActorId()); } diff --git a/lib/Model/ActivityPub/Person.php b/lib/Model/ActivityPub/Person.php index 5c84582f..a4d482cd 100644 --- a/lib/Model/ActivityPub/Person.php +++ b/lib/Model/ActivityPub/Person.php @@ -353,6 +353,10 @@ class Person extends ACore implements JsonSerializable { ->setSharedInbox($this->get('shared_inbox', $data, '')) ->setFeatured($this->get('featured', $data, '')) ->setCreation($this->getInt('creation', $data, 0)); + + if ($this->getPreferredUsername() === '') { + $this->setType('Invalid'); + } } @@ -371,6 +375,7 @@ class Person extends ACore implements JsonSerializable { 'name' => $this->getName(), 'inbox' => $this->getInbox(), 'outbox' => $this->getOutbox(), + 'account' => $this->getAccount(), 'following' => $this->getFollowing(), 'followers' => $this->getFollowers(), 'endpoints' => diff --git a/lib/Service/ActivityPub/NoteService.php b/lib/Service/ActivityPub/NoteService.php index 25edf929..12502e72 100644 --- a/lib/Service/ActivityPub/NoteService.php +++ b/lib/Service/ActivityPub/NoteService.php @@ -236,17 +236,9 @@ class NoteService implements ICoreService { * * @return Note[] */ - public function getTimeline($since = 0, $limit = 5): array { - $notes = $this->notesRequest->getPublicNotes($since, $limit); - $result = []; - /** @var Note $note */ - foreach ($notes as $note) { - $actor = $this->actorService->getActorById($note->getAttributedTo()); - $noteEnhanced = $note->jsonSerialize(); - $noteEnhanced['actor'] = $actor->jsonSerialize(); - $result[] = $noteEnhanced; - } - return $result; + public function getTimeline(int $since = 0, int $limit = 5): array { + return $this->notesRequest->getPublicNotes($since, $limit); +// return $result; } diff --git a/lib/Service/ActivityPub/PersonService.php b/lib/Service/ActivityPub/PersonService.php index f68a3797..6c84718a 100644 --- a/lib/Service/ActivityPub/PersonService.php +++ b/lib/Service/ActivityPub/PersonService.php @@ -175,6 +175,5 @@ class PersonService implements ICoreService { $this->cacheActorsRequest->save($person); } - }