From 27a4785650f0d571ca97fb5ad832ee8cdb817e47 Mon Sep 17 00:00:00 2001 From: Maxence Lange Date: Sat, 29 Dec 2018 12:49:31 -0100 Subject: [PATCH] managing Notifications in the notification steam Signed-off-by: Maxence Lange --- lib/AP.php | 19 ++- lib/Db/CoreRequestBuilder.php | 11 ++ lib/Db/NotesRequest.php | 41 +++++- lib/Db/NotesRequestBuilder.php | 24 ++-- .../SocialAppNotificationInterface.php | 133 ++++++++++++++++++ lib/Model/ActivityPub/ACore.php | 4 +- .../Internal/SocialAppNotification.php | 85 +++++++++++ lib/Model/ActivityPub/Item.php | 22 +++ 8 files changed, 322 insertions(+), 17 deletions(-) create mode 100644 lib/Interfaces/Internal/SocialAppNotificationInterface.php create mode 100644 lib/Model/ActivityPub/Internal/SocialAppNotification.php diff --git a/lib/AP.php b/lib/AP.php index 7d8ae585..02775f55 100644 --- a/lib/AP.php +++ b/lib/AP.php @@ -48,6 +48,7 @@ use OCA\Social\Interfaces\Activity\UndoInterface; use OCA\Social\Interfaces\Activity\UpdateInterface; use OCA\Social\Interfaces\Actor\PersonInterface; use OCA\Social\Interfaces\IActivityPubInterface; +use OCA\Social\Interfaces\Internal\SocialAppNotificationInterface; use OCA\Social\Interfaces\Object\DocumentInterface; use OCA\Social\Interfaces\Object\ImageInterface; use OCA\Social\Interfaces\Object\AnnounceInterface; @@ -69,6 +70,7 @@ use OCA\Social\Model\ActivityPub\Object\Announce; use OCA\Social\Model\ActivityPub\Object\Document; use OCA\Social\Model\ActivityPub\Object\Image; use OCA\Social\Model\ActivityPub\Object\Note; +use OCA\Social\Model\ActivityPub\Internal\SocialAppNotification; use OCA\Social\Model\ActivityPub\Object\Tombstone; use OCA\Social\Service\ConfigService; use OCP\AppFramework\QueryException; @@ -136,6 +138,9 @@ class AP { /** @var UpdateInterface */ public $updateInterface; + /** @var NotificationInterface */ + public $notificationInterface; + /** @var ConfigService */ public $configService; @@ -167,10 +172,11 @@ class AP { $ap->followInterface = \OC::$server->query(FollowInterface::class); $ap->imageInterface = \OC::$server->query(ImageInterface::class); $ap->likeInterface = \OC::$server->query(LikeInterface::class); + $ap->noteInterface = \OC::$server->query(NoteInterface::class); + $ap->notificationInterface = \OC::$server->query(SocialAppNotificationInterface::class); + $ap->personInterface = \OC::$server->query(PersonInterface::class); $ap->rejectInterface = \OC::$server->query(RejectInterface::class); $ap->removeInterface = \OC::$server->query(RemoveInterface::class); - $ap->personInterface = \OC::$server->query(PersonInterface::class); - $ap->noteInterface = \OC::$server->query(NoteInterface::class); $ap->undoInterface = \OC::$server->query(UndoInterface::class); $ap->updateInterface = \OC::$server->query(UpdateInterface::class); @@ -178,6 +184,8 @@ class AP { AP::$activityPub = $ap; } catch (QueryException $e) { + \OC::$server->getLogger() + ->logException($e); } } @@ -303,6 +311,9 @@ class AP { $item = new Note(); break; + case SocialAppNotification::TYPE: + return new SocialAppNotification(); + case Person::TYPE: $item = new Person(); break; @@ -400,6 +411,10 @@ class AP { $interface = $this->noteInterface; break; + case SocialAppNotification::TYPE: + $service = $this->notificationInterface; + break; + case Person::TYPE: $interface = $this->personInterface; break; diff --git a/lib/Db/CoreRequestBuilder.php b/lib/Db/CoreRequestBuilder.php index 04848859..6e989a38 100644 --- a/lib/Db/CoreRequestBuilder.php +++ b/lib/Db/CoreRequestBuilder.php @@ -142,6 +142,17 @@ class CoreRequestBuilder { } + /** + * Limit the request to the Type + * + * @param IQueryBuilder $qb + * @param string $type + */ + protected function limitToType(IQueryBuilder &$qb, string $type) { + $this->limitToDBField($qb, 'id', $type, false); + } + + /** * Limit the request to the UserId * diff --git a/lib/Db/NotesRequest.php b/lib/Db/NotesRequest.php index 30f83c64..d5d8ed9d 100644 --- a/lib/Db/NotesRequest.php +++ b/lib/Db/NotesRequest.php @@ -116,6 +116,7 @@ class NotesRequest extends NotesRequestBuilder { $qb = $this->getNotesSelectSql(); $this->limitToIdString($qb, $id); + $this->limitToType($qb, Note::TYPE); if ($asViewer) { $this->limitToViewer($qb); @@ -130,7 +131,14 @@ class NotesRequest extends NotesRequestBuilder { throw new NoteNotFoundException('Post not found'); } - return $this->parseNotesSelectSql($data); + try { + /** @var Note $note */ + $note = $this->parseNotesSelectSql($data); + } catch (Exception $e) { + throw new NoteNotFoundException('Malformed Post'); + } + + return $note; } @@ -202,6 +210,7 @@ class NotesRequest extends NotesRequestBuilder { public function countNotesFromActorId(string $actorId): int { $qb = $this->countNotesSelectSql(); $this->limitToAttributedTo($qb, $actorId); + $this->limitToType($qb, Note::TYPE); $cursor = $qb->execute(); $data = $cursor->fetch(); @@ -227,6 +236,7 @@ class NotesRequest extends NotesRequestBuilder { $qb = $this->getNotesSelectSql(); $this->joinFollowing($qb, $actor); + $this->limitToType($qb, Note::TYPE); $this->limitPaginate($qb, $since, $limit); $this->leftJoinCacheActors($qb, 'attributed_to'); $this->leftJoinStreamAction($qb); @@ -234,7 +244,10 @@ class NotesRequest extends NotesRequestBuilder { $notes = []; $cursor = $qb->execute(); while ($data = $cursor->fetch()) { - $notes[] = $this->parseNotesSelectSql($data); + try { + $notes[] = $this->parseNotesSelectSql($data); + } catch (Exception $e) { + } } $cursor->closeCursor(); @@ -268,7 +281,10 @@ class NotesRequest extends NotesRequestBuilder { $notes = []; $cursor = $qb->execute(); while ($data = $cursor->fetch()) { - $notes[] = $this->parseNotesSelectSql($data); + try { + $notes[] = $this->parseNotesSelectSql($data); + } catch (Exception $e) { + } } $cursor->closeCursor(); @@ -291,6 +307,7 @@ class NotesRequest extends NotesRequestBuilder { public function getStreamAccount(string $actorId, int $since = 0, int $limit = 5): array { $qb = $this->getNotesSelectSql(); $this->limitPaginate($qb, $since, $limit); + $this->limitToType($qb, Note::TYPE); $this->limitToAttributedTo($qb, $actorId); $this->leftJoinCacheActors($qb, 'attributed_to'); $this->limitToRecipient($qb, ACore::CONTEXT_PUBLIC); @@ -299,7 +316,10 @@ class NotesRequest extends NotesRequestBuilder { $notes = []; $cursor = $qb->execute(); while ($data = $cursor->fetch()) { - $notes[] = $this->parseNotesSelectSql($data); + try { + $notes[] = $this->parseNotesSelectSql($data); + } catch (Exception $e) { + } } $cursor->closeCursor(); @@ -323,6 +343,7 @@ class NotesRequest extends NotesRequestBuilder { $qb = $this->getNotesSelectSql(); $this->limitPaginate($qb, $since, $limit); + $this->limitToType($qb, Note::TYPE); $this->limitToRecipient($qb, $actor->getId(), true); $this->filterToRecipient($qb, ACore::CONTEXT_PUBLIC); $this->filterToRecipient($qb, $actor->getFollowers()); @@ -332,7 +353,10 @@ class NotesRequest extends NotesRequestBuilder { $notes = []; $cursor = $qb->execute(); while ($data = $cursor->fetch()) { - $notes[] = $this->parseNotesSelectSql($data); + try { + $notes[] = $this->parseNotesSelectSql($data); + } catch (Exception $e) { + } } $cursor->closeCursor(); @@ -355,6 +379,7 @@ class NotesRequest extends NotesRequestBuilder { ): array { $qb = $this->getNotesSelectSql(); $this->limitPaginate($qb, $since, $limit); + $this->limitToType($qb, Note::TYPE); if ($localOnly) { $this->limitToLocal($qb, true); } @@ -367,7 +392,10 @@ class NotesRequest extends NotesRequestBuilder { $notes = []; $cursor = $qb->execute(); while ($data = $cursor->fetch()) { - $notes[] = $this->parseNotesSelectSql($data); + try { + $notes[] = $this->parseNotesSelectSql($data); + } catch (Exception $e) { + } } $cursor->closeCursor(); @@ -442,6 +470,7 @@ class NotesRequest extends NotesRequestBuilder { */ public function deleteNoteById(string $id) { $qb = $this->getNotesDeleteSql(); + $this->limitToType($qb, Note::TYPE); $this->limitToIdString($qb, $id); $qb->execute(); diff --git a/lib/Db/NotesRequestBuilder.php b/lib/Db/NotesRequestBuilder.php index e9a64312..67dba3be 100644 --- a/lib/Db/NotesRequestBuilder.php +++ b/lib/Db/NotesRequestBuilder.php @@ -32,11 +32,17 @@ namespace OCA\Social\Db; use daita\MySmallPhpTools\Traits\TArrayTools; use Doctrine\DBAL\Query\QueryBuilder; +use OCA\Social\AP; 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\Exceptions\ItemUnknownException; +use OCA\Social\Exceptions\RedundancyLimitException; +use OCA\Social\Exceptions\SocialAppConfigException; +use OCA\Social\Model\ActivityPub\ACore; +use OCA\Social\Model\ActivityPub\Actor\Person; use OCA\Social\Model\InstancePath; use OCP\DB\QueryBuilder\ICompositeExpression; use OCP\DB\QueryBuilder\IQueryBuilder; @@ -354,25 +360,27 @@ class NotesRequestBuilder extends CoreRequestBuilder { /** * @param array $data * + * @throws ItemUnknownException + * @throws RedundancyLimitException + * @throws SocialAppConfigException * @return Stream */ - protected function parseNotesSelectSql($data): Stream { - $note = new Note(); - $note->importFromDatabase($data); + protected function parseNotesSelectSql($data): ACore { + $item = AP::$activityPub->getItemFromData($data); - $instances = json_decode($data['instances'], true); + $instances = json_decode($this->get('instances', $data, '[]'), true); if (is_array($instances)) { foreach ($instances as $instance) { $instancePath = new InstancePath(); $instancePath->import($instance); - $note->addInstancePath($instancePath); + $item->addInstancePath($instancePath); } } try { $actor = $this->parseCacheActorsLeftJoin($data); - $note->setCompleteDetails(true); - $note->setActor($actor); + $item->setCompleteDetails(true); + $item->setActor($actor); } catch (InvalidResourceException $e) { } @@ -382,7 +390,7 @@ class NotesRequestBuilder extends CoreRequestBuilder { } catch (InvalidResourceException $e) { } - return $note; + return $item; } } diff --git a/lib/Interfaces/Internal/SocialAppNotificationInterface.php b/lib/Interfaces/Internal/SocialAppNotificationInterface.php new file mode 100644 index 00000000..46dc8c56 --- /dev/null +++ b/lib/Interfaces/Internal/SocialAppNotificationInterface.php @@ -0,0 +1,133 @@ + + * @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\Interfaces\Internal; + + +use OCA\Social\Db\NotesRequest; +use OCA\Social\Exceptions\ItemNotFoundException; +use OCA\Social\Interfaces\IActivityPubInterface; +use OCA\Social\Model\ActivityPub\ACore; +use OCA\Social\Model\ActivityPub\Internal\SocialAppNotification; +use OCA\Social\Service\ConfigService; +use OCA\Social\Service\CurlService; +use OCA\Social\Service\MiscService; + + +class SocialAppNotificationInterface implements IActivityPubInterface { + + + /** @var NotesRequest */ + private $notesRequest; + + /** @var CurlService */ + private $curlService; + + /** @var ConfigService */ + private $configService; + + /** @var MiscService */ + private $miscService; + + + /** + * NoteInterface constructor. + * + * @param NotesRequest $notesRequest + * @param CurlService $curlService + * @param ConfigService $configService + * @param MiscService $miscService + */ + public function __construct( + NotesRequest $notesRequest, CurlService $curlService, ConfigService $configService, + MiscService $miscService + ) { + $this->notesRequest = $notesRequest; + $this->curlService = $curlService; + $this->configService = $configService; + $this->miscService = $miscService; + } + + + /** + * @param ACore $note + */ + public function processIncomingRequest(ACore $note) { + } + + + /** + * @param ACore $item + */ + public function processResult(ACore $item) { + } + + + /** + * @param string $id + * + * @return ACore + * @throws ItemNotFoundException + */ + public function getItemById(string $id): ACore { + throw new ItemNotFoundException(); + } + + + /** + * @param ACore $note + */ + public function save(ACore $note) { + /** @var SocialAppNotification $note */ +// +// try { +// $this->notesRequest->getNoteById($note->getId()); +// } catch (NoteNotFoundException $e) { +// $this->notesRequest->save($note); +// } + } + + + /** + * @param ACore $activity + * @param ACore $item + */ + public function activity(Acore $activity, ACore $item) { + } + + + /** + * @param ACore $item + */ + public function delete(ACore $item) { + } + +} + diff --git a/lib/Model/ActivityPub/ACore.php b/lib/Model/ActivityPub/ACore.php index 9db0df3e..42c78152 100644 --- a/lib/Model/ActivityPub/ACore.php +++ b/lib/Model/ActivityPub/ACore.php @@ -577,6 +577,7 @@ class ACore extends Item implements JsonSerializable { $this->setId($this->validate(self::AS_ID, 'id', $data, '')); $this->setType($this->validate(self::AS_TYPE, 'type', $data, '')); $this->setUrl($this->validate(self::AS_URL, 'url', $data, '')); + $this->setAttributedTo($this->validate(self::AS_ID, 'attributedTo', $data, '')); $this->setSummary($this->get('summary', $data, '')); $this->setToArray($this->validateArray(self::AS_ID, 'to', $data, [])); $this->setCcArray($this->validateArray(self::AS_ID, 'cc', $data, [])); @@ -594,6 +595,7 @@ class ACore extends Item implements JsonSerializable { $this->setId($this->validate(self::AS_ID, 'id', $data, '')); $this->setType($this->validate(self::AS_TYPE, 'type', $data, '')); $this->setUrl($this->validate(self::AS_URL, 'url', $data, '')); + $this->setAttributedTo($this->validate(self::AS_ID, 'attributed_to', $data, '')); $this->setSummary($this->validate(self::AS_STRING, 'summary', $data, '')); $this->setTo($this->validate(self::AS_ID, 'to', $data, '')); $this->setToArray($this->validateArray(self::AS_ID, 'to_array', $data, [])); @@ -629,7 +631,7 @@ class ACore extends Item implements JsonSerializable { $this->addEntry('id', $this->getId()); $this->addEntry('type', $this->getType()); $this->addEntry('url', $this->getUrl()); - + $this->addEntry('attributedTo', $this->getAttributedTo()); $this->addEntry('to', $this->getTo()); $this->addEntryArray('to', $this->getToArray()); $this->addEntryArray('cc', $this->getCcArray()); diff --git a/lib/Model/ActivityPub/Internal/SocialAppNotification.php b/lib/Model/ActivityPub/Internal/SocialAppNotification.php new file mode 100644 index 00000000..489de9f4 --- /dev/null +++ b/lib/Model/ActivityPub/Internal/SocialAppNotification.php @@ -0,0 +1,85 @@ + + * @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\ActivityPub\Internal; + + +use JsonSerializable; +use OCA\Social\Model\ActivityPub\ACore; + + +class SocialAppNotification extends ACore implements JsonSerializable { + + + const TYPE = 'SocialAppNotification'; + + + /** + * Notification constructor. + * + * @param null $parent + */ + public function __construct($parent = null) { + parent::__construct($parent); + + $this->setType(self::TYPE); + } + + + /** + * @param array $data + */ + public function import(array $data) { + parent::import($data); + } + + + /** + * @param array $data + */ + public function importFromDatabase(array $data) { + parent::importFromDatabase($data); + } + + + /** + * @return array + */ + public function jsonSerialize(): array { +// $this->addEntryInt('publishedTime', $this->getPublishedTime()); + + return array_merge( + parent::jsonSerialize(), + [ + ] + ); + } + +} + diff --git a/lib/Model/ActivityPub/Item.php b/lib/Model/ActivityPub/Item.php index f6f04af1..e1c2d4f5 100644 --- a/lib/Model/ActivityPub/Item.php +++ b/lib/Model/ActivityPub/Item.php @@ -59,6 +59,9 @@ class Item { /** @var string */ private $url = ''; + /** @var string */ + private $attributedTo = ''; + /** @var string */ private $summary = ''; @@ -174,6 +177,25 @@ class Item { } + /** + * @return string + */ + public function getAttributedTo(): string { + return $this->attributedTo; + } + + /** + * @param string $attributedTo + * + * @return Item + */ + public function setAttributedTo(string $attributedTo): Item { + $this->attributedTo = $attributedTo; + + return $this; + } + + /** * @param InstancePath $instancePath *