From a1221cacf6dc9dbdffc1929f361e9c2e942c049d Mon Sep 17 00:00:00 2001 From: Maxence Lange Date: Thu, 20 Jun 2019 22:59:40 -0100 Subject: new announce system Signed-off-by: Maxence Lange gotActor->hasActor Signed-off-by: Maxence Lange cleaning Signed-off-by: Maxence Lange retrieve Person if missing Signed-off-by: Maxence Lange fix async Signed-off-by: Maxence Lange avoid async duplicate Signed-off-by: Maxence Lange fixing Signed-off-by: Maxence Lange --- lib/Command/Fediverse.php | 3 + lib/Db/CacheActorsRequest.php | 10 +- lib/Db/CoreRequestBuilder.php | 13 +- lib/Db/StreamRequest.php | 138 +++++++++++++++++--- lib/Db/StreamRequestBuilder.php | 22 +++- lib/Interfaces/Activity/AcceptInterface.php | 19 +++ lib/Interfaces/Activity/AddInterface.php | 16 +++ lib/Interfaces/Activity/BlockInterface.php | 16 +++ lib/Interfaces/Activity/CreateInterface.php | 16 +++ lib/Interfaces/Activity/DeleteInterface.php | 17 ++- lib/Interfaces/Activity/LikeInterface.php | 16 +++ lib/Interfaces/Activity/RejectInterface.php | 16 +++ lib/Interfaces/Activity/RemoveInterface.php | 15 +++ lib/Interfaces/Activity/UndoInterface.php | 15 +++ lib/Interfaces/Activity/UpdateInterface.php | 16 +++ lib/Interfaces/Actor/PersonInterface.php | 35 +++-- lib/Interfaces/IActivityPubInterface.php | 19 ++- .../Internal/SocialAppNotificationInterface.php | 24 +++- lib/Interfaces/Object/AnnounceInterface.php | 80 +++++++++++- lib/Interfaces/Object/DocumentInterface.php | 15 +++ lib/Interfaces/Object/FollowInterface.php | 15 +++ lib/Interfaces/Object/ImageInterface.php | 17 +++ lib/Interfaces/Object/NoteInterface.php | 39 ++++-- lib/Migration/Version0002Date20190506000001.php | 8 ++ lib/Migration/Version0002Date20190618000001.php | 18 ++- lib/Model/ActivityPub/ACore.php | 13 +- lib/Model/ActivityPub/Actor/Person.php | 78 +---------- lib/Model/ActivityPub/Item.php | 36 +++++- lib/Model/ActivityPub/Object/Announce.php | 2 +- lib/Model/ActivityPub/Stream.php | 16 +++ lib/Service/AccountService.php | 2 +- lib/Service/ActivityService.php | 4 +- lib/Service/BoostService.php | 47 ++++--- lib/Service/CacheActorService.php | 1 + lib/Service/CurlService.php | 3 + lib/Service/NoteService.php | 20 ++- lib/Service/SignatureService.php | 4 +- lib/Service/StreamQueueService.php | 23 +++- lib/Traits/TDetails.php | 143 +++++++++++++++++++++ 39 files changed, 832 insertions(+), 178 deletions(-) create mode 100644 lib/Traits/TDetails.php diff --git a/lib/Command/Fediverse.php b/lib/Command/Fediverse.php index 0a2dbf6e..ac8ce4ab 100644 --- a/lib/Command/Fediverse.php +++ b/lib/Command/Fediverse.php @@ -33,6 +33,7 @@ namespace OCA\Social\Command; use Exception; use OC\Core\Command\Base; +use OCA\Social\Exceptions\SocialAppConfigException; use OCA\Social\Exceptions\UnauthorizedFediverseException; use OCA\Social\Service\ConfigService; use OCA\Social\Service\FediverseService; @@ -208,6 +209,8 @@ class Fediverse extends Base { /** * @param string $address + * + * @throws SocialAppConfigException */ private function testAddress(string $address) { try { diff --git a/lib/Db/CacheActorsRequest.php b/lib/Db/CacheActorsRequest.php index 4abfe820..3867d7bd 100644 --- a/lib/Db/CacheActorsRequest.php +++ b/lib/Db/CacheActorsRequest.php @@ -31,6 +31,7 @@ namespace OCA\Social\Db; use DateTime; +use Doctrine\DBAL\Exception\UniqueConstraintViolationException; use Exception; use OCA\Social\Exceptions\CacheActorDoesNotExistException; use OCA\Social\Model\ActivityPub\Actor\Person; @@ -84,7 +85,7 @@ class CacheActorsRequest extends CacheActorsRequestBuilder { ->setValue('summary', $qb->createNamedParameter($actor->getSummary())) ->setValue('public_key', $qb->createNamedParameter($actor->getPublicKey())) ->setValue('source', $qb->createNamedParameter($actor->getSource())) - ->setValue('details', $qb->createNamedParameter(json_encode($actor->getDetails()))); + ->setValue('details', $qb->createNamedParameter(json_encode($actor->getDetailsAll()))); try { if ($actor->getCreation() > 0) { @@ -112,7 +113,10 @@ class CacheActorsRequest extends CacheActorsRequestBuilder { $this->generatePrimaryKey($qb, $actor->getId()); - $qb->execute(); + try { + $qb->execute(); + } catch (UniqueConstraintViolationException $e) { + } } @@ -140,7 +144,7 @@ class CacheActorsRequest extends CacheActorsRequestBuilder { ->set('summary', $qb->createNamedParameter($actor->getSummary())) ->set('public_key', $qb->createNamedParameter($actor->getPublicKey())) ->set('source', $qb->createNamedParameter($actor->getSource())) - ->set('details', $qb->createNamedParameter(json_encode($actor->getDetails()))); + ->set('details', $qb->createNamedParameter(json_encode($actor->getDetailsAll()))); try { if ($actor->getCreation() > 0) { diff --git a/lib/Db/CoreRequestBuilder.php b/lib/Db/CoreRequestBuilder.php index a8cb3009..259b0374 100644 --- a/lib/Db/CoreRequestBuilder.php +++ b/lib/Db/CoreRequestBuilder.php @@ -652,8 +652,9 @@ class CoreRequestBuilder { /** * @param IQueryBuilder $qb * @param string $fieldActorId + * @param string $alias */ - protected function leftJoinCacheActors(IQueryBuilder &$qb, string $fieldActorId) { + protected function leftJoinCacheActors(IQueryBuilder &$qb, string $fieldActorId, string $alias = '') { if ($qb->getType() !== QueryBuilder::SELECT) { return; } @@ -661,7 +662,7 @@ class CoreRequestBuilder { $expr = $qb->expr(); $func = $qb->func(); - $pf = $this->defaultSelectAlias; + $pf = ($alias === '') ? $this->defaultSelectAlias : $alias; $qb->selectAlias('ca.id', 'cacheactor_id') ->selectAlias('ca.type', 'cacheactor_type') @@ -949,16 +950,16 @@ class CoreRequestBuilder { try { $this->parseFollowLeftJoin($data, 'as_follower'); - $actor->addDetailBool('following', true); + $actor->setDetailBool('following', true); } catch (InvalidResourceException $e) { - $actor->addDetailBool('following', false); + $actor->setDetailBool('following', false); } try { $this->parseFollowLeftJoin($data, 'as_followed'); - $actor->addDetailBool('followed', true); + $actor->setDetailBool('followed', true); } catch (InvalidResourceException $e) { - $actor->addDetailBool('followed', false); + $actor->setDetailBool('followed', false); } $actor->setCompleteDetails(true); diff --git a/lib/Db/StreamRequest.php b/lib/Db/StreamRequest.php index 745b30d3..152e8f3d 100644 --- a/lib/Db/StreamRequest.php +++ b/lib/Db/StreamRequest.php @@ -32,9 +32,13 @@ namespace OCA\Social\Db; use daita\MySmallPhpTools\Model\Cache; use DateTime; +use Doctrine\DBAL\Driver\Statement; use Doctrine\DBAL\Exception\UniqueConstraintViolationException; +use Doctrine\DBAL\Query\QueryBuilder; use Exception; use OCA\Social\Exceptions\DateTimeException; +use OCA\Social\Exceptions\ItemUnknownException; +use OCA\Social\Exceptions\SocialAppConfigException; use OCA\Social\Exceptions\StreamNotFoundException; use OCA\Social\Model\ActivityPub\ACore; use OCA\Social\Model\ActivityPub\Actor\Person; @@ -73,7 +77,6 @@ class StreamRequest extends StreamRequestBuilder { */ public function save(Stream $stream) { $qb = $this->saveStream($stream); - if ($stream->getType() === Note::TYPE) { /** @var Note $stream */ $qb->setValue( @@ -86,7 +89,30 @@ class StreamRequest extends StreamRequestBuilder { ); } - $qb->execute(); + try { + $qb->execute(); + } catch (UniqueConstraintViolationException $e) { + } + } + + + /** + * @param Stream $stream \ + * + * @return Statement|int + */ + public function update(Stream $stream) { + $qb = $this->getStreamUpdateSql(); + + $qb->set('details', $qb->createNamedParameter(json_encode($stream->getDetailsAll()))); + $qb->set( + 'cc', $qb->createNamedParameter( + json_encode($stream->getCcArray(), JSON_UNESCAPED_SLASHES) + ) + ); + $this->limitToIdString($qb, $stream->getId()); + + return $qb->execute(); } @@ -100,10 +126,21 @@ class StreamRequest extends StreamRequestBuilder { $this->limitToIdString($qb, $stream->getId()); - try { - $qb->execute(); - } catch (UniqueConstraintViolationException $e) { - } + $qb->execute(); + } + + + /** + * @param string $itemId + * @param string $to + */ + public function updateAttributedTo(string $itemId, string $to) { + $qb = $this->getStreamUpdateSql(); + $qb->set('attributed_to', $qb->createNamedParameter($to)); + + $this->limitToIdString($qb, $itemId); + + $qb->execute(); } @@ -176,15 +213,15 @@ class StreamRequest extends StreamRequestBuilder { /** - * @param Person $actor * @param string $type - * * @param string $objectId * * @return Stream * @throws StreamNotFoundException + * @throws ItemUnknownException + * @throws SocialAppConfigException */ - public function getStreamByObjectId(Person $actor, string $type, string $objectId): Stream { + public function getStreamByObjectId(string $objectId, string $type): Stream { if ($objectId === '') { throw new StreamNotFoundException('missing objectId'); }; @@ -192,7 +229,6 @@ class StreamRequest extends StreamRequestBuilder { $qb = $this->getStreamSelectSql(); $this->limitToObjectId($qb, $objectId); $this->limitToType($qb, $type); - $this->limitToAttributedTo($qb, $actor->getId()); $cursor = $qb->execute(); $data = $cursor->fetch(); @@ -200,8 +236,7 @@ class StreamRequest extends StreamRequestBuilder { if ($data === false) { throw new StreamNotFoundException( - 'StreamByObjectId not found - ' . $actor->getId() . ' - ' . $type . ' - ' - . $objectId + 'StreamByObjectId not found - ' . $type . ' - ' . $objectId ); } @@ -245,11 +280,12 @@ class StreamRequest extends StreamRequestBuilder { $this->joinFollowing($qb, $actor); $this->limitPaginate($qb, $since, $limit); - $this->filterHiddenOnTimeline($qb); - $this->leftJoinCacheActors($qb, 'attributed_to'); + $this->leftJoinCacheActors($qb, 'object_id', 'f'); $this->leftJoinStreamAction($qb); + $this->filterDuplicate($qb); + $streams = []; $cursor = $qb->execute(); while ($data = $cursor->fetch()) { @@ -357,7 +393,7 @@ class StreamRequest extends StreamRequestBuilder { $this->limitToRecipient($qb, $actor->getId(), true); $this->filterRecipient($qb, ACore::CONTEXT_PUBLIC); $this->filterRecipient($qb, $actor->getFollowers()); - $this->filterHiddenOnTimeline($qb); +// $this->filterHiddenOnTimeline($qb); $this->leftJoinCacheActors($qb, 'attributed_to'); @@ -395,7 +431,7 @@ class StreamRequest extends StreamRequestBuilder { $this->limitToLocal($qb, true); } - $this->filterHiddenOnTimeline($qb); +// $this->filterHiddenOnTimeline($qb); $this->leftJoinCacheActors($qb, 'attributed_to'); $this->leftJoinStreamAction($qb); @@ -442,7 +478,7 @@ class StreamRequest extends StreamRequestBuilder { $qb->andWhere($this->exprValueWithinJsonFormat($qb, 'hashtags', '' . $hashtag)); $this->limitPaginate($qb, $since, $limit); - $this->filterHiddenOnTimeline($qb); +// $this->filterHiddenOnTimeline($qb); $this->leftJoinCacheActors($qb, 'attributed_to'); $this->leftJoinStreamAction($qb); @@ -463,6 +499,8 @@ class StreamRequest extends StreamRequestBuilder { * * @return Stream[] * @throws DateTimeException + * @throws ItemUnknownException + * @throws SocialAppConfigException */ public function getNoteSince(int $since): array { $qb = $this->getStreamSelectSql(); @@ -561,6 +599,7 @@ class StreamRequest extends StreamRequestBuilder { ->setValue('source', $qb->createNamedParameter($stream->getSource())) ->setValue('activity_id', $qb->createNamedParameter($stream->getActivityId())) ->setValue('object_id', $qb->createNamedParameter($stream->getObjectId())) + ->setValue('details', $qb->createNamedParameter(json_encode($stream->getDetailsAll()))) ->setValue('cache', $qb->createNamedParameter($cache)) ->setValue( 'hidden_on_timeline', @@ -591,5 +630,70 @@ class StreamRequest extends StreamRequestBuilder { return $qb; } + + /** + * @param IQueryBuilder $qb + * @param Person $actor + */ + private function leftJoinFollowStatus(IQueryBuilder $qb, Person $actor) { + if ($qb->getType() !== QueryBuilder::SELECT) { + return; + } + + $expr = $qb->expr(); + $func = $qb->func(); + $pf = $this->defaultSelectAlias . '.'; + + $on = $expr->andX(); + $on->add($this->exprLimitToDBField($qb, 'actor_id', $actor->getId(), false, 'fs')); + $on->add($expr->eq($func->lower($pf . 'attributed_to'), $func->lower('fs.object_id'))); + $on->add($this->exprLimitToDBFieldInt($qb, 'accepted', 1, 'fs')); + + $qb->leftJoin($this->defaultSelectAlias, CoreRequestBuilder::TABLE_FOLLOWS, 'fs', $on); + } + + + /** + * @param IQueryBuilder $qb + */ + private function filterDuplicate(IQueryBuilder $qb) { + $actor = $this->viewer; + + if ($actor === null) { + return; + } + + $this->leftJoinFollowStatus($qb, $actor); + + $func = $qb->func(); + $expr = $qb->expr(); + + $filter = $expr->orX(); + $filter->add($this->exprLimitToDBFieldInt($qb, 'hidden_on_timeline', 0, 's')); + + $follower = $expr->andX(); + $follower->add( + $expr->neq( + $func->lower('attributed_to'), + $func->lower($qb->createNamedParameter($actor->getId())) + ) + ); + $follower->add($expr->isNull('fs.id')); +// $follower->add( +// $expr->eq( +// $func->lower('f.object_id'), +// $func->lower('s.attributed_to') +// ) +// ); + // needed ? +// $follower->add($this->exprLimitToDBField($qb, 'actor_id', $actor->getId(), false, 'f')); +// $follower->add($this->exprLimitToDBFieldInt($qb, 'accepted', 1, 'f')); + + $filter->add($follower); + + $qb->andWhere($filter); + } + + } diff --git a/lib/Db/StreamRequestBuilder.php b/lib/Db/StreamRequestBuilder.php index 910d4641..3198887b 100644 --- a/lib/Db/StreamRequestBuilder.php +++ b/lib/Db/StreamRequestBuilder.php @@ -39,6 +39,7 @@ use OCA\Social\Exceptions\ItemUnknownException; 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\Stream; use OCA\Social\Model\InstancePath; use OCP\DB\QueryBuilder\ICompositeExpression; @@ -98,7 +99,8 @@ class StreamRequestBuilder extends CoreRequestBuilder { 's.object_id', 's.attributed_to', 's.in_reply_to', 's.source', 's.local', 's.instances', 's.creation', 's.hidden_on_timeline' ) - ->from(self::TABLE_STREAMS, 's'); + ->from(self::TABLE_STREAMS, 's') + ->groupBy('s.id'); $this->defaultSelectAlias = 's'; @@ -160,19 +162,26 @@ class StreamRequestBuilder extends CoreRequestBuilder { $func = $qb->func(); $expr = $qb->expr(); + $filter = $expr->orX(); + $filter->add($this->exprLimitToDBFieldInt($qb, 'hidden_on_timeline', 0)); + $filter->add( $expr->neq( $func->lower('attributed_to'), $func->lower($qb->createNamedParameter($actor->getId())) ) ); - $filter->add( + + $follower = $expr->andX(); + $follower->add( $expr->eq( - 'hidden_on_timeline', - $qb->createNamedParameter('0') + $func->lower('f.object_id'), + $func->lower('attributed_to') ) ); + $follower->add($this->exprLimitToDBField($qb, 'actor_id', $actor->getId(), false, 'f')); + $filter->add($follower); $qb->andwhere($filter); } @@ -188,6 +197,7 @@ class StreamRequestBuilder extends CoreRequestBuilder { } $on = $this->exprJoinFollowing($qb, $actor); + $qb->selectAlias('f.object_id', 'following_actor_id'); $qb->join($this->defaultSelectAlias, CoreRequestBuilder::TABLE_FOLLOWS, 'f', $on); } @@ -431,6 +441,10 @@ class StreamRequestBuilder extends CoreRequestBuilder { $item->setAction($action); + if ($item->getType() === Announce::TYPE) { + $item->setAttributedTo($this->get('following_actor_id', $data, '')); + } + return $item; } diff --git a/lib/Interfaces/Activity/AcceptInterface.php b/lib/Interfaces/Activity/AcceptInterface.php index 5e3aa5fb..fc726028 100644 --- a/lib/Interfaces/Activity/AcceptInterface.php +++ b/lib/Interfaces/Activity/AcceptInterface.php @@ -98,12 +98,31 @@ class AcceptInterface implements IActivityPubInterface { } + + /** + * @param ACore $item + */ + public function update(ACore $item) { + } + + /** * @param ACore $item */ public function delete(ACore $item) { } + + + /** + * @param ACore $item + * @param string $source + */ + public function event(ACore $item, string $source) { + } + + + /** * @param ACore $activity * @param ACore $item diff --git a/lib/Interfaces/Activity/AddInterface.php b/lib/Interfaces/Activity/AddInterface.php index 706460ab..8aa7da89 100644 --- a/lib/Interfaces/Activity/AddInterface.php +++ b/lib/Interfaces/Activity/AddInterface.php @@ -98,12 +98,28 @@ class AddInterface implements IActivityPubInterface { } + /** + * @param ACore $item + */ + public function update(ACore $item) { + } + + /** * @param ACore $item */ public function delete(ACore $item) { } + + /** + * @param ACore $item + * @param string $source + */ + public function event(ACore $item, string $source) { + } + + /** * @param ACore $activity * @param ACore $item diff --git a/lib/Interfaces/Activity/BlockInterface.php b/lib/Interfaces/Activity/BlockInterface.php index 4bc2f792..3fe46f94 100644 --- a/lib/Interfaces/Activity/BlockInterface.php +++ b/lib/Interfaces/Activity/BlockInterface.php @@ -98,12 +98,28 @@ class BlockInterface implements IActivityPubInterface { } + /** + * @param ACore $item + */ + public function update(ACore $item) { + } + + /** * @param ACore $item */ public function delete(ACore $item) { } + + /** + * @param ACore $item + * @param string $source + */ + public function event(ACore $item, string $source) { + } + + /** * @param ACore $activity * @param ACore $item diff --git a/lib/Interfaces/Activity/CreateInterface.php b/lib/Interfaces/Activity/CreateInterface.php index e7a72d32..a625655b 100644 --- a/lib/Interfaces/Activity/CreateInterface.php +++ b/lib/Interfaces/Activity/CreateInterface.php @@ -98,12 +98,28 @@ class CreateInterface implements IActivityPubInterface { } + /** + * @param ACore $item + */ + public function update(ACore $item) { + } + + /** * @param ACore $item */ public function delete(ACore $item) { } + + /** + * @param ACore $item + * @param string $source + */ + public function event(ACore $item, string $source) { + } + + /** * @param ACore $activity * @param ACore $item diff --git a/lib/Interfaces/Activity/DeleteInterface.php b/lib/Interfaces/Activity/DeleteInterface.php index 9b631f4d..6f86d8d0 100644 --- a/lib/Interfaces/Activity/DeleteInterface.php +++ b/lib/Interfaces/Activity/DeleteInterface.php @@ -125,6 +125,20 @@ class DeleteInterface implements IActivityPubInterface { } + /** + * @param ACore $item + */ + public function save(ACore $item) { + } + + + /** + * @param ACore $item + */ + public function update(ACore $item) { + } + + /** * @param ACore $item */ @@ -134,8 +148,9 @@ class DeleteInterface implements IActivityPubInterface { /** * @param ACore $item + * @param string $source */ - public function save(ACore $item) { + public function event(ACore $item, string $source) { } diff --git a/lib/Interfaces/Activity/LikeInterface.php b/lib/Interfaces/Activity/LikeInterface.php index d1e78abc..fba4a6e3 100644 --- a/lib/Interfaces/Activity/LikeInterface.php +++ b/lib/Interfaces/Activity/LikeInterface.php @@ -98,12 +98,28 @@ class LikeInterface implements IActivityPubInterface { } + /** + * @param ACore $item + */ + public function update(ACore $item) { + } + + /** * @param ACore $item */ public function delete(ACore $item) { } + + /** + * @param ACore $item + * @param string $source + */ + public function event(ACore $item, string $source) { + } + + /** * @param ACore $activity * @param ACore $item diff --git a/lib/Interfaces/Activity/RejectInterface.php b/lib/Interfaces/Activity/RejectInterface.php index be46e6d3..6f21ba1a 100644 --- a/lib/Interfaces/Activity/RejectInterface.php +++ b/lib/Interfaces/Activity/RejectInterface.php @@ -98,12 +98,28 @@ class RejectInterface implements IActivityPubInterface { } + /** + * @param ACore $item + */ + public function update(ACore $item) { + } + + /** * @param ACore $item */ public function delete(ACore $item) { } + + /** + * @param ACore $item + * @param string $source + */ + public function event(ACore $item, string $source) { + } + + /** * @param ACore $activity * @param ACore $item diff --git a/lib/Interfaces/Activity/RemoveInterface.php b/lib/Interfaces/Activity/RemoveInterface.php index ea5d44f5..c284109e 100644 --- a/lib/Interfaces/Activity/RemoveInterface.php +++ b/lib/Interfaces/Activity/RemoveInterface.php @@ -98,6 +98,13 @@ class RemoveInterface implements IActivityPubInterface { } + /** + * @param ACore $item + */ + public function update(ACore $item) { + } + + /** * @param ACore $item */ @@ -105,6 +112,14 @@ class RemoveInterface implements IActivityPubInterface { } + /** + * @param ACore $item + * @param string $source + */ + public function event(ACore $item, string $source) { + } + + /** * @param ACore $activity * @param ACore $item diff --git a/lib/Interfaces/Activity/UndoInterface.php b/lib/Interfaces/Activity/UndoInterface.php index 7d55b7a0..5231312b 100644 --- a/lib/Interfaces/Activity/UndoInterface.php +++ b/lib/Interfaces/Activity/UndoInterface.php @@ -99,6 +99,13 @@ class UndoInterface implements IActivityPubInterface { } + /** + * @param ACore $item + */ + public function update(ACore $item) { + } + + /** * @param ACore $item */ @@ -106,6 +113,14 @@ class UndoInterface implements IActivityPubInterface { } + /** + * @param ACore $item + * @param string $source + */ + public function event(ACore $item, string $source) { + } + + /** * @param ACore $activity * @param ACore $item diff --git a/lib/Interfaces/Activity/UpdateInterface.php b/lib/Interfaces/Activity/UpdateInterface.php index 3be2c255..465a6968 100644 --- a/lib/Interfaces/Activity/UpdateInterface.php +++ b/lib/Interfaces/Activity/UpdateInterface.php @@ -98,12 +98,28 @@ class UpdateInterface implements IActivityPubInterface { } + /** + * @param ACore $item + */ + public function update(ACore $item) { + } + + /** * @param ACore $item */ public function delete(ACore $item) { } + + /** + * @param ACore $item + * @param string $source + */ + public function event(ACore $item, string $source) { + } + + /** * @param ACore $activity * @param ACore $item diff --git a/lib/Interfaces/Actor/PersonInterface.php b/lib/Interfaces/Actor/PersonInterface.php index 5e843b44..084b277d 100644 --- a/lib/Interfaces/Actor/PersonInterface.php +++ b/lib/Interfaces/Actor/PersonInterface.php @@ -125,6 +125,22 @@ class PersonInterface implements IActivityPubInterface { } + /** + * @param ACore $activity + * @param ACore $item + * + * @throws InvalidOriginException + */ + public function activity(Acore $activity, ACore $item) { + /** @var Person $item */ + $activity->checkOrigin($item->getId()); + + if ($activity->getType() === Update::TYPE) { + $this->updateActor($item, $activity); + } + } + + /** * @param ACore $person */ @@ -140,18 +156,9 @@ class PersonInterface implements IActivityPubInterface { /** - * @param ACore $activity * @param ACore $item - * - * @throws InvalidOriginException */ - public function activity(Acore $activity, ACore $item) { - /** @var Person $item */ - $activity->checkOrigin($item->getId()); - - if ($activity->getType() === Update::TYPE) { - $this->updateActor($item, $activity); - } + public function update(ACore $item) { } @@ -165,6 +172,14 @@ class PersonInterface implements IActivityPubInterface { } + /** + * @param ACore $item + * @param string $source + */ + public function event(ACore $item, string $source) { + } + + /** * @param Person $actor * @param ACore $activity diff --git a/lib/Interfaces/IActivityPubInterface.php b/lib/Interfaces/IActivityPubInterface.php index d0dcc4c1..fe7f4d99 100644 --- a/lib/Interfaces/IActivityPubInterface.php +++ b/lib/Interfaces/IActivityPubInterface.php @@ -62,8 +62,8 @@ interface IActivityPubInterface { /** * @param string $id * - * @throws ItemNotFoundException * @return ACore + * @throws ItemNotFoundException */ public function getItemById(string $id): ACore; @@ -85,6 +85,23 @@ interface IActivityPubInterface { public function save(ACore $item); + /** + * Update the current item. + * + * @param ACore $item + */ + public function update(ACore $item); + + + /** + * Event on the current item. + * + * @param ACore $item + * @param string $source + */ + public function event(ACore $item, string $source); + + /** * Delete the current item. * diff --git a/lib/Interfaces/Internal/SocialAppNotificationInterface.php b/lib/Interfaces/Internal/SocialAppNotificationInterface.php index 0c05eb4c..ed4f5028 100644 --- a/lib/Interfaces/Internal/SocialAppNotificationInterface.php +++ b/lib/Interfaces/Internal/SocialAppNotificationInterface.php @@ -101,6 +101,14 @@ class SocialAppNotificationInterface implements IActivityPubInterface { } + /** + * @param ACore $activity + * @param ACore $item + */ + public function activity(Acore $activity, ACore $item) { + } + + /** * @param ACore $notification */ @@ -113,16 +121,17 @@ class SocialAppNotificationInterface implements IActivityPubInterface { $notification->setPublished(date("c")); $notification->convertPublished(); - $this->miscService->log('Generating notification: ' . json_encode($notification, JSON_UNESCAPED_SLASHES), 1); + $this->miscService->log( + 'Generating notification: ' . json_encode($notification, JSON_UNESCAPED_SLASHES), 1 + ); $this->streamRequest->save($notification); } /** - * @param ACore $activity * @param ACore $item */ - public function activity(Acore $activity, ACore $item) { + public function update(ACore $item) { } @@ -132,5 +141,14 @@ class SocialAppNotificationInterface implements IActivityPubInterface { public function delete(ACore $item) { } + + /** + * @param ACore $item + * @param string $source + */ + public function event(ACore $item, string $source) { + } + + } diff --git a/lib/Interfaces/Object/AnnounceInterface.php b/lib/Interfaces/Object/AnnounceInterface.php index f7a661f5..4cbb095f 100644 --- a/lib/Interfaces/Object/AnnounceInterface.php +++ b/lib/Interfaces/Object/AnnounceInterface.php @@ -31,10 +31,14 @@ declare(strict_types=1); namespace OCA\Social\Interfaces\Object; +use daita\MySmallPhpTools\Exceptions\CacheItemNotFoundException; +use daita\MySmallPhpTools\Traits\TArrayTools; use Exception; use OCA\Social\Db\StreamRequest; use OCA\Social\Exceptions\InvalidOriginException; use OCA\Social\Exceptions\ItemNotFoundException; +use OCA\Social\Exceptions\ItemUnknownException; +use OCA\Social\Exceptions\SocialAppConfigException; use OCA\Social\Exceptions\StreamNotFoundException; use OCA\Social\Interfaces\IActivityPubInterface; use OCA\Social\Model\ActivityPub\ACore; @@ -42,6 +46,7 @@ use OCA\Social\Model\ActivityPub\Activity\Undo; use OCA\Social\Model\ActivityPub\Object\Announce; use OCA\Social\Model\ActivityPub\Stream; use OCA\Social\Model\StreamQueue; +use OCA\Social\Service\CacheActorService; use OCA\Social\Service\MiscService; use OCA\Social\Service\StreamQueueService; @@ -54,12 +59,18 @@ use OCA\Social\Service\StreamQueueService; class AnnounceInterface implements IActivityPubInterface { + use TArrayTools; + + /** @var StreamRequest */ private $streamRequest; /** @var StreamQueueService */ private $streamQueueService; + /** @var CacheActorService */ + private $cacheActorService; + /** @var MiscService */ private $miscService; @@ -69,14 +80,16 @@ class AnnounceInterface implements IActivityPubInterface { * * @param StreamRequest $streamRequest * @param StreamQueueService $streamQueueService + * @param CacheActorService $cacheActorService * @param MiscService $miscService */ public function __construct( StreamRequest $streamRequest, StreamQueueService $streamQueueService, - MiscService $miscService + CacheActorService $cacheActorService, MiscService $miscService ) { $this->streamRequest = $streamRequest; $this->streamQueueService = $streamQueueService; + $this->cacheActorService = $cacheActorService; $this->miscService = $miscService; } @@ -137,7 +150,20 @@ class AnnounceInterface implements IActivityPubInterface { public function save(ACore $item) { /** @var Announce $item */ try { - $this->streamRequest->getStreamById($item->getId()); + $knownItem = + $this->streamRequest->getStreamByObjectId($item->getObjectId(), Announce::TYPE); + + if ($item->hasActor()) { + $actor = $item->getActor(); + } else { + $actor = $this->cacheActorService->getFromId($item->getActorId()); + } + + if (!$knownItem->hasCc($actor->getFollowers())) { + $knownItem->addCc($actor->getFollowers()); + $this->streamRequest->update($knownItem); + } + } catch (StreamNotFoundException $e) { $objectId = $item->getObjectId(); $item->addCacheItem($objectId); @@ -150,11 +176,59 @@ class AnnounceInterface implements IActivityPubInterface { } + /** + * @param ACore $item + */ + public function update(ACore $item) { + } + + /** * @param ACore $item */ public function delete(ACore $item) { - $this->streamRequest->deleteStreamById($item->getId(), Announce::TYPE); + try { + $knownItem = + $this->streamRequest->getStreamByObjectId($item->getObjectId(), Announce::TYPE); + + $actor = $item->getActor(); + $knownItem->removeCc($actor->getFollowers()); + + if (empty($knownItem->getCcArray())) { + $this->streamRequest->deleteStreamById($knownItem->getId(), Announce::TYPE); + } else { + $this->streamRequest->update($knownItem); + } + } catch (StreamNotFoundException $e) { + } catch (ItemUnknownException $e) { + } catch (SocialAppConfigException $e) { + } + } + + + /** + * @param ACore $item + * @param string $source + */ + public function event(ACore $item, string $source) { + /** @var Stream $item */ + switch ($source) { + case 'updateCache': + $objectId = $item->getObjectId(); + try { + $cachedItem = $item->getCache() + ->getItem($objectId); + } catch (CacheItemNotFoundException $e) { + return; + } + + $to = $this->get('attributedTo', $cachedItem->getObject(), ''); + if ($to !== '') { + $this->streamRequest->updateAttributedTo($item->getId(), $to); + } + + break; + } } } diff --git a/lib/Interfaces/Object/DocumentInterface.php b/lib/Interfaces/Object/DocumentInterface.php index b0e6efc5..99f04358 100644 --- a/lib/Interfaces/Object/DocumentInterface.php +++ b/lib/Interfaces/Object/DocumentInterface.php @@ -119,6 +119,13 @@ class DocumentInterface implements IActivityPubInterface { } + /** + * @param ACore $item + */ + public function update(ACore $item) { + } + + /** * @param ACore $item */ @@ -127,5 +134,13 @@ class DocumentInterface implements IActivityPubInterface { } + /** + * @param ACore $item + * @param string $source + */ + public function event(ACore $item, string $source) { + } + + } diff --git a/lib/Interfaces/Object/FollowInterface.php b/lib/Interfaces/Object/FollowInterface.php index 6f45cf82..91609820 100644 --- a/lib/Interfaces/Object/FollowInterface.php +++ b/lib/Interfaces/Object/FollowInterface.php @@ -243,6 +243,13 @@ class FollowInterface implements IActivityPubInterface { } + /** + * @param ACore $item + */ + public function update(ACore $item) { + } + + /** * @param ACore $item */ @@ -250,6 +257,14 @@ class FollowInterface implements IActivityPubInterface { } + /** + * @param ACore $item + * @param string $source + */ + public function event(ACore $item, string $source) { + } + + /** * @param Follow $follow * diff --git a/lib/Interfaces/Object/ImageInterface.php b/lib/Interfaces/Object/ImageInterface.php index 63b2e666..6f3f612d 100644 --- a/lib/Interfaces/Object/ImageInterface.php +++ b/lib/Interfaces/Object/ImageInterface.php @@ -97,6 +97,14 @@ class ImageInterface extends DocumentInterface implements IActivityPubInterface } + /** + * @param ACore $item + */ + public function update(ACore $item) { + parent::update($item); + } + + /** * @param ACore $item */ @@ -105,5 +113,14 @@ class ImageInterface extends DocumentInterface implements IActivityPubInterface } + /** + * @param ACore $item + * @param string $source + */ + public function event(ACore $item, string $source) { + parent::event($item, $source); + } + + } diff --git a/lib/Interfaces/Object/NoteInterface.php b/lib/Interfaces/Object/NoteInterface.php index 6db04f0d..18ac2122 100644 --- a/lib/Interfaces/Object/NoteInterface.php +++ b/lib/Interfaces/Object/NoteInterface.php @@ -108,6 +108,24 @@ class NoteInterface implements IActivityPubInterface { } + /** + * @param ACore $activity + * @param ACore $item + * + * @throws InvalidOriginException + */ + public function activity(Acore $activity, ACore $item) { + /** @var Note $item */ + + if ($activity->getType() === Create::TYPE) { + $activity->checkOrigin($item->getId()); + $activity->checkOrigin($item->getAttributedTo()); + $item->setActivityId($activity->getId()); + $this->save($item); + } + } + + /** * @param ACore $note */ @@ -123,20 +141,9 @@ class NoteInterface implements IActivityPubInterface { /** - * @param ACore $activity * @param ACore $item - * - * @throws InvalidOriginException */ - public function activity(Acore $activity, ACore $item) { - /** @var Note $item */ - - if ($activity->getType() === Create::TYPE) { - $activity->checkOrigin($item->getId()); - $activity->checkOrigin($item->getAttributedTo()); - $item->setActivityId($activity->getId()); - $this->save($item); - } + public function update(ACore $item) { } @@ -153,5 +160,13 @@ class NoteInterface implements IActivityPubInterface { } + /** + * @param ACore $item + * @param string $source + */ + public function event(ACore $item, string $source) { + } + + } diff --git a/lib/Migration/Version0002Date20190506000001.php b/lib/Migration/Version0002Date20190506000001.php index bfee1a1a..975d111b 100644 --- a/lib/Migration/Version0002Date20190506000001.php +++ b/lib/Migration/Version0002Date20190506000001.php @@ -43,6 +43,14 @@ use OCP\Migration\IOutput; use OCP\Migration\SimpleMigrationStep; +// notes on migration for A3: +// +// 'details' in _stream +// 'hidden_on_timeline' in _stream should be replaced by ' +//filter_duplicate' +// +// + /** * Class Version0002Date20190226000001 * diff --git a/lib/Migration/Version0002Date20190618000001.php b/lib/Migration/Version0002Date20190618000001.php index 10dcadd9..a534bf18 100644 --- a/lib/Migration/Version0002Date20190618000001.php +++ b/lib/Migration/Version0002Date20190618000001.php @@ -32,14 +32,10 @@ namespace OCA\Social\Migration; use Closure; -use DateTime; -use Doctrine\DBAL\Exception\UniqueConstraintViolationException; use Doctrine\DBAL\Schema\SchemaException; use Doctrine\DBAL\Types\Type; use Exception; -use OCA\Social\Exceptions\CacheActorDoesNotExistException; use OCP\DB\ISchemaWrapper; -use OCP\DB\QueryBuilder\IQueryBuilder; use OCP\IDBConnection; use OCP\Migration\IOutput; use OCP\Migration\SimpleMigrationStep; @@ -82,12 +78,14 @@ class Version0002Date20190618000001 extends SimpleMigrationStep { } $table = $schema->getTable('social_a2_stream'); - $table->addColumn( - 'details', Type::TEXT, - [ - 'notnull' => false - ] - ); + if (!$table->hasColumn('details')) { + $table->addColumn( + 'details', Type::TEXT, + [ + 'notnull' => false + ] + ); + } return $schema; } diff --git a/lib/Model/ActivityPub/ACore.php b/lib/Model/ActivityPub/ACore.php index 89515e11..27c43ae7 100644 --- a/lib/Model/ActivityPub/ACore.php +++ b/lib/Model/ActivityPub/ACore.php @@ -38,8 +38,8 @@ use OCA\Social\Exceptions\ActivityCantBeVerifiedException; use OCA\Social\Exceptions\InvalidOriginException; use OCA\Social\Exceptions\InvalidResourceEntryException; use OCA\Social\Exceptions\UrlCloudException; -use OCA\Social\Model\LinkedDataSignature; use OCA\Social\Model\ActivityPub\Object\Document; +use OCA\Social\Model\LinkedDataSignature; class ACore extends Item implements JsonSerializable { @@ -222,6 +222,15 @@ class ACore extends Item implements JsonSerializable { } + /** + * @return bool + */ + public function isPublic(): bool { + return ($this->getTo() === self::CONTEXT_PUBLIC + || in_array(self::CONTEXT_PUBLIC, $this->getCcArray())); + } + + /** * @return bool */ @@ -635,7 +644,7 @@ class ACore extends Item implements JsonSerializable { $this->addEntryArray('to', $this->getToArray()); $this->addEntryArray('cc', $this->getCcArray()); - if ($this->gotActor()) { + if ($this->hasActor()) { $this->addEntry( 'actor', $this->getActor() ->getId() diff --git a/lib/Model/ActivityPub/Actor/Person.php b/lib/Model/ActivityPub/Actor/Person.php index bd94f035..af2ebfd9 100644 --- a/lib/Model/ActivityPub/Actor/Person.php +++ b/lib/Model/ActivityPub/Actor/Person.php @@ -41,6 +41,7 @@ use OCA\Social\Exceptions\SocialAppConfigException; use OCA\Social\Exceptions\UrlCloudException; use OCA\Social\Model\ActivityPub\ACore; use OCA\Social\Model\ActivityPub\Object\Image; +use OCA\Social\Traits\TDetails; /** @@ -51,6 +52,9 @@ use OCA\Social\Model\ActivityPub\Object\Image; class Person extends ACore implements JsonSerializable { + use TDetails; + + const TYPE = 'Person'; @@ -93,9 +97,6 @@ class Person extends ACore implements JsonSerializable { /** @var string */ private $featured = ''; - /** @var array */ - private $details = []; - /** @var int */ private $avatarVersion = -1; @@ -358,73 +359,6 @@ class Person extends ACore implements JsonSerializable { } - /** - * @return array - */ - public function getDetails(): array { - return $this->details; - } - - /** - * @param string $detail - * @param string $value - * - * @return Person - */ - public function addDetail(string $detail, string $value): Person { - $this->details[$detail] = $value; - - return $this; - } - - /** - * @param string $detail - * @param int $value - * - * @return Person - */ - public function addDetailInt(string $detail, int $value): Person { - $this->details[$detail] = $value; - - return $this; - } - - /** - * @param string $detail - * @param array $value - * - * @return Person - */ - public function addDetailArray(string $detail, array $value): Person { - $this->details[$detail] = $value; - - return $this; - } - - /** - * @param string $detail - * @param bool $value - * - * @return Person - */ - public function addDetailBool(string $detail, bool $value): Person { - $this->details[$detail] = $value; - - return $this; - } - - /** - * @param array $details - * - * @return Person - */ - public function setDetails(array $details): Person { - $this->details = $details; - - return $this; - } - - /** * @return int */ @@ -497,7 +431,7 @@ class Person extends ACore implements JsonSerializable { ->setFollowing($this->validate(self::AS_URL, 'following', $data, '')) ->setSharedInbox($this->validate(self::AS_URL, 'shared_inbox', $data, '')) ->setFeatured($this->validate(self::AS_URL, 'featured', $data, '')) - ->setDetails($this->getArray('details', $data, [])); + ->setDetailsAll($this->getArray('details', $data, [])); try { $dTime = new DateTime($this->get('creation', $data, 'yesterday')); @@ -536,7 +470,7 @@ class Person extends ACore implements JsonSerializable { ); if ($this->isCompleteDetails()) { - $result['details'] = $this->getDetails(); + $result['details'] = $this->getDetailsAll(); } return $result; diff --git a/lib/Model/ActivityPub/Item.php b/lib/Model/ActivityPub/Item.php index 8184ce1c..f1438583 100644 --- a/lib/Model/ActivityPub/Item.php +++ b/lib/Model/ActivityPub/Item.php @@ -261,7 +261,7 @@ class Item { /** * @return bool */ - public function gotActor(): bool { + public function hasActor(): bool { if ($this->actor === null) { return false; } @@ -394,12 +394,44 @@ class Item { } + /** + * @param string $cc + * + * @return Item + */ public function addCc(string $cc): Item { - $this->cc[] = $cc; + if (!$this->hasCc($cc)) { + $this->cc[] = $cc; + } + + return $this; + } + + /** + * @param string $cc + * + * @return Item + */ + public function removeCc(string $cc): Item { + if (!in_array($cc, $this->cc)) { + return $this; + } + + $this->cc = array_diff($this->cc, [$cc]); return $this; } + /** + * @param string $cc + * + * @return bool + */ + public function hasCc(string $cc): bool { + return (in_array($cc, $this->cc)); + } + + /** * @return array */ diff --git a/lib/Model/ActivityPub/Object/Announce.php b/lib/Model/ActivityPub/Object/Announce.php index 8cc4c81e..a13e5b6a 100644 --- a/lib/Model/ActivityPub/Object/Announce.php +++ b/lib/Model/ActivityPub/Object/Announce.php @@ -88,7 +88,7 @@ class Announce extends Stream implements JsonSerializable { */ public function jsonSerialize(): array { $result = parent::jsonSerialize(); - $result['actor'] = $this->getAttributedTo(); + //$result['actor'] = $this->getAttributedTo(); return $result; } diff --git a/lib/Model/ActivityPub/Stream.php b/lib/Model/ActivityPub/Stream.php index 8aa2f3c7..d8585927 100644 --- a/lib/Model/ActivityPub/Stream.php +++ b/lib/Model/ActivityPub/Stream.php @@ -36,11 +36,15 @@ use DateTime; use Exception; use JsonSerializable; use OCA\Social\Model\StreamAction; +use OCA\Social\Traits\TDetails; class Stream extends ACore implements JsonSerializable { + use TDetails; + + const TYPE = 'Stream'; @@ -48,6 +52,7 @@ class Stream extends ACore implements JsonSerializable { const TYPE_UNLISTED = 'unlisted'; const TYPE_FOLLOWERS = 'followers'; const TYPE_DIRECT = 'direct'; + const TYPE_ANNOUNCE = 'announce'; /** @var string */ @@ -81,6 +86,11 @@ class Stream extends ACore implements JsonSerializable { private $hiddenOnTimeline = false; + /** + * Stream constructor. + * + * @param null $parent + */ public function __construct($parent = null) { parent::__construct($parent); } @@ -346,6 +356,7 @@ class Stream extends ACore implements JsonSerializable { $this->setObjectId($this->validate(self::AS_ID, 'object_id', $data, '')); $this->setAttributedTo($this->validate(self::AS_ID, 'attributed_to', $data, '')); $this->setInReplyTo($this->validate(self::AS_ID, 'in_reply_to', $data)); + $this->setDetailsAll($this->getArray('details', $data, [])); $this->setHiddenOnTimeline($this->getBool('hidden_on_timeline', $data, false)); $cache = new Cache(); @@ -375,11 +386,16 @@ class Stream extends ACore implements JsonSerializable { $result = array_merge( $result, [ + 'details' => $this->getDetailsAll(), 'action' => ($this->hasAction()) ? $this->getAction() : [], 'cache' => ($this->hasCache()) ? $this->getCache() : '', 'publishedTime' => $this->getPublishedTime() ] ); + + $result['cc'] = ''; + $result['bcc'] = ''; + $result['to'] = ''; } $this->cleanArray($result); diff --git a/lib/Service/AccountService.php b/lib/Service/AccountService.php index 004aac51..d7ff1941 100644 --- a/lib/Service/AccountService.php +++ b/lib/Service/AccountService.php @@ -280,7 +280,7 @@ class AccountService { 'following' => $this->followsRequest->countFollowing($actor->getId()), 'post' => $this->streamRequest->countNotesFromActorId($actor->getId()) ]; - $actor->addDetailArray('count', $count); + $actor->setDetailArray('count', $count); } diff --git a/lib/Service/ActivityService.php b/lib/Service/ActivityService.php index 513a048b..f4c85288 100644 --- a/lib/Service/ActivityService.php +++ b/lib/Service/ActivityService.php @@ -358,7 +358,7 @@ class ActivityService { $sharedInboxes = []; $instancePaths = []; foreach ($follows as $follow) { - if (!$follow->gotActor()) { + if (!$follow->hasActor()) { // TODO - check if cache can be empty at this point ? continue; } @@ -415,7 +415,7 @@ class ActivityService { * @return string */ private function getAuthorFromItem(Acore $activity): string { - if ($activity->gotActor()) { + if ($activity->hasActor()) { return $activity->getActor() ->getId(); } diff --git a/lib/Service/BoostService.php b/lib/Service/BoostService.php index bf705e4a..7019d6b6 100644 --- a/lib/Service/BoostService.php +++ b/lib/Service/BoostService.php @@ -34,6 +34,7 @@ use daita\MySmallPhpTools\Traits\TStringTools; use Exception; use OCA\Social\AP; use OCA\Social\Db\StreamRequest; +use OCA\Social\Exceptions\ItemUnknownException; use OCA\Social\Exceptions\SocialAppConfigException; use OCA\Social\Exceptions\StreamNotFoundException; use OCA\Social\Model\ActivityPub\ACore; @@ -114,14 +115,9 @@ class BoostService { * @throws Exception */ public function create(Person $actor, string $postId, &$token = ''): ACore { - - try { - return $this->get($actor, $postId); - } catch (StreamNotFoundException $e) { - } - + /** @var Announce $announce */ $announce = AP::$activityPub->getItemFromType(Announce::TYPE); - $this->noteService->assignItem($announce, $actor, Stream::TYPE_PUBLIC); + $this->noteService->assignItem($announce, $actor, Stream::TYPE_ANNOUNCE); $announce->setActor($actor); $note = $this->noteService->getNoteById($postId, true); @@ -129,7 +125,11 @@ class BoostService { throw new StreamNotFoundException('Stream is not a Note'); } - $announce->addCc($note->getAttributedTo()); + if (!$note->isPublic()) { + throw new StreamNotFoundException('Stream is not Public'); + } + + $announce->addCc($actor->getFollowers()); $announce->setObjectId($note->getId()); $announce->setRequestToken($this->uuid()); @@ -148,14 +148,15 @@ class BoostService { /** - * @param Person $actor * @param string $postId * * @return Stream + * @throws ItemUnknownException + * @throws SocialAppConfigException * @throws StreamNotFoundException */ - public function get(Person $actor, string $postId): Stream { - $stream = $this->streamRequest->getStreamByObjectId($actor, Announce::TYPE, $postId); + public function get(string $postId): Stream { + $stream = $this->streamRequest->getStreamByObjectId($postId, Announce::TYPE); return $stream; } @@ -167,8 +168,8 @@ class BoostService { * @param string $token * * @return ACore - * @throws StreamNotFoundException * @throws SocialAppConfigException + * @throws StreamNotFoundException */ public function delete(Person $actor, string $postId, &$token = ''): ACore { $undo = new Undo(); @@ -180,16 +181,24 @@ class BoostService { throw new StreamNotFoundException('Stream is not a Note'); } - $announce = $this->streamRequest->getStreamByObjectId($actor, Announce::TYPE, $postId); + try { + $announce = $this->streamRequest->getStreamByObjectId($postId, Announce::TYPE); + $announce->setActor($actor); - $undo->setObject($announce); - $undo->setCcArray($announce->getCcArray()); + $undo->setObjectId($announce->getId()); + $undo->addCc($actor->getFollowers()); - $this->streamRequest->deleteStreamById($announce->getId(), Announce::TYPE); - $this->streamActionService->setActionBool($actor->getId(), $postId, 'boosted', false); - $this->signatureService->signObject($actor, $undo); + $interface = AP::$activityPub->getInterfaceFromType(Announce::TYPE); + $interface->delete($announce); +// $this->streamRequest->deleteStreamById($announce->getId(), Announce::TYPE); + $this->signatureService->signObject($actor, $undo); - $token = $this->activityService->request($undo); + $token = $this->activityService->request($undo); + } catch (ItemUnknownException $e) { + } catch (StreamNotFoundException $e) { + } + + $this->streamActionService->setActionBool($actor->getId(), $postId, 'boosted', false); return $undo; } diff --git a/lib/Service/CacheActorService.php b/lib/Service/CacheActorService.php index 2aed18e6..e0c989d8 100644 --- a/lib/Service/CacheActorService.php +++ b/lib/Service/CacheActorService.php @@ -195,6 +195,7 @@ class CacheActorService { * @throws SocialAppConfigException * @throws ItemUnknownException * @throws RequestResultNotJsonException + * @throws UnauthorizedFediverseException */ public function getFromAccount(string $account, bool $retrieve = true): Person { diff --git a/lib/Service/CurlService.php b/lib/Service/CurlService.php index ef12a93e..cbea8819 100644 --- a/lib/Service/CurlService.php +++ b/lib/Service/CurlService.php @@ -230,6 +230,8 @@ class CurlService { $this->fediverseService->authorized($request->getAddress()); $this->maxDownloadSizeReached = false; + $this->assignUserAgent($request); + $curl = $this->initRequest($request); $this->initRequestPost($curl, $request); @@ -292,6 +294,7 @@ class CurlService { try { $this->request($request); + } catch (RequestResultNotJsonException $e) { } catch (Exception $e) { $this->miscService->log( 'Cannot initiate AsyncWithToken ' . json_encode($token) . ' (' . get_class($e) diff --git a/lib/Service/NoteService.php b/lib/Service/NoteService.php index e865d03b..0e807169 100644 --- a/lib/Service/NoteService.php +++ b/lib/Service/NoteService.php @@ -44,6 +44,7 @@ use OCA\Social\Exceptions\RequestResultNotJsonException; use OCA\Social\Exceptions\RequestResultSizeException; use OCA\Social\Exceptions\RequestServerException; use OCA\Social\Exceptions\SocialAppConfigException; +use OCA\Social\Exceptions\UnauthorizedFediverseException; use OCA\Social\Model\ActivityPub\ACore; use OCA\Social\Model\ActivityPub\Actor\Person; use OCA\Social\Model\ActivityPub\Object\Note; @@ -158,7 +159,7 @@ class NoteService { */ private function setRecipient(ACore $stream, Person $actor, string $type) { switch ($type) { - case Note::TYPE_UNLISTED: + case Stream::TYPE_UNLISTED: $stream->setTo($actor->getFollowers()); $stream->addInstancePath( new InstancePath( @@ -169,7 +170,7 @@ class NoteService { $stream->addCc(ACore::CONTEXT_PUBLIC); break; - case Note::TYPE_FOLLOWERS: + case Stream::TYPE_FOLLOWERS: $stream->setTo($actor->getFollowers()); $stream->addInstancePath( new InstancePath( @@ -179,7 +180,17 @@ class NoteService { ); break; - case Note::TYPE_DIRECT: + case Stream::TYPE_ANNOUNCE: + $stream->addInstancePath( + new InstancePath( + $actor->getFollowers(), InstancePath::TYPE_FOLLOWERS, + InstancePath::PRIORITY_LOW + ) + ); + $stream->addCc($actor->getFollowers()); + break; + + case Stream::TYPE_DIRECT: break; default: @@ -215,7 +226,7 @@ class NoteService { $instancePath = new InstancePath( $actor->getInbox(), InstancePath::TYPE_INBOX, InstancePath::PRIORITY_MEDIUM ); - if ($type === Note::TYPE_DIRECT) { + if ($type === Stream::TYPE_DIRECT) { $instancePath->setPriority(InstancePath::PRIORITY_HIGH); $stream->addToArray($actor->getId()); } else { @@ -460,6 +471,7 @@ class NoteService { * @throws RequestResultSizeException * @throws RequestServerException * @throws RequestResultNotJsonException + * @throws UnauthorizedFediverseException */ public function getAuthorFromPostId($noteId) { $note = $this->streamRequest->getStreamById($noteId); diff --git a/lib/Service/SignatureService.php b/lib/Service/SignatureService.php index ac0cdc1e..00f6b906 100644 --- a/lib/Service/SignatureService.php +++ b/lib/Service/SignatureService.php @@ -54,6 +54,7 @@ use OCA\Social\Exceptions\RequestServerException; use OCA\Social\Exceptions\SignatureException; use OCA\Social\Exceptions\SignatureIsGoneException; use OCA\Social\Exceptions\SocialAppConfigException; +use OCA\Social\Exceptions\UnauthorizedFediverseException; use OCA\Social\Model\ActivityPub\ACore; use OCA\Social\Model\ActivityPub\Actor\Person; use OCA\Social\Model\LinkedDataSignature; @@ -402,10 +403,11 @@ class SignatureService { * @throws RedundancyLimitException * @throws RequestContentException * @throws RequestNetworkException + * @throws RequestResultNotJsonException * @throws RequestResultSizeException * @throws RequestServerException * @throws SocialAppConfigException - * @throws RequestResultNotJsonException + * @throws UnauthorizedFediverseException */ private function retrieveKey(string $keyId, bool $refresh = false): string { $actor = $this->cacheActorService->getFromId($keyId, $refresh); diff --git a/lib/Service/StreamQueueService.php b/lib/Service/StreamQueueService.php index de4edb61..6c0534f3 100644 --- a/lib/Service/StreamQueueService.php +++ b/lib/Service/StreamQueueService.php @@ -68,8 +68,12 @@ class StreamQueueService { /** @var StreamQueueRequest */ private $streamQueueRequest; + /** @var ImportService */ private $importService; + /** @var CacheActorService */ + private $cacheActorService; + /** @var CurlService */ private $curlService; @@ -82,17 +86,20 @@ class StreamQueueService { * * @param StreamRequest $streamRequest * @param StreamQueueRequest $streamQueueRequest + * @param CacheActorService $cacheActorService * @param ImportService $importService * @param CurlService $curlService * @param MiscService $miscService */ public function __construct( StreamRequest $streamRequest, StreamQueueRequest $streamQueueRequest, - ImportService $importService, CurlService $curlService, MiscService $miscService + CacheActorService $cacheActorService, ImportService $importService, + CurlService $curlService, MiscService $miscService ) { $this->streamRequest = $streamRequest; $this->streamQueueRequest = $streamQueueRequest; $this->importService = $importService; + $this->cacheActorService = $cacheActorService; $this->curlService = $curlService; $this->miscService = $miscService; } @@ -309,9 +316,8 @@ class StreamQueueService { * @throws UnauthorizedFediverseException */ private function cacheItem(CacheItem &$item) { - try { - $object = $this->streamRequest->getStreamById($item->getUrl()); + $note = $this->streamRequest->getStreamById($item->getUrl()); } catch (StreamNotFoundException $e) { $data = $this->curlService->retrieveObject($item->getUrl()); $object = AP::$activityPub->getItemFromData($data); @@ -330,11 +336,15 @@ class StreamQueueService { throw new InvalidResourceException(); } + /** @var Stream $object */ + $this->cacheActorService->getFromId($object->getAttributedTo()); + $interface = AP::$activityPub->getInterfaceForItem($object); $interface->save($object); + + $note = $this->streamRequest->getStreamById($object->getId()); } - $note = $this->streamRequest->getStreamById($object->getId()); $item->setContent(json_encode($note, JSON_UNESCAPED_SLASHES)); } @@ -347,6 +357,11 @@ class StreamQueueService { */ private function updateCache(Stream $stream, Cache $cache): bool { $this->streamRequest->updateCache($stream, $cache); + try { + $interface = AP::$activityPub->getInterfaceForItem($stream); + $interface->event($stream, 'updateCache'); + } catch (ItemUnknownException $e) { + } $done = true; foreach ($cache->getItems() as $item) { diff --git a/lib/Traits/TDetails.php b/lib/Traits/TDetails.php new file mode 100644 index 00000000..d26a360e --- /dev/null +++ b/lib/Traits/TDetails.php @@ -0,0 +1,143 @@ + + * @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\Traits; + + +/** + * Trait TDetails + * + * @package OCA\Social\Traits + */ +trait TDetails { + + + /** @var array */ + private $details = []; + + + /** + * @return array + */ + public function getDetailsAll(): array { + return $this->details; + } + + /** + * @param array $details + */ + public function setDetailsAll(array $details) { + $this->details = $details; + } + + /** + * @param string $detail + * @param string $value + */ + public function setDetail(string $detail, string $value) { + $this->details[$detail] = $value; + } + + /** + * @param string $detail + * @param int $value + */ + public function setDetailInt(string $detail, int $value) { + $this->details[$detail] = $value; + } + + /** + * @param string $detail + * @param array $value + */ + public function setDetailArray(string $detail, array $value) { + $this->details[$detail] = $value; + } + + /** + * @param string $detail + * @param bool $value + */ + public function setDetailBool(string $detail, bool $value) { + $this->details[$detail] = $value; + } + + + /** + * @param string $detail + * @param string $value + */ + public function addDetail(string $detail, string $value) { + if (!array_key_exists($detail, $this->details) || !is_array($this->details[$detail])) { + $this->details[$detail] = []; + } + + $this->details[$detail][] = $value; + } + + /** + * @param string $detail + * @param int $value + */ + public function addDetailInt(string $detail, int $value) { + if (!array_key_exists($detail, $this->details) || !is_array($this->details[$detail])) { + $this->details[$detail] = []; + } + + $this->details[$detail][] = $value; + } + + /** + * @param string $detail + * @param array $value + */ + public function addDetailArray(string $detail, array $value) { + if (!array_key_exists($detail, $this->details) || !is_array($this->details[$detail])) { + $this->details[$detail] = []; + } + + $this->details[$detail][] = $value; + } + + /** + * @param string $detail + * @param bool $value + */ + public function addDetailBool(string $detail, bool $value) { + if (!array_key_exists($detail, $this->details) || !is_array($this->details[$detail])) { + $this->details[$detail] = []; + } + + $this->details[$detail][] = $value; + } + + +} + -- cgit v1.2.3 From e85bb3495c042a969eca79924bee64c032307c8b Mon Sep 17 00:00:00 2001 From: Maxence Lange Date: Fri, 21 Jun 2019 10:21:15 -0100 Subject: fixing signature check Signed-off-by: Maxence Lange --- lib/Model/LinkedDataSignature.php | 8 ++++---- lib/Service/SignatureService.php | 7 ++++++- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/lib/Model/LinkedDataSignature.php b/lib/Model/LinkedDataSignature.php index d2e46d20..9baacd64 100644 --- a/lib/Model/LinkedDataSignature.php +++ b/lib/Model/LinkedDataSignature.php @@ -320,13 +320,13 @@ class LinkedDataSignature implements JsonSerializable { */ public function import(array $data) { - if (!in_array(ACore::CONTEXT_SECURITY, $this->getArray('@context', $data, []))) { - throw new LinkedDataSignatureMissingException(); - } +// if (!in_array(ACore::CONTEXT_SECURITY, $this->getArray('@context', $data, []))) { +// throw new LinkedDataSignatureMissingException('no @context security entry'); +// } $signature = $this->getArray('signature', $data, []); if ($signature === []) { - throw new LinkedDataSignatureMissingException(); + throw new LinkedDataSignatureMissingException('missing signature'); } $this->setType($this->get('type', $signature, '')); diff --git a/lib/Service/SignatureService.php b/lib/Service/SignatureService.php index 00f6b906..dc7c1452 100644 --- a/lib/Service/SignatureService.php +++ b/lib/Service/SignatureService.php @@ -127,7 +127,7 @@ class SignatureService { public function generateKeys(Person &$actor) { $res = openssl_pkey_new( [ - "digest_alg" => "rsa", + "digest_alg" => "rsa", "private_key_bits" => 2048, "private_key_type" => OPENSSL_KEYTYPE_RSA, ] @@ -232,6 +232,7 @@ class SignatureService { * @throws ItemUnknownException * @throws RequestResultNotJsonException * @throws DateTimeException + * @throws UnauthorizedFediverseException */ public function checkObject(ACore $object): bool { try { @@ -263,6 +264,10 @@ class SignatureService { return true; } catch (LinkedDataSignatureMissingException $e) { + $this->miscService->log( + 'LinkedDataSignatureMissingException while checkObject : ' . $e->getMessage() + . ' --- ' . json_encode($object), 1 + ); } return false; -- cgit v1.2.3 From 177e0a03308bea4cb0cc2449423d4a50af15cb21 Mon Sep 17 00:00:00 2001 From: Maxence Lange Date: Fri, 21 Jun 2019 10:21:35 -0100 Subject: fixing local/federated timeline Signed-off-by: Maxence Lange --- lib/Db/StreamRequest.php | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/lib/Db/StreamRequest.php b/lib/Db/StreamRequest.php index 152e8f3d..db16ad95 100644 --- a/lib/Db/StreamRequest.php +++ b/lib/Db/StreamRequest.php @@ -427,11 +427,12 @@ class StreamRequest extends StreamRequestBuilder { $qb = $this->getStreamSelectSql(); $this->limitPaginate($qb, $since, $limit); - if ($localOnly) { - $this->limitToLocal($qb, true); - } +// if ($localOnly) { + $this->limitToLocal($qb, $localOnly); +// } + + $this->limitToType($qb, Note::TYPE); -// $this->filterHiddenOnTimeline($qb); $this->leftJoinCacheActors($qb, 'attributed_to'); $this->leftJoinStreamAction($qb); -- cgit v1.2.3