kopia lustrzana https://github.com/nextcloud/social
proof of concept
Signed-off-by: Maxence Lange <maxence@artificial-owl.com>pull/985/head
rodzic
db9a804de0
commit
e986ca6a4f
|
@ -52,6 +52,7 @@ return [
|
|||
['name' => 'ActivityPub#actor', 'url' => '/users/{username}', 'verb' => 'GET'],
|
||||
['name' => 'ActivityPub#actorAlias', 'url' => '/@{username}/', 'verb' => 'GET'],
|
||||
['name' => 'ActivityPub#inbox', 'url' => '/@{username}/inbox', 'verb' => 'POST'],
|
||||
['name' => 'ActivityPub#getInbox', 'url' => '/@{username}/inbox', 'verb' => 'GET'],
|
||||
['name' => 'ActivityPub#sharedInbox', 'url' => '/inbox', 'verb' => 'POST'],
|
||||
|
||||
['name' => 'ActivityPub#outbox', 'url' => '/@{username}/outbox', 'verb' => 'GET'],
|
||||
|
@ -65,6 +66,17 @@ return [
|
|||
['name' => 'OStatus#followRemote', 'url' => '/api/v1/ostatus/followRemote/{local}', 'verb' => 'GET'],
|
||||
['name' => 'OStatus#getLink', 'url' => '/api/v1/ostatus/link/{local}/{account}', 'verb' => 'GET'],
|
||||
|
||||
// OAuth
|
||||
['name' => 'ActivityStream#apps', 'url' => '/api/v1/apps', 'verb' => 'POST'],
|
||||
['name' => 'ActivityStream#authorize', 'url' => '/oauth/authorize', 'verb' => 'GET'],
|
||||
['name' => 'ActivityStream#token', 'url' => '/oauth/token', 'verb' => 'POST'],
|
||||
['name' => 'ActivityStream#appsCredentials', 'url' => '/api/v1/apps/verify_credentials', 'verb' => 'GET'],
|
||||
['name' => 'ActivityStream#accountsCredentials', 'url' => '/api/v1/accounts/verify_credentials', 'verb' => 'GET'],
|
||||
|
||||
// New Local
|
||||
['name' => 'ActivityStream#timelines', 'url' => '/api/v1/timelines/{timeline}/', 'verb' => 'GET'],
|
||||
|
||||
|
||||
['name' => 'Local#streamHome', 'url' => '/api/v1/stream/home', 'verb' => 'GET'],
|
||||
['name' => 'Local#streamNotifications', 'url' => '/api/v1/stream/notifications', 'verb' => 'GET'],
|
||||
['name' => 'Local#streamTimeline', 'url' => '/api/v1/stream/timeline', 'verb' => 'GET'],
|
||||
|
|
|
@ -203,7 +203,6 @@ class ActivityPubController extends Controller {
|
|||
* @return Response
|
||||
*/
|
||||
public function sharedInbox(): Response {
|
||||
|
||||
try {
|
||||
$body = file_get_contents('php://input');
|
||||
$this->miscService->log('[<<] sharedInbox: ' . $body, 1);
|
||||
|
@ -281,6 +280,29 @@ class ActivityPubController extends Controller {
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* Method is called when a remote ActivityPub server wants to GET in the INBOX of a USER
|
||||
* Checking that the user exists, and that the header is properly signed.
|
||||
*
|
||||
* @NoCSRFRequired
|
||||
* @PublicPage
|
||||
*
|
||||
* @param string $username
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function getInbox(string $username): Response {
|
||||
try {
|
||||
$body = file_get_contents('php://input');
|
||||
$actor = $this->cacheActorService->getFromLocalAccount($username);
|
||||
|
||||
return $this->success();
|
||||
} catch (Exception $e) {
|
||||
return new DataResponse([], Http::STATUS_NOT_FOUND);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Outbox. does nothing.
|
||||
*
|
||||
|
|
|
@ -0,0 +1,348 @@
|
|||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
|
||||
/**
|
||||
* Nextcloud - Social Support
|
||||
*
|
||||
* This file is licensed under the Affero General Public License version 3 or
|
||||
* later. See the COPYING file.
|
||||
*
|
||||
* @author Maxence Lange <maxence@artificial-owl.com>
|
||||
* @copyright 2018, Maxence Lange <maxence@artificial-owl.com>
|
||||
* @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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace OCA\Social\Controller;
|
||||
|
||||
|
||||
use daita\MySmallPhpTools\Traits\Nextcloud\TNCDataResponse;
|
||||
use Exception;
|
||||
use OC\AppFramework\Http;
|
||||
use OC\User\NoUserException;
|
||||
use OCA\Social\AppInfo\Application;
|
||||
use OCA\Social\Exceptions\AccountAlreadyExistsException;
|
||||
use OCA\Social\Exceptions\AccountDoesNotExistException;
|
||||
use OCA\Social\Exceptions\ActorDoesNotExistException;
|
||||
use OCA\Social\Exceptions\ItemAlreadyExistsException;
|
||||
use OCA\Social\Exceptions\SocialAppConfigException;
|
||||
use OCA\Social\Exceptions\UrlCloudException;
|
||||
use OCA\Social\Model\ActivityPub\Actor\Person;
|
||||
use OCA\Social\Model\ActivityPub\Stream;
|
||||
use OCA\Social\Model\ActivityStream\ClientApp;
|
||||
use OCA\Social\Service\AccountService;
|
||||
use OCA\Social\Service\CacheActorService;
|
||||
use OCA\Social\Service\ClientService;
|
||||
use OCA\Social\Service\ConfigService;
|
||||
use OCA\Social\Service\FollowService;
|
||||
use OCA\Social\Service\MiscService;
|
||||
use OCA\Social\Service\StreamService;
|
||||
use OCP\AppFramework\Controller;
|
||||
use OCP\AppFramework\Http\DataResponse;
|
||||
use OCP\AppFramework\Http\Response;
|
||||
use OCP\IRequest;
|
||||
|
||||
|
||||
class ActivityStreamController extends Controller {
|
||||
|
||||
|
||||
use TNCDataResponse;
|
||||
|
||||
|
||||
/** @var AccountService */
|
||||
private $accountService;
|
||||
|
||||
/** @var CacheActorService */
|
||||
private $cacheActorService;
|
||||
|
||||
/** @var ClientService */
|
||||
private $clientService;
|
||||
|
||||
/** @var FollowService */
|
||||
private $followService;
|
||||
|
||||
/** @var StreamService */
|
||||
private $streamService;
|
||||
|
||||
/** @var ConfigService */
|
||||
private $configService;
|
||||
|
||||
/** @var MiscService */
|
||||
private $miscService;
|
||||
|
||||
|
||||
/** @var string */
|
||||
private $bearer = '';
|
||||
|
||||
/** @var Person */
|
||||
private $viewer;
|
||||
|
||||
|
||||
/**
|
||||
* ActivityStreamController constructor.
|
||||
*
|
||||
* @param IRequest $request
|
||||
* @param AccountService $accountService
|
||||
* @param CacheActorService $cacheActorService
|
||||
* @param ClientService $clientService
|
||||
* @param FollowService $followService
|
||||
* @param StreamService $streamService
|
||||
* @param ConfigService $configService
|
||||
* @param MiscService $miscService
|
||||
*/
|
||||
public function __construct(
|
||||
IRequest $request, AccountService $accountService, CacheActorService $cacheActorService,
|
||||
ClientService $clientService, FollowService $followService, StreamService $streamService,
|
||||
ConfigService $configService,
|
||||
MiscService $miscService
|
||||
) {
|
||||
parent::__construct(Application::APP_NAME, $request);
|
||||
|
||||
$this->accountService = $accountService;
|
||||
$this->cacheActorService = $cacheActorService;
|
||||
$this->clientService = $clientService;
|
||||
$this->followService = $followService;
|
||||
$this->streamService = $streamService;
|
||||
$this->configService = $configService;
|
||||
$this->miscService = $miscService;
|
||||
|
||||
$authHeader = trim($this->request->getHeader('Authorization'));
|
||||
list($authType, $authToken) = explode(' ', $authHeader);
|
||||
if (strtolower($authType) === 'bearer') {
|
||||
$this->bearer = $authToken;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @NoCSRFRequired
|
||||
* @PublicPage
|
||||
*
|
||||
* @param string $website
|
||||
* @param string $redirect_uris
|
||||
* @param string $scopes
|
||||
* @param string $client_name
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function apps(
|
||||
string $website = '', string $redirect_uris = '', string $scopes = '', string $client_name = ''
|
||||
): Response {
|
||||
$clientApp = new ClientApp();
|
||||
$clientApp->setWebsite($website);
|
||||
$clientApp->setRedirectUri($redirect_uris);
|
||||
$clientApp->setScopesFromString($scopes);
|
||||
$clientApp->setName($client_name);
|
||||
|
||||
$this->clientService->createClient($clientApp);
|
||||
$this->miscService->log('### ' . json_encode($clientApp));
|
||||
|
||||
return $this->directSuccess($clientApp);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @NoCSRFRequired
|
||||
* @NoAdminRequired
|
||||
* @PublicPage
|
||||
*
|
||||
* @return DataResponse
|
||||
* @throws SocialAppConfigException
|
||||
* @throws AccountAlreadyExistsException
|
||||
* @throws ActorDoesNotExistException
|
||||
* @throws ItemAlreadyExistsException
|
||||
* @throws UrlCloudException
|
||||
* @throws NoUserException
|
||||
*/
|
||||
public function authorize(): DataResponse {
|
||||
$userId = 'cult';
|
||||
|
||||
$account = $this->accountService->getActorFromUserId($userId);
|
||||
$clientId = (string)$this->request->getParam('client_id', '');
|
||||
$responseType = (string)$this->request->getParam('response_type', '');
|
||||
$redirectUri = (string)$this->request->getParam('redirect_uri', '');
|
||||
|
||||
if ($responseType !== 'code') {
|
||||
return new DataResponse(['error' => 'invalid_type'], Http::STATUS_BAD_REQUEST);
|
||||
}
|
||||
|
||||
// $this->clientService->assignAccount($clientId, $account);
|
||||
$code = 'test1234';
|
||||
|
||||
if ($redirectUri !== '') {
|
||||
header('Location: ' . $redirectUri . '?code=' . $code);
|
||||
exit();
|
||||
}
|
||||
|
||||
// return new DataResponse(
|
||||
// [
|
||||
// 'access_token' => '',
|
||||
// "token_type" => "Bearer",
|
||||
// "scope" => "read write follow push",
|
||||
// "created_at" => 1573979017
|
||||
// ], Http::STATUS_OK
|
||||
// );
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @NoCSRFRequired
|
||||
* @NoAdminRequired
|
||||
* @PublicPage
|
||||
*
|
||||
* @return DataResponse
|
||||
*/
|
||||
public function token() {
|
||||
$body = file_get_contents('php://input');
|
||||
$this->miscService->log('[<<] : ' . $body, 1);
|
||||
////code=test1234&grant_type=authorization_code&
|
||||
//client_secret=amJWTrlnZEhe44aXHsW2xlsTLD8g0DqabDDJ7jdp&
|
||||
//redirect_uri=https%3A%2F%2Forg.mariotaku.twidere%2Fauth%2Fcallback%2Fmastodon&
|
||||
//client_id=ihyiNapjftENlY2dZCbbfLHYoloB1HbpWQyLGtvr
|
||||
return new DataResponse(
|
||||
[
|
||||
"access_token" => "ZA-Yj3aBD8U8Cm7lKUp-lm9O9BmDgdhHzDeqsY8tlL0",
|
||||
"token_type" => "Bearer",
|
||||
"scope" => "read write follow push",
|
||||
"created_at" => time()
|
||||
], 200
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @NoCSRFRequired
|
||||
* @NoAdminRequired
|
||||
* @PublicPage
|
||||
*
|
||||
* @return DataResponse
|
||||
*/
|
||||
public function appsCredentials() {
|
||||
return new DataResponse(
|
||||
[
|
||||
'name' => 'Twidere for Android',
|
||||
'website' => 'https://github.com/TwidereProject/'
|
||||
], 200
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @NoCSRFRequired
|
||||
* @NoAdminRequired
|
||||
* @PublicPage
|
||||
*
|
||||
* @return DataResponse
|
||||
*/
|
||||
public function accountsCredentials() {
|
||||
return new DataResponse(
|
||||
[
|
||||
"id" => "137148",
|
||||
"username" => "cult",
|
||||
"acct" => "cult",
|
||||
"display_name" => "Maxence Lange",
|
||||
"locked" => false,
|
||||
"bot" => false,
|
||||
"discoverable" => null,
|
||||
"group" => false,
|
||||
"created_at" => "2017-05-11T09=>20=>28.055Z",
|
||||
"note" => "\u003cp\u003e\u003c/p\u003e",
|
||||
"url" => "https://test.artificial-owl.com/index.php/apps/social/@cult",
|
||||
"avatar" => "https://mastodon.social/avatars/original/missing.png",
|
||||
"avatar_static" => "https://mastodon.social/avatars/original/missing.png",
|
||||
"header" => "https://mastodon.social/headers/original/missing.png",
|
||||
"header_static" => "https://mastodon.social/headers/original/missing.png",
|
||||
"followers_count" => 9,
|
||||
"following_count" => 5,
|
||||
"statuses_count" => 13,
|
||||
"last_status_at" => "2019-09-15",
|
||||
"source" => [
|
||||
"privacy" => "public",
|
||||
"sensitive" => false,
|
||||
"language" => null,
|
||||
"note" => "",
|
||||
"fields" => [],
|
||||
"follow_requests_count" => 0
|
||||
],
|
||||
"emojis" => [],
|
||||
"fields" => []
|
||||
], 200
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @NoCSRFRequired
|
||||
* @NoAdminRequired
|
||||
* @PublicPage
|
||||
*
|
||||
* @param string $timeline
|
||||
* @param int $limit
|
||||
*
|
||||
* @return DataResponse
|
||||
*/
|
||||
public function timelines(string $timeline, int $limit = 20): DataResponse {
|
||||
try {
|
||||
$this->initViewer(true);
|
||||
$posts = $this->streamService->getStreamHome(0, $limit, Stream::FORMAT_LOCAL);
|
||||
|
||||
return new DataResponse($posts, 200);
|
||||
} catch (Exception $e) {
|
||||
return $this->fail($e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @param bool $exception
|
||||
*
|
||||
* @return bool
|
||||
* @throws AccountDoesNotExistException
|
||||
*/
|
||||
private function initViewer(bool $exception = false): bool {
|
||||
if ($this->bearer === '') {
|
||||
// if ($exception) {
|
||||
// throw new AccountDoesNotExistException('userId not defined');
|
||||
// }
|
||||
//
|
||||
// return false;
|
||||
}
|
||||
|
||||
try {
|
||||
$this->viewer = $this->cacheActorService->getFromLocalAccount('cult');
|
||||
|
||||
$this->streamService->setViewer($this->viewer);
|
||||
$this->followService->setViewer($this->viewer);
|
||||
$this->cacheActorService->setViewer($this->viewer);
|
||||
} catch (Exception $e) {
|
||||
if ($exception) {
|
||||
throw new AccountDoesNotExistException(
|
||||
'unable to initViewer - ' . get_class($e) . ' - ' . $e->getMessage()
|
||||
);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,110 @@
|
|||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
|
||||
/**
|
||||
* Nextcloud - Social Support
|
||||
*
|
||||
* This file is licensed under the Affero General Public License version 3 or
|
||||
* later. See the COPYING file.
|
||||
*
|
||||
* @author Maxence Lange <maxence@artificial-owl.com>
|
||||
* @copyright 2018, Maxence Lange <maxence@artificial-owl.com>
|
||||
* @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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
namespace OCA\Social\Db;
|
||||
|
||||
|
||||
use daita\MySmallPhpTools\Traits\TArrayTools;
|
||||
use DateTime;
|
||||
use Exception;
|
||||
use OCA\Social\Exceptions\ClientAppDoesNotExistException;
|
||||
use OCA\Social\Model\ActivityStream\ClientApp;
|
||||
use OCP\DB\QueryBuilder\IQueryBuilder;
|
||||
|
||||
|
||||
/**
|
||||
* Class ActionsRequest
|
||||
*
|
||||
* @package OCA\Social\Db
|
||||
*/
|
||||
class ClientAppRequest extends ClientAppRequestBuilder {
|
||||
|
||||
|
||||
use TArrayTools;
|
||||
|
||||
|
||||
/**
|
||||
* Insert a new OAuth client in the database.
|
||||
*
|
||||
* @param ClientApp $clientApp
|
||||
*/
|
||||
public function save(ClientApp $clientApp) {
|
||||
$qb = $this->getClientAppInsertSql();
|
||||
$qb->setValue('name', $qb->createNamedParameter($clientApp->getName()))
|
||||
->setValue('website', $qb->createNamedParameter($clientApp->getWebsite()))
|
||||
->setValue('redirect_uri', $qb->createNamedParameter($clientApp->getRedirectUri()))
|
||||
->setValue('client_id', $qb->createNamedParameter($clientApp->getClientId()))
|
||||
->setValue('client_secret', $qb->createNamedParameter($clientApp->getClientSecret()));
|
||||
|
||||
try {
|
||||
$qb->setValue(
|
||||
'creation',
|
||||
$qb->createNamedParameter(new DateTime('now'), IQueryBuilder::PARAM_DATE)
|
||||
);
|
||||
} catch (Exception $e) {
|
||||
}
|
||||
|
||||
$qb->execute();
|
||||
|
||||
$clientApp->setId($qb->getLastInsertId());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $clientId
|
||||
* @param string $account
|
||||
*/
|
||||
public function assignAccount(string $clientId, string $account): void {
|
||||
$qb = $this->getClientAppUpdateSql();
|
||||
$qb->set('account', $qb->createNamedParameter($account));
|
||||
|
||||
$qb->limitToClientId($clientId);
|
||||
$qb->limitToAccount('');
|
||||
|
||||
$qb->execute();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $clientId
|
||||
*
|
||||
* @return ClientApp
|
||||
* @throws ClientAppDoesNotExistException
|
||||
*/
|
||||
public function getByClientId(string $clientId): ClientApp {
|
||||
$qb = $this->getClientAppSelectSql();
|
||||
|
||||
$qb->limitToClientId($clientId);
|
||||
|
||||
return $this->getClientAppFromRequest($qb);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,156 @@
|
|||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
|
||||
/**
|
||||
* Nextcloud - Social Support
|
||||
*
|
||||
* This file is licensed under the Affero General Public License version 3 or
|
||||
* later. See the COPYING file.
|
||||
*
|
||||
* @author Maxence Lange <maxence@artificial-owl.com>
|
||||
* @copyright 2018, Maxence Lange <maxence@artificial-owl.com>
|
||||
* @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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
namespace OCA\Social\Db;
|
||||
|
||||
|
||||
use daita\MySmallPhpTools\Exceptions\RowNotFoundException;
|
||||
use daita\MySmallPhpTools\Traits\TArrayTools;
|
||||
use OCA\Social\Exceptions\ClientAppDoesNotExistException;
|
||||
use OCA\Social\Model\ActivityStream\ClientApp;
|
||||
|
||||
|
||||
/**
|
||||
* Class ClientAppRequestBuilder
|
||||
*
|
||||
* @package OCA\Social\Db
|
||||
*/
|
||||
class ClientAppRequestBuilder extends CoreRequestBuilder {
|
||||
|
||||
|
||||
use TArrayTools;
|
||||
|
||||
|
||||
/**
|
||||
* Base of the Sql Insert request
|
||||
*
|
||||
* @return SocialQueryBuilder
|
||||
*/
|
||||
protected function getClientAppInsertSql(): SocialQueryBuilder {
|
||||
$qb = $this->getQueryBuilder();
|
||||
$qb->insert(self::TABLE_CLIENT_APP);
|
||||
|
||||
return $qb;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Base of the Sql Update request
|
||||
*
|
||||
* @return SocialQueryBuilder
|
||||
*/
|
||||
protected function getClientAppUpdateSql(): SocialQueryBuilder {
|
||||
$qb = $this->getQueryBuilder();
|
||||
$qb->update(self::TABLE_CLIENT_APP);
|
||||
|
||||
return $qb;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Base of the Sql Select request for Shares
|
||||
*
|
||||
* @return SocialQueryBuilder
|
||||
*/
|
||||
protected function getClientAppSelectSql(): SocialQueryBuilder {
|
||||
$qb = $this->getQueryBuilder();
|
||||
|
||||
/** @noinspection PhpMethodParametersCountMismatchInspection */
|
||||
$qb->select(
|
||||
'ca.id', 'ca.name', 'ca.website', 'ca.redirect_uri', 'ca.client_id', 'ca.client_secret',
|
||||
'ca.creation'
|
||||
)
|
||||
->from(self::TABLE_CLIENT_APP, 'ca');
|
||||
|
||||
$this->defaultSelectAlias = 'ca';
|
||||
$qb->setDefaultSelectAlias('ca');
|
||||
|
||||
return $qb;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Base of the Sql Delete request
|
||||
*
|
||||
* @return SocialQueryBuilder
|
||||
*/
|
||||
protected function getClientAppDeleteSql(): SocialQueryBuilder {
|
||||
$qb = $this->getQueryBuilder();
|
||||
$qb->delete(self::TABLE_CLIENT_APP);
|
||||
|
||||
return $qb;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param SocialQueryBuilder $qb
|
||||
*
|
||||
* @return ClientApp
|
||||
* @throws ClientAppDoesNotExistException
|
||||
*/
|
||||
public function getClientAppFromRequest(SocialQueryBuilder $qb): ClientApp {
|
||||
/** @var ClientApp $result */
|
||||
try {
|
||||
$result = $qb->getRow([$this, 'parseClientAppSelectSql']);
|
||||
} catch (RowNotFoundException $e) {
|
||||
throw new ClientAppDoesNotExistException($e->getMessage());
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param SocialQueryBuilder $qb
|
||||
*
|
||||
* @return ClientApp[]
|
||||
*/
|
||||
public function getClientAppsFromRequest(SocialQueryBuilder $qb): array {
|
||||
/** @var ClientApp[] $result */
|
||||
$result = $qb->getRows([$this, 'parseClientAppSelectSql']);
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
*
|
||||
* @return ClientApp
|
||||
*/
|
||||
public function parseClientAppSelectSql($data): ClientApp {
|
||||
$item = new ClientApp();
|
||||
$item->importFromDatabase($data);
|
||||
|
||||
return $item;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -76,6 +76,9 @@ class CoreRequestBuilder {
|
|||
const TABLE_CACHE_ACTORS = 'social_3_cache_actor';
|
||||
const TABLE_CACHE_DOCUMENTS = 'social_3_cache_doc';
|
||||
|
||||
const TABLE_CLIENT_APP = 'social_3_client_app';
|
||||
|
||||
|
||||
/** @var array */
|
||||
private $tables = [
|
||||
self::TABLE_REQUEST_QUEUE,
|
||||
|
@ -89,9 +92,11 @@ class CoreRequestBuilder {
|
|||
self::TABLE_STREAM_QUEUE,
|
||||
self::TABLE_STREAM_DEST,
|
||||
self::TABLE_STREAM_TAGS,
|
||||
self::TABLE_STREAM_ACTIONS
|
||||
self::TABLE_STREAM_ACTIONS,
|
||||
self::TABLE_CLIENT_APP
|
||||
];
|
||||
|
||||
|
||||
/** @var ILogger */
|
||||
protected $logger;
|
||||
|
||||
|
|
|
@ -91,6 +91,16 @@ class SocialLimitsQueryBuilder extends SocialCrossQueryBuilder {
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* Limit the request to clientId
|
||||
*
|
||||
* @param string $clientId
|
||||
*/
|
||||
public function limitToClientId(string $clientId) {
|
||||
$this->limitToDBField('client_id', $clientId);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $type
|
||||
*/
|
||||
|
|
|
@ -39,6 +39,25 @@ namespace OCA\Social\Db;
|
|||
class SocialQueryBuilder extends SocialFiltersQueryBuilder {
|
||||
|
||||
|
||||
/** @var int */
|
||||
private $format = 1;
|
||||
|
||||
|
||||
/**
|
||||
* @param int $format
|
||||
*/
|
||||
public function setFormat(int $format) {
|
||||
$this->format = $format;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getFormat(): int {
|
||||
return $this->format;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $id
|
||||
* @param string $field
|
||||
|
|
|
@ -364,12 +364,13 @@ class StreamRequest extends StreamRequestBuilder {
|
|||
*
|
||||
* @param int $since
|
||||
* @param int $limit
|
||||
* @param int $format
|
||||
*
|
||||
* @return Stream[]
|
||||
* @throws DateTimeException
|
||||
*/
|
||||
public function getTimelineHome(int $since = 0, int $limit = 5): array {
|
||||
$qb = $this->getStreamSelectSql();
|
||||
public function getTimelineHome(int $since = 0, int $limit = 5, int $format = Stream::FORMAT_ACTIVITYPUB): array {
|
||||
$qb = $this->getStreamSelectSql($format);
|
||||
$qb->setChunk(1);
|
||||
|
||||
$qb->filterType(SocialAppNotification::TYPE);
|
||||
|
|
|
@ -84,10 +84,13 @@ class StreamRequestBuilder extends CoreRequestBuilder {
|
|||
/**
|
||||
* Base of the Sql Select request for Shares
|
||||
*
|
||||
* @param int $format
|
||||
*
|
||||
* @return SocialQueryBuilder
|
||||
*/
|
||||
protected function getStreamSelectSql(): SocialQueryBuilder {
|
||||
protected function getStreamSelectSql(int $format = Stream::FORMAT_ACTIVITYPUB): SocialQueryBuilder {
|
||||
$qb = $this->getQueryBuilder();
|
||||
$qb->setFormat($format);
|
||||
|
||||
/** @noinspection PhpMethodParametersCountMismatchInspection */
|
||||
$qb->selectDistinct('s.id')
|
||||
|
@ -195,17 +198,19 @@ class StreamRequestBuilder extends CoreRequestBuilder {
|
|||
/**
|
||||
* @param array $data
|
||||
*
|
||||
* @param SocialQueryBuilder $qb
|
||||
*
|
||||
* @return Stream
|
||||
* @throws ItemUnknownException
|
||||
* @throws SocialAppConfigException
|
||||
*/
|
||||
public function parseStreamSelectSql(array $data): Stream {
|
||||
public function parseStreamSelectSql(array $data, SocialQueryBuilder $qb): Stream {
|
||||
$as = $this->get('type', $data, Stream::TYPE);
|
||||
|
||||
/** @var Stream $item */
|
||||
$item = AP::$activityPub->getItemFromType($as);
|
||||
$item->importFromDatabase($data);
|
||||
|
||||
$item->setExportFormat($qb->getFormat());
|
||||
$instances = json_decode($this->get('instances', $data, '[]'), true);
|
||||
if (is_array($instances)) {
|
||||
foreach ($instances as $instance) {
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
<?php
|
||||
|
||||
|
||||
/**
|
||||
* Nextcloud - Social Support
|
||||
*
|
||||
* This file is licensed under the Affero General Public License version 3 or
|
||||
* later. See the COPYING file.
|
||||
*
|
||||
* @author Maxence Lange <maxence@artificial-owl.com>
|
||||
* @copyright 2018, Maxence Lange <maxence@artificial-owl.com>
|
||||
* @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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
namespace OCA\Social\Exceptions;
|
||||
|
||||
|
||||
use Exception;
|
||||
|
||||
|
||||
class ClientAppDoesNotExistException extends Exception {
|
||||
|
||||
}
|
||||
|
|
@ -33,9 +33,11 @@ namespace OCA\Social\Interfaces\Object;
|
|||
|
||||
use OCA\Social\Db\CacheDocumentsRequest;
|
||||
use OCA\Social\Exceptions\CacheDocumentDoesNotExistException;
|
||||
use OCA\Social\Exceptions\InvalidOriginException;
|
||||
use OCA\Social\Exceptions\ItemNotFoundException;
|
||||
use OCA\Social\Interfaces\IActivityPubInterface;
|
||||
use OCA\Social\Model\ActivityPub\ACore;
|
||||
use OCA\Social\Model\ActivityPub\Actor\Person;
|
||||
use OCA\Social\Model\ActivityPub\Object\Document;
|
||||
use OCA\Social\Service\MiscService;
|
||||
|
||||
|
@ -67,8 +69,13 @@ class DocumentInterface implements IActivityPubInterface {
|
|||
/**
|
||||
* @param ACore $activity
|
||||
* @param ACore $item
|
||||
*
|
||||
* @throws InvalidOriginException
|
||||
*/
|
||||
public function activity(Acore $activity, ACore $item) {
|
||||
if ($activity->getType() === Person::TYPE) {
|
||||
$activity->checkOrigin($item->getId());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -76,6 +76,7 @@ class Version0003Date20200611000001 extends SimpleMigrationStep {
|
|||
$this->createActors($schema);
|
||||
$this->createCacheActors($schema);
|
||||
$this->createCacheDocuments($schema);
|
||||
$this->createClientOauth($schema);
|
||||
$this->createFollows($schema);
|
||||
$this->createHashtags($schema);
|
||||
$this->createRequestQueue($schema);
|
||||
|
@ -85,6 +86,7 @@ class Version0003Date20200611000001 extends SimpleMigrationStep {
|
|||
$this->createStreamQueue($schema);
|
||||
$this->createStreamTags($schema);
|
||||
|
||||
|
||||
return $schema;
|
||||
}
|
||||
|
||||
|
@ -902,6 +904,75 @@ class Version0003Date20200611000001 extends SimpleMigrationStep {
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param ISchemaWrapper $schema
|
||||
*/
|
||||
private function createClientOauth(ISchemaWrapper $schema) {
|
||||
if ($schema->hasTable('social_3_client_app')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$table = $schema->createTable('social_3_client_app');
|
||||
$table->addColumn(
|
||||
'id', 'integer',
|
||||
[
|
||||
'autoincrement' => true,
|
||||
'notnull' => true,
|
||||
'length' => 7,
|
||||
'unsigned' => true,
|
||||
]
|
||||
);
|
||||
$table->addColumn(
|
||||
'name', 'string',
|
||||
[
|
||||
'notnull' => false,
|
||||
'length' => 127,
|
||||
'default' => ''
|
||||
]
|
||||
);
|
||||
$table->addColumn(
|
||||
'website', 'string',
|
||||
[
|
||||
'notnull' => false,
|
||||
'length' => 255,
|
||||
'default' => ''
|
||||
]
|
||||
);
|
||||
$table->addColumn(
|
||||
'redirect_uri', 'string',
|
||||
[
|
||||
'notnull' => false,
|
||||
'length' => 255,
|
||||
'default' => ''
|
||||
]
|
||||
);
|
||||
$table->addColumn(
|
||||
'client_id', 'string',
|
||||
[
|
||||
'notnull' => false,
|
||||
'length' => 63,
|
||||
'default' => ''
|
||||
]
|
||||
);
|
||||
$table->addColumn(
|
||||
'client_secret', 'string',
|
||||
[
|
||||
'notnull' => false,
|
||||
'length' => 63,
|
||||
'default' => ''
|
||||
]
|
||||
);
|
||||
$table->addColumn(
|
||||
'creation', 'datetime',
|
||||
[
|
||||
'notnull' => false,
|
||||
]
|
||||
);
|
||||
|
||||
$table->setPrimaryKey(['id']);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param ISchemaWrapper $schema
|
||||
*/
|
||||
|
|
|
@ -45,7 +45,7 @@ use OCP\Migration\SimpleMigrationStep;
|
|||
*
|
||||
* @package OCA\Social\Migration
|
||||
*/
|
||||
class Version0003Date20200730213528 extends SimpleMigrationStep {
|
||||
class Version0003Date20200823023911 extends SimpleMigrationStep {
|
||||
|
||||
|
||||
/** @var IDBConnection */
|
||||
|
@ -73,6 +73,8 @@ class Version0003Date20200730213528 extends SimpleMigrationStep {
|
|||
/** @var ISchemaWrapper $schema */
|
||||
$schema = $schemaClosure();
|
||||
|
||||
$this->createClientOauth($schema);
|
||||
|
||||
$this->addChunkToTable($schema, 'social_3_stream', '');
|
||||
$this->addChunkToTable($schema, 'social_3_stream_act', '_act');
|
||||
$this->addChunkToTable($schema, 'social_3_stream_dest', '_dest');
|
||||
|
@ -81,9 +83,79 @@ class Version0003Date20200730213528 extends SimpleMigrationStep {
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param ISchemaWrapper $schema
|
||||
*/
|
||||
private function createClientOauth(ISchemaWrapper $schema) {
|
||||
if ($schema->hasTable('social_3_client_app')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$table = $schema->createTable('social_3_client_app');
|
||||
$table->addColumn(
|
||||
'id', 'integer',
|
||||
[
|
||||
'autoincrement' => true,
|
||||
'notnull' => true,
|
||||
'length' => 7,
|
||||
'unsigned' => true,
|
||||
]
|
||||
);
|
||||
$table->addColumn(
|
||||
'name', 'string',
|
||||
[
|
||||
'notnull' => false,
|
||||
'length' => 127,
|
||||
'default' => ''
|
||||
]
|
||||
);
|
||||
$table->addColumn(
|
||||
'website', 'string',
|
||||
[
|
||||
'notnull' => false,
|
||||
'length' => 255,
|
||||
'default' => ''
|
||||
]
|
||||
);
|
||||
$table->addColumn(
|
||||
'redirect_uri', 'string',
|
||||
[
|
||||
'notnull' => false,
|
||||
'length' => 255,
|
||||
'default' => ''
|
||||
]
|
||||
);
|
||||
$table->addColumn(
|
||||
'client_id', 'string',
|
||||
[
|
||||
'notnull' => false,
|
||||
'length' => 63,
|
||||
'default' => ''
|
||||
]
|
||||
);
|
||||
$table->addColumn(
|
||||
'client_secret', 'string',
|
||||
[
|
||||
'notnull' => false,
|
||||
'length' => 63,
|
||||
'default' => ''
|
||||
]
|
||||
);
|
||||
$table->addColumn(
|
||||
'creation', 'datetime',
|
||||
[
|
||||
'notnull' => false,
|
||||
]
|
||||
);
|
||||
|
||||
$table->setPrimaryKey(['id']);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param ISchemaWrapper $schema
|
||||
* @param string $tableName
|
||||
* @param string $indexName
|
||||
*
|
||||
* @throws SchemaException
|
||||
*/
|
|
@ -63,6 +63,9 @@ class ACore extends Item implements JsonSerializable {
|
|||
const AS_STRING = 7;
|
||||
const AS_TAGS = 10;
|
||||
|
||||
const FORMAT_ACTIVITYPUB = 1;
|
||||
const FORMAT_LOCAL = 2;
|
||||
|
||||
|
||||
/** @var null Item */
|
||||
private $parent = null;
|
||||
|
@ -85,6 +88,9 @@ class ACore extends Item implements JsonSerializable {
|
|||
/** @var LinkedDataSignature */
|
||||
private $signature = null;
|
||||
|
||||
/** @var int */
|
||||
private $format = self::FORMAT_ACTIVITYPUB;
|
||||
|
||||
|
||||
/**
|
||||
* Core constructor.
|
||||
|
@ -647,11 +653,41 @@ class ACore extends Item implements JsonSerializable {
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param int $format
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setExportFormat(int $format): self {
|
||||
$this->format = $format;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getExportFormat(): int {
|
||||
return $this->format;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function jsonSerialize(): array {
|
||||
if ($this->getExportFormat() === self::FORMAT_LOCAL) {
|
||||
return $this->exportAsLocal();
|
||||
}
|
||||
|
||||
return $this->exportAsActivityPub();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function exportAsActivityPub(): array {
|
||||
if ($this->gotSignature()) {
|
||||
$this->entries['signature'] = $this->getSignature();
|
||||
}
|
||||
|
@ -715,6 +751,104 @@ class ACore extends Item implements JsonSerializable {
|
|||
return $result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function exportAsLocal(): array {
|
||||
return [
|
||||
"id" => "104745311773345735",
|
||||
"created_at" => "2020-08-24T16=>29=>13.000Z",
|
||||
"in_reply_to_id" => null,
|
||||
"in_reply_to_account_id" => null,
|
||||
"sensitive" => false,
|
||||
"spoiler_text" => "",
|
||||
"visibility" => "unlisted",
|
||||
"language" => "de",
|
||||
// 'id' => $this->getId(),
|
||||
// 'uri' => $this->getId(),
|
||||
// 'url' => $this->getId(),
|
||||
'replies_count' => 0,
|
||||
'reblogs_count' => 0,
|
||||
'favourites_count' => 0,
|
||||
'favourited' => false,
|
||||
'reblogged' => false,
|
||||
'muted' => false,
|
||||
'bookmarked' => false,
|
||||
"content" => "\u003cp\u003e\"Mit den frisch freigegebenen Versionen 3.0 und 3.13 aktualisiert Nextcloud seine Desktop- und Android-Clients. Zentrale Neuerung ist die nun für den produktiven Einsatz einsatzbereite Ende-zu-Ende-Verschlüsselung.\" | iX Magazin @heiseonline \u003cbr\u003e\u003ca href=\"https://www.heise.de/news/Neue-Nextcloud-Clients-mit-Ende-zu-Ende-Verschluesselung-4873632.html\" rel=\"nofollow noopener noreferrer\" target=\"_blank\"\u003e\u003cspan class=\"invisible\"\u003ehttps://www.\u003c/span\u003e\u003cspan class=\"ellipsis\"\u003eheise.de/news/Neue-Nextcloud-C\u003c/span\u003e\u003cspan class=\"invisible\"\u003elients-mit-Ende-zu-Ende-Verschluesselung-4873632.html\u003c/span\u003e\u003c/a\u003e\u003c/p\u003e",
|
||||
"reblog" => null,
|
||||
"account" => [
|
||||
"id" => "126222",
|
||||
"username" => "nextcloud",
|
||||
"acct" => "nextcloud@mastodon.xyz",
|
||||
"display_name" => "Nextcloud 📱☁️💻",
|
||||
"locked" => false,
|
||||
"bot" => false,
|
||||
"discoverable" => false,
|
||||
"group" => false,
|
||||
"created_at" => "2017-05-02T09=>56=>41.951Z",
|
||||
"note" => "\u003cp\u003eA safe home for all your data, community-driven \u0026amp; open source!\u003cbr\u003e\u003ca href=\"https=>//nextcloud.com\" rel=\"nofollow noopener noreferrer\" target=\"_blank\"\u003e\u003cspan class=\"invisible\"\u003ehttps=>//\u003c/span\u003e\u003cspan class=\"\"\u003enextcloud.com\u003c/span\u003e\u003cspan class=\"invisible\"\u003e\u003c/span\u003e\u003c/a\u003e\u003cbr\u003eJoin us at \u003ca href=\"https=>//help.nextcloud.com\" rel=\"nofollow noopener noreferrer\" target=\"_blank\"\u003e\u003cspan class=\"invisible\"\u003ehttps=>//\u003c/span\u003e\u003cspan class=\"\"\u003ehelp.nextcloud.com\u003c/span\u003e\u003cspan class=\"invisible\"\u003e\u003c/span\u003e\u003c/a\u003e and \u003ca href=\"https=>//github.com/nextcloud\" rel=\"nofollow noopener noreferrer\" target=\"_blank\"\u003e\u003cspan class=\"invisible\"\u003ehttps=>//\u003c/span\u003e\u003cspan class=\"\"\u003egithub.com/nextcloud\u003c/span\u003e\u003cspan class=\"invisible\"\u003e\u003c/span\u003e\u003c/a\u003e 😊\u003c/p\u003e",
|
||||
"url" => "https=>//mastodon.xyz/@nextcloud",
|
||||
"avatar" => "https=>//files.mastodon.social/accounts/avatars/000/126/222/original/50785214e44d10cc.jpeg",
|
||||
"avatar_static" => "https=>//files.mastodon.social/accounts/avatars/000/126/222/original/50785214e44d10cc.jpeg",
|
||||
"header" => "https=>//files.mastodon.social/accounts/headers/000/126/222/original/6d7b41fdd92cfd6f.jpeg",
|
||||
"header_static" => "https=>//files.mastodon.social/accounts/headers/000/126/222/original/6d7b41fdd92cfd6f.jpeg",
|
||||
"followers_count" => 9451,
|
||||
"following_count" => 132,
|
||||
"statuses_count" => 3020,
|
||||
"last_status_at" => "2020-08-24",
|
||||
"emojis" => []
|
||||
]
|
||||
// "fields": [
|
||||
// {
|
||||
// "name": "💻 Website",
|
||||
// "value": "\u003ca href=\"https://nextcloud.com\" rel=\"nofollow noopener noreferrer\" target=\"_blank\"\u003e\u003cspan class=\"invisible\"\u003ehttps://\u003c/span\u003e\u003cspan class=\"\"\u003enextcloud.com\u003c/span\u003e\u003cspan class=\"invisible\"\u003e\u003c/span\u003e\u003c/a\u003e",
|
||||
// "verified_at": null
|
||||
// },
|
||||
// {
|
||||
// "name": "😍 Contribute",
|
||||
// "value": "\u003ca href=\"https://nextcloud.com/contribute\" rel=\"nofollow noopener noreferrer\" target=\"_blank\"\u003e\u003cspan class=\"invisible\"\u003ehttps://\u003c/span\u003e\u003cspan class=\"\"\u003enextcloud.com/contribute\u003c/span\u003e\u003cspan class=\"invisible\"\u003e\u003c/span\u003e\u003c/a\u003e",
|
||||
// "verified_at": null
|
||||
// },
|
||||
// {
|
||||
// "name": "🌈 Include initiative",
|
||||
// "value": "\u003ca href=\"https://nextcloud.com/include\" rel=\"nofollow noopener noreferrer\" target=\"_blank\"\u003e\u003cspan class=\"invisible\"\u003ehttps://\u003c/span\u003e\u003cspan class=\"\"\u003enextcloud.com/include\u003c/span\u003e\u003cspan class=\"invisible\"\u003e\u003c/span\u003e\u003c/a\u003e",
|
||||
// "verified_at": null
|
||||
// },
|
||||
// {
|
||||
// "name": "💬 Forum",
|
||||
// "value": "\u003ca href=\"https://help.nextcloud.com\" rel=\"nofollow noopener noreferrer\" target=\"_blank\"\u003e\u003cspan class=\"invisible\"\u003ehttps://\u003c/span\u003e\u003cspan class=\"\"\u003ehelp.nextcloud.com\u003c/span\u003e\u003cspan class=\"invisible\"\u003e\u003c/span\u003e\u003c/a\u003e",
|
||||
// "verified_at": null
|
||||
// }
|
||||
// ]
|
||||
// }
|
||||
|
||||
];
|
||||
|
||||
// "media_attachments": [],
|
||||
// "mentions": [],
|
||||
// "tags": [],
|
||||
// "emojis": [],
|
||||
// "card": {
|
||||
// "url": "https://www.heise.de/news/Neue-Nextcloud-Clients-mit-Ende-zu-Ende-Verschluesselung-4873632.html",
|
||||
// "title": "Neue Nextcloud-Clients mit Ende-zu-Ende-Verschlüsselung",
|
||||
// "description": "Nextcloud aktualisiert seine Desktop- und Android-Clients. Zentrale Neuerung ist die Ende-zu-Ende-Verschlüsselung, die aber nicht für alle Dateien gedacht ist.",
|
||||
// "type": "link",
|
||||
// "author_name": "",
|
||||
// "author_url": "",
|
||||
// "provider_name": "",
|
||||
// "provider_url": "",
|
||||
// "html": "",
|
||||
// "width": 400,
|
||||
// "height": 225,
|
||||
// "image": "https://files.mastodon.social/cache/preview_cards/images/023/249/328/original/3710f7a1b54f0319.png",
|
||||
// "embed_url": "",
|
||||
// "blurhash": "UbNwWf_3%L00Rkayt6ofRkIVjYxut7fkoej["
|
||||
// },
|
||||
// "poll": null
|
||||
// },
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -396,9 +396,9 @@ class Stream extends ACore implements IQueryRow, JsonSerializable {
|
|||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function jsonSerialize(): array {
|
||||
public function exportAsActivityPub(): array {
|
||||
$result = array_merge(
|
||||
parent::jsonSerialize(),
|
||||
parent::exportAsActivityPub(),
|
||||
[
|
||||
'content' => $this->getContent(),
|
||||
'attributedTo' => ($this->getAttributedTo() !== '') ? $this->getUrlSocial()
|
||||
|
@ -409,6 +409,7 @@ class Stream extends ACore implements IQueryRow, JsonSerializable {
|
|||
]
|
||||
);
|
||||
|
||||
// TODO: use exportFormat
|
||||
if ($this->isCompleteDetails()) {
|
||||
$result = array_merge(
|
||||
$result,
|
||||
|
@ -430,5 +431,16 @@ class Stream extends ACore implements IQueryRow, JsonSerializable {
|
|||
return $result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function exportAsLocal(): array {
|
||||
$result = array_merge(
|
||||
parent::exportAsLocal(),
|
||||
[]);
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,257 @@
|
|||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
|
||||
/**
|
||||
* Nextcloud - Social Support
|
||||
*
|
||||
* This file is licensed under the Affero General Public License version 3 or
|
||||
* later. See the COPYING file.
|
||||
*
|
||||
* @author Maxence Lange <maxence@artificial-owl.com>
|
||||
* @copyright 2018, Maxence Lange <maxence@artificial-owl.com>
|
||||
* @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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
namespace OCA\Social\Model\ActivityStream;
|
||||
|
||||
|
||||
use daita\MySmallPhpTools\IQueryRow;
|
||||
use daita\MySmallPhpTools\Traits\TArrayTools;
|
||||
use JsonSerializable;
|
||||
|
||||
|
||||
/**
|
||||
* Class ClientApp
|
||||
*
|
||||
* @package OCA\Social\Model\ActivityStream
|
||||
*/
|
||||
class ClientApp implements IQueryRow, JsonSerializable {
|
||||
|
||||
|
||||
use TArrayTools;
|
||||
|
||||
|
||||
/** @var int */
|
||||
private $id = 0;
|
||||
|
||||
/** @var string */
|
||||
private $name = '';
|
||||
|
||||
/** @var string */
|
||||
private $website = '';
|
||||
|
||||
/** @var string */
|
||||
private $redirectUri = '';
|
||||
|
||||
/** @var array */
|
||||
private $scopes = [];
|
||||
|
||||
/** @var string */
|
||||
private $clientId = '';
|
||||
|
||||
/** @var string */
|
||||
private $clientSecret = '';
|
||||
|
||||
|
||||
/**
|
||||
* ClientApp constructor.
|
||||
*/
|
||||
public function __construct() {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getId(): int {
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $id
|
||||
*
|
||||
* @return ClientApp
|
||||
*/
|
||||
public function setId(int $id): self {
|
||||
$this->id = $id;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getName(): string {
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
*
|
||||
* @return ClientApp
|
||||
*/
|
||||
public function setName(string $name): self {
|
||||
$this->name = $name;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getWebsite(): string {
|
||||
return $this->website;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $website
|
||||
*
|
||||
* @return ClientApp
|
||||
*/
|
||||
public function setWebsite(string $website): self {
|
||||
$this->website = $website;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getRedirectUri(): string {
|
||||
return $this->redirectUri;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $redirectUri
|
||||
*
|
||||
* @return ClientApp
|
||||
*/
|
||||
public function setRedirectUri(string $redirectUri): self {
|
||||
$this->redirectUri = $redirectUri;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getScopes(): array {
|
||||
return $this->scopes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $scopes
|
||||
*
|
||||
* @return ClientApp
|
||||
*/
|
||||
public function setScopes(array $scopes): self {
|
||||
$this->scopes = $scopes;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $scopes
|
||||
*
|
||||
* @return ClientApp
|
||||
*/
|
||||
public function setScopesFromString(string $scopes): self {
|
||||
$this->scopes = explode(' ', $scopes);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getClientId(): string {
|
||||
return $this->clientId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $clientId
|
||||
*
|
||||
* @return ClientApp
|
||||
*/
|
||||
public function setClientId(string $clientId): self {
|
||||
$this->clientId = $clientId;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getClientSecret(): string {
|
||||
return $this->clientSecret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $clientSecret
|
||||
*
|
||||
* @return ClientApp
|
||||
*/
|
||||
public function setClientSecret(string $clientSecret): self {
|
||||
$this->clientSecret = $clientSecret;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
*
|
||||
* @return ClientApp
|
||||
*/
|
||||
public function importFromDatabase(array $data): self {
|
||||
$this->setId($this->getInt('id', $data));
|
||||
$this->setName($this->get('name', $data));
|
||||
$this->setWebsite($this->get('website', $data));
|
||||
$this->setRedirectUri($this->get('redirect_uri', $data));
|
||||
$this->setClientId($this->get('client_id', $data));
|
||||
$this->setClientSecret($this->get('client_secret', $data));
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function jsonSerialize(): array {
|
||||
$arr = [
|
||||
'id' => $this->getId(),
|
||||
'name' => $this->getName(),
|
||||
'website' => $this->getWebsite(),
|
||||
'redirect_uri' => $this->getRedirectUri(),
|
||||
'client_id' => $this->getClientId(),
|
||||
'client_secret' => $this->getClientSecret()
|
||||
];
|
||||
|
||||
return array_filter($arr);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,101 @@
|
|||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
|
||||
/**
|
||||
* Nextcloud - Social Support
|
||||
*
|
||||
* This file is licensed under the Affero General Public License version 3 or
|
||||
* later. See the COPYING file.
|
||||
*
|
||||
* @author Maxence Lange <maxence@artificial-owl.com>
|
||||
* @copyright 2018, Maxence Lange <maxence@artificial-owl.com>
|
||||
* @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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace OCA\Social\Service;
|
||||
|
||||
|
||||
use daita\MySmallPhpTools\Traits\TStringTools;
|
||||
use OCA\Social\Db\ClientAppRequest;
|
||||
use OCA\Social\Exceptions\ClientAppDoesNotExistException;
|
||||
use OCA\Social\Model\ActivityPub\Actor\Person;
|
||||
use OCA\Social\Model\ActivityStream\ClientApp;
|
||||
|
||||
|
||||
/**
|
||||
* Class ClientService
|
||||
*
|
||||
* @package OCA\Social\Service
|
||||
*/
|
||||
class ClientService {
|
||||
|
||||
|
||||
use TStringTools;
|
||||
|
||||
|
||||
/** @var ClientAppRequest */
|
||||
private $clientAppRequest;
|
||||
|
||||
/** @var MiscService */
|
||||
private $miscService;
|
||||
|
||||
|
||||
/**
|
||||
* BoostService constructor.
|
||||
*
|
||||
* @param ClientAppRequest $clientAppRequest
|
||||
* @param MiscService $miscService
|
||||
*/
|
||||
public function __construct(ClientAppRequest $clientAppRequest, MiscService $miscService) {
|
||||
$this->clientAppRequest = $clientAppRequest;
|
||||
$this->miscService = $miscService;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param ClientApp $clientApp
|
||||
*/
|
||||
public function createClient(ClientApp $clientApp): void {
|
||||
$clientApp->setClientId($this->token(40));
|
||||
$clientApp->setClientSecret($this->token(40));
|
||||
|
||||
$this->clientAppRequest->save($clientApp);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $clientId
|
||||
* @param Person $account
|
||||
*/
|
||||
public function assignAccount(string $clientId, Person $account) {
|
||||
$this->clientAppRequest->assignAccount($clientId, $account->getPreferredUsername());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $clientId
|
||||
*
|
||||
* @return ClientApp
|
||||
* @throws ClientAppDoesNotExistException
|
||||
*/
|
||||
public function getByClientId(string $clientId): ClientApp {
|
||||
return $this->clientAppRequest->getByClientId($clientId);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -138,6 +138,8 @@ class PostService {
|
|||
$token = $this->activityService->createActivity($actor, $note, $activity);
|
||||
$this->accountService->cacheLocalActorDetailCount($actor);
|
||||
|
||||
$this->miscService->log('Activity: ' . json_encode($activity));
|
||||
|
||||
return $activity;
|
||||
}
|
||||
|
||||
|
|
|
@ -285,6 +285,10 @@ class StreamService {
|
|||
'name' => '#' . $hashtag
|
||||
]
|
||||
);
|
||||
\OC::$server->getLogger()
|
||||
->log(
|
||||
3, '___' . $this->configService->getSocialUrl() . 'tag/' . strtolower($hashtag)
|
||||
);
|
||||
} catch (SocialAppConfigException $e) {
|
||||
}
|
||||
}
|
||||
|
@ -405,12 +409,13 @@ class StreamService {
|
|||
/**
|
||||
* @param int $since
|
||||
* @param int $limit
|
||||
* @param int $format
|
||||
*
|
||||
* @return Note[]
|
||||
* @throws Exception
|
||||
* @throws DateTimeException
|
||||
*/
|
||||
public function getStreamHome(int $since = 0, int $limit = 5): array {
|
||||
return $this->streamRequest->getTimelineHome($since, $limit);
|
||||
public function getStreamHome(int $since = 0, int $limit = 5, int $format = Stream::FORMAT_ACTIVITYPUB): array {
|
||||
return $this->streamRequest->getTimelineHome($since, $limit, $format);
|
||||
}
|
||||
|
||||
|
||||
|
|
Ładowanie…
Reference in New Issue