From b4d773940c9d6c601a2dc9a2ba39c0f6348e9545 Mon Sep 17 00:00:00 2001 From: Maxence Lange Date: Mon, 8 Apr 2019 15:52:03 -0100 Subject: [PATCH] Returns if a post is boosted, and allow unboost Signed-off-by: Maxence Lange --- appinfo/routes.php | 1 + lib/Command/NoteBoost.php | 26 ++- lib/Command/NoteCreate.php | 13 +- lib/Controller/LocalController.php | 38 +++- lib/Db/CoreRequestBuilder.php | 92 +++++++- lib/Db/NotesRequest.php | 62 ++++- lib/Db/NotesRequestBuilder.php | 11 +- lib/Db/StreamActionsRequest.php | 118 ++++++++++ lib/Db/StreamActionsRequestBuilder.php | 120 ++++++++++ .../StreamActionDoesNotExistException.php | 8 + lib/Interfaces/Object/AnnounceInterface.php | 25 +- .../Version0002Date20190313133046.php | 94 ++++++++ lib/Model/ActivityPub/Stream.php | 40 ++++ lib/Model/StreamAction.php | 214 ++++++++++++++++++ lib/Service/BoostService.php | 192 ++++++++++++++++ lib/Service/NoteService.php | 68 ++---- lib/Service/PostService.php | 18 +- lib/Service/StreamActionService.php | 117 ++++++++++ 18 files changed, 1180 insertions(+), 77 deletions(-) create mode 100644 lib/Db/StreamActionsRequest.php create mode 100644 lib/Db/StreamActionsRequestBuilder.php create mode 100644 lib/Exceptions/StreamActionDoesNotExistException.php create mode 100644 lib/Migration/Version0002Date20190313133046.php create mode 100644 lib/Model/StreamAction.php create mode 100644 lib/Service/BoostService.php create mode 100644 lib/Service/StreamActionService.php diff --git a/appinfo/routes.php b/appinfo/routes.php index d0816a74..620d46c0 100644 --- a/appinfo/routes.php +++ b/appinfo/routes.php @@ -72,6 +72,7 @@ return [ ['name' => 'Local#postDelete', 'url' => '/api/v1/post', 'verb' => 'DELETE'], ['name' => 'Local#postBoost', 'url' => '/api/v1/post/boost', 'verb' => 'POST'], + ['name' => 'Local#postUnboost', 'url' => '/api/v1/post/boost', 'verb' => 'DELETE'], ['name' => 'Local#actionFollow', 'url' => '/api/v1/current/follow', 'verb' => 'PUT'], ['name' => 'Local#actionUnfollow', 'url' => '/api/v1/current/follow', 'verb' => 'DELETE'], diff --git a/lib/Command/NoteBoost.php b/lib/Command/NoteBoost.php index dd1888ff..b435c10c 100644 --- a/lib/Command/NoteBoost.php +++ b/lib/Command/NoteBoost.php @@ -30,10 +30,12 @@ declare(strict_types=1); namespace OCA\Social\Command; + use Exception; use OC\Core\Command\Base; use OCA\Social\Service\AccountService; use OCA\Social\Service\ActivityService; +use OCA\Social\Service\BoostService; use OCA\Social\Service\ConfigService; use OCA\Social\Service\CurlService; use OCA\Social\Service\MiscService; @@ -44,6 +46,11 @@ use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; +/** + * Class NoteBoost + * + * @package OCA\Social\Command + */ class NoteBoost extends Base { @@ -59,6 +66,9 @@ class NoteBoost extends Base { /** @var AccountService */ private $accountService; + /** @var BoostService */ + private $boostService; + /** @var PostService */ private $postService; @@ -70,11 +80,12 @@ class NoteBoost extends Base { /** - * NoteCreate constructor. + * NoteBoost constructor. * * @param ActivityService $activityService * @param AccountService $accountService * @param NoteService $noteService + * @param BoostService $boostService * @param PostService $postService * @param CurlService $curlService * @param ConfigService $configService @@ -82,13 +93,14 @@ class NoteBoost extends Base { */ public function __construct( ActivityService $activityService, AccountService $accountService, - NoteService $noteService, PostService $postService, CurlService $curlService, - ConfigService $configService, MiscService $miscService + NoteService $noteService, BoostService $boostService, PostService $postService, + CurlService $curlService, ConfigService $configService, MiscService $miscService ) { parent::__construct(); $this->activityService = $activityService; $this->noteService = $noteService; + $this->boostService = $boostService; $this->accountService = $accountService; $this->postService = $postService; $this->curlService = $curlService; @@ -105,6 +117,7 @@ class NoteBoost extends Base { $this->setName('social:note:boost') ->addArgument('userid', InputArgument::REQUIRED, 'userId of the author') ->addArgument('note', InputArgument::REQUIRED, 'Note to boost') + ->addOption('unboost', '',InputOption::VALUE_NONE, 'Unboost') ->setDescription('Boost a note'); } @@ -121,7 +134,12 @@ class NoteBoost extends Base { $actor = $this->accountService->getActorFromUserId($userId); $this->noteService->setViewer($actor); - $token = $this->noteService->createBoost($actor, $noteId, $activity); + + if ($input->getOption('unboost') === null) { + $activity = $this->boostService->create($actor, $noteId, $token); + } else { + $activity= $this->boostService->delete($actor, $noteId, $token ); + } 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 99c3d18c..b6b8edb5 100644 --- a/lib/Command/NoteCreate.php +++ b/lib/Command/NoteCreate.php @@ -30,6 +30,7 @@ declare(strict_types=1); namespace OCA\Social\Command; + use Exception; use OC\Core\Command\Base; use OCA\Social\Model\Post; @@ -45,6 +46,11 @@ use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; +/** + * Class NoteCreate + * + * @package OCA\Social\Command + */ class NoteCreate extends Base { @@ -78,9 +84,8 @@ class NoteCreate extends Base { * @param MiscService $miscService */ public function __construct( - ActivityService $activityService, AccountService $accountService, - PostService $postService, CurlService $curlService, - ConfigService $configService, MiscService $miscService + ActivityService $activityService, AccountService $accountService, PostService $postService, + CurlService $curlService, ConfigService $configService, MiscService $miscService ) { parent::__construct(); @@ -142,7 +147,7 @@ class NoteCreate extends Base { $post->addTo(($to === null) ? '' : $to); $post->setHashtags(($hashtag === null) ? [] : [$hashtag]); - $token = $this->postService->createPost($post, $activity); + $activity = $this->postService->createPost($post, $token); echo 'object: ' . json_encode($activity, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES) . "\n"; echo 'token: ' . $token . "\n"; diff --git a/lib/Controller/LocalController.php b/lib/Controller/LocalController.php index bd1978a6..d28cd49b 100644 --- a/lib/Controller/LocalController.php +++ b/lib/Controller/LocalController.php @@ -41,6 +41,7 @@ use OCA\Social\Model\ActivityPub\Actor\Person; use OCA\Social\Model\ActivityPub\Stream; use OCA\Social\Model\Post; use OCA\Social\Service\AccountService; +use OCA\Social\Service\BoostService; use OCA\Social\Service\CacheActorService; use OCA\Social\Service\DocumentService; use OCA\Social\Service\FollowService; @@ -77,6 +78,9 @@ class LocalController extends Controller { /** @var FollowService */ private $followService; + /** @var BoostService */ + private $boostService; + /** @var PostService */ private $postService; @@ -111,6 +115,7 @@ class LocalController extends Controller { * @param PostService $postService * @param NoteService $noteService * @param SearchService $searchService + * @param BoostService $boostService * @param DocumentService $documentService * @param MiscService $miscService */ @@ -118,7 +123,7 @@ class LocalController extends Controller { IRequest $request, $userId, AccountService $accountService, CacheActorService $cacheActorService, FollowService $followService, PostService $postService, NoteService $noteService, SearchService $searchService, - DocumentService $documentService, MiscService $miscService + BoostService $boostService, DocumentService $documentService, MiscService $miscService ) { parent::__construct(Application::APP_NAME, $request); @@ -129,6 +134,7 @@ class LocalController extends Controller { $this->searchService = $searchService; $this->postService = $postService; $this->followService = $followService; + $this->boostService = $boostService; $this->documentService = $documentService; $this->miscService = $miscService; } @@ -156,7 +162,7 @@ class LocalController extends Controller { $post->setHashtags($this->getArray('hashtags', $data, [])); /** @var ACore $activity */ - $token = $this->postService->createPost($post, $activity); + $activity = $this->postService->createPost($post, $token); return $this->success( [ @@ -208,8 +214,34 @@ class LocalController extends Controller { public function postBoost(string $postId): DataResponse { try { $this->initViewer(true); + $announce = $this->boostService->create($this->viewer, $postId, $token); - $token = $this->noteService->createBoost($this->viewer, $postId, $announce); + return $this->success( + [ + 'boost' => $announce, + 'token' => $token + ] + ); + } catch (Exception $e) { + return $this->fail($e); + } + } + + + /** + * Delete a boost. + * + * @NoAdminRequired + * + * @param string $postId + * + * @return DataResponse + */ + public function postUnboost(string $postId): DataResponse { + try { + $this->initViewer(true); + + $token = $this->boostService->delete($this->viewer, $postId, $announce); return $this->success( [ diff --git a/lib/Db/CoreRequestBuilder.php b/lib/Db/CoreRequestBuilder.php index ac1956be..f87f15b2 100644 --- a/lib/Db/CoreRequestBuilder.php +++ b/lib/Db/CoreRequestBuilder.php @@ -36,10 +36,11 @@ use DateTime; use Doctrine\DBAL\Query\QueryBuilder; use Exception; use OCA\Social\Exceptions\InvalidResourceException; +use OCA\Social\Model\ActivityPub\Actor\Person; use OCA\Social\Model\ActivityPub\Object\Document; use OCA\Social\Model\ActivityPub\Object\Follow; use OCA\Social\Model\ActivityPub\Object\Image; -use OCA\Social\Model\ActivityPub\Actor\Person; +use OCA\Social\Model\StreamAction; use OCA\Social\Service\ConfigService; use OCA\Social\Service\MiscService; use OCP\DB\QueryBuilder\IQueryBuilder; @@ -65,6 +66,8 @@ class CoreRequestBuilder { const TABLE_CACHE_DOCUMENTS = 'social_cache_documents'; const TABLE_QUEUE_STREAM = 'social_queue_stream'; + const TABLE_STREAM_ACTIONS = 'social_stream_actions'; + /** @var IDBConnection */ @@ -161,6 +164,28 @@ class CoreRequestBuilder { } + /** + * Limit the request to the StreamId + * + * @param IQueryBuilder $qb + * @param string $streamId + */ + protected function limitToStreamId(IQueryBuilder &$qb, string $streamId) { + $this->limitToDBField($qb, 'user_id', $streamId, false); + } + + + /** + * Limit the request to the Type + * + * @param IQueryBuilder $qb + * @param string $type + */ + protected function limitToType(IQueryBuilder &$qb, string $type) { + $this->limitToDBField($qb, 'type', $type); + } + + /** * Limit the request to the Preferred Username * @@ -410,6 +435,8 @@ class CoreRequestBuilder { * @param IQueryBuilder $qb * @param int $since * @param int $limit + * + * @throws Exception */ protected function limitPaginate(IQueryBuilder &$qb, int $since = 0, int $limit = 5) { if ($since > 0) { @@ -547,6 +574,8 @@ class CoreRequestBuilder { * @param IQueryBuilder $qb * @param int $timestamp * @param string $field + * + * @throws Exception */ protected function limitToSince(IQueryBuilder $qb, int $timestamp, string $field) { $dTime = new \DateTime(); @@ -666,6 +695,65 @@ class CoreRequestBuilder { } + /** + * @param IQueryBuilder $qb + */ + protected function leftJoinStreamAction(IQueryBuilder &$qb) { + if ($qb->getType() !== QueryBuilder::SELECT || $this->viewer === null) { + return; + } + + $expr = $qb->expr(); + $func = $qb->func(); + + $pf = $this->defaultSelectAlias; + + $qb->selectAlias('sa.id', 'streamaction_id') + ->selectAlias('sa.actor_id', 'streamaction_actor_id') + ->selectAlias('sa.stream_id', 'streamaction_stream_id') + ->selectAlias('sa.values', 'streamaction_values'); + + $andX = $expr->andX(); + $andX->add($expr->eq($func->lower($pf . '.id'), $func->lower('sa.stream_id'))); + $andX->add( + $expr->eq( + $func->lower('sa.actor_id'), + $qb->createNamedParameter(strtolower($this->viewer->getId())) + ) + ); + + $qb->leftJoin( + $this->defaultSelectAlias, CoreRequestBuilder::TABLE_STREAM_ACTIONS, 'sa', + $andX + ); + } + + + /** + * @param array $data + * + * @return StreamAction + * @throws InvalidResourceException + */ + protected function parseStreamActionsLeftJoin(array $data): StreamAction { + $new = []; + foreach ($data as $k => $v) { + if (substr($k, 0, 13) === 'streamaction_') { + $new[substr($k, 13)] = $v; + } + } + + $action = new StreamAction(); + $action->importFromDatabase($new); + + if ($action->getId() === 0) { + throw new InvalidResourceException(); + } + + return $action; + } + + /** * @param IQueryBuilder $qb * @param string $fieldDocumentId @@ -704,12 +792,12 @@ class CoreRequestBuilder { */ protected function parseCacheDocumentsLeftJoin(array $data): Document { $new = []; - foreach ($data as $k => $v) { if (substr($k, 0, 14) === 'cachedocument_') { $new[substr($k, 14)] = $v; } } + $document = new Document(); $document->importFromDatabase($new); diff --git a/lib/Db/NotesRequest.php b/lib/Db/NotesRequest.php index 4f44415a..ae226e1c 100644 --- a/lib/Db/NotesRequest.php +++ b/lib/Db/NotesRequest.php @@ -33,6 +33,7 @@ namespace OCA\Social\Db; use daita\MySmallPhpTools\Model\Cache; use DateTime; use Doctrine\DBAL\Exception\UniqueConstraintViolationException; +use Exception; use OCA\Social\Exceptions\NoteNotFoundException; use OCA\Social\Model\ActivityPub\ACore; use OCA\Social\Model\ActivityPub\Actor\Person; @@ -62,6 +63,8 @@ class NotesRequest extends NotesRequestBuilder { /** * @param Stream $stream + * + * @throws Exception */ public function save(Stream $stream) { $qb = $this->saveStream($stream); @@ -103,10 +106,10 @@ class NotesRequest extends NotesRequestBuilder { * @param string $id * @param bool $asViewer * - * @return Note + * @return Stream * @throws NoteNotFoundException */ - public function getNoteById(string $id, bool $asViewer = false): Note { + public function getNoteById(string $id, bool $asViewer = false): Stream { if ($id === '') { throw new NoteNotFoundException(); }; @@ -116,6 +119,7 @@ class NotesRequest extends NotesRequestBuilder { if ($asViewer) { $this->limitToViewer($qb); + $this->leftJoinStreamAction($qb); } $cursor = $qb->execute(); @@ -133,10 +137,10 @@ class NotesRequest extends NotesRequestBuilder { /** * @param string $id * - * @return Note + * @return Stream * @throws NoteNotFoundException */ - public function getNoteByActivityId(string $id): Note { + public function getNoteByActivityId(string $id): Stream { if ($id === '') { throw new NoteNotFoundException(); }; @@ -156,6 +160,37 @@ class NotesRequest extends NotesRequestBuilder { } + /** + * @param Person $actor + * @param string $type + * + * @param string $objectId + * + * @return Stream + * @throws NoteNotFoundException + */ + public function getNoteByObjectId(Person $actor, string $type, string $objectId): Stream { + if ($objectId === '') { + throw new NoteNotFoundException('missing objectId'); + }; + + $qb = $this->getNotesSelectSql(); + $this->limitToObjectId($qb, $objectId); + $this->limitToType($qb, $type); + $this->limitToActorId($qb, $actor->getId()); + + $cursor = $qb->execute(); + $data = $cursor->fetch(); + $cursor->closeCursor(); + + if ($data === false) { + throw new NoteNotFoundException('Post not found'); + } + + return $this->parseNotesSelectSql($data); + } + + /** * @param string $actorId * @@ -182,7 +217,8 @@ class NotesRequest extends NotesRequestBuilder { * @param int $since * @param int $limit * - * @return array + * @return Stream[] + * @throws Exception */ public function getStreamHome(Person $actor, int $since = 0, int $limit = 5): array { $qb = $this->getNotesSelectSql(); @@ -190,6 +226,7 @@ class NotesRequest extends NotesRequestBuilder { $this->joinFollowing($qb, $actor); $this->limitPaginate($qb, $since, $limit); $this->leftJoinCacheActors($qb, 'attributed_to'); + $this->leftJoinStreamAction($qb); $notes = []; $cursor = $qb->execute(); @@ -215,6 +252,7 @@ class NotesRequest extends NotesRequestBuilder { * @param int $limit * * @return array + * @throws Exception */ public function getStreamNotifications(Person $actor, int $since = 0, int $limit = 5): array { $qb = $this->getNotesSelectSql(); @@ -244,6 +282,7 @@ class NotesRequest extends NotesRequestBuilder { * @param int $limit * * @return array + * @throws Exception */ public function getStreamAccount(string $actorId, int $since = 0, int $limit = 5): array { $qb = $this->getNotesSelectSql(); @@ -273,6 +312,7 @@ class NotesRequest extends NotesRequestBuilder { * @param int $limit * * @return array + * @throws Exception */ public function getStreamDirect(Person $actor, int $since = 0, int $limit = 5): array { $qb = $this->getNotesSelectSql(); @@ -304,6 +344,7 @@ class NotesRequest extends NotesRequestBuilder { * @param bool $localOnly * * @return array + * @throws Exception */ public function getStreamTimeline(int $since = 0, int $limit = 5, bool $localOnly = true ): array { @@ -339,6 +380,7 @@ class NotesRequest extends NotesRequestBuilder { * @param int $limit * * @return array + * @throws Exception */ public function getStreamTag(Person $actor, string $hashtag, int $since = 0, int $limit = 5 ): array { @@ -369,6 +411,7 @@ class NotesRequest extends NotesRequestBuilder { * @param int $since * * @return Note[] + * @throws Exception */ public function getNotesSince(int $since): array { $qb = $this->getNotesSelectSql(); @@ -413,6 +456,7 @@ class NotesRequest extends NotesRequestBuilder { * @param Stream $note * * @return IQueryBuilder + * @throws Exception */ public function saveStream(Stream $note): IQueryBuilder { $dTime = new DateTime(); @@ -423,6 +467,12 @@ class NotesRequest extends NotesRequestBuilder { $cache = json_encode($note->getCache(), JSON_UNESCAPED_SLASHES); } + $attributedTo = $note->getAttributedTo(); + if ($attributedTo === '' && $note->isLocal()) { + $attributedTo = $note->getActor() + ->getId(); + } + $qb = $this->getNotesInsertSql(); $qb->setValue('id', $qb->createNamedParameter($note->getId())) ->setValue('type', $qb->createNamedParameter($note->getType())) @@ -448,7 +498,7 @@ class NotesRequest extends NotesRequestBuilder { ->setValue( 'published_time', $qb->createNamedParameter($dTime, IQueryBuilder::PARAM_DATE) ) - ->setValue('attributed_to', $qb->createNamedParameter($note->getAttributedTo())) + ->setValue('attributed_to', $qb->createNamedParameter($attributedTo)) ->setValue('in_reply_to', $qb->createNamedParameter($note->getInReplyTo())) ->setValue('source', $qb->createNamedParameter($note->getSource())) ->setValue('object_id', $qb->createNamedParameter($note->getObjectId())) diff --git a/lib/Db/NotesRequestBuilder.php b/lib/Db/NotesRequestBuilder.php index 011c478a..e9a64312 100644 --- a/lib/Db/NotesRequestBuilder.php +++ b/lib/Db/NotesRequestBuilder.php @@ -36,6 +36,7 @@ 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\InstancePath; use OCP\DB\QueryBuilder\ICompositeExpression; use OCP\DB\QueryBuilder\IQueryBuilder; @@ -353,9 +354,9 @@ class NotesRequestBuilder extends CoreRequestBuilder { /** * @param array $data * - * @return Note + * @return Stream */ - protected function parseNotesSelectSql($data): Note { + protected function parseNotesSelectSql($data): Stream { $note = new Note(); $note->importFromDatabase($data); @@ -375,6 +376,12 @@ class NotesRequestBuilder extends CoreRequestBuilder { } catch (InvalidResourceException $e) { } + try { + $action = $this->parseStreamActionsLeftJoin($data); + $note->setAction($action); + } catch (InvalidResourceException $e) { + } + return $note; } diff --git a/lib/Db/StreamActionsRequest.php b/lib/Db/StreamActionsRequest.php new file mode 100644 index 00000000..7008f131 --- /dev/null +++ b/lib/Db/StreamActionsRequest.php @@ -0,0 +1,118 @@ + + * @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\Db; + + +use OCA\Social\Exceptions\StreamActionDoesNotExistException; +use OCA\Social\Model\StreamAction; + + +/** + * Class StreamActionsRequest + * + * @package OCA\Social\Db + */ +class StreamActionsRequest extends StreamActionsRequestBuilder { + + + /** + * create a new Queue in the database. + * + * @param StreamAction $action + */ + public function create(StreamAction $action) { + $qb = $this->getStreamActionInsertSql(); + $qb->setValue('actor_id', $qb->createNamedParameter($action->getActorId())) + ->setValue('stream_id', $qb->createNamedParameter($action->getStreamId())) + ->setValue( + 'values', $qb->createNamedParameter( + json_encode($action->getValues(), JSON_UNESCAPED_SLASHES) + ) + ); + + $qb->execute(); + } + + + /** + * create a new Queue in the database. + * + * @param StreamAction $action + */ + public function update(StreamAction $action) { + $qb = $this->getStreamActionUpdateSql(); + + $values = json_encode($action->getValues(), JSON_UNESCAPED_SLASHES); + $qb->set('values', $qb->createNamedParameter($values)); + + $this->limitToActorId($qb, $action->getActorId()); + $this->limitToStreamId($qb, $action->getStreamId()); + + $qb->execute(); + } + + + /** + * @param string $actorId + * @param string $streamId + * + * @return StreamAction + * @throws StreamActionDoesNotExistException + */ + public function getAction(string $actorId, string $streamId): StreamAction { + $qb = $this->getStreamActionDeleteSql(); + $this->limitToActorId($qb, $actorId); + $this->limitToStreamId($qb, $streamId); + + $cursor = $qb->execute(); + $data = $cursor->fetch(); + if ($data === false) { + throw new StreamActionDoesNotExistException(); + } + $cursor->closeCursor(); + + return $this->parseStreamActionsSelectSql($data); + } + + + /** + * @param StreamAction $action + */ + public function delete(StreamAction $action) { + $qb = $this->getStreamActionDeleteSql(); + $this->limitToActorId($qb, $action->getActorId()); + $this->limitToStreamId($qb, $action->getStreamId()); + + $qb->execute(); + } + +} + diff --git a/lib/Db/StreamActionsRequestBuilder.php b/lib/Db/StreamActionsRequestBuilder.php new file mode 100644 index 00000000..e2afa894 --- /dev/null +++ b/lib/Db/StreamActionsRequestBuilder.php @@ -0,0 +1,120 @@ + + * @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\Db; + + +use daita\MySmallPhpTools\Traits\TArrayTools; +use OCA\Social\Model\RequestQueue; +use OCA\Social\Model\StreamAction; +use OCP\DB\QueryBuilder\IQueryBuilder; + + +/** + * Class StreamActionsRequestBuilder + * + * @package OCA\Social\Db + */ +class StreamActionsRequestBuilder extends CoreRequestBuilder { + + + use TArrayTools; + + + /** + * Base of the Sql Insert request + * + * @return IQueryBuilder + */ + protected function getStreamActionInsertSql(): IQueryBuilder { + $qb = $this->dbConnection->getQueryBuilder(); + $qb->insert(self::TABLE_STREAM_ACTIONS); + + return $qb; + } + + + /** + * Base of the Sql Update request + * + * @return IQueryBuilder + */ + protected function getStreamActionUpdateSql(): IQueryBuilder { + $qb = $this->dbConnection->getQueryBuilder(); + $qb->update(self::TABLE_STREAM_ACTIONS); + + return $qb; + } + + + /** + * Base of the Sql Select request for Shares + * + * @return IQueryBuilder + */ + protected function getStreamActionSelectSql(): IQueryBuilder { + $qb = $this->dbConnection->getQueryBuilder(); + + /** @noinspection PhpMethodParametersCountMismatchInspection */ + $qb->select('sa.id', 'sa.actor_id', 'sa.stream_id', 'sa.values') + ->from(self::TABLE_STREAM_ACTIONS, 'sa'); + + $this->defaultSelectAlias = 'sa'; + + return $qb; + } + + + /** + * Base of the Sql Delete request + * + * @return IQueryBuilder + */ + protected function getStreamActionDeleteSql(): IQueryBuilder { + $qb = $this->dbConnection->getQueryBuilder(); + $qb->delete(self::TABLE_STREAM_ACTIONS); + + return $qb; + } + + + /** + * @param array $data + * + * @return StreamAction + */ + protected function parseStreamActionsSelectSql($data): StreamAction { + $action = new StreamAction(); + $action->importFromDatabase($data); + + return $action; + } + +} + diff --git a/lib/Exceptions/StreamActionDoesNotExistException.php b/lib/Exceptions/StreamActionDoesNotExistException.php new file mode 100644 index 00000000..55790160 --- /dev/null +++ b/lib/Exceptions/StreamActionDoesNotExistException.php @@ -0,0 +1,8 @@ +miscService->log('activity: ' . json_encode($activity)); + $item->checkOrigin($activity->getId()); + + if ($activity->getType() === Undo::TYPE) { + $item->checkOrigin($item->getId()); + $this->delete($item); + } } @@ -93,6 +100,7 @@ class AnnounceInterface implements IActivityPubInterface { * @param ACore $item * * @throws InvalidOriginException + * @throws Exception */ public function processIncomingRequest(ACore $item) { /** @var Stream $item */ @@ -119,8 +127,11 @@ class AnnounceInterface implements IActivityPubInterface { throw new ItemNotFoundException(); } + /** * @param ACore $item + * + * @throws Exception */ public function save(ACore $item) { /** @var Announce $item */ @@ -142,8 +153,14 @@ class AnnounceInterface implements IActivityPubInterface { * @param ACore $item */ public function delete(ACore $item) { + try { + $stream = $this->notesRequest->getNoteById($item->getId()); + if ($stream->getType() === Announce::TYPE) { + $this->notesRequest->deleteNoteById($item->getId()); + } + } catch (NoteNotFoundException $e) { + } } - } diff --git a/lib/Migration/Version0002Date20190313133046.php b/lib/Migration/Version0002Date20190313133046.php new file mode 100644 index 00000000..54af7b47 --- /dev/null +++ b/lib/Migration/Version0002Date20190313133046.php @@ -0,0 +1,94 @@ + + * @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\Migration; + + +use Closure; +use Doctrine\DBAL\Types\Type; +use OCP\DB\ISchemaWrapper; +use OCP\Migration\IOutput; +use OCP\Migration\SimpleMigrationStep; + + +/** + * Class Version0002Date20190313133046 + * + * @package OCA\Social\Migration + */ +class Version0002Date20190313133046 extends SimpleMigrationStep { + + + /** + * @param IOutput $output + * @param Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper` + * @param array $options + * + * @return null|ISchemaWrapper + */ + public function changeSchema(IOutput $output, Closure $schemaClosure, array $options) { + /** @var ISchemaWrapper $schema */ + $schema = $schemaClosure(); + + if (!$schema->hasTable('social_stream_actions')) { + $table = $schema->createTable('social_stream_actions'); + $table->addColumn( + 'id', Type::INTEGER, [ + 'autoincrement' => true, + 'notnull' => true, + 'length' => 11, + 'unsigned' => true + ] + ); + $table->addColumn( + 'actor_id', 'string', [ + 'notnull' => true, + 'length' => 127, + ] + ); + $table->addColumn( + 'stream_id', 'string', [ + 'notnull' => true, + 'length' => 1000, + ] + ); + $table->addColumn( + 'values', Type::TEXT, [ + 'notnull' => false + ] + ); + $table->setPrimaryKey(['id']); + } + + return $schema; + } + +} + diff --git a/lib/Model/ActivityPub/Stream.php b/lib/Model/ActivityPub/Stream.php index f9cf86f2..dc0ff248 100644 --- a/lib/Model/ActivityPub/Stream.php +++ b/lib/Model/ActivityPub/Stream.php @@ -33,7 +33,9 @@ namespace OCA\Social\Model\ActivityPub; use daita\MySmallPhpTools\Model\Cache; use daita\MySmallPhpTools\Model\CacheItem; use DateTime; +use Exception; use JsonSerializable; +use OCA\Social\Model\StreamAction; class Stream extends ACore implements JsonSerializable { @@ -69,6 +71,9 @@ class Stream extends ACore implements JsonSerializable { /** @var int */ private $publishedTime = 0; + /** @var StreamAction */ + private $action = null; + public function __construct($parent = null) { parent::__construct($parent); @@ -208,6 +213,7 @@ class Stream extends ACore implements JsonSerializable { /** * + * @throws Exception */ public function convertPublished() { $dTime = new DateTime($this->getPublished()); @@ -255,6 +261,37 @@ class Stream extends ACore implements JsonSerializable { } + /** + * @return StreamAction + */ + public function getAction(): StreamAction { + return $this->action; + } + + /** + * @param StreamAction $action + * + * @return Stream + */ + public function setAction(StreamAction $action): Stream { + $this->action = $action; + + return $this; + } + + /** + * @return bool + */ + public function hasAction(): bool { + return ($this->action !== null); + } + + + /** + * @param array $data + * + * @throws Exception + */ public function import(array $data) { parent::import($data); @@ -270,6 +307,8 @@ class Stream extends ACore implements JsonSerializable { /** * @param array $data + * + * @throws Exception */ public function importFromDatabase(array $data) { parent::importFromDatabase($data); @@ -310,6 +349,7 @@ class Stream extends ACore implements JsonSerializable { $result = array_merge( $result, [ + 'action' => ($this->hasAction()) ? $this->getAction() : [], 'cache' => ($this->gotCache()) ? $this->getCache() : '', 'publishedTime' => $this->getPublishedTime() ] diff --git a/lib/Model/StreamAction.php b/lib/Model/StreamAction.php new file mode 100644 index 00000000..af34db46 --- /dev/null +++ b/lib/Model/StreamAction.php @@ -0,0 +1,214 @@ + + * @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\Model; + + +use daita\MySmallPhpTools\Traits\TArrayTools; +use daita\MySmallPhpTools\Traits\TStringTools; +use JsonSerializable; + + +/** + * Class StreamAction + * + * @package OCA\Social\Model + */ +class StreamAction implements JsonSerializable { + + + use TArrayTools; + use TStringTools; + + + /** @var integer */ + private $id = 0; + + /** @var string */ + private $actorId = ''; + + /** @var string */ + private $streamId = ''; + + /** @var array */ + private $values = []; + + + /** + * StreamAction constructor. + */ + public function __construct() { + } + + + /** + * @return int + */ + public function getId(): int { + return $this->id; + } + + /** + * @param int $id + * + * @return StreamAction + */ + public function setId(int $id): StreamAction { + $this->id = $id; + + return $this; + } + + + /** + * @return string + */ + public function getActorId(): string { + return $this->actorId; + } + + /** + * @param string $actorId + * + * @return StreamAction + */ + public function setActorId(string $actorId): StreamAction { + $this->actorId = $actorId; + + return $this; + } + + + /** + * @return string + */ + public function getStreamId(): string { + return $this->streamId; + } + + /** + * @param string $streamId + * + * @return StreamAction + */ + public function setStreamId(string $streamId): StreamAction { + $this->streamId = $streamId; + + return $this; + } + + + /** + * @param string $key + * @param string $value + */ + public function updateValue(string $key, string $value) { + $this->values[$key] = $value; + } + + /** + * @param string $key + * @param int $value + */ + public function updateValueInt(string $key, int $value) { + $this->values[$key] = $value; + } + + /** + * @param string $key + * + * @return bool + */ + public function hasValue(string $key): bool { + return (array_key_exists($key, $this->values)); + } + + /** + * @param string $key + * + * @return string + */ + public function getValue(string $key): string { + return $this->values[$key]; + } + + /** + * @param string $key + * + * @return int + */ + public function getValueInt(string $key): int { + return $this->values[$key]; + } + + /** + * @return array + */ + public function getValues(): array { + return $this->values; + } + + /** + * @param array $values + * + * @return StreamAction + */ + public function setValues(array $values): StreamAction { + $this->values = $values; + + return $this; + } + + + /** + * @param array $data + */ + public function importFromDatabase(array $data) { + $this->setId($this->getInt('id', $data, 0)); + $this->setActorId($this->get('actor_id', $data, '')); + $this->setStreamId($this->get('stream_id', $data, '')); + $this->setValues($this->getArray('values', $data, [])); + } + + + /** + * @return array + */ + public function jsonSerialize(): array { + return [ + 'id' => $this->getId(), + 'actorId' => $this->getActorId(), + 'streamId' => $this->getStreamId(), + 'values' => $this->getValues(), + ]; + } + +} + diff --git a/lib/Service/BoostService.php b/lib/Service/BoostService.php new file mode 100644 index 00000000..b0e22aaa --- /dev/null +++ b/lib/Service/BoostService.php @@ -0,0 +1,192 @@ + + * @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\Service; + + +use Exception; +use OCA\Social\Db\NotesRequest; +use OCA\Social\Exceptions\NoteNotFoundException; +use OCA\Social\Exceptions\SocialAppConfigException; +use OCA\Social\Model\ActivityPub\ACore; +use OCA\Social\Model\ActivityPub\Activity\Undo; +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; + +/** + * Class BoostService + * + * @package OCA\Social\Service + */ +class BoostService { + + + /** @var NotesRequest */ + private $notesRequest; + + /** @var NoteService */ + private $noteService; + + /** @var SignatureService */ + private $signatureService; + + /** @var ActivityService */ + private $activityService; + + /** @var StreamActionService */ + private $streamActionService; + + /** @var StreamQueueService */ + private $streamQueueService; + + /** @var MiscService */ + private $miscService; + + + /** + * BoostService constructor. + * + * @param NotesRequest $notesRequest + * @param NoteService $noteService + * @param SignatureService $signatureService + * @param ActivityService $activityService + * @param StreamActionService $streamActionService + * @param StreamQueueService $streamQueueService + * @param MiscService $miscService + */ + public function __construct( + NotesRequest $notesRequest, NoteService $noteService, SignatureService $signatureService, + ActivityService $activityService, StreamActionService $streamActionService, + StreamQueueService $streamQueueService, MiscService $miscService + ) { + $this->notesRequest = $notesRequest; + $this->noteService = $noteService; + $this->signatureService = $signatureService; + $this->activityService = $activityService; + $this->streamActionService = $streamActionService; + $this->streamQueueService = $streamQueueService; + $this->miscService = $miscService; + } + + + /** + * @param Person $actor + * @param string $postId + * @param string $token + * + * @return ACore + * @throws NoteNotFoundException + * @throws SocialAppConfigException + */ + public function create(Person $actor, string $postId, string &$token = ''): ACore { + + try { + return $this->get($actor, $postId); + } catch (NoteNotFoundException $e) { + } + + $announce = new Announce(); + $this->noteService->assignItem($announce, $actor, Stream::TYPE_PUBLIC); + $announce->setActor($actor); + + $note = $this->noteService->getNoteById($postId, true); + if ($note->getType() !== Note::TYPE) { + throw new NoteNotFoundException('Stream is not a Note'); + } + + $announce->addCc($note->getAttributedTo()); + if ($note->isLocal()) { + $announce->setObject($note); + } else { + $announce->setObjectId($note->getId()); + $announce->addCacheItem($note->getId()); + } + + $this->notesRequest->save($announce); + + $this->streamActionService->setActionBool($actor->getActorId(), $postId, 'boosted', true); + $this->signatureService->signObject($actor, $announce); + $token = $this->activityService->request($announce); + + $this->streamQueueService->cacheStreamByToken($token); + + return $announce; + } + + + /** + * @param Person $actor + * @param string $postId + * + * @return Stream + * @throws NoteNotFoundException + */ + public function get(Person $actor, string $postId): Stream { + $stream = $this->notesRequest->getNoteByObjectId($actor, Announce::TYPE, $postId); + + return $stream; + } + + + /** + * @param Person $actor + * @param string $postId + * @param ACore $undo + * + * @return string + * @throws SocialAppConfigException + * @throws NoteNotFoundException + */ + public function delete(Person $actor, string $postId, ACore &$undo = null): string { + $undo = new Undo(); + $this->noteService->assignItem($undo, $actor, Stream::TYPE_PUBLIC); + $undo->setActor($actor); + + $note = $this->noteService->getNoteById($postId, true); + if ($note->getType() !== Note::TYPE) { + throw new NoteNotFoundException('Stream is not a Note'); + } + + $announce = $this->notesRequest->getNoteByObjectId($actor, Announce::TYPE, $postId); + $undo->setObject($announce); + $undo->setCcArray($announce->getCcArray()); + + $this->notesRequest->deleteNoteById($announce->getId()); + $this->streamActionService->setActionBool($actor->getActorId(), $postId, 'boosted', false); + $this->signatureService->signObject($actor, $undo); + $token = $this->activityService->request($undo); + + return $token; + } + + +} + diff --git a/lib/Service/NoteService.php b/lib/Service/NoteService.php index 5788bebc..5b9d8069 100644 --- a/lib/Service/NoteService.php +++ b/lib/Service/NoteService.php @@ -46,7 +46,6 @@ 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; @@ -122,66 +121,42 @@ class NoteService { /** - * @param Person $actor - * @param string $postId - * @param ACore|null $announce - * - * @return string - * @throws NoteNotFoundException - * @throws SocialAppConfigException - * @throws Exception - */ - public function createBoost(Person $actor, string $postId, ACore &$announce = null): string { - - $announce = new Announce(); - $this->assignStream($announce, $actor, Stream::TYPE_PUBLIC); - $announce->setActor($actor); - - $note = $this->getNoteById($postId, true); - if ($note->getType() !== Note::TYPE) { - throw new NoteNotFoundException('Stream is not a Note'); - } - - $announce->addCc($note->getAttributedTo()); - if ($note->isLocal()) { - $announce->setObject($note); - } else { - $announce->setObjectId($note->getId()); - $announce->addCacheItem($note->getId()); - } - - $this->signatureService->signObject($actor, $announce); - $token = $this->activityService->request($announce); - - $this->streamQueueService->cacheStreamByToken($token); - - return $token; - } - - - /** - * @param Stream $stream + * @param ACore $stream * @param Person $actor * @param string $type * * @throws SocialAppConfigException + * @throws Exception */ - public function assignStream(Stream &$stream, Person $actor, string $type) { + public function assignItem(Acore &$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); + + if ($stream instanceof Stream) { + $this->assignStream($stream); + } } /** * @param Stream $stream + * + * @throws Exception + */ + public function assignStream(Stream &$stream) { + $stream->convertPublished(); + } + + + /** + * @param ACore $stream * @param Person $actor * @param string $type */ - private function setRecipient(Stream $stream, Person $actor, string $type) { + private function setRecipient(ACore $stream, Person $actor, string $type) { switch ($type) { case Note::TYPE_UNLISTED: $stream->setTo($actor->getFollowers()); @@ -370,6 +345,7 @@ class NoteService { * @param int $limit * * @return Note[] + * @throws Exception */ public function getStreamHome(Person $actor, int $since = 0, int $limit = 5): array { return $this->notesRequest->getStreamHome($actor, $since, $limit); @@ -382,6 +358,7 @@ class NoteService { * @param int $limit * * @return Note[] + * @throws Exception */ public function getStreamNotifications(Person $actor, int $since = 0, int $limit = 5): array { return $this->notesRequest->getStreamNotifications($actor, $since, $limit); @@ -394,6 +371,7 @@ class NoteService { * @param int $limit * * @return Note[] + * @throws Exception */ public function getStreamAccount(string $actorId, int $since = 0, int $limit = 5): array { return $this->notesRequest->getStreamAccount($actorId, $since, $limit); @@ -406,6 +384,7 @@ class NoteService { * @param int $limit * * @return Note[] + * @throws Exception */ public function getStreamDirect(Person $actor, int $since = 0, int $limit = 5): array { return $this->notesRequest->getStreamDirect($actor, $since, $limit); @@ -417,6 +396,7 @@ class NoteService { * @param int $limit * * @return Note[] + * @throws Exception */ public function getStreamLocalTimeline(int $since = 0, int $limit = 5): array { return $this->notesRequest->getStreamTimeline($since, $limit, true); @@ -430,6 +410,7 @@ class NoteService { * @param int $limit * * @return Note[] + * @throws Exception */ public function getStreamLocalTag(Person $actor, string $hashtag, int $since = 0, int $limit = 5 ): array { @@ -455,6 +436,7 @@ class NoteService { * @param int $limit * * @return Note[] + * @throws Exception */ public function getStreamGlobalTimeline(int $since = 0, int $limit = 5): array { return $this->notesRequest->getStreamTimeline($since, $limit, false); diff --git a/lib/Service/PostService.php b/lib/Service/PostService.php index e8803402..3e6dba3a 100644 --- a/lib/Service/PostService.php +++ b/lib/Service/PostService.php @@ -88,26 +88,26 @@ class PostService { /** * @param Post $post - * @param ACore $activity + * @param string $token * - * @return string - * @throws SocialAppConfigException + * @return ACore * @throws InvalidOriginException * @throws InvalidResourceException * @throws ItemUnknownException + * @throws MalformedArrayException * @throws NoteNotFoundException * @throws RedundancyLimitException * @throws RequestContentException * @throws RequestNetworkException + * @throws RequestResultNotJsonException * @throws RequestResultSizeException * @throws RequestServerException - * @throws MalformedArrayException - * @throws RequestResultNotJsonException + * @throws SocialAppConfigException */ - public function createPost(Post $post, ACore &$activity = null): string { + public function createPost(Post $post, string &$token = ''): ACore { $note = new Note(); $actor = $post->getActor(); - $this->noteService->assignStream($note, $actor, $post->getType()); + $this->noteService->assignItem($note, $actor, $post->getType()); $note->setAttributedTo( $this->configService->getUrlSocial() . '@' . $actor->getPreferredUsername() @@ -119,10 +119,10 @@ class PostService { $this->noteService->addRecipients($note, $post->getType(), $post->getTo()); $this->noteService->addHashtags($note, $post->getHashtags()); - $result = $this->activityService->createActivity($actor, $note, $activity); + $token = $this->activityService->createActivity($actor, $note, $activity); $this->accountService->cacheLocalActorDetailCount($actor); - return $result; + return $activity; } diff --git a/lib/Service/StreamActionService.php b/lib/Service/StreamActionService.php new file mode 100644 index 00000000..978b9952 --- /dev/null +++ b/lib/Service/StreamActionService.php @@ -0,0 +1,117 @@ + + * @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\Service; + + +use daita\MySmallPhpTools\Exceptions\MalformedArrayException; +use Exception; +use OCA\Social\Db\NotesRequest; +use OCA\Social\Db\StreamActionsRequest; +use OCA\Social\Exceptions\InvalidOriginException; +use OCA\Social\Exceptions\InvalidResourceException; +use OCA\Social\Exceptions\ItemUnknownException; +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\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 StreamActionService + * + * @package OCA\Social\Service + */ +class StreamActionService { + + + /** @var StreamActionsRequest */ + private $streamActionsRequest; + + /** @var MiscService */ + private $miscService; + + + /** + * StreamActionService constructor. + * + * @param StreamActionsRequest $streamActionsRequest + * @param MiscService $miscService + */ + public function __construct(StreamActionsRequest $streamActionsRequest, MiscService $miscService + ) { + $this->streamActionsRequest = $streamActionsRequest; + $this->miscService = $miscService; + } + + + /** + * @param string $actorId + * @param string $streamId + * @param string $key + * @param string $value + */ + public function setAction(string $actorId, string $streamId, string $key, string $value) { + + } + + + /** + * @param string $actorId + * @param string $streamId + * @param string $key + * @param int $value + */ + public function setActionInt(string $actorId, string $streamId, string $key, int $value) { + + } + + + /** + * @param string $actorId + * @param string $streamId + * @param string $key + * @param bool $value + */ + public function setActionBool(string $actorId, string $streamId, string $key, bool $value) { + + } + +} +