diff --git a/appinfo/database.xml b/appinfo/database.xml
index d942c063..54153c46 100644
--- a/appinfo/database.xml
+++ b/appinfo/database.xml
@@ -345,6 +345,13 @@
true
+
+ icon_id
+ text
+ 127
+ true
+
+
summary
text
@@ -374,5 +381,85 @@
+
+ *dbprefix*social_cache_documents
+
+
+
+ id
+ string
+ 127
+ true
+ true
+
+
+
+ type
+ text
+ 31
+ true
+
+
+
+ media_type
+ text
+ 63
+ true
+
+
+
+ mime_type
+ text
+ 63
+ true
+
+
+
+ url
+ text
+ 127
+ true
+
+
+
+ local_copy
+ text
+ 127
+ true
+
+
+
+ public
+ boolean
+ true
+
+
+
+ error
+ integer
+ 1
+ true
+
+
+
+ creation
+ timestamp
+
+
+
+ caching
+ timestamp
+
+
+
+ unique_url
+ true
+
+ url
+
+
+
+
+
diff --git a/appinfo/info.xml b/appinfo/info.xml
index 90e62061..1283707a 100644
--- a/appinfo/info.xml
+++ b/appinfo/info.xml
@@ -5,7 +5,7 @@
Social
🎉 Nextcloud becomes part of the federated social networks!
- 0.0.37
+ 0.0.43
agpl
Maxence Lange
Julius Härtl
@@ -26,7 +26,12 @@
+
+ OCA\Social\Cron\Cache
+
+
+ OCA\Social\Command\CacheRefresh
OCA\Social\Command\NoteCreate
diff --git a/appinfo/routes.php b/appinfo/routes.php
index 3703c956..6f86395e 100644
--- a/appinfo/routes.php
+++ b/appinfo/routes.php
@@ -20,8 +20,9 @@ return [
'name' => 'Navigation#account', 'url' => '/account/{path}', 'verb' => 'GET',
'requirements' => ['path' => '.+'], 'defaults' => ['path' => '']
],
- // ['name' => 'Navigation#public', 'url' => '/{username}', 'verb' => 'GET'],
-
+ ['name' => 'Navigation#public', 'url' => '/{username}', 'verb' => 'GET'],
+ ['name' => 'Navigation#documentGet', 'url' => '/document/get', 'verb' => 'GET'],
+ ['name' => 'Navigation#documentGetPublic', 'url' => '/document/public', 'verb' => 'GET'],
// ['name' => 'Account#create', 'url' => '/local/account/{username}', 'verb' => 'POST'],
['name' => 'Account#info', 'url' => '/local/account/{username}', 'verb' => 'GET'],
@@ -47,7 +48,9 @@ return [
['name' => 'Local#accountsSearch', 'url' => '/api/v1/accounts/search', 'verb' => 'GET'],
['name' => 'Local#accountFollow', 'url' => '/api/v1/account/follow', 'verb' => 'PUT'],
['name' => 'Local#accountUnfollow', 'url' => '/api/v1/account/follow', 'verb' => 'DELETE'],
+ ['name' => 'Local#accountInfo', 'url' => '/api/v1/account/info', 'verb' => 'GET'],
['name' => 'Local#actorInfo', 'url' => '/api/v1/actor/info', 'verb' => 'GET'],
+ ['name' => 'Local#documentsCache', 'url' => '/api/v1/documents/cache', 'verb' => 'POST'],
[
'name' => 'Config#setCloudAddress', 'url' => '/api/v1/config/cloudAddress',
diff --git a/lib/Command/CacheRefresh.php b/lib/Command/CacheRefresh.php
new file mode 100644
index 00000000..fae76806
--- /dev/null
+++ b/lib/Command/CacheRefresh.php
@@ -0,0 +1,117 @@
+
+ * @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\Command;
+
+
+use Exception;
+use OC\Core\Command\Base;
+use OCA\Social\Service\ActivityPub\DocumentService;
+use OCA\Social\Service\ActivityPub\PersonService;
+use OCA\Social\Service\ActorService;
+use OCA\Social\Service\ConfigService;
+use OCA\Social\Service\MiscService;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Output\OutputInterface;
+
+
+class CacheRefresh extends Base {
+
+
+ /** @var ActorService */
+ private $actorService;
+
+ /** @var PersonService */
+ private $personService;
+
+ /** @var DocumentService */
+ private $documentService;
+
+ /** @var ConfigService */
+ private $configService;
+
+ /** @var MiscService */
+ private $miscService;
+
+
+ /**
+ * CacheUpdate constructor.
+ *
+ * @param ActorService $actorService
+ * @param PersonService $personService
+ * @param DocumentService $documentService
+ * @param ConfigService $configService
+ * @param MiscService $miscService
+ */
+ public function __construct(
+ ActorService $actorService, PersonService $personService, DocumentService $documentService,
+ ConfigService $configService, MiscService $miscService
+ ) {
+ parent::__construct();
+
+ $this->actorService = $actorService;
+ $this->personService = $personService;
+ $this->documentService = $documentService;
+ $this->configService = $configService;
+ $this->miscService = $miscService;
+ }
+
+
+ /**
+ *
+ */
+ protected function configure() {
+ parent::configure();
+ $this->setName('social:cache:refresh')
+ ->setDescription('Update the cache');
+ }
+
+
+ /**
+ * @param InputInterface $input
+ * @param OutputInterface $output
+ *
+ * @throws Exception
+ */
+ protected function execute(InputInterface $input, OutputInterface $output) {
+
+ $result = $this->actorService->manageCacheLocalActors();
+ $output->writeLn($result . ' local accounts regenerated');
+
+ $result = $this->personService->manageCacheRemoteActors();
+ $output->writeLn($result . ' remote accounts updated');
+
+ $result = $this->documentService->manageCacheDocuments();
+ $output->writeLn($result . ' documents cached');
+ }
+
+
+}
+
diff --git a/lib/Controller/LocalController.php b/lib/Controller/LocalController.php
index c824aeaa..1217d523 100644
--- a/lib/Controller/LocalController.php
+++ b/lib/Controller/LocalController.php
@@ -37,6 +37,7 @@ use OCA\Social\AppInfo\Application;
use OCA\Social\Exceptions\InvalidResourceException;
use OCA\Social\Model\ActivityPub\ACore;
use OCA\Social\Model\Post;
+use OCA\Social\Service\ActivityPub\DocumentService;
use OCA\Social\Service\ActivityPub\FollowService;
use OCA\Social\Service\ActivityPub\NoteService;
use OCA\Social\Service\ActivityPub\PersonService;
@@ -78,6 +79,9 @@ class LocalController extends Controller {
/** @var NoteService */
private $noteService;
+ /** @var DocumentService */
+ private $documentService;
+
/** @var MiscService */
private $miscService;
@@ -92,12 +96,14 @@ class LocalController extends Controller {
* @param ActorService $actorService
* @param PostService $postService
* @param NoteService $noteService
+ * @param DocumentService $documentService
* @param MiscService $miscService
*/
public function __construct(
IRequest $request, $userId, PersonService $personService,
FollowService $followService, ActorService $actorService,
PostService $postService, NoteService $noteService,
+ DocumentService $documentService,
MiscService $miscService
) {
parent::__construct(Application::APP_NAME, $request);
@@ -109,6 +115,7 @@ class LocalController extends Controller {
$this->followService = $followService;
$this->postService = $postService;
$this->noteService = $noteService;
+ $this->documentService = $documentService;
$this->miscService = $miscService;
}
@@ -179,6 +186,9 @@ class LocalController extends Controller {
* @NoAdminRequired
* @NoSubAdminRequired
*
+ * @param int $since
+ * @param int $limit
+ *
* @return DataResponse
*/
public function streamHome(int $since = 0, int $limit = 5): DataResponse {
@@ -343,6 +353,29 @@ class LocalController extends Controller {
}
+ /**
+ *
+ * // TODO: Delete the NoCSRF check
+ *
+ * @NoCSRFRequired
+ * @NoAdminRequired
+ * @NoSubAdminRequired
+ *
+ * @param string $account
+ *
+ * @return DataResponse
+ */
+ public function accountInfo(string $account): DataResponse {
+ try {
+ $actor = $this->personService->getFromAccount($account);
+
+ return $this->success(['account' => $actor]);
+ } catch (Exception $e) {
+ return $this->fail($e);
+ }
+ }
+
+
/**
*
* // TODO: Delete the NoCSRF check
@@ -365,4 +398,35 @@ class LocalController extends Controller {
}
}
+
+ /**
+ * // TODO: Delete the NoCSRF check
+ *
+ * @NoCSRFRequired
+ * @NoAdminRequired
+ * @NoSubAdminRequired
+ *
+ * @param array $documents
+ *
+ * @return DataResponse
+ */
+ public function documentsCache(array $documents): DataResponse {
+ try {
+ $cached = [];
+ foreach ($documents as $id) {
+ try {
+
+ $document = $this->documentService->cacheRemoteDocument($id);
+ $cached[] = $document;
+ } catch (Exception $e) {
+ }
+ }
+
+ return $this->success($cached);
+ } catch (Exception $e) {
+ return $this->fail($e);
+ }
+ }
+
}
+
diff --git a/lib/Controller/NavigationController.php b/lib/Controller/NavigationController.php
index 54c7e184..864b9eb8 100644
--- a/lib/Controller/NavigationController.php
+++ b/lib/Controller/NavigationController.php
@@ -32,16 +32,22 @@ namespace OCA\Social\Controller;
use daita\MySmallPhpTools\Traits\TArrayTools;
use daita\MySmallPhpTools\Traits\Nextcloud\TNCDataResponse;
+use Exception;
+use OC\Files\Node\File;
+use OC\Files\SimpleFS\SimpleFile;
use OC\User\NoUserException;
use OCA\Social\AppInfo\Application;
use OCA\Social\Exceptions\AccountAlreadyExistsException;
use OCA\Social\Exceptions\SocialAppConfigException;
+use OCA\Social\Service\ActivityPub\DocumentService;
use OCA\Social\Service\ActorService;
use OCA\Social\Service\ConfigService;
use OCA\Social\Service\MiscService;
use OCP\AppFramework\Controller;
use OCP\AppFramework\Http\DataResponse;
+use OCP\AppFramework\Http\FileDisplayResponse;
use OCP\AppFramework\Http\RedirectResponse;
+use OCP\AppFramework\Http\Response;
use OCP\AppFramework\Http\Template\PublicTemplateResponse;
use OCP\AppFramework\Http\TemplateResponse;
use OCP\IConfig;
@@ -68,6 +74,8 @@ class NavigationController extends Controller {
/** @var ActorService */
private $actorService;
+ private $documentService;
+
/** @var ConfigService */
private $configService;
@@ -85,14 +93,15 @@ class NavigationController extends Controller {
* @param IConfig $config
* @param IURLGenerator $urlGenerator
* @param ActorService $actorService
+ * @param DocumentService $documentService
* @param ConfigService $configService
* @param MiscService $miscService
* @param IL10N $l10n
*/
public function __construct(
IRequest $request, $userId, IConfig $config, IURLGenerator $urlGenerator,
- ActorService $actorService, ConfigService $configService, MiscService $miscService,
- IL10N $l10n
+ ActorService $actorService, DocumentService $documentService, ConfigService $configService,
+ MiscService $miscService, IL10N $l10n
) {
parent::__construct(Application::APP_NAME, $request);
@@ -101,6 +110,7 @@ class NavigationController extends Controller {
$this->urlGenerator = $urlGenerator;
$this->actorService = $actorService;
+ $this->documentService = $documentService;
$this->configService = $configService;
$this->miscService = $miscService;
$this->l10n = $l10n;
@@ -130,13 +140,18 @@ class NavigationController extends Controller {
$data['serverData']['cloudAddress'] = $this->configService->getCloudAddress();
} catch (SocialAppConfigException $e) {
$data['serverData']['setup'] = true;
- $data['serverData']['isAdmin'] = \OC::$server->getGroupManager()->isAdmin($this->userId);
+ $data['serverData']['isAdmin'] = \OC::$server->getGroupManager()
+ ->isAdmin($this->userId);
if ($data['serverData']['isAdmin']) {
$cloudAddress = $this->request->getParam('cloudAddress');
if ($cloudAddress !== null) {
$this->configService->setCloudAddress($cloudAddress);
} else {
- $data['serverData']['cliUrl'] = $this->config->getSystemValue('overwrite.cli.url', \OC::$server->getURLGenerator()->getBaseUrl());
+ $data['serverData']['cliUrl'] = $this->config->getSystemValue(
+ 'overwrite.cli.url', \OC::$server->getURLGenerator()
+ ->getBaseUrl()
+ );
+
return new TemplateResponse(Application::APP_NAME, 'main', $data);
}
}
@@ -153,8 +168,6 @@ class NavigationController extends Controller {
}
-
-
/**
* Display the navigation page of the Social app.
*
@@ -237,4 +250,54 @@ class NavigationController extends Controller {
return $page;
}
+
+ /**
+ *
+ * // TODO: Delete the NoCSRF check
+ *
+ * @NoCSRFRequired
+ * @NoAdminRequired
+ * @NoSubAdminRequired
+ *
+ * @param string $id
+ *
+ * @return Response
+ */
+ public function documentGet(string $id): Response {
+
+ try {
+ $file = $this->documentService->getFromCache($id);
+
+ return new FileDisplayResponse($file);
+ } catch (Exception $e) {
+ return $this->fail($e);
+ }
+ }
+
+
+ /**
+ *
+ * // TODO: Delete the NoCSRF check
+ *
+ * @PublicPage
+ * @NoCSRFRequired
+ * @NoAdminRequired
+ * @NoSubAdminRequired
+ *
+ * @param string $id
+ *
+ * @return Response
+ */
+ public function documentGetPublic(string $id): Response {
+
+ try {
+ $file = $this->documentService->getFromCache($id, true);
+
+ return new FileDisplayResponse($file);
+ } catch (Exception $e) {
+ return $this->fail($e);
+ }
+ }
+
}
+
diff --git a/lib/Cron/Cache.php b/lib/Cron/Cache.php
new file mode 100644
index 00000000..df9b741a
--- /dev/null
+++ b/lib/Cron/Cache.php
@@ -0,0 +1,114 @@
+
+ * @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\Cron;
+
+
+use Exception;
+use OC\BackgroundJob\TimedJob;
+use OCA\Social\AppInfo\Application;
+use OCA\Social\Service\ActivityPub\DocumentService;
+use OCA\Social\Service\ActivityPub\PersonService;
+use OCA\Social\Service\ActorService;
+use OCA\Social\Service\ConfigService;
+use OCA\Social\Service\MiscService;
+use OCP\AppFramework\QueryException;
+
+
+/**
+ * Class Cache
+ *
+ * @package OCA\Social\Cron
+ */
+class Cache extends TimedJob {
+
+
+ /** @var ActorService */
+ private $actorService;
+
+ /** @var PersonService */
+ private $personService;
+
+ /** @var DocumentService */
+ private $documentService;
+
+ /** @var ConfigService */
+ private $configService;
+
+ /** @var MiscService */
+ private $miscService;
+
+
+ /**
+ * Cache constructor.
+ */
+ public function __construct() {
+ $this->setInterval(12 * 60); // 12 minutes
+ }
+
+
+ /**
+ * @param mixed $argument
+ *
+ * @throws QueryException
+ */
+ protected function run($argument) {
+ $app = new Application();
+ $c = $app->getContainer();
+
+ $this->actorService = $c->query(ActorService::class);
+ $this->personService = $c->query(PersonService::class);
+ $this->documentService = $c->query(DocumentService::class);
+ $this->configService = $c->query(ConfigService::class);
+ $this->miscService = $c->query(MiscService::class);
+
+ $this->manageCache();
+ }
+
+
+ private function manageCache() {
+ try {
+ $this->actorService->manageCacheLocalActors();
+ } catch (Exception $e) {
+ }
+
+ try {
+ $this->personService->manageCacheRemoteActors();
+ } catch (Exception $e) {
+ }
+
+ try {
+ $this->documentService->manageCacheDocuments();
+ } catch (Exception $e) {
+ }
+ }
+
+
+}
diff --git a/lib/Db/ActorsRequest.php b/lib/Db/ActorsRequest.php
index 208f9723..09b37e4b 100644
--- a/lib/Db/ActorsRequest.php
+++ b/lib/Db/ActorsRequest.php
@@ -64,7 +64,7 @@ class ActorsRequest extends ActorsRequestBuilder {
*/
public function create(Person $actor): string {
- $id = $this->configService->getUrlRoot() . '@' . $actor->getPreferredUsername();
+ $id = $this->configService->getUrlSocial() . '@' . $actor->getPreferredUsername();
try {
$qb = $this->getActorsInsertSql();
@@ -161,6 +161,24 @@ class ActorsRequest extends ActorsRequestBuilder {
}
+ /**
+ * @return Person[]
+ * @throws SocialAppConfigException
+ */
+ public function getAll(): array {
+ $qb = $this->getActorsSelectSql();
+
+ $accounts = [];
+ $cursor = $qb->execute();
+ while ($data = $cursor->fetch()) {
+ $accounts[] = $this->parseActorsSelectSql($data);
+ }
+ $cursor->closeCursor();
+
+ return $accounts;
+ }
+
+
/**
* @param string $search
*
diff --git a/lib/Db/ActorsRequestBuilder.php b/lib/Db/ActorsRequestBuilder.php
index 3d11b9ca..5cf283cb 100644
--- a/lib/Db/ActorsRequestBuilder.php
+++ b/lib/Db/ActorsRequestBuilder.php
@@ -109,10 +109,10 @@ class ActorsRequestBuilder extends CoreRequestBuilder {
* @throws SocialAppConfigException
*/
protected function parseActorsSelectSql($data): Person {
- $root = $this->configService->getUrlRoot();
+ $root = $this->configService->getUrlSocial();
$actor = new Person();
- $actor->import($data);
+ $actor->importFromDatabase($data);
$actor->setInbox($actor->getId() . '/inbox')
->setOutbox($actor->getId() . '/outbox')
->setFollowers($actor->getId() . '/followers')
@@ -122,7 +122,7 @@ class ActorsRequestBuilder extends CoreRequestBuilder {
->setAccount(
$actor->getPreferredUsername() . '@' . $this->configService->getCloudAddress(true)
);
- $actor->setUrlRoot($root)
+ $actor->setUrlSocial($root)
->setUrl($actor->getId());
return $actor;
diff --git a/lib/Db/CacheActorsRequest.php b/lib/Db/CacheActorsRequest.php
index fe722dcc..dd3d9489 100644
--- a/lib/Db/CacheActorsRequest.php
+++ b/lib/Db/CacheActorsRequest.php
@@ -30,15 +30,20 @@ declare(strict_types=1);
namespace OCA\Social\Db;
+use DateTime;
+use Exception;
use OCA\Social\Exceptions\CacheActorDoesNotExistException;
use OCA\Social\Model\ActivityPub\Person;
use OCA\Social\Service\ConfigService;
use OCA\Social\Service\MiscService;
+use OCP\DB\QueryBuilder\IQueryBuilder;
use OCP\IDBConnection;
class CacheActorsRequest extends CacheActorsRequestBuilder {
+ const CACHE_TTL = 60 * 24; // 1d
+
/**
* CacheActorsRequest constructor.
*
@@ -78,7 +83,17 @@ class CacheActorsRequest extends CacheActorsRequestBuilder {
->setValue('name', $qb->createNamedParameter($actor->getName()))
->setValue('summary', $qb->createNamedParameter($actor->getSummary()))
->setValue('public_key', $qb->createNamedParameter($actor->getPublicKey()))
- ->setValue('source', $qb->createNamedParameter($actor->getSource()));
+ ->setValue('source', $qb->createNamedParameter($actor->getSource()))
+ ->setValue(
+ 'creation',
+ $qb->createNamedParameter(new DateTime('now'), IQueryBuilder::PARAM_DATE)
+ );
+
+ if ($actor->gotIcon()) {
+ $iconId = $actor->getIcon()
+ ->getId();
+ $qb->setValue('icon_id', $qb->createNamedParameter($iconId));
+ }
$qb->execute();
@@ -86,30 +101,6 @@ class CacheActorsRequest extends CacheActorsRequestBuilder {
}
-// /**
-// * get Cached value about an Actor, based on the account.
-// *
-// * @param string $account
-// *
-// * @return CacheActor
-// * @throws CacheActorDoesNotExistException
-// */
-// public function getFromAccount(string $account): CacheActor {
-// $qb = $this->getCacheActorsSelectSql();
-// $this->limitToAccount($qb, $account);
-//
-// $cursor = $qb->execute();
-// $data = $cursor->fetch();
-// $cursor->closeCursor();
-//
-// if ($data === false) {
-// throw new CacheActorDoesNotExistException();
-// }
-//
-// return $this->parseCacheActorsSelectSql($data);
-// }
-
-
/**
* get Cached version of an Actor, based on the UriId
*
@@ -121,6 +112,7 @@ class CacheActorsRequest extends CacheActorsRequestBuilder {
public function getFromId(string $id): Person {
$qb = $this->getCacheActorsSelectSql();
$this->limitToIdString($qb, $id);
+ $this->leftJoinCacheDocuments($qb, 'icon_id');
$cursor = $qb->execute();
$data = $cursor->fetch();
@@ -145,6 +137,7 @@ class CacheActorsRequest extends CacheActorsRequestBuilder {
public function getFromAccount(string $account): Person {
$qb = $this->getCacheActorsSelectSql();
$this->limitToAccount($qb, $account);
+ $this->leftJoinCacheDocuments($qb, 'icon_id');
$cursor = $qb->execute();
$data = $cursor->fetch();
@@ -166,6 +159,7 @@ class CacheActorsRequest extends CacheActorsRequestBuilder {
public function searchAccounts(string $search): array {
$qb = $this->getCacheActorsSelectSql();
$this->searchInAccount($qb, $search);
+ $this->leftJoinCacheDocuments($qb, 'icon_id');
$accounts = [];
$cursor = $qb->execute();
@@ -178,6 +172,26 @@ class CacheActorsRequest extends CacheActorsRequestBuilder {
}
+ /**
+ * @return Person[]
+ * @throws Exception
+ */
+ public function getRemoteActorsToUpdate(): array {
+ $qb = $this->getCacheActorsSelectSql();
+ $this->limitToLocal($qb, false);
+ $this->limitToCreation($qb, self::CACHE_TTL);
+
+ $update = [];
+ $cursor = $qb->execute();
+ while ($data = $cursor->fetch()) {
+ $update[] = $this->parseCacheActorsSelectSql($data);
+ }
+ $cursor->closeCursor();
+
+ return $update;
+ }
+
+
/**
* delete cached version of an Actor, based on the UriId
*
diff --git a/lib/Db/CacheActorsRequestBuilder.php b/lib/Db/CacheActorsRequestBuilder.php
index 7f91e976..3d6847d1 100644
--- a/lib/Db/CacheActorsRequestBuilder.php
+++ b/lib/Db/CacheActorsRequestBuilder.php
@@ -31,7 +31,7 @@ namespace OCA\Social\Db;
use daita\MySmallPhpTools\Traits\TArrayTools;
-use OCA\Social\Model\ActivityPub\Cache\CacheActor;
+use OCA\Social\Exceptions\InvalidResourceException;
use OCA\Social\Model\ActivityPub\Person;
use OCP\DB\QueryBuilder\IQueryBuilder;
@@ -110,7 +110,14 @@ class CacheActorsRequestBuilder extends CoreRequestBuilder {
*/
protected function parseCacheActorsSelectSql(array $data): Person {
$actor = new Person();
- $actor->import($data);
+ $actor->importFromDatabase($data);
+
+ try {
+ $icon = $this->parseCacheDocumentsLeftJoin($data);
+ $icon->setParent($actor);
+ $actor->setIcon($icon);
+ } catch (InvalidResourceException $e) {
+ }
return $actor;
}
diff --git a/lib/Db/CacheDocumentsRequest.php b/lib/Db/CacheDocumentsRequest.php
new file mode 100644
index 00000000..6c7f7b68
--- /dev/null
+++ b/lib/Db/CacheDocumentsRequest.php
@@ -0,0 +1,165 @@
+
+ * @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\Db;
+
+
+use DateTime;
+use Exception;
+use OCA\Social\Exceptions\CacheDocumentDoesNotExistException;
+use OCA\Social\Model\ActivityPub\Document;
+use OCP\DB\QueryBuilder\IQueryBuilder;
+
+class CacheDocumentsRequest extends CacheDocumentsRequestBuilder {
+
+
+ const CACHE_TTL = 15; // 15 min
+
+
+ /**
+ * insert cache about an Actor in database.
+ *
+ * @param Document $document
+ */
+ public function save(Document $document) {
+ $qb = $this->getCacheDocumentsInsertSql();
+ $qb->setValue('id', $qb->createNamedParameter($document->getId()))
+ ->setValue('type', $qb->createNamedParameter($document->getType()))
+ ->setValue('url', $qb->createNamedParameter($document->getUrl()))
+ ->setValue('media_type', $qb->createNamedParameter($document->getMediaType()))
+ ->setValue('mime_type', $qb->createNamedParameter($document->getMimeType()))
+ ->setValue('error', $qb->createNamedParameter($document->getError()))
+ ->setValue('local_copy', $qb->createNamedParameter($document->getLocalCopy()))
+ ->setValue('public', $qb->createNamedParameter(($document->isPublic()) ? '1' : '0'))
+ ->setValue(
+ 'creation',
+ $qb->createNamedParameter(new DateTime('now'), IQueryBuilder::PARAM_DATE)
+ );
+ $qb->execute();
+ }
+
+
+ /**
+ * @param Document $document
+ */
+ public function initCaching(Document $document) {
+ $qb = $this->getCacheDocumentsUpdateSql();
+ $this->limitToIdString($qb, $document->getId());
+ $qb->set(
+ 'caching', $qb->createNamedParameter(new DateTime('now'), IQueryBuilder::PARAM_DATE)
+ );
+
+ $qb->execute();
+ }
+
+
+ /**
+ * @param Document $document
+ */
+ public function endCaching(Document $document) {
+ $qb = $this->getCacheDocumentsUpdateSql();
+ $this->limitToIdString($qb, $document->getId());
+ $qb->set('local_copy', $qb->createNamedParameter($document->getLocalCopy()));
+ $qb->set('error', $qb->createNamedParameter($document->getError()));
+
+ $qb->execute();
+ }
+
+
+ /**
+ * @param string $url
+ *
+ * @return Document
+ * @throws CacheDocumentDoesNotExistException
+ */
+ public function getBySource(string $url) {
+ $qb = $this->getCacheDocumentsSelectSql();
+ $this->limitToUrl($qb, $url);
+
+ $cursor = $qb->execute();
+ $data = $cursor->fetch();
+ $cursor->closeCursor();
+
+ if ($data === false) {
+ throw new CacheDocumentDoesNotExistException();
+ }
+
+ return $this->parseCacheDocumentsSelectSql($data);
+ }
+
+
+ /**
+ * @param string $id
+ *
+ * @param bool $public
+ *
+ * @return Document
+ * @throws CacheDocumentDoesNotExistException
+ */
+ public function getById(string $id, bool $public = false) {
+ $qb = $this->getCacheDocumentsSelectSql();
+ $this->limitToIdString($qb, $id);
+
+ if ($public === true) {
+ $this->limitToPublic($qb);
+ }
+
+ $cursor = $qb->execute();
+ $data = $cursor->fetch();
+ $cursor->closeCursor();
+
+ if ($data === false) {
+ throw new CacheDocumentDoesNotExistException();
+ }
+
+ return $this->parseCacheDocumentsSelectSql($data);
+ }
+
+
+ /**
+ * @return Document[]
+ * @throws Exception
+ */
+ public function getNotCachedDocuments() {
+ $qb = $this->getCacheDocumentsSelectSql();
+ $this->limitToDBFieldEmpty($qb, 'local_copy');
+ $this->limitToCaching($qb, self::CACHE_TTL);
+
+ $documents = [];
+ $cursor = $qb->execute();
+ while ($data = $cursor->fetch()) {
+ $documents[] = $this->parseCacheDocumentsSelectSql($data);
+ }
+ $cursor->closeCursor();
+
+ return $documents;
+ }
+
+}
+
diff --git a/lib/Db/CacheDocumentsRequestBuilder.php b/lib/Db/CacheDocumentsRequestBuilder.php
new file mode 100644
index 00000000..56e0c223
--- /dev/null
+++ b/lib/Db/CacheDocumentsRequestBuilder.php
@@ -0,0 +1,116 @@
+
+ * @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\Db;
+
+
+use daita\MySmallPhpTools\Traits\TArrayTools;
+use OCA\Social\Model\ActivityPub\Document;
+use OCP\DB\QueryBuilder\IQueryBuilder;
+
+class CacheDocumentsRequestBuilder extends CoreRequestBuilder {
+
+
+ use TArrayTools;
+
+
+ /**
+ * Base of the Sql Insert request
+ *
+ * @return IQueryBuilder
+ */
+ protected function getCacheDocumentsInsertSql(): IQueryBuilder {
+ $qb = $this->dbConnection->getQueryBuilder();
+ $qb->insert(self::TABLE_CACHE_DOCUMENTS);
+
+ return $qb;
+ }
+
+
+ /**
+ * Base of the Sql Update request
+ *
+ * @return IQueryBuilder
+ */
+ protected function getCacheDocumentsUpdateSql(): IQueryBuilder {
+ $qb = $this->dbConnection->getQueryBuilder();
+ $qb->update(self::TABLE_CACHE_DOCUMENTS);
+
+ return $qb;
+ }
+
+
+ /**
+ * Base of the Sql Select request for Shares
+ *
+ * @return IQueryBuilder
+ */
+ protected function getCacheDocumentsSelectSql(): IQueryBuilder {
+ $qb = $this->dbConnection->getQueryBuilder();
+
+ /** @noinspection PhpMethodParametersCountMismatchInspection */
+ $qb->select(
+ 'cd.id', 'cd.type', 'cd.media_type', 'cd.mime_type', 'cd.url', 'cd.local_copy',
+ 'cd.public', 'cd.error', 'cd.creation', 'cd.caching'
+ )
+ ->from(self::TABLE_CACHE_DOCUMENTS, 'cd');
+
+ $this->defaultSelectAlias = 'cd';
+
+ return $qb;
+ }
+
+
+ /**
+ * Base of the Sql Delete request
+ *
+ * @return IQueryBuilder
+ */
+ protected function getCacheDocumentsDeleteSql(): IQueryBuilder {
+ $qb = $this->dbConnection->getQueryBuilder();
+ $qb->delete(self::TABLE_CACHE_DOCUMENTS);
+
+ return $qb;
+ }
+
+
+ /**
+ * @param array $data
+ *
+ * @return Document
+ */
+ protected function parseCacheDocumentsSelectSql(array $data): Document {
+ $document = new Document();
+ $document->importFromDatabase($data);
+
+ return $document;
+ }
+
+}
+
diff --git a/lib/Db/CoreRequestBuilder.php b/lib/Db/CoreRequestBuilder.php
index 7c41e594..538d9751 100644
--- a/lib/Db/CoreRequestBuilder.php
+++ b/lib/Db/CoreRequestBuilder.php
@@ -27,24 +27,38 @@ declare(strict_types=1);
*
*/
+
namespace OCA\Social\Db;
+use DateInterval;
+use DateTime;
use Doctrine\DBAL\Query\QueryBuilder;
+use Exception;
use OCA\Social\Exceptions\InvalidResourceException;
+use OCA\Social\Model\ActivityPub\Document;
+use OCA\Social\Model\ActivityPub\Image;
use OCA\Social\Model\ActivityPub\Person;
use OCA\Social\Service\ConfigService;
use OCA\Social\Service\MiscService;
use OCP\DB\QueryBuilder\IQueryBuilder;
use OCP\IDBConnection;
+
+/**
+ * Class CoreRequestBuilder
+ *
+ * @package OCA\Social\Db
+ */
class CoreRequestBuilder {
+
const TABLE_SERVER_ACTORS = 'social_server_actors';
const TABLE_SERVER_NOTES = 'social_server_notes';
const TABLE_SERVER_FOLLOWS = 'social_server_follows';
const TABLE_CACHE_ACTORS = 'social_cache_actors';
+ const TABLE_CACHE_DOCUMENTS = 'social_cache_documents';
/** @var IDBConnection */
@@ -134,6 +148,16 @@ class CoreRequestBuilder {
}
+ /**
+ * Limit the request to the ActorId
+ *
+ * @param IQueryBuilder $qb
+ */
+ protected function limitToPublic(IQueryBuilder &$qb) {
+ $this->limitToDBFieldInt($qb, 'public', 1);
+ }
+
+
/**
* Limit the request to the ActorId
*
@@ -191,6 +215,38 @@ class CoreRequestBuilder {
}
+ /**
+ * Limit the request to the creation
+ *
+ * @param IQueryBuilder $qb
+ * @param int $delay
+ *
+ * @throws Exception
+ */
+ protected function limitToCreation(IQueryBuilder &$qb, int $delay = 0) {
+ $date = new DateTime('now');
+ $date->sub(new DateInterval('PT' . $delay . 'M'));
+
+ $this->limitToDBFieldDateTime($qb, 'creation', $date);
+ }
+
+
+ /**
+ * Limit the request to the creation
+ *
+ * @param IQueryBuilder $qb
+ * @param int $delay
+ *
+ * @throws Exception
+ */
+ protected function limitToCaching(IQueryBuilder &$qb, int $delay = 0) {
+ $date = new DateTime('now');
+ $date->sub(new DateInterval('PT' . $delay . 'M'));
+
+ $this->limitToDBFieldDateTime($qb, 'caching', $date);
+ }
+
+
/**
* Limit the request to the url
*
@@ -299,7 +355,7 @@ class CoreRequestBuilder {
* @param bool $cs - case sensitive
* @param string $alias
*/
- private function limitToDBField(
+ protected function limitToDBField(
IQueryBuilder &$qb, string $field, string $value, bool $cs = true, string $alias = ''
) {
$expr = $qb->expr();
@@ -326,7 +382,7 @@ class CoreRequestBuilder {
* @param string $field
* @param int $value
*/
- private function limitToDBFieldInt(IQueryBuilder &$qb, string $field, int $value) {
+ protected function limitToDBFieldInt(IQueryBuilder &$qb, string $field, int $value) {
$expr = $qb->expr();
$pf = ($qb->getType() === QueryBuilder::SELECT) ? $this->defaultSelectAlias . '.' : '';
$field = $pf . $field;
@@ -335,12 +391,42 @@ class CoreRequestBuilder {
}
+ /**
+ * @param IQueryBuilder $qb
+ * @param string $field
+ */
+ protected function limitToDBFieldEmpty(IQueryBuilder &$qb, string $field) {
+ $expr = $qb->expr();
+ $pf = ($qb->getType() === QueryBuilder::SELECT) ? $this->defaultSelectAlias . '.' : '';
+ $field = $pf . $field;
+
+ $qb->andWhere($expr->eq($field, $qb->createNamedParameter('')));
+ }
+
+
+ /**
+ * @param IQueryBuilder $qb
+ * @param string $field
+ * @param DateTime $date
+ */
+ protected function limitToDBFieldDateTime(IQueryBuilder &$qb, string $field, DateTime $date) {
+ $expr = $qb->expr();
+ $pf = ($qb->getType() === QueryBuilder::SELECT) ? $this->defaultSelectAlias . '.' : '';
+ $field = $pf . $field;
+
+ $orX = $expr->orX();
+ $orX->add($expr->lte($field, $qb->createNamedParameter($date, IQueryBuilder::PARAM_DATE)));
+ $orX->add($expr->isNull($field));
+ $qb->andWhere($orX);
+ }
+
+
/**
* @param IQueryBuilder $qb
* @param string $field
* @param array $values
*/
- private function limitToDBFieldArray(IQueryBuilder &$qb, string $field, array $values) {
+ protected function limitToDBFieldArray(IQueryBuilder &$qb, string $field, array $values) {
$expr = $qb->expr();
$pf = ($qb->getType() === QueryBuilder::SELECT) ? $this->defaultSelectAlias . '.' : '';
$field = $pf . $field;
@@ -363,7 +449,7 @@ class CoreRequestBuilder {
* @param string $field
* @param string $value
*/
- private function searchInDBField(IQueryBuilder &$qb, string $field, string $value) {
+ protected function searchInDBField(IQueryBuilder &$qb, string $field, string $value) {
$expr = $qb->expr();
$pf = ($qb->getType() === QueryBuilder::SELECT) ? $this->defaultSelectAlias . '.' : '';
@@ -425,7 +511,7 @@ class CoreRequestBuilder {
}
$actor = new Person();
- $actor->import($new);
+ $actor->importFromDatabase($new);
if ($actor->getType() !== Person::TYPE) {
throw new InvalidResourceException();
@@ -434,6 +520,62 @@ class CoreRequestBuilder {
return $actor;
}
+
+ /**
+ * @param IQueryBuilder $qb
+ * @param string $fieldDocumentId
+ */
+ protected function leftJoinCacheDocuments(IQueryBuilder &$qb, string $fieldDocumentId) {
+ if ($qb->getType() !== QueryBuilder::SELECT) {
+ return;
+ }
+
+ $expr = $qb->expr();
+ $pf = $this->defaultSelectAlias;
+
+// /** @noinspection PhpMethodParametersCountMismatchInspection */
+ $qb->selectAlias('cd.id', 'cachedocument_id')
+ ->selectAlias('cd.type', 'cachedocument_type')
+ ->selectAlias('cd.mime_type', 'cachedocument_mime_type')
+ ->selectAlias('cd.media_type', 'cachedocument_media_type')
+ ->selectAlias('cd.url', 'cachedocument_url')
+ ->selectAlias('cd.local_copy', 'cachedocument_local_copy')
+ ->selectAlias('cd.caching', 'cachedocument_caching')
+ ->selectAlias('cd.public', 'cachedocument_public')
+ ->selectAlias('cd.error', 'cachedocument_error')
+ ->selectAlias('ca.creation', 'cachedocument_creation')
+ ->leftJoin(
+ $this->defaultSelectAlias, CoreRequestBuilder::TABLE_CACHE_DOCUMENTS, 'cd',
+ $expr->eq($pf . '.' . $fieldDocumentId, 'cd.id')
+ );
+ }
+
+
+ /**
+ * @param array $data
+ *
+ * @return Document
+ * @throws InvalidResourceException
+ */
+ protected function parseCacheDocumentsLeftJoin(array $data): Document {
+ $new = [];
+
+ foreach ($data as $k => $v) {
+ if (substr($k, 0, 14) === 'cachedocument_') {
+ $new[substr($k, 14)] = $v;
+ }
+ }
+ $document = new Document();
+
+ $document->importFromDatabase($new);
+
+ if ($document->getType() !== Image::TYPE) {
+ throw new InvalidResourceException();
+ }
+
+ return $document;
+ }
+
}
diff --git a/lib/Db/NotesRequestBuilder.php b/lib/Db/NotesRequestBuilder.php
index c4444eea..16c5999d 100644
--- a/lib/Db/NotesRequestBuilder.php
+++ b/lib/Db/NotesRequestBuilder.php
@@ -160,6 +160,7 @@ class NotesRequestBuilder extends CoreRequestBuilder {
protected function parseNotesSelectSql($data): Note {
$dTime = new DateTime($this->get('published_time', $data, 'yesterday'));
+ // TODO - use $note->importFromDatabase() ?
$note = new Note();
$note->setId($data['id'])
->setTo($data['to'])
diff --git a/lib/Exceptions/CacheContentException.php b/lib/Exceptions/CacheContentException.php
new file mode 100644
index 00000000..7ef15f28
--- /dev/null
+++ b/lib/Exceptions/CacheContentException.php
@@ -0,0 +1,8 @@
+getUrlCloud() === '') {
+ throw new UrlCloudException();
+ }
+
+ if ($base !== '') {
+ $base = $this->withoutEndSlash($this->withBeginSlash($base));
+ }
+
$uuid = sprintf(
'%04x%04x-%04x-%04x-%04x-%04x%04x%04x', mt_rand(0, 0xffff), mt_rand(0, 0xffff),
mt_rand(0, 0xffff), mt_rand(0, 0xfff) | 0x4000, mt_rand(0, 0x3fff) | 0x8000,
mt_rand(0, 0xffff), mt_rand(0, 0xffff), mt_rand(0, 0xffff)
);
- $this->setId($base . '/' . $uuid);
+ $this->setId($this->getUrlCloud() . $base . '/' . $uuid);
}
/**
@@ -178,9 +200,10 @@ abstract class ACore implements JsonSerializable {
* @return ACore
*/
public function setType(string $type): ACore {
- if ($type !== '') {
- $this->type = $type;
- }
+// if ($type !== '') {
+ $this->type = $type;
+
+// }
return $this;
}
@@ -343,8 +366,8 @@ abstract class ACore implements JsonSerializable {
/**
* @return string
*/
- public function getUrlRoot(): string {
- return $this->root;
+ public function getUrlSocial(): string {
+ return $this->urlSocial;
}
/**
@@ -352,8 +375,27 @@ abstract class ACore implements JsonSerializable {
*
* @return ACore
*/
- public function setUrlRoot(string $path): ACore {
- $this->root = $path;
+ public function setUrlSocial(string $path): ACore {
+ $this->urlSocial = $path;
+
+ return $this;
+ }
+
+
+ /**
+ * @return string
+ */
+ public function getUrlCloud(): string {
+ return $this->urlCloud;
+ }
+
+ /**
+ * @param string $path
+ *
+ * @return ACore
+ */
+ public function setUrlCloud(string $path): ACore {
+ $this->urlCloud = $path;
return $this;
}
@@ -568,6 +610,36 @@ abstract class ACore implements JsonSerializable {
}
+ /**
+ * @return bool
+ */
+ public function gotIcon(): bool {
+ if ($this->icon === null) {
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * @return Document
+ */
+ public function getIcon(): Document {
+ return $this->icon;
+ }
+
+ /**
+ * @param Document $icon
+ *
+ * @return ACore
+ */
+ public function setIcon(Document $icon): ACore {
+ $this->icon = $icon;
+
+ return $this;
+ }
+
+
/**
* @return bool
*/
@@ -623,7 +695,6 @@ abstract class ACore implements JsonSerializable {
return $this;
}
-
return $this->getParent()
->getRoot($chain);
}
@@ -792,6 +863,23 @@ abstract class ACore implements JsonSerializable {
* @param array $data
*/
public function import(array $data) {
+ $this->setId($this->get('id', $data, ''));
+ $this->setType($this->get('type', $data, ''));
+ $this->setUrl($this->get('url', $data, ''));
+ $this->setSummary($this->get('summary', $data, ''));
+ $this->setToArray($this->getArray('to', $data, []));
+ $this->setCcArray($this->getArray('cc', $data, []));
+ $this->setPublished($this->get('published', $data, ''));
+ $this->setActorId($this->get('actor', $data, ''));
+ $this->setObjectId($this->get('object', $data, ''));
+ $this->setLocal(($this->getInt('local', $data, 0) === 1));
+ }
+
+
+ /**
+ * @param array $data
+ */
+ public function importFromDatabase(array $data) {
$this->setId($this->get('id', $data, ''));
$this->setType($this->get('type', $data, ''));
$this->setUrl($this->get('url', $data, ''));
@@ -821,7 +909,7 @@ abstract class ACore implements JsonSerializable {
$this->addEntry('id', $this->getId());
$this->addEntry('type', $this->getType());
- $this->addEntry('url', $this->getId());
+ $this->addEntry('url', $this->getUrl());
$this->addEntry('to', $this->getTo());
$this->addEntryArray('to', $this->getToArray());
@@ -850,11 +938,17 @@ abstract class ACore implements JsonSerializable {
$this->addEntry('object', $this->getObjectId());
}
+ if ($this->gotIcon()) {
+ $this->addEntryItem('icon', $this->getIcon());
+ }
+
if ($this->isCompleteDetails()) {
$this->addEntry('source', $this->getSource());
}
- $this->addEntryBool('local', $this->isLocal());
+ if ($this->isLocal()) {
+ $this->addEntryBool('local', $this->isLocal());
+ }
return $this->getEntries();
}
diff --git a/lib/Model/ActivityPub/Cache/CacheActor.php b/lib/Model/ActivityPub/Cache/CacheActor.php
deleted file mode 100644
index 27768ae5..00000000
--- a/lib/Model/ActivityPub/Cache/CacheActor.php
+++ /dev/null
@@ -1,157 +0,0 @@
-
- * @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\Model\ActivityPub\Cache;
-
-
-class CacheActor {
-
- /** @var int */
- private $id;
-
- /** @var string */
- private $account = '';
-
- /** @var string */
- private $url;
-
- /** @var array */
- private $actor = [];
-
- /** @var int */
- private $creation = 0;
-
-
- /**
- * CacheActor constructor.
- *
- * @param int $id
- */
- public function __construct($id = 0) {
- $this->id = $id;
- }
-
-
- /**
- * @return int
- */
- public function getId(): int {
- return $this->id;
- }
-
- /**
- * @param int $id
- *
- * @return CacheActor
- */
- public function setId(int $id): CacheActor {
- $this->account = $id;
-
- return $this;
- }
-
-
- /**
- * @return string
- */
- public function getAccount(): string {
- return $this->account;
- }
-
- /**
- * @param string $account
- *
- * @return CacheActor
- */
- public function setAccount(string $account): CacheActor {
- $this->account = $account;
-
- return $this;
- }
-
-
- /**
- * @return string
- */
- public function getUrl(): string {
- return $this->url;
- }
-
- /**
- * @param string $url
- *
- * @return CacheActor
- */
- public function setUrl(string $url): CacheActor {
- $this->url = $url;
-
- return $this;
- }
-
-
- /**
- * @return array
- */
- public function getActor(): array {
- return $this->actor;
- }
-
- /**
- * @param array $actor
- *
- * @return CacheActor
- */
- public function setActor(array $actor): CacheActor {
- $this->actor = $actor;
-
- return $this;
- }
-
-
- /**
- * @return int
- */
- public function getCreation(): int {
- return $this->creation;
- }
-
- /**
- * @param int $creation
- *
- * @return CacheActor
- */
- public function setCreation(int $creation): CacheActor {
- $this->creation = $creation;
-
- return $this;
- }
-
-
-}
-
diff --git a/lib/Model/ActivityPub/Document.php b/lib/Model/ActivityPub/Document.php
new file mode 100644
index 00000000..c7da00f8
--- /dev/null
+++ b/lib/Model/ActivityPub/Document.php
@@ -0,0 +1,246 @@
+
+ * @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\Model\ActivityPub;
+
+
+use DateTime;
+use JsonSerializable;
+use OCA\Social\Exceptions\UrlCloudException;
+
+
+/**
+ * Class Document
+ *
+ * @package OCA\Social\Model\ActivityPub
+ */
+class Document extends ACore implements JsonSerializable {
+
+
+ const TYPE = 'Document';
+
+
+ /** @var string */
+ private $mediaType = '';
+
+ /** @var string */
+ private $mimeType = '';
+
+ /** @var string */
+ private $localCopy = '';
+
+ /** @var int */
+ private $caching = 0;
+
+ /** @var bool */
+ private $public = false;
+
+ /** @var int */
+ private $error = 0;
+
+
+ /**
+ * Document constructor.
+ *
+ * @param ACore $parent
+ */
+ public function __construct($parent = null) {
+ parent::__construct($parent);
+
+ $this->setType(self::TYPE);
+ }
+
+
+ /**
+ * @return string
+ */
+ public function getMediaType(): string {
+ return $this->mediaType;
+ }
+
+ /**
+ * @param string $mediaType
+ *
+ * @return ACore
+ */
+ public function setMediaType(string $mediaType): ACore {
+ $this->mediaType = $mediaType;
+
+ return $this;
+ }
+
+
+ /**
+ * @return string
+ */
+ public function getMimeType(): string {
+ return $this->mimeType;
+ }
+
+ /**
+ * @param string $mimeType
+ *
+ * @return ACore
+ */
+ public function setMimeType(string $mimeType): ACore {
+ $this->mimeType = $mimeType;
+
+ return $this;
+ }
+
+
+ /**
+ * @return string
+ */
+ public function getLocalCopy(): string {
+ return $this->localCopy;
+ }
+
+ /**
+ * @param string $localCopy
+ *
+ * @return Document
+ */
+ public function setLocalCopy(string $localCopy): Document {
+ $this->localCopy = $localCopy;
+
+ return $this;
+ }
+
+
+ /**
+ * @return bool
+ */
+ public function isPublic(): bool {
+ return $this->public;
+ }
+
+ /**
+ * @param bool $public
+ *
+ * @return Document
+ */
+ public function setPublic(bool $public): Document {
+ $this->public = $public;
+
+ return $this;
+ }
+
+
+ /**
+ * @return int
+ */
+ public function getError(): int {
+ return $this->error;
+ }
+
+ /**
+ * @param int $error
+ *
+ * @return Document
+ */
+ public function setError(int $error): Document {
+ $this->error = $error;
+
+ return $this;
+ }
+
+
+ /**
+ * @return int
+ */
+ public function getCaching(): int {
+ return $this->caching;
+ }
+
+ /**
+ * @param int $caching
+ *
+ * @return Document
+ */
+ public function setCaching(int $caching): Document {
+ $this->caching = $caching;
+
+ return $this;
+ }
+
+
+ /**
+ * @param array $data
+ *
+ * @throws UrlCloudException
+ */
+ public function import(array $data) {
+ parent::import($data);
+
+ $this->setMediaType($this->get('mediaType', $data, ''));
+
+ if ($this->getId() === '') {
+ $this->generateUniqueId('/documents/g');
+ }
+ }
+
+
+ /**
+ * @param array $data
+ */
+ public function importFromDatabase(array $data) {
+ parent::importFromDatabase($data);
+
+ $this->setPublic(($this->getInt('public', $data, 0) === 1) ? true : false);
+ $this->setError($this->getInt('error', $data, 0));
+ $this->setLocalCopy($this->get('local_copy', $data, ''));
+ $this->setMediaType($this->get('media_type', $data, ''));
+ $this->setMimeType($this->get('mime_type', $data, ''));
+
+ if ($this->get('caching', $data, '') === '') {
+ $this->setCaching(0);
+ } else {
+ $date = new DateTime($this->get('caching', $data, ''));
+ $this->setCaching($date->getTimestamp());
+ }
+ }
+
+ /**
+ * @return array
+ */
+ public function jsonSerialize(): array {
+ return array_merge(
+ parent::jsonSerialize(),
+ [
+ 'mediaType' => $this->getMediaType(),
+ 'mimeType' => $this->getMimeType(),
+ 'localCopy' => $this->getLocalCopy()
+ ]
+ );
+ }
+
+}
+
diff --git a/lib/Model/ActivityPub/Image.php b/lib/Model/ActivityPub/Image.php
new file mode 100644
index 00000000..5947c4a6
--- /dev/null
+++ b/lib/Model/ActivityPub/Image.php
@@ -0,0 +1,83 @@
+
+ * @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\Model\ActivityPub;
+
+
+use JsonSerializable;
+use OCA\Social\Exceptions\UrlCloudException;
+
+
+/**
+ * Class Image
+ *
+ * @package OCA\Social\Model\ActivityPub
+ */
+class Image extends Document implements JsonSerializable {
+
+
+ const TYPE = 'Image';
+
+
+ /**
+ * Image constructor.
+ *
+ * @param ACore $parent
+ */
+ public function __construct($parent = null) {
+ parent::__construct($parent);
+
+ $this->setType(self::TYPE);
+ }
+
+
+ /**
+ * @param array $data
+ *
+ * @throws UrlCloudException
+ */
+ public function import(array $data) {
+ parent::import($data);
+ }
+
+
+ /**
+ * @return array
+ */
+ public function jsonSerialize(): array {
+ return array_merge(
+ parent::jsonSerialize(),
+ [
+ ]
+ );
+ }
+
+}
+
diff --git a/lib/Model/ActivityPub/Note.php b/lib/Model/ActivityPub/Note.php
index 7a71493c..53b91c06 100644
--- a/lib/Model/ActivityPub/Note.php
+++ b/lib/Model/ActivityPub/Note.php
@@ -199,7 +199,6 @@ class Note extends ACore implements JsonSerializable {
public function import(array $data) {
parent::import($data);
- $this->setSummary($this->get('summary', $data, ''));
$this->setInReplyTo($this->get('inReplyTo', $data, ''));
$this->setAttributedTo($this->get('attributedTo', $data, ''));
$this->setSensitive($this->getBool('sensitive', $data, false));
@@ -219,7 +218,7 @@ class Note extends ACore implements JsonSerializable {
parent::jsonSerialize(),
[
'content' => $this->getContent(),
- 'attributedTo' => $this->getUrlRoot() . $this->getAttributedTo(),
+ 'attributedTo' => $this->getUrlSocial() . $this->getAttributedTo(),
'inReplyTo' => $this->getInReplyTo(),
'sensitive' => $this->isSensitive(),
'conversation' => $this->getConversation()
diff --git a/lib/Model/ActivityPub/Person.php b/lib/Model/ActivityPub/Person.php
index 18c73be6..41f3b375 100644
--- a/lib/Model/ActivityPub/Person.php
+++ b/lib/Model/ActivityPub/Person.php
@@ -32,6 +32,7 @@ namespace OCA\Social\Model\ActivityPub;
use JsonSerializable;
+use OCA\Social\Exceptions\UrlCloudException;
/**
@@ -340,9 +341,44 @@ class Person extends ACore implements JsonSerializable {
/**
* @param array $data
+ *
+ * @throws UrlCloudException
*/
public function import(array $data) {
parent::import($data);
+ $this->setPreferredUsername($this->get('preferredUsername', $data, ''))
+ ->setPublicKey($this->get('publicKey.publicKeyPem', $data))
+ ->setSharedInbox($this->get('endpoints.sharedInbox', $data))
+ ->setName($this->get('name', $data, ''))
+ ->setAccount($this->get('account', $data, ''))
+ ->setInbox($this->get('inbox', $data, ''))
+ ->setOutbox($this->get('outbox', $data, ''))
+ ->setFollowers($this->get('followers', $data, ''))
+ ->setFollowing($this->get('following', $data, ''))
+ ->setFeatured($this->get('featured', $data, ''));
+
+ $icon = new Image($this);
+ $icon->setUrlCloud($this->getUrlCloud());
+ $icon->import($this->getArray('icon', $data, []));
+
+ if ($icon->getType() === Image::TYPE) {
+ $this->setIcon($icon);
+ }
+
+
+// ->setCreation($this->getInt('creation', $data, 0));
+
+// if ($this->getPreferredUsername() === '') {
+// $this->setType('Invalid');
+// }
+ }
+
+
+ /**
+ * @param array $data
+ */
+ public function importFromDatabase(array $data) {
+ parent::importFromDatabase($data);
$this->setPreferredUsername($this->get('preferred_username', $data, ''))
->setName($this->get('name', $data, ''))
->setAccount($this->get('account', $data, ''))
@@ -370,8 +406,8 @@ class Person extends ACore implements JsonSerializable {
parent::jsonSerialize(),
[
'aliases' => [
- $this->getUrlRoot() . '@' . $this->getPreferredUsername(),
- $this->getUrlRoot() . 'users/' . $this->getPreferredUsername()
+ $this->getUrlSocial() . '@' . $this->getPreferredUsername(),
+ $this->getUrlSocial() . 'users/' . $this->getPreferredUsername()
],
'preferredUsername' => $this->getPreferredUsername(),
'name' => $this->getName(),
diff --git a/lib/Service/ActivityPub/DocumentService.php b/lib/Service/ActivityPub/DocumentService.php
new file mode 100644
index 00000000..134ff5c7
--- /dev/null
+++ b/lib/Service/ActivityPub/DocumentService.php
@@ -0,0 +1,161 @@
+
+ * @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\CacheDocumentsRequest;
+use OCA\Social\Exceptions\CacheContentException;
+use OCA\Social\Exceptions\CacheContentSizeException;
+use OCA\Social\Exceptions\CacheDocumentDoesNotExistException;
+use OCA\Social\Model\ActivityPub\ACore;
+use OCA\Social\Model\ActivityPub\Document;
+use OCA\Social\Service\CacheService;
+use OCA\Social\Service\MiscService;
+use OCP\Files\NotPermittedException;
+use OCP\Files\SimpleFS\ISimpleFile;
+
+
+class DocumentService implements ICoreService {
+
+
+ /** @var CacheDocumentsRequest */
+ private $cacheDocumentsRequest;
+
+ /** @var CacheService */
+ private $cacheService;
+
+ /** @var MiscService */
+ private $miscService;
+
+
+ /**
+ * DocumentService constructor.
+ *
+ * @param CacheDocumentsRequest $cacheDocumentsRequest
+ * @param CacheService $cacheService
+ * @param MiscService $miscService
+ */
+ public function __construct(
+ CacheDocumentsRequest $cacheDocumentsRequest, CacheService $cacheService,
+ MiscService $miscService
+ ) {
+ $this->cacheDocumentsRequest = $cacheDocumentsRequest;
+ $this->cacheService = $cacheService;
+ $this->miscService = $miscService;
+ }
+
+
+ /**
+ * @param string $id
+ * @param bool $public
+ *
+ * @return Document
+ * @throws CacheDocumentDoesNotExistException
+ * @throws NotPermittedException
+ */
+ public function cacheRemoteDocument(string $id, bool $public = false) {
+ $document = $this->cacheDocumentsRequest->getById($id, $public);
+ if ($document->getLocalCopy() !== '') {
+ return $document;
+ }
+
+ // TODO - ignore this if getCaching is older than 15 minutes
+ if ($document->getCaching() > (time() - (CacheDocumentsRequest::CACHE_TTL * 60))) {
+ return $document;
+ }
+
+ $this->cacheDocumentsRequest->initCaching($document);
+
+ try {
+ $localCopy = $this->cacheService->saveRemoteFileToCache($document->getUrl(), $mime);
+ $document->setMimeType($mime);
+ $document->setLocalCopy($localCopy);
+ $this->cacheDocumentsRequest->endCaching($document);
+ } catch (CacheContentSizeException $e) {
+ $this->cacheDocumentsRequest->endCaching($document);
+ } catch (CacheContentException $e) {
+ }
+
+ return $document;
+ }
+
+
+ /**
+ * @param string $id
+ *
+ * @param bool $public
+ *
+ * @return ISimpleFile
+ * @throws CacheContentException
+ * @throws CacheDocumentDoesNotExistException
+ * @throws NotPermittedException
+ */
+ public function getFromCache(string $id, bool $public = false) {
+ $document = $this->cacheRemoteDocument($id, $public);
+
+ return $this->cacheService->getContentFromCache($document->getLocalCopy());
+ }
+
+
+ /**
+ * @return int
+ * @throws CacheDocumentDoesNotExistException
+ * @throws NotPermittedException
+ * @throws Exception
+ */
+ public function manageCacheDocuments(): int {
+ $update = $this->cacheDocumentsRequest->getNotCachedDocuments();
+
+ foreach ($update as $item) {
+ $this->cacheRemoteDocument($item->getId());
+ }
+
+ return sizeof($update);
+ }
+
+
+ /**
+ * @param ACore $item
+ */
+ public function parse(ACore $item) {
+ // TODO: Implement parse() method.
+ }
+
+ /**
+ * @param ACore $item
+ */
+ public function delete(ACore $item) {
+ // TODO: Implement delete() method.
+ }
+
+}
+
diff --git a/lib/Service/ActivityPub/FollowService.php b/lib/Service/ActivityPub/FollowService.php
index 43871642..36423fbc 100644
--- a/lib/Service/ActivityPub/FollowService.php
+++ b/lib/Service/ActivityPub/FollowService.php
@@ -34,7 +34,9 @@ namespace OCA\Social\Service\ActivityPub;
use Exception;
use OCA\Social\Db\FollowsRequest;
use OCA\Social\Exceptions\ActorDoesNotExistException;
+use OCA\Social\Exceptions\CacheActorDoesNotExistException;
use OCA\Social\Exceptions\FollowDoesNotExistException;
+use OCA\Social\Exceptions\InvalidResourceException;
use OCA\Social\Exceptions\RequestException;
use OCA\Social\Exceptions\SocialAppConfigException;
use OCA\Social\Model\ActivityPub\ACore;
@@ -96,14 +98,17 @@ class FollowService implements ICoreService {
* @param Person $actor
* @param string $account
*
+ * @throws ActorDoesNotExistException
* @throws RequestException
* @throws SocialAppConfigException
- * @throws ActorDoesNotExistException
+ * @throws CacheActorDoesNotExistException
+ * @throws InvalidResourceException
*/
public function followAccount(Person $actor, string $account) {
$remoteActor = $this->personService->getFromAccount($account);
$follow = new Follow();
- $follow->generateUniqueId($this->configService->getCloudAddress());
+ $follow->setUrlCloud($this->configService->getCloudAddress());
+ $follow->generateUniqueId();
$follow->setActorId($actor->getId());
$follow->setObjectId($remoteActor->getId());
@@ -124,6 +129,8 @@ class FollowService implements ICoreService {
* @param Person $actor
* @param string $account
*
+ * @throws CacheActorDoesNotExistException
+ * @throws InvalidResourceException
* @throws RequestException
*/
public function unfollowAccount(Person $actor, string $account) {
diff --git a/lib/Service/ActivityPub/NoteService.php b/lib/Service/ActivityPub/NoteService.php
index 2adecf1c..7107c1fe 100644
--- a/lib/Service/ActivityPub/NoteService.php
+++ b/lib/Service/ActivityPub/NoteService.php
@@ -126,7 +126,7 @@ class NoteService implements ICoreService {
$note->setId($this->configService->generateId('@' . $actor->getPreferredUsername()));
$note->setPublished(date("c"));
$note->setAttributedTo(
- $this->configService->getUrlRoot() . '@' . $actor->getPreferredUsername()
+ $this->configService->getUrlSocial() . '@' . $actor->getPreferredUsername()
);
$this->setRecipient($note, $actor, $type);
diff --git a/lib/Service/ActivityPub/PersonService.php b/lib/Service/ActivityPub/PersonService.php
index a4d4eee1..432ab2a9 100644
--- a/lib/Service/ActivityPub/PersonService.php
+++ b/lib/Service/ActivityPub/PersonService.php
@@ -34,11 +34,16 @@ namespace OCA\Social\Service\ActivityPub;
use daita\MySmallPhpTools\Traits\TArrayTools;
use Exception;
use OCA\Social\Db\CacheActorsRequest;
+use OCA\Social\Db\CacheDocumentsRequest;
use OCA\Social\Exceptions\CacheActorDoesNotExistException;
+use OCA\Social\Exceptions\CacheDocumentDoesNotExistException;
use OCA\Social\Exceptions\InvalidResourceException;
use OCA\Social\Exceptions\RequestException;
+use OCA\Social\Exceptions\SocialAppConfigException;
+use OCA\Social\Exceptions\UrlCloudException;
use OCA\Social\Model\ActivityPub\ACore;
use OCA\Social\Model\ActivityPub\Person;
+use OCA\Social\Service\ConfigService;
use OCA\Social\Service\ICoreService;
use OCA\Social\Service\InstanceService;
use OCA\Social\Service\MiscService;
@@ -58,9 +63,15 @@ class PersonService implements ICoreService {
/** @var CacheActorsRequest */
private $cacheActorsRequest;
+ /** @var CacheDocumentsRequest */
+ private $cacheDocumentsRequest;
+
/** @var InstanceService */
private $instanceService;
+ /** @var ConfigService */
+ private $configService;
+
/** @var MiscService */
private $miscService;
@@ -69,15 +80,19 @@ class PersonService implements ICoreService {
* UndoService constructor.
*
* @param CacheActorsRequest $cacheActorsRequest
+ * @param CacheDocumentsRequest $cacheDocumentsRequest
* @param InstanceService $instanceService
+ * @param ConfigService $configService
* @param MiscService $miscService
*/
public function __construct(
- CacheActorsRequest $cacheActorsRequest, InstanceService $instanceService,
- MiscService $miscService
+ CacheActorsRequest $cacheActorsRequest, CacheDocumentsRequest $cacheDocumentsRequest,
+ InstanceService $instanceService, ConfigService $configService, MiscService $miscService
) {
$this->cacheActorsRequest = $cacheActorsRequest;
+ $this->cacheDocumentsRequest = $cacheDocumentsRequest;
$this->instanceService = $instanceService;
+ $this->configService = $configService;
$this->miscService = $miscService;
}
@@ -108,6 +123,8 @@ class PersonService implements ICoreService {
* @return Person
* @throws InvalidResourceException
* @throws RequestException
+ * @throws SocialAppConfigException
+ * @throws UrlCloudException
*/
public function getFromId(string $id, bool $refresh = false): Person {
@@ -125,19 +142,8 @@ class PersonService implements ICoreService {
$actor = $this->cacheActorsRequest->getFromId($id);
} catch (CacheActorDoesNotExistException $e) {
$object = $this->instanceService->retrieveObject($id);
- $actor = new Person();
- $actor->import($object);
- $actor->setSource(json_encode($object, JSON_UNESCAPED_SLASHES));
-
- $actor->setPreferredUsername($this->get('preferredUsername', $object, ''));
- $actor->setPublicKey($this->get('publicKey.publicKeyPem', $object));
- $actor->setSharedInbox($this->get('endpoints.sharedInbox', $object));
+ $actor = $this->generateActorFromObject($object);
$actor->setAccount($actor->getPreferredUsername() . '@' . $this->get('_host', $object));
-
- if ($actor->getType() !== Person::TYPE) {
- throw new InvalidResourceException();
- }
-
try {
$this->parse($actor);
} catch (Exception $e) {
@@ -158,6 +164,8 @@ class PersonService implements ICoreService {
* @throws InvalidResourceException
* @throws RequestException
* @throws CacheActorDoesNotExistException
+ * @throws SocialAppConfigException
+ * @throws UrlCloudException
*/
public function getFromAccount(string $account, bool $retrieve = true): Person {
@@ -169,19 +177,8 @@ class PersonService implements ICoreService {
}
$object = $this->instanceService->retrieveAccount($account);
-
- $actor = new Person();
- $actor->import($object);
-
+ $actor = $this->generateActorFromObject($object);
$actor->setAccount($account);
- $actor->setPreferredUsername($this->get('preferredUsername', $object, ''));
- $actor->setPublicKey($this->get('publicKey.publicKeyPem', $object));
- $actor->setSharedInbox($this->get('endpoints.sharedInbox', $object));
-
- if ($actor->getType() !== Person::TYPE) {
- throw new InvalidResourceException();
- }
-
try {
$this->parse($actor);
} catch (Exception $e) {
@@ -193,6 +190,40 @@ class PersonService implements ICoreService {
}
+ /**
+ * @param array $object
+ *
+ * @return Person
+ * @throws InvalidResourceException
+ * @throws SocialAppConfigException
+ * @throws UrlCloudException
+ */
+ private function generateActorFromObject(array $object) {
+
+ $actor = new Person();
+ $actor->setUrlCloud($this->configService->getCloudAddress());
+ $actor->import($object);
+
+ if ($actor->getType() !== Person::TYPE) {
+ throw new InvalidResourceException();
+ }
+
+ $actor->setSource(json_encode($object, JSON_UNESCAPED_SLASHES));
+// $actor->setPreferredUsername($this->get('preferredUsername', $object, ''));
+// $actor->setPublicKey($this->get('publicKey.publicKeyPem', $object));
+// $actor->setSharedInbox($this->get('endpoints.sharedInbox', $object));
+// $actor->setAccount($actor->getPreferredUsername() . '@' . $this->get('_host', $object));
+//
+// $icon = new Image($actor);
+// $icon->setUrlCloud($this->configService->getCloudAddress());
+// $icon->import($this->getArray('icon', $object, []));
+// if ($icon->getType() === Image::TYPE) {
+// $actor->setIcon($icon);
+// }
+//
+ return $actor;
+ }
+
/**
* @param string $search
*
@@ -216,10 +247,40 @@ class PersonService implements ICoreService {
return;
}
+ if ($person->gotIcon()) {
+ try {
+ $icon = $this->cacheDocumentsRequest->getBySource(
+ $person->getIcon()
+ ->getUrl()
+ );
+ $person->setIcon($icon);
+ } catch (CacheDocumentDoesNotExistException $e) {
+ $this->cacheDocumentsRequest->save($person->getIcon());
+ }
+ }
+
$this->cacheActorsRequest->save($person);
}
+ /**
+ * @throws Exception
+ * @return int
+ */
+ public function manageCacheRemoteActors(): int {
+ $update = $this->cacheActorsRequest->getRemoteActorsToUpdate();
+
+ foreach ($update as $item) {
+ try {
+ $this->getFromId($item->getId(), true);
+ } catch (Exception $e) {
+ }
+ }
+
+ return sizeof($update);
+ }
+
+
/**
* @param ACore $item
*/
diff --git a/lib/Service/ActivityService.php b/lib/Service/ActivityService.php
index 7f402221..ac87e854 100644
--- a/lib/Service/ActivityService.php
+++ b/lib/Service/ActivityService.php
@@ -309,7 +309,7 @@ class ActivityService {
$localActor = $this->getActorFromItem($activity);
$localActorLink =
- $this->configService->getUrlRoot() . '@' . $localActor->getPreferredUsername();
+ $this->configService->getUrlSocial() . '@' . $localActor->getPreferredUsername();
$signature = "(request-target): post " . $path->getPath() . "\nhost: " . $path->getAddress()
. "\ndate: " . $date;
diff --git a/lib/Service/ActorService.php b/lib/Service/ActorService.php
index 25758d89..348d1a1f 100644
--- a/lib/Service/ActorService.php
+++ b/lib/Service/ActorService.php
@@ -128,18 +128,6 @@ class ActorService {
}
- /**
- * @param string $search
- *
- * @deprecated - used !?
- * @return Person[]
- * @throws SocialAppConfigException
- */
- public function searchLocalAccounts(string $search): array {
- return $this->actorsRequest->searchFromUsername($search);
- }
-
-
/**
* Method should be called by the frontend and will generate a fresh Social account for
* the user, using the userId and the username.
@@ -234,4 +222,22 @@ class ActorService {
}
+ /**
+ * @throws Exception
+ * @return int
+ */
+ public function manageCacheLocalActors(): int {
+ $update = $this->actorsRequest->getAll();
+
+ foreach ($update as $item) {
+ try {
+ $this->cacheLocalActorByUsername($item->getPreferredUsername(), true);
+ } catch (Exception $e) {
+ }
+ }
+
+ return sizeof($update);
+ }
+
+
}
diff --git a/lib/Service/CacheService.php b/lib/Service/CacheService.php
new file mode 100644
index 00000000..60c5827a
--- /dev/null
+++ b/lib/Service/CacheService.php
@@ -0,0 +1,170 @@
+
+ * @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 Exception;
+use OCA\Social\Exceptions\CacheContentException;
+use OCA\Social\Exceptions\CacheContentSizeException;
+use OCP\Files\IAppData;
+use OCP\Files\NotFoundException;
+use OCP\Files\NotPermittedException;
+use OCP\Files\SimpleFS\ISimpleFile;
+
+
+class CacheService {
+
+
+ const ERROR_MAX_SIZE = 1;
+
+
+ /** @var IAppData */
+ private $appData;
+
+ /** @var ConfigService */
+ private $configService;
+
+ /** @var MiscService */
+ private $miscService;
+
+
+ /**
+ * CacheService constructor.
+ *
+ * @param IAppData $appData
+ * @param ConfigService $configService
+ * @param MiscService $miscService
+ */
+ public function __construct(
+ IAppData $appData, ConfigService $configService, MiscService $miscService
+ ) {
+ $this->appData = $appData;
+ $this->configService = $configService;
+ $this->miscService = $miscService;
+ }
+
+
+ /**
+ * @param string $url
+ *
+ * @param string $mime
+ *
+ * @return string
+ * @throws CacheContentException
+ * @throws NotPermittedException
+ * @throws CacheContentSizeException
+ */
+ public function saveRemoteFileToCache(string $url, &$mime = '') {
+
+ $filename = sprintf(
+ '%04x%04x-%04x-%04x-%04x-%04x%04x%04x', mt_rand(0, 0xffff), mt_rand(0, 0xffff),
+ mt_rand(0, 0xffff), mt_rand(0, 0xfff) | 0x4000, mt_rand(0, 0x3fff) | 0x8000,
+ mt_rand(0, 0xffff), mt_rand(0, 0xffff), mt_rand(0, 0xffff)
+ );
+
+ // creating a path aa/bb/cc/dd/ from the filename aabbccdd-0123-[...]
+ $path = chunk_split(substr($filename, 0, 8), 2, '/');
+
+ try {
+ $folder = $this->appData->getFolder($path);
+ } catch (NotFoundException $e) {
+ $folder = $this->appData->newFolder($path);
+ }
+
+ $content = $this->retrieveContent($url);
+
+ // TODO - get mime type in a better way.
+ // To get the mime type, we create a temp file
+ $tmpFile = tmpfile();
+ $tmpPath = stream_get_meta_data($tmpFile)['uri'];
+ fwrite($tmpFile, $content);
+ $mime = mime_content_type($tmpPath);
+ fclose($tmpFile);
+
+ $cache = $folder->newFile($filename);
+ $cache->putContent($content);
+
+ return $path . $filename;
+ }
+
+
+ /**
+ * @param string $path
+ *
+ * @return ISimpleFile
+ * @throws CacheContentException
+ */
+ public function getContentFromCache(string $path) {
+
+ $pos = strrpos($path, '/');
+ $dir = substr($path, 0, $pos);
+ $filename = substr($path, $pos + 1);
+
+ try {
+ $file = $this->appData->getFolder($dir)
+ ->getFile($filename);
+
+ return $file;
+ } catch (Exception $e) {
+ throw new CacheContentException();
+ }
+ }
+
+
+ /**
+ * @param string $url
+ *
+ * @return string
+ * @throws CacheContentException
+ * @throws CacheContentSizeException
+ */
+ public function retrieveContent(string $url) {
+ $maxSize =
+ $this->configService->getAppValueInt(ConfigService::SOCIAL_MAX_SIZE) * 1024 * 1024;
+
+ $fd = fopen($url, "r");
+ if ($fd === false) {
+ throw new CacheContentException();
+ }
+
+ $content = '';
+ while (!feof($fd)) {
+ $content .= fread($fd, 4096);
+ if (strlen($content) > $maxSize) {
+ throw new CacheContentSizeException();
+ }
+ }
+ fclose($fd);
+
+ return $content;
+ }
+
+
+}
diff --git a/lib/Service/ConfigService.php b/lib/Service/ConfigService.php
index 4ecaa335..34d4bb16 100644
--- a/lib/Service/ConfigService.php
+++ b/lib/Service/ConfigService.php
@@ -52,10 +52,12 @@ class ConfigService {
const SOCIAL_ADDRESS = 'address';
+ const SOCIAL_MAX_SIZE = 'max_size';
/** @var array */
public $defaults = [
- self::SOCIAL_ADDRESS => ''
+ self::SOCIAL_ADDRESS => '',
+ self::SOCIAL_MAX_SIZE => 25
];
/** @var string */
@@ -111,6 +113,22 @@ class ConfigService {
return $this->config->getAppValue(Application::APP_NAME, $key, $defaultValue);
}
+ /**
+ * Get a value by key
+ *
+ * @param string $key
+ *
+ * @return int
+ */
+ public function getAppValueInt(string $key): int {
+ $defaultValue = null;
+ if (array_key_exists($key, $this->defaults)) {
+ $defaultValue = $this->defaults[$key];
+ }
+
+ return (int)$this->config->getAppValue(Application::APP_NAME, $key, $defaultValue);
+ }
+
/**
* Set a value by key
*
@@ -211,13 +229,11 @@ class ConfigService {
}
/**
- * @param bool $host
+ * @param string $cloudAddress
*
* @return string
- * @throws SocialAppConfigException
*/
public function setCloudAddress(string $cloudAddress) {
- // TODO: Validate
$this->setAppValue(self::SOCIAL_ADDRESS, $cloudAddress);
}
@@ -249,10 +265,12 @@ class ConfigService {
/**
+ * // TODO - check the Apps folder
+ *
* @return string
* @throws SocialAppConfigException
*/
- public function getUrlRoot(): string {
+ public function getUrlSocial(): string {
return $this->getCloudAddress() . '/apps/social/';
}
@@ -267,7 +285,7 @@ class ConfigService {
public function generateId(string $path = '', $generateId = true): string {
$path = $this->withoutBeginSlash($this->withEndSlash($path));
- $id = $this->getUrlRoot() . $path;
+ $id = $this->getUrlSocial() . $path;
if ($generateId === true) {
$id .= time() . crc32(uniqid());
}
diff --git a/lib/Service/ImportService.php b/lib/Service/ImportService.php
index 294c6acd..381fac1e 100644
--- a/lib/Service/ImportService.php
+++ b/lib/Service/ImportService.php
@@ -33,14 +33,18 @@ namespace OCA\Social\Service;
use daita\MySmallPhpTools\Traits\TArrayTools;
use Exception;
+use OCA\Social\Exceptions\SocialAppConfigException;
use OCA\Social\Exceptions\UnknownItemException;
+use OCA\Social\Exceptions\UrlCloudException;
use OCA\Social\Model\ActivityPub\ACore;
use OCA\Social\Model\ActivityPub\Activity\Accept;
use OCA\Social\Model\ActivityPub\Activity\Create;
use OCA\Social\Model\ActivityPub\Activity\Delete;
use OCA\Social\Model\ActivityPub\Activity\Reject;
use OCA\Social\Model\ActivityPub\Activity\Tombstone;
+use OCA\Social\Model\ActivityPub\Document;
use OCA\Social\Model\ActivityPub\Follow;
+use OCA\Social\Model\ActivityPub\Image;
use OCA\Social\Model\ActivityPub\Note;
use OCA\Social\Model\ActivityPub\Activity\Undo;
use OCA\Social\Service\ActivityPub\DeleteService;
@@ -67,6 +71,8 @@ class ImportService {
/** @var DeleteService */
private $deleteService;
+ private $configService;
+
/** @var MiscService */
private $miscService;
@@ -78,17 +84,18 @@ class ImportService {
* @param UndoService $undoService
* @param FollowService $followService
* @param DeleteService $deleteService
+ * @param ConfigService $configService
* @param MiscService $miscService
*/
public function __construct(
NoteService $noteService, UndoService $undoService, FollowService $followService,
- DeleteService $deleteService,
- MiscService $miscService
+ DeleteService $deleteService, ConfigService $configService, MiscService $miscService
) {
$this->noteService = $noteService;
$this->undoService = $undoService;
$this->followService = $followService;
$this->deleteService = $deleteService;
+ $this->configService = $configService;
$this->miscService = $miscService;
}
@@ -98,6 +105,8 @@ class ImportService {
*
* @return ACore
* @throws UnknownItemException
+ * @throws UrlCloudException
+ * @throws SocialAppConfigException
*/
public function import(string $json) {
$data = json_decode($json, true);
@@ -113,6 +122,8 @@ class ImportService {
*
* @return ACore
* @throws UnknownItemException
+ * @throws UrlCloudException
+ * @throws SocialAppConfigException
*/
private function createItem(array $data, $root = null): ACore {
@@ -133,6 +144,10 @@ class ImportService {
$item = new Note($root);
break;
+ case Image::TYPE:
+ $item = new Image($root);
+ break;
+
case Follow::TYPE:
$item = new Follow($root);
break;
@@ -153,6 +168,7 @@ class ImportService {
throw new UnknownItemException();
}
+ $item->setUrlCloud($this->configService->getCloudAddress());
$item->import($data);
$item->setSource(json_encode($data, JSON_UNESCAPED_SLASHES));
@@ -162,6 +178,13 @@ class ImportService {
} catch (UnknownItemException $e) {
}
+ try {
+ /** @var Document $icon */
+ $icon = $this->createItem($this->getArray('icon', $data, []), $item);
+ $item->setIcon($icon);
+ } catch (UnknownItemException $e) {
+ }
+
return $item;
}
@@ -205,6 +228,10 @@ class ImportService {
$service = $this->followService;
break;
+// case Image::TYPE:
+// $service = $this->imageService;
+// break;
+
case Note::TYPE:
$service = $this->noteService;
break;