From f4a93ec743bee2beb19f45ba3132a1d7d996b49c Mon Sep 17 00:00:00 2001 From: Maxence Lange Date: Mon, 12 Nov 2018 21:57:32 -0100 Subject: [PATCH] cleaning code Signed-off-by: Maxence Lange --- lib/Service/ActivityPub/FollowService.php | 100 ++++++++++++ lib/Service/ActivityPub/NoteService.php | 95 ++++++++++-- lib/Service/ActivityPub/PersonService.php | 143 ++++++++++++++++++ lib/Service/ActivityPub/UndoService.php | 66 ++++++++ ...vityPubService.php => ActivityService.php} | 143 ++++++++++++++---- lib/Service/ActorService.php | 101 ++----------- lib/Service/ConfigService.php | 32 ++-- lib/Service/CurlService.php | 3 +- lib/Service/ICoreService.php | 4 +- lib/Service/ImportService.php | 123 +++++++++++++++ lib/Service/InstanceService.php | 42 ++++- lib/Service/MiscService.php | 49 +----- lib/Service/PostService.php | 93 ++++++++++++ 13 files changed, 805 insertions(+), 189 deletions(-) create mode 100644 lib/Service/ActivityPub/FollowService.php create mode 100644 lib/Service/ActivityPub/PersonService.php create mode 100644 lib/Service/ActivityPub/UndoService.php rename lib/Service/{ActivityPubService.php => ActivityService.php} (72%) create mode 100644 lib/Service/ImportService.php create mode 100644 lib/Service/PostService.php diff --git a/lib/Service/ActivityPub/FollowService.php b/lib/Service/ActivityPub/FollowService.php new file mode 100644 index 00000000..644ea74b --- /dev/null +++ b/lib/Service/ActivityPub/FollowService.php @@ -0,0 +1,100 @@ + + * @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\ActivityPub; + + +use Exception; +use OCA\Social\Db\FollowsRequest; +use OCA\Social\Model\ActivityPub\ACore; +use OCA\Social\Model\ActivityPub\Person; +use OCA\Social\Model\ActivityPub\Follow; +use OCA\Social\Model\ActivityPub\OrderedCollection; +use OCA\Social\Service\ICoreService; +use OCA\Social\Service\MiscService; + + +class FollowService implements ICoreService { + + + /** @var FollowsRequest */ + private $followsRequest; + + /** @var MiscService */ + private $miscService; + + + /** + * NoteService constructor. + * + * @param FollowsRequest $followsRequest + * @param MiscService $miscService + */ + public function __construct(FollowsRequest $followsRequest, MiscService $miscService) { + $this->followsRequest = $followsRequest; + $this->miscService = $miscService; + } + + + /** + * @param Person $actor + * + * @return OrderedCollection + */ + public function getFollowers(Person $actor): OrderedCollection { + $collection = new OrderedCollection(); + $collection->setId($actor->getFollowers()); + $collection->setTotalItems(20); + $collection->setFirst('...'); + + return $collection; + } + + + /** + * This method is called when saving the Follow object + * + * @param ACore $follow + * + * @throws Exception + */ + public function save(ACore $follow) { + /** @var Follow $follow */ + + if ($follow->getMetaBool('Undo') === false) { + $this->followsRequest->save($follow); + } else { + $this->followsRequest->delete($follow); + } + } + + +} + diff --git a/lib/Service/ActivityPub/NoteService.php b/lib/Service/ActivityPub/NoteService.php index 47bf912c..d6f96558 100644 --- a/lib/Service/ActivityPub/NoteService.php +++ b/lib/Service/ActivityPub/NoteService.php @@ -34,10 +34,12 @@ use Exception; use OC\User\NoUserException; use OCA\Social\Db\NotesRequest; use OCA\Social\Exceptions\ActorDoesNotExistException; -use OCA\Social\Model\ActivityPub\Core; +use OCA\Social\Exceptions\RequestException; +use OCA\Social\Model\ActivityPub\ACore; use OCA\Social\Model\ActivityPub\Note; +use OCA\Social\Model\ActivityPub\Person; use OCA\Social\Model\InstancePath; -use OCA\Social\Service\ActivityPubService; +use OCA\Social\Service\ActivityService; use OCA\Social\Service\ActorService; use OCA\Social\Service\ConfigService; use OCA\Social\Service\CurlService; @@ -53,6 +55,9 @@ class NoteService implements ICoreService { /** @var ActorService */ private $actorService; + /** @var PersonService */ + private $personService; + /** @var CurlService */ private $curlService; @@ -68,17 +73,18 @@ class NoteService implements ICoreService { * * @param NotesRequest $notesRequest * @param ActorService $actorService + * @param PersonService $personService * @param CurlService $curlService * @param ConfigService $configService * @param MiscService $miscService */ public function __construct( - NotesRequest $notesRequest, ActorService $actorService, - CurlService $curlService, ConfigService $configService, - MiscService $miscService + NotesRequest $notesRequest, ActorService $actorService, PersonService $personService, + CurlService $curlService, ConfigService $configService, MiscService $miscService ) { $this->notesRequest = $notesRequest; $this->actorService = $actorService; + $this->personService = $personService; $this->curlService = $curlService; $this->configService = $configService; $this->miscService = $miscService; @@ -102,7 +108,7 @@ class NoteService implements ICoreService { $note->setAttributedTo( $this->configService->getRoot() . '@' . $actor->getPreferredUsername() ); - $note->setTo(ActivityPubService::TO_PUBLIC); + $note->setTo(ActivityService::TO_PUBLIC); $note->setContent($content); $note->saveAs($this); @@ -113,19 +119,43 @@ class NoteService implements ICoreService { /** * @param Note $note - * @param string $to - * @param int $type + * @param string $account + * + * @throws RequestException */ - public function assignTo(Note $note, string $to, int $type) { - $note->addToArray($to); + public function assignTo(Note $note, string $account) { + if ($account === '') { + return; + } + + $actor = $this->personService->getFromAccount($account); + + $note->addToArray($actor->getId()); $note->addTag( [ 'type' => 'Mention', - 'href' => $to + 'href' => $actor->getId() ] ); - $note->addInstancePath(new InstancePath($to, $type)); + $note->addInstancePath(new InstancePath($actor->getInbox())); + } + + + /** + * @param Note $note + * @param array $accounts + * + * @throws RequestException + */ + public function assignToArray(Note $note, array $accounts) { + if ($accounts === []) { + return; + } + + foreach ($accounts as $account) { + $this->assignTo($note, $account); + } } @@ -134,6 +164,10 @@ class NoteService implements ICoreService { * @param string $replyTo */ public function replyTo(Note $note, string $replyTo) { + if ($replyTo === '') { + return; + } + $note->setInReplyTo($replyTo); $note->addInstancePath(new InstancePath($replyTo)); } @@ -142,13 +176,44 @@ class NoteService implements ICoreService { /** * This method is called when saving the Note object * - * @param Core $note + * @param ACore $note * * @throws Exception */ - public function save(Core $note) { + public function save(ACore $note) { /** @var Note $note */ - $this->notesRequest->create($note); + $this->notesRequest->save($note); } + + /** + * @param string $userId + * + * @return Note[] + */ + public function getTimeline(): array { + return $this->notesRequest->getPublicNotes(); + } + + + /** + * @param Person $actor + * + * @return Note[] + */ + public function getNotesForActor(Person $actor): array { + $privates = $this->getPrivateNotesForActor($actor); + + return $privates; + } + + + /** + * @param Person $actor + * + * @return Note[] + */ + private function getPrivateNotesForActor(Person $actor): array { + return $this->notesRequest->getNotesForActorId($actor->getId()); + } } diff --git a/lib/Service/ActivityPub/PersonService.php b/lib/Service/ActivityPub/PersonService.php new file mode 100644 index 00000000..93e4ee82 --- /dev/null +++ b/lib/Service/ActivityPub/PersonService.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\Service\ActivityPub; + + +use daita\MySmallPhpTools\Traits\TArrayTools; +use Exception; +use OCA\Social\Db\CacheActorsRequest; +use OCA\Social\Exceptions\CacheActorDoesNotExistException; +use OCA\Social\Exceptions\RequestException; +use OCA\Social\Model\ActivityPub\ACore; +use OCA\Social\Model\ActivityPub\Person; +use OCA\Social\Model\InstancePath; +use OCA\Social\Service\ICoreService; +use OCA\Social\Service\InstanceService; +use OCA\Social\Service\MiscService; + + +/** + * Class PersonService + * + * @package OCA\Social\Service\ActivityPub + */ +class PersonService implements ICoreService { + + + use TArrayTools; + + + /** @var CacheActorsRequest */ + private $cacheActorsRequest; + + /** @var InstanceService */ + private $instanceService; + + /** @var MiscService */ + private $miscService; + + + /** + * UndoService constructor. + * + * @param CacheActorsRequest $cacheActorsRequest + * @param InstanceService $instanceService + * @param MiscService $miscService + */ + public function __construct( + CacheActorsRequest $cacheActorsRequest, InstanceService $instanceService, + MiscService $miscService + ) { + $this->cacheActorsRequest = $cacheActorsRequest; + $this->instanceService = $instanceService; + $this->miscService = $miscService; + } + + + /** + * @param string $account + * + * @return Person + * @throws RequestException + * @throws Exception + */ + public function getFromAccount(string $account): Person { + + try { + $actor = $this->cacheActorsRequest->getFromAccount($account); + } catch (CacheActorDoesNotExistException $e) { + + $object = $this->instanceService->retrieveAccount($account); + $actor = new Person(); + $actor->import($object); + + $actor->setAccount($account); + $actor->setPreferredUsername($this->get('preferredUsername', $object, '')); + $actor->setPublicKey($this->get('publicKey.publicKeyPem', $object)); + $actor->setSharedInbox($this->get('endpoints.sharedInbox', $object)); + $this->save($actor); + } + + return $actor; + } + + + /** + * This method is called when saving the Follow object + * + * @param ACore $person + * + * @throws Exception + */ + public function save(ACore $person) { + /** @var Person $person */ + $this->cacheActorsRequest->save($person); + } + + + // /** + // * @param Person $actor + // * @param int $type + // * + // * @return string + // */ + // public function getPathFromActor(Person $actor, int $type) { + // switch ($type) { + // case InstancePath::INBOX: + // return parse_url($actor->getInbox(), PHP_URL_PATH); + // } + // + // return ''; + // } + + +} + diff --git a/lib/Service/ActivityPub/UndoService.php b/lib/Service/ActivityPub/UndoService.php new file mode 100644 index 00000000..c1d0efae --- /dev/null +++ b/lib/Service/ActivityPub/UndoService.php @@ -0,0 +1,66 @@ + + * @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\ActivityPub; + + +use Exception; +use OCA\Social\Model\ActivityPub\ACore; +use OCA\Social\Service\ICoreService; +use OCA\Social\Service\MiscService; + + +class UndoService implements ICoreService { + + + /** @var MiscService */ + private $miscService; + + + /** + * UndoService constructor. + * + * @param MiscService $miscService + */ + public function __construct(MiscService $miscService) { + $this->miscService = $miscService; + } + + + /** + * @param ACore $undo + * + * @throws Exception + */ + public function save(ACore $undo) { + } + +} + diff --git a/lib/Service/ActivityPubService.php b/lib/Service/ActivityService.php similarity index 72% rename from lib/Service/ActivityPubService.php rename to lib/Service/ActivityService.php index b2d65423..45e8e489 100644 --- a/lib/Service/ActivityPubService.php +++ b/lib/Service/ActivityService.php @@ -31,21 +31,32 @@ namespace OCA\Social\Service; use daita\MySmallPhpTools\Model\Request; +use daita\MySmallPhpTools\Traits\TArrayTools; use DateTime; use Exception; use OC\User\NoUserException; use OCA\Social\Db\ActorsRequest; use OCA\Social\Exceptions\ActorDoesNotExistException; use OCA\Social\Exceptions\RequestException; -use OCA\Social\Model\ActivityPub\ActivityCreate; -use OCA\Social\Model\ActivityPub\Actor; -use OCA\Social\Model\ActivityPub\Core; +use OCA\Social\Exceptions\UnknownItemException; +use OCA\Social\Model\ActivityPub\ACore; +use OCA\Social\Model\ActivityPub\Activity; +use OCA\Social\Model\ActivityPub\Person; use OCA\Social\Model\InstancePath; +use OCA\Social\Service\ActivityPub\FollowService; +use OCA\Social\Service\ActivityPub\NoteService; +use OCA\Social\Service\ActivityPub\PersonService; +use OCA\Social\Service\ActivityPub\UndoService; use OCP\IRequest; -class ActivityPubService { +class ActivityService { + use TArrayTools; + + + const REQUEST_INBOX = 1; + const CONTEXT_ACTIVITYSTREAMS = 'https://www.w3.org/ns/activitystreams'; const CONTEXT_SECURITY = 'https://w3id.org/security/v1'; @@ -60,6 +71,18 @@ class ActivityPubService { /** @var ActorService */ private $actorService; + /** @var PersonService */ + private $personService; + + /** @var NoteService */ + private $noteService; + + /** @var UndoService */ + private $undoService; + + /** @var FollowService */ + private $followService; + /** @var InstanceService */ private $instanceService; @@ -74,22 +97,33 @@ class ActivityPubService { /** - * ActivityPubService constructor. + * ActivityService constructor. * * @param ActorsRequest $actorsRequest * @param CurlService $curlService * @param ActorService $actorService + * @param PersonService $personService + * @param NoteService $noteService + * @param UndoService $undoService + * @param FollowService $followService * @param InstanceService $instanceService * @param ConfigService $configService * @param MiscService $miscService */ public function __construct( ActorsRequest $actorsRequest, CurlService $curlService, ActorService $actorService, - InstanceService $instanceService, ConfigService $configService, MiscService $miscService + PersonService $personService, NoteService $noteService, UndoService $undoService, + FollowService $followService, + InstanceService $instanceService, ConfigService $configService, + MiscService $miscService ) { $this->curlService = $curlService; $this->actorsRequest = $actorsRequest; $this->actorService = $actorService; + $this->personService = $personService; + $this->noteService = $noteService; + $this->undoService = $undoService; + $this->followService = $followService; $this->instanceService = $instanceService; $this->configService = $configService; $this->miscService = $miscService; @@ -105,22 +139,24 @@ class ActivityPubService { /** * @param string $userId * - * @param Core $item - * @param Core $activity + * @param ACore $item + * @param int $type + * @param ACore $activity * * @return array * @throws ActorDoesNotExistException * @throws NoUserException * @throws RequestException */ - public function createActivity($userId, Core $item, Core &$activity = null): array { + public function createActivity($userId, ACore $item, int $type, ACore &$activity = null + ): array { + + $activity = new Activity(true); - $activity = new ActivityCreate(true); // $this->activityStreamsService->initCore($activity); - $actor = $this->actorService->getActorFromUserId($userId); + $activity->setObject($item); $activity->setId($item->getId() . '/activity'); - $activity->addInstancePaths($item->getInstancePaths()); // if ($item->getToArray() !== []) { @@ -129,30 +165,30 @@ class ActivityPubService { // $activity->setTo($item->getTo()); // } + $actor = $this->actorService->getActorFromUserId($userId); $activity->setActor($actor); - $activity->setObject($item); $this->setupCore($activity); - $result = $this->request($activity); + $result = $this->request($activity, $type); return $result; } /** - * @param Core $activity + * @param ACore $activity * * @return array * @throws RequestException */ - public function request(Core $activity) { + public function request(ACore $activity, int $type) { $hosts = $this->instanceService->getInstancesFromActivity($activity); $result = []; foreach ($hosts as $host) { foreach ($host->getInstancePaths() as $path) { - $result[] = $this->generateRequest($host->getAddress(), $path, $activity); + $result[] = $this->generateRequest($host->getAddress(), $path, $type, $activity); } } @@ -163,23 +199,24 @@ class ActivityPubService { /** * @param string $address * @param InstancePath $path - * @param Core $activity + * @param ACore $activity * * @return Request[] * @throws RequestException */ - public function generateRequest(string $address, InstancePath $path, Core $activity): array { + public function generateRequest(string $address, InstancePath $path, int $type, ACore $activity + ): array { $document = json_encode($activity); - $date = date(self::DATE_FORMAT); - + $date = gmdate(self::DATE_FORMAT); +//$date = str_replace('UTC', 'GMT', $date); $localActor = $activity->getActor(); - $remoteActor = $this->getRemoteActor($path->getUri()); +// $remoteActor = $this->getRemoteActor($path->getUri()); - $remotePath = $this->actorService->getPathFromActor($remoteActor, $path->getType()); +// $remotePath = $this->personService->getPathFromActor($remoteActor, $path->getType()); $localActorLink = $this->configService->getRoot() . '@' . $localActor->getPreferredUsername(); - $signature = "(request-target): post " . $remotePath . "\nhost: " . $address + $signature = "(request-target): post " . $path->getPath() . "\nhost: " . $address . "\ndate: " . $date; openssl_sign($signature, $signed, $localActor->getPrivateKey(), OPENSSL_ALGO_SHA256); @@ -189,7 +226,11 @@ class ActivityPubService { 'keyId="' . $localActorLink . '",headers="(request-target) host date",signature="' . $signed . '"'; - $request = new Request($remotePath, Request::TYPE_POST); + if ($type === self::REQUEST_INBOX) { + $requestType = Request::TYPE_POST; + } + + $request = new Request($path->getPath(), $requestType); $request->addHeader('Host: ' . $address); $request->addHeader('Date: ' . $date); $request->addHeader('Signature: ' . $header); @@ -245,11 +286,11 @@ class ActivityPubService { /** * @param string $uriId * - * @return Actor + * @return Person * @throws RequestException */ private function getRemoteActor(string $uriId) { - $actor = $this->actorService->getFromUri($uriId); + $actor = $this->personService->getFromAccount($uriId); return $actor; } @@ -284,7 +325,7 @@ class ActivityPubService { $signatureHeader = $request->getHeader('Signature'); $sign = $this->parseSignatureHeader($signatureHeader); - $this->miscService->mustContains(['keyId', 'headers', 'signature'], $sign); + $this->mustContains(['keyId', 'headers', 'signature'], $sign); $keyId = $sign['keyId']; $headers = $sign['headers']; @@ -360,9 +401,9 @@ class ActivityPubService { /** - * @param Core $activity + * @param ACore $activity */ - private function setupCore(Core $activity) { + private function setupCore(ACore $activity) { // $this->initCore($activity); if ($activity->isTopLevel()) { @@ -379,4 +420,46 @@ class ActivityPubService { } } + + /** + * @param ACore $activity + * + * @throws UnknownItemException + */ + public function save(Acore $activity) { + + if ($activity->gotObject()) { + $this->save($activity->getObject()); + } + + switch ($activity->getType()) { +// case 'Activity': +// $service = $this; +// break; + + case 'Undo': + $service = $this->undoService; + break; + + case 'Follow': + $service = $this->followService; + break; + + case 'Note': + $service = $this->noteService; + break; + + default: + throw new UnknownItemException(); + } + + try { + $service->save($activity); + } catch (Exception $e) { + $this->miscService->log( + 2, 'Cannot save ' . $activity->getType() . ': ' . $e->getMessage() + ); + } + } } + diff --git a/lib/Service/ActorService.php b/lib/Service/ActorService.php index b7d3cecb..1d293647 100644 --- a/lib/Service/ActorService.php +++ b/lib/Service/ActorService.php @@ -34,32 +34,29 @@ use daita\MySmallPhpTools\Traits\TArrayTools; use Exception; use OC\User\NoUserException; use OCA\Social\Db\ActorsRequest; -use OCA\Social\Db\CacheActorsRequest; use OCA\Social\Exceptions\AccountAlreadyExistsException; use OCA\Social\Exceptions\ActorDoesNotExistException; -use OCA\Social\Exceptions\CacheActorDoesNotExistException; -use OCA\Social\Exceptions\RequestException; -use OCA\Social\Model\ActivityPub\Actor; +use OCA\Social\Model\ActivityPub\Person; use OCA\Social\Model\InstancePath; + +/** + * Class ActorService + * + * @package OCA\Social\Service + */ class ActorService { use TArrayTools; - /** @var InstanceService */ - private $instanceService; - /** @var ConfigService */ private $configService; /** @var ActorsRequest */ private $actorsRequest; - /** @var CacheActorsRequest */ - private $cacheActorsRequest; - /** @var MiscService */ private $miscService; @@ -68,20 +65,14 @@ class ActorService { * ActorService constructor. * * @param ActorsRequest $actorsRequest - * @param CacheActorsRequest $cacheActorsRequest - * @param InstanceService $instanceService * @param ConfigService $configService * @param MiscService $miscService */ public function __construct( - ActorsRequest $actorsRequest, - CacheActorsRequest $cacheActorsRequest, InstanceService $instanceService, - ConfigService $configService, MiscService $miscService + ActorsRequest $actorsRequest, ConfigService $configService, MiscService $miscService ) { $this->configService = $configService; - $this->instanceService = $instanceService; $this->actorsRequest = $actorsRequest; - $this->cacheActorsRequest = $cacheActorsRequest; $this->miscService = $miscService; } @@ -89,11 +80,11 @@ class ActorService { /** * @param string $username * - * @return Actor + * @return Person * @throws ActorDoesNotExistException */ - public function getActor(string $username): Actor { + public function getActor(string $username): Person { $actor = $this->actorsRequest->getFromUsername($username); return $actor; @@ -103,11 +94,11 @@ class ActorService { /** * @param string $userId * - * @return Actor + * @return Person * @throws ActorDoesNotExistException * @throws NoUserException */ - public function getActorFromUserId(string $userId): Actor { + public function getActorFromUserId(string $userId): Person { $this->miscService->confirmUserId($userId); $actor = $this->actorsRequest->getFromUserId($userId); @@ -115,67 +106,6 @@ class ActorService { } - /** - * @param string $uriId - * - * @return Actor - * @throws RequestException - * @throws Exception - */ - public function getFromUri(string $uriId) { - - try { - $cache = $this->cacheActorsRequest->getFromUrl($uriId); - - return $this->generateActor($cache->getActor()); - } catch (CacheActorDoesNotExistException $e) { - $object = $this->instanceService->retrieveObject($uriId); - $actor = $this->generateActor($object); - $this->cacheActorsRequest->create($actor, $object); - - return $actor; - } - } - - - /** - * @param Actor $actor - * @param int $type - * - * @return string - */ - public function getPathFromActor(Actor $actor, int $type) { - switch ($type) { - case InstancePath::INBOX: - return parse_url($actor->getInbox(), PHP_URL_PATH); - } - - return ''; - } - - - /** - * @param array $object - * - * @return Actor - */ - public function generateActor(array $object) { - $actor = new Actor(); - - - $actor->setId($this->get('id', $object)); - $actor->setFollowers($this->get('followers', $object)); - $actor->setFollowing($this->get('following', $object)); - $actor->setInbox($this->get('inbox', $object)); - $actor->setOutbox($this->get('outbox', $object)); - $actor->setPublicKey($object['publicKey']['publicKeyPem']); - $actor->setPreferredUsername($this->get('preferredUsername', $object)); - $actor->setAccount('@' . $actor->getPreferredUsername() . '@' . $object['_address']); - -// $actor->setSharedInbox($this->get('')) - - return $actor; - } /** @@ -215,7 +145,7 @@ class ActorService { $this->configService->setCoreValue('public_webfinger', 'social/lib/webfinger.php'); - $actor = new Actor(); + $actor = new Person(); $actor->setUserId($userId); $actor->setPreferredUsername($username); @@ -233,10 +163,11 @@ class ActorService { return; } + /** - * @param Actor $actor + * @param Person $actor */ - private function generateKeys(Actor &$actor) { + private function generateKeys(Person &$actor) { $res = openssl_pkey_new( [ "digest_alg" => "rsa", diff --git a/lib/Service/ConfigService.php b/lib/Service/ConfigService.php index be155bee..86bae751 100644 --- a/lib/Service/ConfigService.php +++ b/lib/Service/ConfigService.php @@ -29,25 +29,29 @@ declare(strict_types=1); namespace OCA\Social\Service; +use daita\MySmallPhpTools\Traits\TPathTools; use OCA\Social\AppInfo\Application; use OCP\IConfig; use OCP\IRequest; +use OCP\IURLGenerator; use OCP\PreConditionNotMetException; +/** + * Class ConfigService + * + * @package OCA\Social\Service + */ class ConfigService { + + use TPathTools; + + /** @var array */ public $defaults = [ ]; -// public $serviceTypes = [ -// [ -// 'id' => 'mastodon', -// 'name' => 'Mastodon (OAuth2)' -// ] -// ]; - /** @var string */ private $userId; @@ -57,6 +61,9 @@ class ConfigService { /** @var IRequest */ private $request; + /** @var IURLGenerator */ + private $urlGenerator; + /** @var MiscService */ private $miscService; @@ -67,15 +74,17 @@ class ConfigService { * @param string $userId * @param IConfig $config * @param IRequest $request + * @param IURLGenerator $urlGenerator * @param MiscService $miscService */ public function __construct( - $userId, IConfig $config, IRequest $request, + $userId, IConfig $config, IRequest $request, IURLGenerator $urlGenerator, MiscService $miscService ) { $this->userId = $userId; $this->config = $config; $this->request = $request; + $this->urlGenerator = $urlGenerator; $this->miscService = $miscService; } @@ -202,9 +211,12 @@ class ConfigService { /** * @return string + * // TODO: improve this ! */ public function getRoot(): string { - return 'https://test.artificial-owl.com/apps/social/'; +// $this->urlGenerator->linkToRoute('social.Navigation.navigate'); + return $this->withoutEndSlash($this->getSystemValue('overwrite.cli.url'), false, false) + . '/apps/social/'; } @@ -215,7 +227,7 @@ class ConfigService { * @return string */ public function generateId(string $path = '', $generateId = true): string { - $this->miscService->formatPath($path); + $path = $this->withoutBeginSlash($this->withEndSlash($path)); $id = $this->getRoot() . $path; if ($generateId === true) { diff --git a/lib/Service/CurlService.php b/lib/Service/CurlService.php index c485dd76..bfbc0238 100644 --- a/lib/Service/CurlService.php +++ b/lib/Service/CurlService.php @@ -114,11 +114,10 @@ class CurlService { */ private function generateCurlRequest(Request $request) { $url = 'https://' . $request->getAddress() . $request->getParsedUrl(); -// echo 'curl: ' . $request->getUrl() . "\n"; if ($request->getType() !== Request::TYPE_GET) { $curl = curl_init($url); } else { - $curl = curl_init($url . '?' . $request->getDataBody()); + $curl = curl_init($url . '?' . $request->getUrlData()); } return $curl; diff --git a/lib/Service/ICoreService.php b/lib/Service/ICoreService.php index f0b94dcd..8f2f4ef9 100644 --- a/lib/Service/ICoreService.php +++ b/lib/Service/ICoreService.php @@ -30,10 +30,10 @@ declare(strict_types=1); namespace OCA\Social\Service; -use OCA\Social\Model\ActivityPub\Core; +use OCA\Social\Model\ActivityPub\ACore; interface ICoreService { - public function save(Core $core); + public function save(ACore $core); } diff --git a/lib/Service/ImportService.php b/lib/Service/ImportService.php new file mode 100644 index 00000000..bacaed27 --- /dev/null +++ b/lib/Service/ImportService.php @@ -0,0 +1,123 @@ + + * @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\Traits\TArrayTools; +use OCA\Social\Exceptions\UnknownItemException; +use OCA\Social\Model\ActivityPub\ACore; +use OCA\Social\Model\ActivityPub\Activity; +use OCA\Social\Model\ActivityPub\Follow; +use OCA\Social\Model\ActivityPub\Note; +use OCA\Social\Model\ActivityPub\Undo; + +class ImportService { + + + use TArrayTools; + + + /** @var MiscService */ + private $miscService; + + + /** + * ActorService constructor. + * + * @param MiscService $miscService + */ + public function __construct(MiscService $miscService) { + $this->miscService = $miscService; + } + + + /** + * @param string $json + * + * @return ACore + * @throws UnknownItemException + */ + public function import(string $json) { + $data = json_decode($json, true); + + $activity = $this->createItem($data, null); + + return $activity; + } + + + /** + * @param array $data + * @param ACore $root + * + * @return ACore + * @throws UnknownItemException + */ + private function createItem(array $data, $root = null): ACore { + + $isTopLevel = ($root === null); + switch ($this->get('type', $data)) { + case 'Create': + $item = new Activity($isTopLevel); + break; + + case 'Note': + $item = new Note($isTopLevel); + break; + + case 'Follow': + $item = new Follow($isTopLevel); + break; + + case 'Undo': + $item = new Undo($isTopLevel); + break; + + default: + throw new UnknownItemException(); + } + + if ($root instanceof ACore) { + $item->setMetaAll($root->getMetaAll()); + } + + $item->import($data); + + try { + $object = $this->createItem($this->getArray('object', $data, []), $item); + $item->setObject($object); + } catch (UnknownItemException $e) { + } + + return $item; + } + +} + diff --git a/lib/Service/InstanceService.php b/lib/Service/InstanceService.php index 777866e5..6d91e7cb 100644 --- a/lib/Service/InstanceService.php +++ b/lib/Service/InstanceService.php @@ -30,15 +30,22 @@ declare(strict_types=1); namespace OCA\Social\Service; +use daita\MySmallPhpTools\Exceptions\ArrayNotFoundException; use daita\MySmallPhpTools\Model\Request; +use daita\MySmallPhpTools\Traits\TArrayTools; +use daita\MySmallPhpTools\Traits\TPathTools; use OCA\Social\Exceptions\RequestException; -use OCA\Social\Model\ActivityPub\Core; +use OCA\Social\Model\ActivityPub\ACore; use OCA\Social\Model\Instance; use OCA\Social\Model\InstancePath; class InstanceService { + use TPathTools; + use TArrayTools; + + /** @var ConfigService */ private $configService; @@ -65,6 +72,32 @@ class InstanceService { } + /** + * @param string $account + * + * @return mixed + * @throws RequestException + */ + public function retrieveAccount(string $account) { + $account = $this->withoutBeginAt($account); + + list($username, $host) = explode('@', $account); + + $request = new Request('/.well-known/webfinger'); + $request->addData('resource', 'acct:' . $account); + $request->setAddress($host); + $result = $this->curlService->request($request); + + try { + $link = $this->extractArray('rel', 'self', $this->getArray('links', $result)); + } catch (ArrayNotFoundException $e) { + throw new RequestException(); + } + + return $this->retrieveObject($this->get('href', $link, '')); + } + + /** * @param $id * @@ -73,7 +106,6 @@ class InstanceService { */ public function retrieveObject($id) { $url = parse_url($id); - $request = new Request($url['path'], Request::TYPE_GET); $request->setAddress($url['host']); @@ -84,12 +116,13 @@ class InstanceService { /** - * @param Core $activity + * @param ACore $activity * * @return Instance[] */ - public function getInstancesFromActivity(Core $activity): array { + public function getInstancesFromActivity(ACore $activity): array { $instances = []; + foreach ($activity->getInstancePaths() as $instancePath) { $this->addInstances($instancePath, $instances); // $uriIds[] = $to; @@ -105,6 +138,7 @@ class InstanceService { */ private function addInstances(InstancePath $instancePath, array &$instances) { $address = $this->getHostFromUriId($instancePath->getUri()); + if ($address === '') { return; } diff --git a/lib/Service/MiscService.php b/lib/Service/MiscService.php index c8f276f3..0feb57fc 100644 --- a/lib/Service/MiscService.php +++ b/lib/Service/MiscService.php @@ -27,14 +27,22 @@ declare(strict_types=1); * */ + namespace OCA\Social\Service; + use Exception; use OC\User\NoUserException; use OCA\Social\AppInfo\Application; use OCP\ILogger; use OCP\IUserManager; + +/** + * Class MiscService + * + * @package OCA\Social\Service + */ class MiscService { @@ -71,47 +79,6 @@ class MiscService { } - /** - * @param array $keys - * @param array $arr - * - * @throws Exception - */ - public function mustContains(array $keys, array $arr) { - foreach ($keys as $key) { - if (!array_key_exists($key, $arr)) { - throw new Exception('missing elements'); - } - } - } - - public static function noEndSlash($path) { - if (substr($path, -1) === '/') { - $path = substr($path, 0, -1); - } - - return $path; - } - - - /** - * @param string $path - */ - public function formatPath(string &$path) { - if ($path === '') { - return; - } - - if (substr($path, 0, 1) === '/') { - $path = substr($path, 1); - } - - if (substr($path, -1) !== '/') { - $path .= '/'; - } - } - - /** * @param string $userId * diff --git a/lib/Service/PostService.php b/lib/Service/PostService.php new file mode 100644 index 00000000..fba1a675 --- /dev/null +++ b/lib/Service/PostService.php @@ -0,0 +1,93 @@ + + * @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 OC\User\NoUserException; +use OCA\Social\Exceptions\ActorDoesNotExistException; +use OCA\Social\Exceptions\RequestException; +use OCA\Social\Model\ActivityPub\ACore; +use OCA\Social\Model\InstancePath; +use OCA\Social\Model\Post; +use OCA\Social\Service\ActivityPub\NoteService; + +class PostService { + + + /** @var NoteService */ + private $noteService; + + /** @var ActivityService */ + private $activityService; + + /** @var MiscService */ + private $miscService; + + + /** + * PostService constructor. + * + * @param NoteService $noteService + * @param ActivityService $activityService + * @param MiscService $miscService + */ + public function __construct( + NoteService $noteService, ActivityService $activityService, MiscService $miscService + ) { + $this->noteService = $noteService; + $this->activityService = $activityService; + $this->miscService = $miscService; + } + + + /** + * @param Post $post + * @param ACore $activity + * + * @return array + * @throws ActorDoesNotExistException + * @throws NoUserException + * @throws RequestException + */ + public function createPost(Post $post, ACore &$activity = null) { + $note = + $this->noteService->generateNote($post->getUserId(), $post->getContent()); + + $this->noteService->assignToArray($note, $post->getTo()); + $this->noteService->replyTo($note, $post->getReplyTo()); + + return $this->activityService->createActivity( + $post->getUserId(), $note, ActivityService::REQUEST_INBOX, $activity + ); + } + + +} +