diff --git a/src/Activities/AnnounceHandler.php b/src/Activities/AnnounceHandler.php new file mode 100644 index 0000000..055368d --- /dev/null +++ b/src/Activities/AnnounceHandler.php @@ -0,0 +1,78 @@ + 'handleInbox', + ); + } + + public function __construct( ObjectsService $objectsService, + CollectionsService $collectionsService, + ContextProvider $contextProvider ) + { + $this->objectsService = $objectsService; + $this->collectionsService = $collectionsService; + $this->contextProvider = $contextProvider; + } + + public function handleInbox( InboxActivityEvent $event ) + { + $activity = $event->getActivity(); + if ( $activity['type'] !== 'Announce' ) { + return; + } + $objectId = $activity['object']; + if ( is_array( $objectId ) && array_key_exists( 'id', $objectId ) ) { + $objectId = $objectId['id']; + } + if ( ! is_string( $objectId ) ) { + throw new BadRequestHttpException( 'Invalid object' ); + } + $object = $this->objectsService->dereference( $objectId ); + if ( ! $object->hasField( 'shares' ) ) { + $object = $this->addCollectionToObject( $object, 'shares' ); + + } + $shares = $object['shares']; + $this->collectionsService->addItem( $shares, $activity ); + } + + private function addCollectionToObject( ActivityPubObject $object, $collectionName ) + { + $updatedObject = $object->asArray(); + $updatedObject[$collectionName] = array( + '@context' => $this->contextProvider->getContext(), + 'id' => rtrim( $updatedObject['id'], '/' ) . '/' . $collectionName, + 'type' => 'Collection', + 'items' => array(), + ); + return $this->objectsService->update( $object['id'], $updatedObject ); + } +} \ No newline at end of file diff --git a/test/Activities/AnnounceHandlerTest.php b/test/Activities/AnnounceHandlerTest.php new file mode 100644 index 0000000..c3bf110 --- /dev/null +++ b/test/Activities/AnnounceHandlerTest.php @@ -0,0 +1,125 @@ + array( + 'id' => 'https://example.com/notes/withshares', + 'shares' => array( + 'type' => 'Collection', + 'items' => array(), + ), + ), + 'https://example.com/notes/withoutshares' => array( + 'id' => 'https://example.com/notes/withoutshares', + ), + ); + } + + public function testAnnounceHandler() + { + $testCases = array( + array( + 'id' => 'basicInboxTest', + 'eventName' => InboxActivityEvent::NAME, + 'event' => new InboxActivityEvent( + array( + 'id' => 'https://elsewhere.com/announces/1', + 'type' => 'Announce', + 'object' => 'https://example.com/notes/withshares', + ), + TestActivityPubObject::fromArray( array( + 'id' => 'https://example.com/actors/1', + ) ), + self::requestWithAttributes( + 'https://example.com/actors/1/inbox', + array( + 'actor' => TestActivityPubObject::fromArray( array( + 'id' => 'https://elsewhere.com/actors/1', + ) ), + ) + ) + ), + 'expectedNewShares' => array( + 'id' => 'https://elsewhere.com/announces/1', + 'type' => 'Announce', + 'object' => 'https://example.com/notes/withshares', + ) + ), + array( + 'id' => 'generatesSharesCollectionTest', + 'eventName' => InboxActivityEvent::NAME, + 'event' => new InboxActivityEvent( + array( + 'id' => 'https://elsewhere.com/announces/1', + 'type' => 'Announce', + 'object' => 'https://example.com/notes/withoutshares', + ), + TestActivityPubObject::fromArray( array( + 'id' => 'https://example.com/actors/1', + ) ), + self::requestWithAttributes( + 'https://example.com/actors/1/inbox', + array( + 'actor' => TestActivityPubObject::fromArray( array( + 'id' => 'https://elsewhere.com/actors/1', + ) ), + ) + ) + ), + 'expectedNewShares' => array( + 'id' => 'https://elsewhere.com/announces/1', + 'type' => 'Announce', + 'object' => 'https://example.com/notes/withoutshares', + ) + ), + ); + foreach( $testCases as $testCase ) { + $objectsService = $this->getMock( ObjectsService::class ); + $objectsService->method( 'dereference')->willReturnCallback( function( $id ) { + $objects = self::getObjects(); + if ( array_key_exists( $id, $objects ) ) { + return TestActivityPubObject::fromArray( $objects[$id] ); + } else { + return null; + } + }); + $objectsService->method( 'update')->willReturnCallback( function( $id, $arr ) { + return TestActivityPubObject::fromArray( $arr ); + }); + $collectionsService = $this->getMockBuilder( CollectionsService::class ) + ->disableOriginalConstructor() + ->setMethods( array( 'addItem' ) ) + ->getMock(); + if ( array_key_exists( 'expectedNewShares', $testCase ) ) { + $collectionsService->expects( $this->once() ) + ->method( 'addItem' ) + ->with( + $this->anything(), + $this->equalTo( $testCase['expectedNewShares'] ) + ); + } else { + $collectionsService->expects( $this->never() ) + ->method( 'addItem' ); + } + $contextProvider = new ContextProvider(); + $announceHandler = new AnnounceHandler( $objectsService, $collectionsService, $contextProvider ); + $eventDispatcher = new EventDispatcher(); + $eventDispatcher->addSubscriber( $announceHandler ); + $eventDispatcher->dispatch( $testCase['eventName'], $testCase['event'] ); + } + } +} \ No newline at end of file