diff --git a/lib/Command/Timeline.php b/lib/Command/Timeline.php index d8334b34..8330afd0 100644 --- a/lib/Command/Timeline.php +++ b/lib/Command/Timeline.php @@ -169,12 +169,12 @@ class Timeline extends ExtendedBase { break; case 'local': - $stream = $this->streamRequest->getTimelineGlobal(0, $this->count, true); + $stream = $this->streamRequest->getTimelineGlobal_dep(0, $this->count, true); $this->outputStreams($stream); break; case 'global': - $stream = $this->streamRequest->getTimelineGlobal(0, $this->count, false); + $stream = $this->streamRequest->getTimelineGlobal_dep(0, $this->count, false); $this->outputStreams($stream); break; diff --git a/lib/Controller/ApiController.php b/lib/Controller/ApiController.php index 1b4be8a7..a0b7bc0a 100644 --- a/lib/Controller/ApiController.php +++ b/lib/Controller/ApiController.php @@ -261,14 +261,17 @@ class ApiController extends Controller { * * @param string $timeline * @param int $limit - * + * @param int $max_id + * @param int $min_id * @return DataResponse */ - public function timelines(string $timeline, int $limit = 20): DataResponse { + public function timelines(string $timeline, int $limit = 20, int $max_id = 0, int $min_id = 0): DataResponse { $options = new TimelineOptions($this->request); $options->setFormat(Stream::FORMAT_LOCAL); $options->setTimeline($timeline); $options->setLimit($limit); + $options->setMaxId($max_id); + $options->setMinId($min_id); try { $this->initViewer(true); diff --git a/lib/Db/StreamRequest.php b/lib/Db/StreamRequest.php index 7e5ec825..6b4c677b 100644 --- a/lib/Db/StreamRequest.php +++ b/lib/Db/StreamRequest.php @@ -412,7 +412,7 @@ class StreamRequest extends StreamRequestBuilder { * * @return Stream[] * @throws DateTimeException - * @deprecated - use GetTimeline() + * @deprecated - use getTimelineHome() */ public function getTimelineHome_dep( int $since = 0, int $limit = 5, int $format = Stream::FORMAT_ACTIVITYPUB @@ -521,6 +521,37 @@ class StreamRequest extends StreamRequestBuilder { return $this->getStreamsFromRequest($qb); } + /** + * Should returns: + * * All local public/federated posts + * + * @param TimelineOptions $options + * + * @return Stream[] + * @throws DateTimeException + */ + public function getTimelinePublic(TimelineOptions $options): array { + $qb = $this->getStreamSelectSql($options->getFormat()); + $qb->paginate($options); + + $qb->limitToLocal($options->isLocal()); + $qb->limitToType(Note::TYPE); + + $qb->linkToCacheActors('ca', 's.attributed_to_prim'); + $qb->leftJoinStreamAction(); + + $qb->selectDestFollowing('sd', ''); + $qb->innerJoinSteamDest('recipient', 'id_prim', 'sd', 's'); + $qb->limitToDest(ACore::CONTEXT_PUBLIC, 'recipient', 'to', 'sd'); + + $result = $this->getStreamsFromRequest($qb); + if ($options->isInverted()) { + $result = array_reverse($result); + } + + return $result; + } + /** * Should returns: @@ -532,8 +563,9 @@ class StreamRequest extends StreamRequestBuilder { * * @return Stream[] * @throws DateTimeException + * @deprecated - use getTimelinePublic() */ - public function getTimelineGlobal(int $since = 0, int $limit = 5, bool $localOnly = true + public function getTimelineGlobal_dep(int $since = 0, int $limit = 5, bool $localOnly = true ): array { $qb = $this->getStreamSelectSql(); $qb->limitPaginate($since, $limit); diff --git a/lib/Model/ActivityPub/ACore.php b/lib/Model/ActivityPub/ACore.php index ee8bfcb7..2e00e0dc 100644 --- a/lib/Model/ActivityPub/ACore.php +++ b/lib/Model/ActivityPub/ACore.php @@ -61,6 +61,7 @@ class ACore extends Item implements JsonSerializable { const AS_USERNAME = 5; const AS_ACCOUNT = 6; const AS_STRING = 7; + const AS_CONTENT = 8; const AS_TAGS = 10; const FORMAT_ACTIVITYPUB = 1; @@ -559,14 +560,16 @@ class ACore extends Item implements JsonSerializable { return $value; case self::AS_STRING: - // try to preserve some whitespace from the html tags - $value = preg_replace("/\
/", "\n", $value); - $value = preg_replace("/\<\/?p>/", "\n", $value); - $value = strip_tags($value); $value = html_entity_decode($value, ENT_QUOTES | ENT_HTML5); - return trim($value); + return $value; + + case self::AS_CONTENT: + $value = strip_tags($value, ['a', 'p', 'span', 'br']); + $value = html_entity_decode($value, ENT_QUOTES | ENT_HTML5); + + return $value; case self::AS_USERNAME: $value = strip_tags($value); @@ -654,6 +657,12 @@ class ACore extends Item implements JsonSerializable { $this->setLocal(($this->getInt('local', $data, 0) === 1)); } + /** + * @param array $data + */ + public function importFromCache(array $data) { + $this->import($data); + } /** * @param int $format diff --git a/lib/Model/ActivityPub/Actor/Person.php b/lib/Model/ActivityPub/Actor/Person.php index f9f3b5c3..e55030ec 100644 --- a/lib/Model/ActivityPub/Actor/Person.php +++ b/lib/Model/ActivityPub/Actor/Person.php @@ -741,7 +741,7 @@ class Person extends ACore implements IQueryRow, JsonSerializable { $result = [ "username" => $this->getPreferredUsername(), - "acct" => $this->getPreferredUsername(), + "acct" => $this->getAccount(), "display_name" => $this->getDisplayName(), "locked" => $this->isLocked(), "bot" => $this->isBot(), diff --git a/lib/Model/ActivityPub/Object/Announce.php b/lib/Model/ActivityPub/Object/Announce.php index a13e5b6a..0d4eab15 100644 --- a/lib/Model/ActivityPub/Object/Announce.php +++ b/lib/Model/ActivityPub/Object/Announce.php @@ -33,6 +33,7 @@ namespace OCA\Social\Model\ActivityPub\Object; use Exception; use JsonSerializable; +use OCA\Social\AP; use OCA\Social\Model\ActivityPub\ACore; use OCA\Social\Model\ActivityPub\Stream; @@ -72,26 +73,25 @@ class Announce extends Stream implements JsonSerializable { $this->setAttributedTo($this->getActorId()); } - - /** - * @param array $data - * - * @throws Exception - */ - public function importFromDatabase(array $data) { - parent::importFromDatabase($data); - } - - /** * @return array */ - public function jsonSerialize(): array { - $result = parent::jsonSerialize(); - //$result['actor'] = $this->getAttributedTo(); + public function exportAsLocal(): array { + $result = parent::exportAsLocal(); + + if ($this->hasCache()) { + $cache = $this->getCache(); + if ($object = $cache->getItem($this->getObjectId())) { + $object = $object->getObject(); + /** @var Stream $item */ + $item = AP::$activityPub->getItemFromType($this->get('type', $object, Stream::TYPE)); + $item->importFromCache($object); + $result['reblog'] = $item->exportAsLocal(); + $result['content'] = $item->getContent(); + } + } return $result; } - } diff --git a/lib/Model/ActivityPub/Stream.php b/lib/Model/ActivityPub/Stream.php index 88dd1fdd..68b187a7 100644 --- a/lib/Model/ActivityPub/Stream.php +++ b/lib/Model/ActivityPub/Stream.php @@ -36,6 +36,7 @@ use daita\MySmallPhpTools\Model\CacheItem; use DateTime; use Exception; use JsonSerializable; +use OCA\Social\Model\ActivityPub\Actor\Person; use OCA\Social\Model\StreamAction; use OCA\Social\Traits\TDetails; @@ -424,7 +425,7 @@ class Stream extends ACore implements IQueryRow, JsonSerializable { } $this->setActivityId($this->validate(self::AS_ID, 'activity_id', $data, '')); - $this->setContent($this->validate(self::AS_STRING, 'content', $data, '')); + $this->setContent($this->validate(self::AS_CONTENT, 'content', $data, '')); $this->setObjectId($this->validate(self::AS_ID, 'object_id', $data, '')); $this->setAttributedTo($this->validate(self::AS_ID, 'attributed_to', $data, '')); $this->setInReplyTo($this->validate(self::AS_ID, 'in_reply_to', $data)); @@ -436,6 +437,15 @@ class Stream extends ACore implements IQueryRow, JsonSerializable { $this->setCache($cache); } + public function importFromCache(array $data) { + parent::importFromCache($data); + + $actor = new Person(); + $actor->importFromCache($data['actor_info']); + $this->setActor($actor); + $this->setCompleteDetails(true); + } + /** * @return array @@ -480,7 +490,23 @@ class Stream extends ACore implements IQueryRow, JsonSerializable { * @return array */ public function exportAsLocal(): array { + $actions = ($this->hasAction()) ? $this->getAction()->getValues() : []; + $favorited = false; + $reblogged = false; + foreach ($actions as $action => $value) { + if ($value) { + switch ($action) { + case StreamAction::BOOSTED: + $reblogged = true; + break; + case StreamAction::LIKED: + $favorited = true; + break; + } + } + } $result = [ + "local" => $this->isLocal(), "content" => $this->getContent(), "sensitive" => $this->isSensitive(), "spoiler_text" => $this->getSpoilerText(), @@ -491,8 +517,8 @@ class Stream extends ACore implements IQueryRow, JsonSerializable { 'replies_count' => 0, 'reblogs_count' => 0, 'favourites_count' => 0, - 'favourited' => false, - 'reblogged' => false, + 'favourited' => $favorited, + 'reblogged' => $reblogged, 'muted' => false, 'bookmarked' => false, 'uri' => $this->getId(), @@ -504,7 +530,7 @@ class Stream extends ACore implements IQueryRow, JsonSerializable { // TODO - store created_at full string with milliseconds ? if ($this->hasActor()) { $actor = $this->getActor(); - $result['account'] = $actor; + $result['account'] = $actor->exportAsLocal(); } return array_merge(parent::exportAsLocal(), $result); diff --git a/lib/Service/StreamService.php b/lib/Service/StreamService.php index 8c37cf54..c8f21513 100644 --- a/lib/Service/StreamService.php +++ b/lib/Service/StreamService.php @@ -426,9 +426,9 @@ class StreamService { public function getTimeline(TimelineOptions $options): array { if ($options->getTimeline() === 'home') { return $this->streamRequest->getTimelineHome($options); + } else if ($options->getTimeline() === 'public') { + return $this->streamRequest->getTimelinePublic($options); } - - } /** @@ -480,7 +480,7 @@ class StreamService { * @deprecated */ public function getStreamLocalTimeline(int $since = 0, int $limit = 5): array { - return $this->streamRequest->getTimelineGlobal($since, $limit, true); + return $this->streamRequest->getTimelineGlobal_dep($since, $limit, true); } @@ -518,7 +518,7 @@ class StreamService { * @throws Exception */ public function getStreamGlobalTimeline(int $since = 0, int $limit = 5): array { - return $this->streamRequest->getTimelineGlobal($since, $limit, false); + return $this->streamRequest->getTimelineGlobal_dep($since, $limit, false); }