From 9ac8eb965b930110d0ec42d56988a10adf1e3f96 Mon Sep 17 00:00:00 2001 From: Maxence Lange Date: Fri, 22 Feb 2019 23:04:00 -0100 Subject: [PATCH] boost creation Signed-off-by: Maxence Lange --- appinfo/info.xml | 1 + lib/Command/NoteBoost.php | 136 ++++++++++++++++++++++ lib/Command/NoteCreate.php | 1 + lib/Controller/LocalController.php | 40 ++++++- lib/Db/CoreRequestBuilder.php | 59 +++++----- lib/Db/NotesRequest.php | 127 +++++++++++--------- lib/Db/NotesRequestBuilder.php | 30 ++++- lib/Model/ActivityPub/ACore.php | 5 +- lib/Model/ActivityPub/Object/Announce.php | 2 - lib/Model/ActivityPub/Object/Note.php | 6 +- lib/Model/ActivityPub/Stream.php | 11 +- lib/Model/LinkedDataSignature.php | 7 +- lib/Service/ActorService.php | 17 --- lib/Service/CacheActorService.php | 17 ++- lib/Service/FollowService.php | 16 +-- lib/Service/NoteService.php | 132 +++++++++++++-------- lib/Service/PostService.php | 21 +++- 17 files changed, 426 insertions(+), 202 deletions(-) create mode 100644 lib/Command/NoteBoost.php diff --git a/appinfo/info.xml b/appinfo/info.xml index f1a3c69b..83c87f31 100644 --- a/appinfo/info.xml +++ b/appinfo/info.xml @@ -47,6 +47,7 @@ OCA\Social\Command\CacheRefresh OCA\Social\Command\NoteCreate + OCA\Social\Command\NoteBoost OCA\Social\Command\Reset OCA\Social\Command\QueueStatus OCA\Social\Command\QueueProcess diff --git a/lib/Command/NoteBoost.php b/lib/Command/NoteBoost.php new file mode 100644 index 00000000..477d806b --- /dev/null +++ b/lib/Command/NoteBoost.php @@ -0,0 +1,136 @@ + + * @copyright 2018, Maxence Lange + * @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 . + * + */ + + +namespace OCA\Social\Command; + +use Exception; +use OC\Core\Command\Base; +use OCA\Social\Model\ActivityPub\ACore; +use OCA\Social\Model\ActivityPub\Object\Announce; +use OCA\Social\Model\ActivityPub\Stream; +use OCA\Social\Model\Post; +use OCA\Social\Service\AccountService; +use OCA\Social\Service\ActivityService; +use OCA\Social\Service\ConfigService; +use OCA\Social\Service\CurlService; +use OCA\Social\Service\MiscService; +use OCA\Social\Service\NoteService; +use OCA\Social\Service\PostService; +use Symfony\Component\Console\Input\InputArgument; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Input\InputOption; +use Symfony\Component\Console\Output\OutputInterface; + + +class NoteBoost extends Base { + + + /** @var ConfigService */ + private $configService; + + /** @var ActivityService */ + private $activityService; + + /** @var NoteService */ + private $noteService; + + /** @var AccountService */ + private $accountService; + + /** @var PostService */ + private $postService; + + /** @var CurlService */ + private $curlService; + + /** @var MiscService */ + private $miscService; + + + /** + * NoteCreate constructor. + * + * @param ActivityService $activityService + * @param AccountService $accountService + * @param NoteService $noteService + * @param PostService $postService + * @param CurlService $curlService + * @param ConfigService $configService + * @param MiscService $miscService + */ + public function __construct( + ActivityService $activityService, AccountService $accountService, + NoteService $noteService, PostService $postService, CurlService $curlService, + ConfigService $configService, MiscService $miscService + ) { + parent::__construct(); + + $this->activityService = $activityService; + $this->noteService = $noteService; + $this->accountService = $accountService; + $this->postService = $postService; + $this->curlService = $curlService; + $this->configService = $configService; + $this->miscService = $miscService; + } + + + /** + * + */ + protected function configure() { + parent::configure(); + $this->setName('social:note:boost') + ->addArgument('userid', InputArgument::REQUIRED, 'userId of the author') + ->addArgument('note', InputArgument::REQUIRED, 'Note to boost') + ->setDescription('Boost a note'); + } + + + /** + * @param InputInterface $input + * @param OutputInterface $output + * + * @throws Exception + */ + protected function execute(InputInterface $input, OutputInterface $output) { + $userId = $input->getArgument('userid'); + $noteId = $input->getArgument('note'); + + $actor = $this->accountService->getActorFromUserId($userId); + $this->noteService->setViewer($actor); + $token = $this->noteService->createBoost($actor, $noteId, $activity); + + echo 'object: ' . json_encode($activity, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES) . "\n"; + echo 'token: ' . $token . "\n"; + } + +} + diff --git a/lib/Command/NoteCreate.php b/lib/Command/NoteCreate.php index 96867c54..99c3d18c 100644 --- a/lib/Command/NoteCreate.php +++ b/lib/Command/NoteCreate.php @@ -47,6 +47,7 @@ use Symfony\Component\Console\Output\OutputInterface; class NoteCreate extends Base { + /** @var ConfigService */ private $configService; diff --git a/lib/Controller/LocalController.php b/lib/Controller/LocalController.php index 57d67d96..2c21ffa2 100644 --- a/lib/Controller/LocalController.php +++ b/lib/Controller/LocalController.php @@ -38,7 +38,6 @@ use OCA\Social\Exceptions\AccountDoesNotExistException; use OCA\Social\Exceptions\InvalidResourceException; 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\Stream; use OCA\Social\Model\Post; use OCA\Social\Service\AccountService; @@ -198,6 +197,35 @@ class LocalController extends Controller { /** + * Create a new boost. + * + * @NoAdminRequired + * + * @param array $data + * + * @return DataResponse + */ + public function boostPost(array $data): DataResponse { + try { + $this->initViewer(true); + + $postId = $this->get('postId', $data, ''); + $token = $this->noteService->createBoost($this->viewer, $postId, $announce); + + return $this->success( + [ + 'boost' => $announce, + 'token' => $token + ] + ); + } catch (Exception $e) { + return $this->fail($e); + } + } + + + /** + * @NoCSRFRequired * @NoAdminRequired * * @param int $since @@ -669,13 +697,19 @@ class LocalController extends Controller { */ private function initViewer(bool $exception = false) { if (!isset($this->userId)) { + if ($exception) { + throw new AccountDoesNotExistException('userId not defined'); + } + return; } + try { $this->viewer = $this->accountService->getActorFromUserId($this->userId, true); - $this->followService->setViewerId($this->viewer->getId()); - $this->cacheActorService->setViewerId($this->viewer->getId()); + $this->noteService->setViewer($this->viewer); + $this->followService->setViewer($this->viewer); + $this->cacheActorService->setViewer($this->viewer); } catch (Exception $e) { if ($exception) { throw new AccountDoesNotExistException(); diff --git a/lib/Db/CoreRequestBuilder.php b/lib/Db/CoreRequestBuilder.php index 27059c49..ff94b98d 100644 --- a/lib/Db/CoreRequestBuilder.php +++ b/lib/Db/CoreRequestBuilder.php @@ -79,8 +79,8 @@ class CoreRequestBuilder { /** @var string */ protected $defaultSelectAlias; - /** @var string */ - private $viewerId = ''; + /** @var Person */ + protected $viewer = null; /** @@ -100,17 +100,10 @@ class CoreRequestBuilder { /** - * @return string + * @param Person $viewer */ - public function getViewerId(): string { - return $this->viewerId; - } - - /** - * @param string $viewerId - */ - public function setViewerId(string $viewerId) { - $this->viewerId = $viewerId; + public function setViewer(Person $viewer) { + $this->viewer = $viewer; } @@ -722,8 +715,7 @@ class CoreRequestBuilder { return; } - $viewerId = $this->getViewerId(); - if ($viewerId === '') { + if ($this->viewer === null) { return; } @@ -744,7 +736,7 @@ class CoreRequestBuilder { $andX->add( $expr->eq( $func->lower($prefix . '_f.actor_id'), - $func->lower($qb->createNamedParameter($viewerId)) + $func->lower($qb->createNamedParameter($this->viewer->getId())) ) ); } else { @@ -756,7 +748,7 @@ class CoreRequestBuilder { $andX->add( $expr->eq( $func->lower($prefix . '_f.object_id'), - $func->lower($qb->createNamedParameter($viewerId)) + $func->lower($qb->createNamedParameter($this->viewer->getId())) ) ); } @@ -820,24 +812,25 @@ class CoreRequestBuilder { * @param array $data */ protected function assignDetails(Person $actor, array $data) { - if ($this->getViewerId() !== '') { - - try { - $this->parseFollowLeftJoin($data, 'as_follower'); - $actor->addDetailBool('following', true); - } catch (InvalidResourceException $e) { - $actor->addDetailBool('following', false); - } - - try { - $this->parseFollowLeftJoin($data, 'as_followed'); - $actor->addDetailBool('followed', true); - } catch (InvalidResourceException $e) { - $actor->addDetailBool('followed', false); - } - - $actor->setCompleteDetails(true); + if ($this->viewer === null) { + return; } + + try { + $this->parseFollowLeftJoin($data, 'as_follower'); + $actor->addDetailBool('following', true); + } catch (InvalidResourceException $e) { + $actor->addDetailBool('following', false); + } + + try { + $this->parseFollowLeftJoin($data, 'as_followed'); + $actor->addDetailBool('followed', true); + } catch (InvalidResourceException $e) { + $actor->addDetailBool('followed', false); + } + + $actor->setCompleteDetails(true); } diff --git a/lib/Db/NotesRequest.php b/lib/Db/NotesRequest.php index 005d5202..2eef3de0 100644 --- a/lib/Db/NotesRequest.php +++ b/lib/Db/NotesRequest.php @@ -60,61 +60,18 @@ class NotesRequest extends NotesRequestBuilder { /** - * Insert a new Note in the database. - * - * @param Stream $note + * @param Stream $stream */ - public function save(Stream $note) { - $dTime = new DateTime(); - $dTime->setTimestamp($note->getPublishedTime()); + public function save(Stream $stream) { + $qb = $this->saveStream($stream); - $cache = '[]'; - if ($note->gotCache()) { - $cache = json_encode($note->getCache(), JSON_UNESCAPED_SLASHES); + if ($stream->getType() === Note::TYPE) { + /** @var Note $stream */ + $qb->setValue( + 'hashtags', $qb->createNamedParameter(json_encode($stream->getHashtags())) + ); } - $qb = $this->getNotesInsertSql(); - $qb->setValue('id', $qb->createNamedParameter($note->getId())) - ->setValue('type', $qb->createNamedParameter($note->getType())) - ->setValue('to', $qb->createNamedParameter($note->getTo())) - ->setValue( - 'to_array', $qb->createNamedParameter( - json_encode($note->getToArray(), JSON_UNESCAPED_SLASHES) - ) - ) - ->setValue( - 'cc', $qb->createNamedParameter( - json_encode($note->getCcArray(), JSON_UNESCAPED_SLASHES) - ) - ) - ->setValue( - 'bcc', $qb->createNamedParameter( - json_encode($note->getBccArray()), JSON_UNESCAPED_SLASHES - ) - ) - ->setValue('content', $qb->createNamedParameter($note->getContent())) - ->setValue('summary', $qb->createNamedParameter($note->getSummary())) - ->setValue('hashtags', $qb->createNamedParameter(json_encode($note->getHashtags()))) - ->setValue('published', $qb->createNamedParameter($note->getPublished())) - ->setValue( - 'published_time', $qb->createNamedParameter($dTime, IQueryBuilder::PARAM_DATE) - ) - ->setValue('attributed_to', $qb->createNamedParameter($note->getAttributedTo())) - ->setValue('in_reply_to', $qb->createNamedParameter($note->getInReplyTo())) - ->setValue('source', $qb->createNamedParameter($note->getSource())) - ->setValue('object_id', $qb->createNamedParameter($note->getObjectId())) - ->setValue('cache', $qb->createNamedParameter($cache)) - ->setValue( - 'instances', $qb->createNamedParameter( - json_encode($note->getInstancePaths(), JSON_UNESCAPED_SLASHES) - ) - ) - ->setValue('local', $qb->createNamedParameter(($note->isLocal()) ? '1' : '0')) - ->setValue( - 'creation', - $qb->createNamedParameter(new DateTime('now'), IQueryBuilder::PARAM_DATE) - ); - $qb->execute(); } @@ -135,11 +92,12 @@ class NotesRequest extends NotesRequestBuilder { /** * @param string $id + * @param bool $asViewer * * @return Note * @throws NoteNotFoundException */ - public function getNoteById(string $id): Note { + public function getNoteById(string $id, bool $asViewer = false): Note { if ($id === '') { throw new NoteNotFoundException(); }; @@ -147,6 +105,10 @@ class NotesRequest extends NotesRequestBuilder { $qb = $this->getNotesSelectSql(); $this->limitToIdString($qb, $id); + if ($asViewer) { + $this->limitToViewer($qb); + } + $cursor = $qb->execute(); $data = $cursor->fetch(); $cursor->closeCursor(); @@ -435,5 +397,66 @@ class NotesRequest extends NotesRequestBuilder { $qb->execute(); } + + /** + * Insert a new Note in the database. + * + * @param Stream $note + * + * @return IQueryBuilder + */ + public function saveStream(Stream $note): IQueryBuilder { + $dTime = new DateTime(); + $dTime->setTimestamp($note->getPublishedTime()); + + $cache = '[]'; + if ($note->gotCache()) { + $cache = json_encode($note->getCache(), JSON_UNESCAPED_SLASHES); + } + + $qb = $this->getNotesInsertSql(); + $qb->setValue('id', $qb->createNamedParameter($note->getId())) + ->setValue('type', $qb->createNamedParameter($note->getType())) + ->setValue('to', $qb->createNamedParameter($note->getTo())) + ->setValue( + 'to_array', $qb->createNamedParameter( + json_encode($note->getToArray(), JSON_UNESCAPED_SLASHES) + ) + ) + ->setValue( + 'cc', $qb->createNamedParameter( + json_encode($note->getCcArray(), JSON_UNESCAPED_SLASHES) + ) + ) + ->setValue( + 'bcc', $qb->createNamedParameter( + json_encode($note->getBccArray()), JSON_UNESCAPED_SLASHES + ) + ) + ->setValue('content', $qb->createNamedParameter($note->getContent())) + ->setValue('summary', $qb->createNamedParameter($note->getSummary())) + ->setValue('published', $qb->createNamedParameter($note->getPublished())) + ->setValue( + 'published_time', $qb->createNamedParameter($dTime, IQueryBuilder::PARAM_DATE) + ) + ->setValue('attributed_to', $qb->createNamedParameter($note->getAttributedTo())) + ->setValue('in_reply_to', $qb->createNamedParameter($note->getInReplyTo())) + ->setValue('source', $qb->createNamedParameter($note->getSource())) + ->setValue('object_id', $qb->createNamedParameter($note->getObjectId())) + ->setValue('cache', $qb->createNamedParameter($cache)) + ->setValue( + 'instances', $qb->createNamedParameter( + json_encode($note->getInstancePaths(), JSON_UNESCAPED_SLASHES) + ) + ) + ->setValue('local', $qb->createNamedParameter(($note->isLocal()) ? '1' : '0')) + ->setValue( + 'creation', + $qb->createNamedParameter(new DateTime('now'), IQueryBuilder::PARAM_DATE) + ); + + return $qb; + } + } diff --git a/lib/Db/NotesRequestBuilder.php b/lib/Db/NotesRequestBuilder.php index 09e6f6a8..bd9e3a7b 100644 --- a/lib/Db/NotesRequestBuilder.php +++ b/lib/Db/NotesRequestBuilder.php @@ -33,6 +33,7 @@ namespace OCA\Social\Db; use daita\MySmallPhpTools\Traits\TArrayTools; use Doctrine\DBAL\Query\QueryBuilder; use OCA\Social\Exceptions\InvalidResourceException; +use OCA\Social\Model\ActivityPub\ACore; use OCA\Social\Model\ActivityPub\Actor\Person; use OCA\Social\Model\ActivityPub\Object\Note; use OCA\Social\Model\InstancePath; @@ -83,10 +84,10 @@ class NotesRequestBuilder extends CoreRequestBuilder { $qb->selectDistinct('sn.id') ->addSelect( 'sn.type', 'sn.to', 'sn.to_array', 'sn.cc', 'sn.bcc', 'sn.content', - 'sn.summary', 'sn.published', 'sn.published_time', 'sn.cache', 'sn.object_id', - 'sn.attributed_to', 'sn.in_reply_to', 'sn.source', 'sn.local', 'sn.instances', - 'sn.creation' - ) + 'sn.summary', 'sn.published', 'sn.published_time', 'sn.cache', 'sn.object_id', + 'sn.attributed_to', 'sn.in_reply_to', 'sn.source', 'sn.local', 'sn.instances', + 'sn.creation' + ) ->from(self::TABLE_SERVER_NOTES, 'sn'); $this->defaultSelectAlias = 'sn'; @@ -124,6 +125,19 @@ class NotesRequestBuilder extends CoreRequestBuilder { } + /** + * @param IQueryBuilder $qb + */ + protected function limitToViewer(IQueryBuilder $qb) { + $actor = $this->viewer; + + $on = $this->exprJoinFollowing($qb, $actor, false); + $on->add($this->exprLimitToRecipient($qb, ACore::CONTEXT_PUBLIC, false)); + $on->add($this->exprLimitToRecipient($qb, $actor->getId(), true)); + $qb->join($this->defaultSelectAlias, CoreRequestBuilder::TABLE_SERVER_FOLLOWS, 'f', $on); + } + + /** * @param IQueryBuilder $qb * @param Person $actor @@ -143,15 +157,19 @@ class NotesRequestBuilder extends CoreRequestBuilder { * @param IQueryBuilder $qb * @param Person $actor * + * @param bool $followers + * * @return ICompositeExpression */ - protected function exprJoinFollowing(IQueryBuilder $qb, Person $actor) { + protected function exprJoinFollowing(IQueryBuilder $qb, Person $actor, bool $followers = true) { $expr = $qb->expr(); $func = $qb->func(); $pf = $this->defaultSelectAlias . '.'; $on = $expr->orX(); - $on->add($this->exprLimitToRecipient($qb, $actor->getFollowers(), false)); + if ($followers) { + $on->add($this->exprLimitToRecipient($qb, $actor->getFollowers(), false)); + } // list of possible recipient as a follower (to, to_array, cc, ...) $recipientFields = $expr->orX(); diff --git a/lib/Model/ActivityPub/ACore.php b/lib/Model/ActivityPub/ACore.php index e248a7a1..9db0df3e 100644 --- a/lib/Model/ActivityPub/ACore.php +++ b/lib/Model/ActivityPub/ACore.php @@ -669,7 +669,10 @@ class ACore extends Item implements JsonSerializable { $this->addEntryBool('local', $this->isLocal()); } - return $this->getEntries(); + $result = $this->getEntries(); + $this->cleanArray($result); + + return $result; } } diff --git a/lib/Model/ActivityPub/Object/Announce.php b/lib/Model/ActivityPub/Object/Announce.php index 31076a0c..1b23d518 100644 --- a/lib/Model/ActivityPub/Object/Announce.php +++ b/lib/Model/ActivityPub/Object/Announce.php @@ -64,8 +64,6 @@ class Announce extends Stream implements JsonSerializable { */ public function import(array $data) { parent::import($data); - - $this->setAttributedTo($this->getActorId()); } diff --git a/lib/Model/ActivityPub/Object/Note.php b/lib/Model/ActivityPub/Object/Note.php index 9edb5300..6207e59e 100644 --- a/lib/Model/ActivityPub/Object/Note.php +++ b/lib/Model/ActivityPub/Object/Note.php @@ -107,7 +107,7 @@ class Note extends Stream implements JsonSerializable { public function importFromDatabase(array $data) { parent::importFromDatabase($data); - $this->setHashtags($this->getArray('hashtags', $data, [])); + $this->setHashtags($this->getArray('hashtags', $data, [])); } @@ -117,10 +117,12 @@ class Note extends Stream implements JsonSerializable { public function jsonSerialize(): array { $result = parent::jsonSerialize(); - if ($this->isCompleteDetails()) { + if ($this->isCompleteDetails()) { $result['hashtags'] = $this->getHashtags(); } + $this->cleanArray($result); + return $result; } diff --git a/lib/Model/ActivityPub/Stream.php b/lib/Model/ActivityPub/Stream.php index c24e4fb2..f9cf86f2 100644 --- a/lib/Model/ActivityPub/Stream.php +++ b/lib/Model/ActivityPub/Stream.php @@ -293,13 +293,13 @@ class Stream extends ACore implements JsonSerializable { * @return array */ public function jsonSerialize(): array { - $this->addEntryInt('publishedTime', $this->getPublishedTime()); - $result = array_merge( parent::jsonSerialize(), [ 'content' => $this->getContent(), - 'attributedTo' => $this->getUrlSocial() . $this->getAttributedTo(), + 'attributedTo' => ($this->getAttributedTo() !== '') ? $this->getUrlSocial() + . $this->getAttributedTo( + ) : '', 'inReplyTo' => $this->getInReplyTo(), 'sensitive' => $this->isSensitive(), 'conversation' => $this->getConversation() @@ -310,11 +310,14 @@ class Stream extends ACore implements JsonSerializable { $result = array_merge( $result, [ - 'cache' => $this->getCache() + 'cache' => ($this->gotCache()) ? $this->getCache() : '', + 'publishedTime' => $this->getPublishedTime() ] ); } + $this->cleanArray($result); + return $result; } diff --git a/lib/Model/LinkedDataSignature.php b/lib/Model/LinkedDataSignature.php index abf4406d..00532cef 100644 --- a/lib/Model/LinkedDataSignature.php +++ b/lib/Model/LinkedDataSignature.php @@ -293,12 +293,7 @@ class LinkedDataSignature implements JsonSerializable { */ private function hashedCanonicalize(array $data, bool $removeEmptyValue = false): string { if ($removeEmptyValue) { - $data = array_filter( - $data, - function($v) { - return ($v !== ''); - } - ); + $this->cleanArray($data); } $object = json_decode(json_encode($data, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE)); diff --git a/lib/Service/ActorService.php b/lib/Service/ActorService.php index e15dbae5..dc6f5e1e 100644 --- a/lib/Service/ActorService.php +++ b/lib/Service/ActorService.php @@ -65,10 +65,6 @@ class ActorService { private $miscService; - /** @var string */ - private $viewerId = ''; - - /** * ActorService constructor. * @@ -92,19 +88,6 @@ class ActorService { } - /** - * @param string $viewerId - */ - public function setViewerId(string $viewerId) { - $this->viewerId = $viewerId; - $this->cacheActorsRequest->setViewerId($viewerId); - } - - public function getViewerId(): string { - return $this->viewerId; - } - - /** * @param Person $actor */ diff --git a/lib/Service/CacheActorService.php b/lib/Service/CacheActorService.php index 6da7772a..5d16fc05 100644 --- a/lib/Service/CacheActorService.php +++ b/lib/Service/CacheActorService.php @@ -69,8 +69,8 @@ class CacheActorService { private $miscService; - /** @var string */ - private $viewerId; + /** @var Person */ + private $viewer = null; /** @@ -93,15 +93,11 @@ class CacheActorService { /** - * @param string $viewerId + * @param Person $viewer */ - public function setViewerId(string $viewerId) { - $this->viewerId = $viewerId; - $this->cacheActorsRequest->setViewerId($viewerId); - } - - public function getViewerId(): string { - return $this->viewerId; + public function setViewer(Person $viewer) { + $this->viewer = $viewer; + $this->cacheActorsRequest->setViewer($viewer); } @@ -171,6 +167,7 @@ class CacheActorService { if (strrpos($account, '@')) { $account = substr($account, 0, strrpos($account, '@')); } + return $this->cacheActorsRequest->getFromLocalAccount($account); } diff --git a/lib/Service/FollowService.php b/lib/Service/FollowService.php index b6ee5c54..e41cec6d 100644 --- a/lib/Service/FollowService.php +++ b/lib/Service/FollowService.php @@ -77,8 +77,8 @@ class FollowService { private $miscService; - /** @var string */ - private $viewerId = ''; + /** @var Person */ + private $viewer = null; /** @@ -104,15 +104,11 @@ class FollowService { /** - * @param string $viewerId + * @param Person $viewer */ - public function setViewerId(string $viewerId) { - $this->viewerId = $viewerId; - $this->followsRequest->setViewerId($viewerId); - } - - public function getViewerId(): string { - return $this->viewerId; + public function setViewer(Person $viewer) { + $this->viewer = $viewer; + $this->followsRequest->setViewer($viewer); } diff --git a/lib/Service/NoteService.php b/lib/Service/NoteService.php index a4d432a3..d0bf47ac 100644 --- a/lib/Service/NoteService.php +++ b/lib/Service/NoteService.php @@ -46,7 +46,9 @@ use OCA\Social\Exceptions\RequestServerException; use OCA\Social\Exceptions\SocialAppConfigException; use OCA\Social\Model\ActivityPub\ACore; use OCA\Social\Model\ActivityPub\Actor\Person; +use OCA\Social\Model\ActivityPub\Object\Announce; use OCA\Social\Model\ActivityPub\Object\Note; +use OCA\Social\Model\ActivityPub\Stream; use OCA\Social\Model\InstancePath; class NoteService { @@ -61,6 +63,9 @@ class NoteService { /** @var AccountService */ private $accountService; + /** @var SignatureService */ + private $signatureService; + /** @var CacheActorService */ private $cacheActorService; @@ -71,8 +76,8 @@ class NoteService { private $miscService; - /** @var string */ - private $viewerId = ''; + /** @var Person */ + private $viewer = null; /** @@ -81,18 +86,20 @@ class NoteService { * @param NotesRequest $notesRequest * @param ActivityService $activityService * @param AccountService $accountService + * @param SignatureService $signatureService * @param CacheActorService $cacheActorService * @param ConfigService $configService * @param MiscService $miscService */ public function __construct( NotesRequest $notesRequest, ActivityService $activityService, - AccountService $accountService, CacheActorService $cacheActorService, - ConfigService $configService, MiscService $miscService + AccountService $accountService, SignatureService $signatureService, + CacheActorService $cacheActorService, ConfigService $configService, MiscService $miscService ) { $this->notesRequest = $notesRequest; $this->activityService = $activityService; $this->accountService = $accountService; + $this->signatureService = $signatureService; $this->cacheActorService = $cacheActorService; $this->configService = $configService; $this->miscService = $miscService; @@ -100,65 +107,84 @@ class NoteService { /** - * @param string $viewerId + * @param Person $viewer */ - public function setViewerId(string $viewerId) { - $this->viewerId = $viewerId; - $this->notesRequest->setViewerId($viewerId); - } - - public function getViewerId(): string { - return $this->viewerId; + public function setViewer(Person $viewer) { + $this->viewer = $viewer; + $this->notesRequest->setViewer($viewer); } /** * @param Person $actor - * @param string $content + * @param string $postId + * @param ACore|null $announce * - * @param string $type - * - * @return Note + * @return string + * @throws NoteNotFoundException * @throws SocialAppConfigException */ - public function generateNote(Person $actor, string $content, string $type) { - $note = new Note(); - $note->setId($this->configService->generateId('@' . $actor->getPreferredUsername())); - $note->setPublished(date("c")); - $note->setAttributedTo( - $this->configService->getUrlSocial() . '@' . $actor->getPreferredUsername() - ); + public function createBoost(Person $actor, string $postId, ACore &$announce = null): string { - $this->setRecipient($note, $actor, $type); - $note->setContent($content); - $note->convertPublished(); - $note->setLocal(true); + $announce = new Announce(); + $this->assignStream($announce, $actor, Stream::TYPE_PUBLIC); - return $note; + $announce->setActor($actor); + $note = $this->getNoteById($postId, true); + + $announce->addCc($note->getAttributedTo()); + if ($note->isLocal()) { + $announce->setObject($note); + } else { + $announce->setObjectId($note->getId()); + } + + $this->signatureService->signObject($actor, $announce); + $this->notesRequest->save($announce); + $token = $this->activityService->request($announce); + + return $token; } /** - * @param Note $note + * @param Stream $stream + * @param Person $actor + * @param string $type + * + * @throws SocialAppConfigException + */ + public function assignStream(Stream &$stream, Person $actor, string $type) { + $stream->setId($this->configService->generateId('@' . $actor->getPreferredUsername())); + $stream->setPublished(date("c")); + + $this->setRecipient($stream, $actor, $type); + $stream->convertPublished(); + $stream->setLocal(true); + } + + + /** + * @param Stream $stream * @param Person $actor * @param string $type */ - private function setRecipient(Note $note, Person $actor, string $type) { + private function setRecipient(Stream $stream, Person $actor, string $type) { switch ($type) { case Note::TYPE_UNLISTED: - $note->setTo($actor->getFollowers()); - $note->addInstancePath( + $stream->setTo($actor->getFollowers()); + $stream->addInstancePath( new InstancePath( $actor->getFollowers(), InstancePath::TYPE_FOLLOWERS, InstancePath::PRIORITY_LOW ) ); - $note->addCc(ACore::CONTEXT_PUBLIC); + $stream->addCc(ACore::CONTEXT_PUBLIC); break; case Note::TYPE_FOLLOWERS: - $note->setTo($actor->getFollowers()); - $note->addInstancePath( + $stream->setTo($actor->getFollowers()); + $stream->addInstancePath( new InstancePath( $actor->getFollowers(), InstancePath::TYPE_FOLLOWERS, InstancePath::PRIORITY_LOW @@ -170,9 +196,9 @@ class NoteService { break; default: - $note->setTo(ACore::CONTEXT_PUBLIC); - $note->addCc($actor->getFollowers()); - $note->addInstancePath( + $stream->setTo(ACore::CONTEXT_PUBLIC); + $stream->addCc($actor->getFollowers()); + $stream->addInstancePath( new InstancePath( $actor->getFollowers(), InstancePath::TYPE_FOLLOWERS, InstancePath::PRIORITY_LOW @@ -184,11 +210,11 @@ class NoteService { /** - * @param Note $note + * @param Stream $stream * @param string $type * @param string $account */ - public function addRecipient(Note $note, string $type, string $account) { + public function addRecipient(Stream $stream, string $type, string $account) { if ($account === '') { return; } @@ -204,12 +230,12 @@ class NoteService { ); if ($type === Note::TYPE_DIRECT) { $instancePath->setPriority(InstancePath::PRIORITY_HIGH); - $note->addToArray($actor->getId()); + $stream->addToArray($actor->getId()); } else { - $note->addCc($actor->getId()); + $stream->addCc($actor->getId()); } - $note->addTag( + $stream->addTag( [ 'type' => 'Mention', 'href' => $actor->getId(), @@ -217,7 +243,7 @@ class NoteService { ] ); - $note->addInstancePath($instancePath); + $stream->addInstancePath($instancePath); } @@ -242,13 +268,13 @@ class NoteService { /** - * @param Note $note + * @param Stream $stream * @param string $type * @param array $accounts */ - public function addRecipients(Note $note, string $type, array $accounts) { + public function addRecipients(Stream $stream, string $type, array $accounts) { foreach ($accounts as $account) { - $this->addRecipient($note, $type, $account); + $this->addRecipient($stream, $type, $account); } } @@ -316,12 +342,13 @@ class NoteService { /** * @param string $id + * @param bool $asViewer * * @return Note * @throws NoteNotFoundException */ - public function getNoteById(string $id): Note { - return $this->notesRequest->getNoteById($id); + public function getNoteById(string $id, bool $asViewer = false): Note { + return $this->notesRequest->getNoteById($id, $asViewer); } @@ -392,7 +419,8 @@ class NoteService { * * @return Note[] */ - public function getStreamLocalTag(Person $actor, string $hashtag, int $since = 0, int $limit = 5): array { + public function getStreamLocalTag(Person $actor, string $hashtag, int $since = 0, int $limit = 5 + ): array { return $this->notesRequest->getStreamTag($actor, $hashtag, $since, $limit); } @@ -409,7 +437,8 @@ class NoteService { } - /** + /**m + * * @param int $since * @param int $limit * @@ -443,5 +472,6 @@ class NoteService { return $this->cacheActorService->getFromId($note->getAttributedTo()); } + } diff --git a/lib/Service/PostService.php b/lib/Service/PostService.php index 817ddc40..b2fa6616 100644 --- a/lib/Service/PostService.php +++ b/lib/Service/PostService.php @@ -38,10 +38,12 @@ use OCA\Social\Exceptions\NoteNotFoundException; use OCA\Social\Exceptions\RedundancyLimitException; use OCA\Social\Exceptions\RequestContentException; use OCA\Social\Exceptions\RequestNetworkException; +use OCA\Social\Exceptions\RequestResultNotJsonException; use OCA\Social\Exceptions\RequestResultSizeException; use OCA\Social\Exceptions\RequestServerException; use OCA\Social\Exceptions\SocialAppConfigException; use OCA\Social\Model\ActivityPub\ACore; +use OCA\Social\Model\ActivityPub\Object\Note; use OCA\Social\Model\Post; class PostService { @@ -56,6 +58,9 @@ class PostService { /** @var ActivityService */ private $activityService; + /** @var ConfigService */ + private $configService; + /** @var MiscService */ private $miscService; @@ -66,15 +71,17 @@ class PostService { * @param NoteService $noteService * @param AccountService $accountService * @param ActivityService $activityService + * @param ConfigService $configService * @param MiscService $miscService */ public function __construct( NoteService $noteService, AccountService $accountService, ActivityService $activityService, - MiscService $miscService + ConfigService $configService, MiscService $miscService ) { $this->noteService = $noteService; $this->accountService = $accountService; $this->activityService = $activityService; + $this->configService = $configService; $this->miscService = $miscService; } @@ -95,12 +102,16 @@ class PostService { * @throws RequestResultSizeException * @throws RequestServerException * @throws MalformedArrayException + * @throws RequestResultNotJsonException */ public function createPost(Post $post, ACore &$activity = null): string { - $note = - $this->noteService->generateNote( - $post->getActor(), htmlentities($post->getContent(), ENT_QUOTES), $post->getType() - ); + $note = new Note(); + $this->noteService->assignStream($note, $post->getActor(), $post->getType()); + $note->setAttributedTo( + $this->configService->getUrlSocial() . '@' . $actor->getPreferredUsername() + ); + + $note->setContent(htmlentities($post->getContent(), ENT_QUOTES)); $this->noteService->replyTo($note, $post->getReplyTo()); $this->noteService->addRecipients($note, $post->getType(), $post->getTo());