diff --git a/appinfo/routes.php b/appinfo/routes.php index 8b28ae27..2b64e712 100644 --- a/appinfo/routes.php +++ b/appinfo/routes.php @@ -54,6 +54,10 @@ return [ ['name' => 'ActivityPub#followers', 'url' => '/@{username}/followers', 'verb' => 'GET'], ['name' => 'ActivityPub#following', 'url' => '/@{username}/following', 'verb' => 'GET'], + ['name' => 'OStatus#subscribe', 'url' => '/ostatus/follow/{uri}', 'verb' => 'GET'], + ['name' => 'OStatus#followRemote', 'url' => '/api/v1/ostatus/followRemote/{local}', 'verb' => 'GET'], + ['name' => 'OStatus#getLink', 'url' => '/api/v1/ostatus/link/{local}/{account}', 'verb' => 'GET'], + ['name' => 'SocialPub#displayPost', 'url' => '/@{username}/{postId}', 'verb' => 'GET'], ['name' => 'Local#streamHome', 'url' => '/api/v1/stream/home', 'verb' => 'GET'], diff --git a/lib/Controller/OStatusController.php b/lib/Controller/OStatusController.php new file mode 100644 index 00000000..182c4a3d --- /dev/null +++ b/lib/Controller/OStatusController.php @@ -0,0 +1,188 @@ + + * @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\Controller; + + +use daita\MySmallPhpTools\Exceptions\ArrayNotFoundException; +use daita\MySmallPhpTools\Traits\Nextcloud\TNCDataResponse; +use daita\MySmallPhpTools\Traits\TArrayTools; +use Exception; +use OCA\Social\AppInfo\Application; +use OCA\Social\Exceptions\RetrieveAccountFormatException; +use OCA\Social\Service\AccountService; +use OCA\Social\Service\CacheActorService; +use OCA\Social\Service\CurlService; +use OCA\Social\Service\MiscService; +use OCP\AppFramework\Controller; +use OCP\AppFramework\Http\Response; +use OCP\AppFramework\Http\TemplateResponse; +use OCP\IRequest; +use OCP\IUserManager; +use OCP\IUserSession; + + +class OStatusController extends Controller { + + + use TNCDataResponse; + use TArrayTools; + + + /** @var CacheActorService */ + private $cacheActorService; + + /** @var AccountService */ + private $accountService; + + /** @var CurlService */ + private $curlService; + + /** @var MiscService */ + private $miscService; + + /** @var IUserManager */ + private $userSession; + + + /** + * OStatusController constructor. + * + * @param IRequest $request + * @param CacheActorService $cacheActorService + * @param AccountService $accountService + * @param CurlService $curlService + * @param MiscService $miscService + */ + public function __construct( + IRequest $request, CacheActorService $cacheActorService, AccountService $accountService, + CurlService $curlService, MiscService $miscService, IUserSession $userSession + ) { + parent::__construct(Application::APP_NAME, $request); + + $this->cacheActorService = $cacheActorService; + $this->accountService = $accountService; + $this->curlService = $curlService; + $this->miscService = $miscService; + $this->userSession = $userSession; + } + + + /** + * @NoCSRFRequired + * @NoAdminRequired + * + * @param string $uri + * + * @return Response + */ + public function subscribe(string $uri): Response { + + try { + $actor = $this->cacheActorService->getFromAccount($uri); + + $user = $this->userSession->getUser(); + if ($user === null) { + return $this->fail('Failed to retrieve current user'); + } + + return new TemplateResponse('social', 'ostatus', [ + 'serverData' => [ + 'account' => $actor->getAccount(), + 'currentUser' => [ + 'uid' => $user->getUID(), + 'displayName' => $user->getDisplayName(), + ] + ] + ], 'guest'); + } catch (Exception $e) { + return $this->fail($e); + } + } + + + /** + * @NoCSRFRequired + * @NoAdminRequired + * @PublicPage + * + * @param string $local + * @return Response + */ + public function followRemote(string $local): Response { + try { + $following = $this->accountService->getActor($local); + + return new TemplateResponse('social', 'ostatus', [ + 'serverData' => [ + 'local' => $local, + 'account' => $following->getAccount() + ] + ], 'guest'); + } catch (\Exception $e) { + return $this->fail($e); + } + } + + /** + * @NoCSRFRequired + * @NoAdminRequired + * @PublicPage + * + * @param string $local + * @param string $account + * + * @return Response + */ + public function getLink(string $local, string $account): Response { + + try { + $following = $this->accountService->getActor($local); + $result = $this->curlService->webfingerAccount($account); + + try { + $link = $this->extractArray( + 'rel', 'http://ostatus.org/schema/1.0/subscribe', + $this->getArray('links', $result) + ); + } catch (ArrayNotFoundException $e) { + throw new RetrieveAccountFormatException(); + } + + $template = $this->get('template', $link, ''); + $url = str_replace('{uri}', $following->getAccount(), $template); + + return $this->success(['url' => $url]); + } catch (Exception $e) { + return $this->fail($e); + } + } + +} + diff --git a/lib/Service/AccountService.php b/lib/Service/AccountService.php index 497b732b..13dde24d 100644 --- a/lib/Service/AccountService.php +++ b/lib/Service/AccountService.php @@ -161,6 +161,7 @@ class AccountService { * @throws NoUserException * @throws SocialAppConfigException * @throws UrlCloudException + * @throws ItemUnknownException */ public function getActorFromUserId(string $userId, bool $create = false): Person { $this->miscService->confirmUserId($userId); diff --git a/lib/Service/CurlService.php b/lib/Service/CurlService.php index 923596d1..c9b0c1c1 100644 --- a/lib/Service/CurlService.php +++ b/lib/Service/CurlService.php @@ -90,21 +90,15 @@ class CurlService { /** * @param string $account * - * @return Person - * @throws InvalidOriginException + * @return array * @throws InvalidResourceException - * @throws MalformedArrayException - * @throws RedundancyLimitException * @throws RequestContentException - * @throws RetrieveAccountFormatException * @throws RequestNetworkException * @throws RequestResultSizeException * @throws RequestServerException - * @throws SocialAppConfigException - * @throws ItemUnknownException * @throws RequestResultNotJsonException */ - public function retrieveAccount(string $account): Person { + public function webfingerAccount(string $account): array { $account = $this->withoutBeginAt($account); // we consider an account is like an email @@ -122,6 +116,29 @@ class CurlService { $request->setAddress($host); $result = $this->request($request); + return $result; + } + + + /** + * @param string $account + * + * @return Person + * @throws InvalidOriginException + * @throws InvalidResourceException + * @throws MalformedArrayException + * @throws RedundancyLimitException + * @throws RequestContentException + * @throws RetrieveAccountFormatException + * @throws RequestNetworkException + * @throws RequestResultSizeException + * @throws RequestServerException + * @throws SocialAppConfigException + * @throws ItemUnknownException + */ + public function retrieveAccount(string $account): Person { + $result = $this->webfingerAccount($account); + try { $link = $this->extractArray('rel', 'self', $this->getArray('links', $result)); } catch (ArrayNotFoundException $e) { diff --git a/lib/webfinger.php b/lib/webfinger.php index 8a50b82c..7794abad 100644 --- a/lib/webfinger.php +++ b/lib/webfinger.php @@ -83,6 +83,11 @@ $finger = [ 'rel' => 'self', 'type' => 'application/activity+json', 'href' => $href + ], + [ + 'rel' => 'http://ostatus.org/schema/1.0/subscribe', + 'template' => urldecode( + $href = $urlGenerator->linkToRouteAbsolute('social.OStatus.subscribe', ['uri' => '{uri}'])) ] ] ]; diff --git a/src/components/ProfileInfo.vue b/src/components/ProfileInfo.vue index 439da6df..e1352084 100644 --- a/src/components/ProfileInfo.vue +++ b/src/components/ProfileInfo.vue @@ -35,6 +35,9 @@

+