summaryrefslogtreecommitdiffstats
path: root/lib/Service
diff options
context:
space:
mode:
authorMaxence Lange <maxence@artificial-owl.com>2019-03-05 14:11:16 -0100
committerGitHub <noreply@github.com>2019-03-05 14:11:16 -0100
commita6ad99eed17b0318af731e8452a3eda092a676e6 (patch)
tree3acffb5d7e751c068b8f6989ddc32fa7910e6abc /lib/Service
parentee81f3717cc03f5aa80dea13d075e7eea3898059 (diff)
parent88f7a56aadd5e769c6714fb28cd9cd1907f84c61 (diff)
Merge branch 'master' into feature/noid/attachments
Diffstat (limited to 'lib/Service')
-rw-r--r--lib/Service/AccountService.php46
-rw-r--r--lib/Service/ActivityService.php34
-rw-r--r--lib/Service/ActorService.php39
-rw-r--r--lib/Service/CacheActorService.php17
-rw-r--r--lib/Service/CacheDocumentService.php8
-rw-r--r--lib/Service/CheckService.php2
-rw-r--r--lib/Service/ConfigService.php11
-rw-r--r--lib/Service/CurlService.php40
-rw-r--r--lib/Service/FollowService.php18
-rw-r--r--lib/Service/HashtagService.php233
-rw-r--r--lib/Service/ImportService.php3
-rw-r--r--lib/Service/NoteService.php186
-rw-r--r--lib/Service/PostService.php65
-rw-r--r--lib/Service/RequestQueueService.php (renamed from lib/Service/QueueService.php)4
-rw-r--r--lib/Service/SearchService.php190
-rw-r--r--lib/Service/SignatureService.php120
-rw-r--r--lib/Service/StreamQueueService.php386
17 files changed, 1223 insertions, 179 deletions
diff --git a/lib/Service/AccountService.php b/lib/Service/AccountService.php
index f94bd965..13dde24d 100644
--- a/lib/Service/AccountService.php
+++ b/lib/Service/AccountService.php
@@ -161,6 +161,7 @@ class AccountService {
* @throws NoUserException
* @throws SocialAppConfigException
* @throws UrlCloudException
+ * @throws ItemUnknownException
*/
public function getActorFromUserId(string $userId, bool $create = false): Person {
$this->miscService->confirmUserId($userId);
@@ -195,6 +196,7 @@ class AccountService {
* @throws NoUserException
* @throws SocialAppConfigException
* @throws UrlCloudException
+ * @throws ItemUnknownException
*/
public function createActor(string $userId, string $username) {
@@ -225,18 +227,18 @@ class AccountService {
$this->actorsRequest->create($actor);
// generate cache.
- $this->cacheLocalActorByUsername($username, true);
+ $this->cacheLocalActorByUsername($username);
}
/**
* @param string $username
- * @param bool $refresh
*
* @throws SocialAppConfigException
* @throws UrlCloudException
+ * @throws ItemUnknownException
*/
- public function cacheLocalActorByUsername(string $username, bool $refresh = false) {
+ public function cacheLocalActorByUsername(string $username) {
try {
$actor = $this->getActor($username);
@@ -252,14 +254,8 @@ class AccountService {
} catch (ItemUnknownException $e) {
}
- $count = [
- 'followers' => $this->followsRequest->countFollowers($actor->getId()),
- 'following' => $this->followsRequest->countFollowing($actor->getId()),
- 'post' => $this->notesRequest->countNotesFromActorId($actor->getId())
- ];
- $actor->addDetailArray('count', $count);
-
- $this->actorService->cacheLocalActor($actor, $refresh);
+ $this->addLocalActorDetailCount($actor);
+ $this->actorService->cacheLocalActor($actor);
} catch (ActorDoesNotExistException $e) {
}
}
@@ -267,6 +263,32 @@ class AccountService {
/**
* @param Person $actor
+ */
+ public function cacheLocalActorDetailCount(Person $actor) {
+ if (!$actor->isLocal()) {
+ return;
+ }
+
+ $this->addLocalActorDetailCount($actor);
+ $this->actorService->cacheLocalActor($actor);
+ }
+
+
+ /**
+ * @param Person $actor
+ */
+ public function addLocalActorDetailCount(Person &$actor) {
+ $count = [
+ 'followers' => $this->followsRequest->countFollowers($actor->getId()),
+ 'following' => $this->followsRequest->countFollowing($actor->getId()),
+ 'post' => $this->notesRequest->countNotesFromActorId($actor->getId())
+ ];
+ $actor->addDetailArray('count', $count);
+ }
+
+
+ /**
+ * @param Person $actor
*
* @throws NoUserException
*/
@@ -308,7 +330,7 @@ class AccountService {
$update = $this->actorsRequest->getAll();
foreach ($update as $item) {
try {
- $this->cacheLocalActorByUsername($item->getPreferredUsername(), true);
+ $this->cacheLocalActorByUsername($item->getPreferredUsername());
} catch (Exception $e) {
}
}
diff --git a/lib/Service/ActivityService.php b/lib/Service/ActivityService.php
index 904807cf..7c8dbc93 100644
--- a/lib/Service/ActivityService.php
+++ b/lib/Service/ActivityService.php
@@ -76,8 +76,8 @@ class ActivityService {
/** @var SignatureService */
private $signatureService;
- /** @var QueueService */
- private $queueService;
+ /** @var RequestQueueService */
+ private $requestQueueService;
/** @var AccountService */
private $accountService;
@@ -102,7 +102,7 @@ class ActivityService {
* @param NotesRequest $notesRequest
* @param FollowsRequest $followsRequest
* @param SignatureService $signatureService
- * @param QueueService $queueService
+ * @param RequestQueueService $requestQueueService
* @param AccountService $accountService
* @param CurlService $curlService
* @param ConfigService $configService
@@ -110,13 +110,13 @@ class ActivityService {
*/
public function __construct(
NotesRequest $notesRequest, FollowsRequest $followsRequest,
- SignatureService $signatureService, QueueService $queueService,
+ SignatureService $signatureService, RequestQueueService $requestQueueService,
AccountService $accountService, CurlService $curlService, ConfigService $configService,
MiscService $miscService
) {
$this->notesRequest = $notesRequest;
$this->followsRequest = $followsRequest;
- $this->queueService = $queueService;
+ $this->requestQueueService = $requestQueueService;
$this->accountService = $accountService;
$this->signatureService = $signatureService;
$this->curlService = $curlService;
@@ -131,7 +131,7 @@ class ActivityService {
* @param ACore $activity
*
* @return string
- * @throws Exception
+ * @throws SocialAppConfigException
*/
public function createActivity(Person $actor, ACore $item, ACore &$activity = null): string {
@@ -217,11 +217,11 @@ class ActivityService {
$author = $this->getAuthorFromItem($activity);
$instancePaths = $this->generateInstancePaths($activity);
- $token = $this->queueService->generateRequestQueue($instancePaths, $activity, $author);
+ $token = $this->requestQueueService->generateRequestQueue($instancePaths, $activity, $author);
$this->manageInit();
try {
- $directRequest = $this->queueService->getPriorityRequest($token);
+ $directRequest = $this->requestQueueService->getPriorityRequest($token);
$directRequest->setTimeout(self::TIMEOUT_LIVE);
$this->manageRequest($directRequest);
} catch (NoHighPriorityRequestException $e) {
@@ -229,7 +229,7 @@ class ActivityService {
return '';
}
- $requests = $this->queueService->getRequestFromToken($token, RequestQueue::STATUS_STANDBY);
+ $requests = $this->requestQueueService->getRequestFromToken($token, RequestQueue::STATUS_STANDBY);
if (sizeof($requests) > 0) {
$this->curlService->asyncWithToken($token);
}
@@ -256,7 +256,7 @@ class ActivityService {
}
try {
- $this->queueService->initRequest($queue);
+ $this->requestQueueService->initRequest($queue);
} catch (QueueStatusException $e) {
return;
}
@@ -266,24 +266,24 @@ class ActivityService {
try {
$this->signatureService->signRequest($request, $queue);
$this->curlService->request($request);
- $this->queueService->endRequest($queue, true);
+ $this->requestQueueService->endRequest($queue, true);
} catch (RequestResultNotJsonException $e) {
- $this->queueService->endRequest($queue, true);
+ $this->requestQueueService->endRequest($queue, true);
} catch (ActorDoesNotExistException $e) {
$this->miscService->log(
'Error while managing request: ' . json_encode($request) . ' ' . $e->getMessage(), 1
);
- $this->queueService->deleteRequest($queue);
+ $this->requestQueueService->deleteRequest($queue);
} catch (RequestContentException $e) {
$this->miscService->log(
'Error while managing request: ' . json_encode($request) . ' ' . $e->getMessage(), 1
);
- $this->queueService->deleteRequest($queue);
+ $this->requestQueueService->deleteRequest($queue);
} catch (RequestResultSizeException $e) {
$this->miscService->log(
'Error while managing request: ' . json_encode($request) . ' ' . $e->getMessage(), 1
);
- $this->queueService->deleteRequest($queue);
+ $this->requestQueueService->deleteRequest($queue);
} catch (RequestServerException $e) {
$this->miscService->log(
'Temporary error while managing request: RequestServerException - ' . json_encode(
@@ -291,7 +291,7 @@ class ActivityService {
) . ' - '
. $e->getMessage(), 1
);
- $this->queueService->endRequest($queue, false);
+ $this->requestQueueService->endRequest($queue, false);
$this->failInstances[] = $host;
} catch (RequestNetworkException $e) {
$this->miscService->log(
@@ -299,7 +299,7 @@ class ActivityService {
$request
) . ' - ' . $e->getMessage(), 1
);
- $this->queueService->endRequest($queue, false);
+ $this->requestQueueService->endRequest($queue, false);
$this->failInstances[] = $host;
}
}
diff --git a/lib/Service/ActorService.php b/lib/Service/ActorService.php
index fdf9df75..78b6620c 100644
--- a/lib/Service/ActorService.php
+++ b/lib/Service/ActorService.php
@@ -34,6 +34,7 @@ use daita\MySmallPhpTools\Traits\TArrayTools;
use OCA\Social\AP;
use OCA\Social\Db\CacheActorsRequest;
use OCA\Social\Db\CacheDocumentsRequest;
+use OCA\Social\Exceptions\CacheActorDoesNotExistException;
use OCA\Social\Exceptions\CacheDocumentDoesNotExistException;
use OCA\Social\Exceptions\ItemUnknownException;
use OCA\Social\Model\ActivityPub\Actor\Person;
@@ -66,10 +67,6 @@ class ActorService {
private $miscService;
- /** @var string */
- private $viewerId = '';
-
-
/**
* ActorService constructor.
*
@@ -94,31 +91,18 @@ class ActorService {
/**
- * @param string $viewerId
- */
- public function setViewerId(string $viewerId) {
- $this->viewerId = $viewerId;
- $this->cacheActorsRequest->setViewerId($viewerId);
- }
-
- public function getViewerId(): string {
- return $this->viewerId;
- }
-
-
- /**
* @param Person $actor
- * @param bool $refresh
*/
- public function cacheLocalActor(Person $actor, bool $refresh = false) {
- if ($refresh) {
- $this->cacheActorsRequest->deleteFromId($actor->getId());
- }
-
+ public function cacheLocalActor(Person $actor) {
$actor->setLocal(true);
$actor->setSource(json_encode($actor, JSON_UNESCAPED_SLASHES));
- $this->save($actor);
+ try {
+ $this->cacheActorsRequest->getFromId($actor->getId());
+ $this->update($actor);
+ } catch (CacheActorDoesNotExistException $e) {
+ $this->save($actor);
+ }
}
@@ -133,10 +117,13 @@ class ActorService {
/**
* @param Person $actor
+ *
+ * @return int
*/
- public function update(Person $actor) {
+ public function update(Person $actor): int {
$this->cacheDocumentIfNeeded($actor);
- $this->cacheActorsRequest->update($actor);
+
+ return $this->cacheActorsRequest->update($actor);
}
diff --git a/lib/Service/CacheActorService.php b/lib/Service/CacheActorService.php
index 6da7772a..5d16fc05 100644
--- a/lib/Service/CacheActorService.php
+++ b/lib/Service/CacheActorService.php
@@ -69,8 +69,8 @@ class CacheActorService {
private $miscService;
- /** @var string */
- private $viewerId;
+ /** @var Person */
+ private $viewer = null;
/**
@@ -93,15 +93,11 @@ class CacheActorService {
/**
- * @param string $viewerId
+ * @param Person $viewer
*/
- public function setViewerId(string $viewerId) {
- $this->viewerId = $viewerId;
- $this->cacheActorsRequest->setViewerId($viewerId);
- }
-
- public function getViewerId(): string {
- return $this->viewerId;
+ public function setViewer(Person $viewer) {
+ $this->viewer = $viewer;
+ $this->cacheActorsRequest->setViewer($viewer);
}
@@ -171,6 +167,7 @@ class CacheActorService {
if (strrpos($account, '@')) {
$account = substr($account, 0, strrpos($account, '@'));
}
+
return $this->cacheActorsRequest->getFromLocalAccount($account);
}
diff --git a/lib/Service/CacheDocumentService.php b/lib/Service/CacheDocumentService.php
index 8f5c3fe0..cf861a2f 100644
--- a/lib/Service/CacheDocumentService.php
+++ b/lib/Service/CacheDocumentService.php
@@ -33,6 +33,7 @@ namespace OCA\Social\Service;
use daita\MySmallPhpTools\Exceptions\MalformedArrayException;
use daita\MySmallPhpTools\Model\Request;
use daita\MySmallPhpTools\Traits\TArrayTools;
+use daita\MySmallPhpTools\Traits\TStringTools;
use Exception;
use OCA\Social\Exceptions\CacheContentException;
use OCA\Social\Exceptions\CacheContentMimeTypeException;
@@ -52,6 +53,7 @@ class CacheDocumentService {
use TArrayTools;
+ use TStringTools;
/** @var IAppData */
@@ -103,11 +105,7 @@ class CacheDocumentService {
*/
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)
- );
+ $filename = $this->uuid();
// creating a path aa/bb/cc/dd/ from the filename aabbccdd-0123-[...]
$path = chunk_split(substr($filename, 0, 8), 2, '/');
diff --git a/lib/Service/CheckService.php b/lib/Service/CheckService.php
index 281e4b38..ff3960b5 100644
--- a/lib/Service/CheckService.php
+++ b/lib/Service/CheckService.php
@@ -27,7 +27,7 @@ namespace OCA\Social\Service;
use daita\MySmallPhpTools\Traits\TArrayTools;
use daita\MySmallPhpTools\Traits\TStringTools;
use OCA\Social\Db\FollowsRequest;
-use OCA\Social\Model\ActivityPub\Activity\Follow;
+use OCA\Social\Model\ActivityPub\Object\Follow;
use OCP\AppFramework\Http;
use OCP\Http\Client\IClientService;
use OCP\ICache;
diff --git a/lib/Service/ConfigService.php b/lib/Service/ConfigService.php
index 7e4c04e1..4236b9de 100644
--- a/lib/Service/ConfigService.php
+++ b/lib/Service/ConfigService.php
@@ -242,6 +242,7 @@ class ConfigService {
return $this->config->getSystemValue($key, '');
}
+
/**
* @param string $cloudAddress
*/
@@ -277,13 +278,17 @@ class ConfigService {
/**
- * // TODO - check the Apps folder
+ * @param string $path
*
* @return string
* @throws SocialAppConfigException
*/
- public function getUrlSocial(): string {
- return $this->getCloudAddress() . '/apps/social/';
+ public function getUrlSocial(string $path = ''): string {
+ if ($path === '') {
+ $path = $this->urlGenerator->linkToRoute('social.Navigation.navigate');
+ }
+
+ return 'https://' . $this->getCloudAddress(true) . $path;
}
diff --git a/lib/Service/CurlService.php b/lib/Service/CurlService.php
index f9554670..8499bc3b 100644
--- a/lib/Service/CurlService.php
+++ b/lib/Service/CurlService.php
@@ -57,7 +57,7 @@ class CurlService {
use TPathTools;
- const ASYNC_TOKEN = '/async/token/{token}';
+ const ASYNC_REQUEST_TOKEN = '/async/request/{token}';
const USER_AGENT = 'Nextcloud Social';
@@ -90,21 +90,15 @@ class CurlService {
/**
* @param string $account
*
- * @return Person
- * @throws InvalidOriginException
+ * @return array
* @throws InvalidResourceException
- * @throws MalformedArrayException
- * @throws RedundancyLimitException
* @throws RequestContentException
- * @throws RetrieveAccountFormatException
* @throws RequestNetworkException
* @throws RequestResultSizeException
* @throws RequestServerException
- * @throws SocialAppConfigException
- * @throws ItemUnknownException
* @throws RequestResultNotJsonException
*/
- public function retrieveAccount(string $account): Person {
+ public function webfingerAccount(string $account): array {
$account = $this->withoutBeginAt($account);
// we consider an account is like an email
@@ -122,6 +116,29 @@ class CurlService {
$request->setAddress($host);
$result = $this->request($request);
+ return $result;
+ }
+
+
+ /**
+ * @param string $account
+ *
+ * @return Person
+ * @throws InvalidOriginException
+ * @throws InvalidResourceException
+ * @throws MalformedArrayException
+ * @throws RedundancyLimitException
+ * @throws RequestContentException
+ * @throws RetrieveAccountFormatException
+ * @throws RequestNetworkException
+ * @throws RequestResultSizeException
+ * @throws RequestServerException
+ * @throws SocialAppConfigException
+ * @throws ItemUnknownException
+ */
+ public function retrieveAccount(string $account): Person {
+ $result = $this->webfingerAccount($account);
+
try {
$link = $this->extractArray('rel', 'self', $this->getArray('links', $result));
} catch (ArrayNotFoundException $e) {
@@ -237,7 +254,7 @@ class CurlService {
$parse = parse_url($address);
$host = $this->get('host', $parse, '');
$path = $this->withEndSlash($this->get('path', $parse, '')) . $this->withoutBeginSlash(
- self::ASYNC_TOKEN
+ self::ASYNC_REQUEST_TOKEN
);
$path = str_replace('{token}', $token, $path);
@@ -274,6 +291,8 @@ class CurlService {
curl_setopt($curl, CURLOPT_BINARYTRANSFER, $request->isBinary());
curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
+ curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true);
+
$this->maxDownloadSize =
$this->configService->getAppValue(ConfigService::SOCIAL_MAX_SIZE) * (1024 * 1024);
curl_setopt($curl, CURLOPT_BUFFERSIZE, 128);
@@ -399,6 +418,7 @@ class CurlService {
}
}
+
/**
* @param int $code
* @param Request $request
diff --git a/lib/Service/FollowService.php b/lib/Service/FollowService.php
index 7998760c..e41cec6d 100644
--- a/lib/Service/FollowService.php
+++ b/lib/Service/FollowService.php
@@ -49,7 +49,7 @@ use OCA\Social\Exceptions\RequestServerException;
use OCA\Social\Exceptions\SocialAppConfigException;
use OCA\Social\Exceptions\ItemUnknownException;
use OCA\Social\Exceptions\UrlCloudException;
-use OCA\Social\Model\ActivityPub\Activity\Follow;
+use OCA\Social\Model\ActivityPub\Object\Follow;
use OCA\Social\Model\ActivityPub\Activity\Undo;
use OCA\Social\Model\ActivityPub\Actor\Person;
use OCA\Social\Model\ActivityPub\OrderedCollection;
@@ -77,8 +77,8 @@ class FollowService {
private $miscService;
- /** @var string */
- private $viewerId = '';
+ /** @var Person */
+ private $viewer = null;
/**
@@ -104,15 +104,11 @@ class FollowService {
/**
- * @param string $viewerId
+ * @param Person $viewer
*/
- public function setViewerId(string $viewerId) {
- $this->viewerId = $viewerId;
- $this->followsRequest->setViewerId($viewerId);
- }
-
- public function getViewerId(): string {
- return $this->viewerId;
+ public function setViewer(Person $viewer) {
+ $this->viewer = $viewer;
+ $this->followsRequest->setViewer($viewer);
}
diff --git a/lib/Service/HashtagService.php b/lib/Service/HashtagService.php
new file mode 100644
index 00000000..cf1b8e7e
--- /dev/null
+++ b/lib/Service/HashtagService.php
@@ -0,0 +1,233 @@
+<?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\TArrayTools;
+use OCA\Social\Db\HashtagsRequest;
+use OCA\Social\Db\NotesRequest;
+use OCA\Social\Exceptions\HashtagDoesNotExistException;
+
+
+class HashtagService {
+
+
+ const TREND_1H = 3600;
+ const TREND_12H = 43200;
+ const TREND_1D = 86400;
+ const TREND_3D = 259200;
+ const TREND_10D = 864000;
+
+
+ use TArrayTools;
+
+
+ /** @var HashtagsRequest */
+ private $hashtagsRequest;
+
+ /** @var NotesRequest */
+ private $notesRequest;
+
+ /** @var ConfigService */
+ private $configService;
+
+ /** @var MiscService */
+ private $miscService;
+
+
+ /**
+ * ImportService constructor.
+ *
+ * @param HashtagsRequest $hashtagsRequest
+ * @param NotesRequest $notesRequest
+ * @param ConfigService $configService
+ * @param MiscService $miscService
+ */
+ public function __construct(
+ HashtagsRequest $hashtagsRequest, NotesRequest $notesRequest, ConfigService $configService,
+ MiscService $miscService
+ ) {
+ $this->hashtagsRequest = $hashtagsRequest;
+ $this->notesRequest = $notesRequest;
+ $this->configService = $configService;
+ $this->miscService = $miscService;
+ }
+
+ /*
+ * note: trend is:
+ * [
+ * '1h' => x,
+ * '12h' => x,
+ * '1d' => x,
+ * '3d' => x,
+ * '10d' => x
+ * ]
+ */
+
+ /**
+ *
+ */
+ public function manageHashtags(): int {
+ $current = $this->hashtagsRequest->getAll();
+
+ $time = time();
+ $hashtags = [
+ '1h' => $this->getTrendSince($time - self::TREND_1H),
+ '12h' => $this->getTrendSince($time - self::TREND_12H),
+ '1d' => $this->getTrendSince($time - self::TREND_1D),
+ '3d' => $this->getTrendSince($time - self::TREND_3D),
+ '10d' => $this->getTrendSince($time - self::TREND_10D)
+ ];
+
+ $count = 0;
+ $formatted = $this->formatTrend($hashtags);
+ foreach ($formatted as $hashtag => $trend) {
+ $count++;
+ try {
+ $this->getFromList($current, $hashtag);
+ $this->hashtagsRequest->update($hashtag, $trend);
+ } catch (HashtagDoesNotExistException $e) {
+ $this->hashtagsRequest->save($hashtag, $trend);
+ }
+ }
+
+ return $count;
+ }
+
+
+ /**
+ * @param string $hashtag
+ *
+ * @return array
+ * @throws HashtagDoesNotExistException
+ */
+ public function getHashtag(string $hashtag): array {
+ if (substr($hashtag, 0, 1) !== '#') {
+ $hashtag = '#' . $hashtag;
+ }
+
+ return $this->hashtagsRequest->getHashtag($hashtag);
+ }
+
+
+ /**
+ * @param string $hashtag
+ *
+ * @return array
+ */
+ public function searchHashtags(string $hashtag): array {
+ return $this->hashtagsRequest->searchHashtags($hashtag);
+ }
+
+
+ /**
+ * @param int $timestamp
+ *
+ * @return array
+ */
+ private function getTrendSince(int $timestamp): array {
+ $result = [];
+
+ $notes = $this->notesRequest->getNotesSince($timestamp);
+ foreach ($notes as $note) {
+
+ foreach ($note->getHashtags() as $hashtag) {
+ if (array_key_exists($hashtag, $result)) {
+ $result[$hashtag]++;
+ } else {
+ $result[$hashtag] = 1;
+ }
+ }
+ }
+
+ return $result;
+ }
+
+
+ /**
+ * @param array $hashtags
+ *
+ * @return array
+ */
+ private function formatTrend(array $hashtags): array {
+ $trends = [];
+ foreach (end($hashtags) as $hashtag => $count) {
+ $trends[$hashtag] = [];
+ }
+
+ $all = array_keys($trends);
+ $periods = array_keys($hashtags);
+ foreach ($all as $hashtag) {
+ foreach ($periods as $period) {
+ $count = $this->countFromList($hashtags[$period], $hashtag);
+ $trends[$hashtag][$period] = $count;
+ }
+ }
+
+ return $trends;
+ }
+
+
+ /**
+ * @param array $list
+ * @param string $hashtag
+ *
+ * @return int
+ */
+ private function countFromList(array $list, string $hashtag): int {
+ foreach ($list as $key => $count) {
+ if ($key === $hashtag) {
+ return $count;
+ }
+ }
+
+ return 0;
+ }
+
+
+ /**
+ * @param array $list
+ * @param string $hashtag
+ *
+ * @return array
+ * @throws HashtagDoesNotExistException
+ */
+ private function getFromList(array $list, string $hashtag): array {
+ foreach ($list as $item) {
+ if ($this->get('hashtag', $item, '') === $hashtag) {
+ return $item;
+ }
+ }
+
+ throw new HashtagDoesNotExistException();
+ }
+}
+
diff --git a/lib/Service/ImportService.php b/lib/Service/ImportService.php
index 24d8390e..de25268a 100644
--- a/lib/Service/ImportService.php
+++ b/lib/Service/ImportService.php
@@ -32,6 +32,7 @@ namespace OCA\Social\Service;
use daita\MySmallPhpTools\Traits\TArrayTools;
+use daita\MySmallPhpTools\Traits\TStringTools;
use Exception;
use OCA\Social\AP;
use OCA\Social\Exceptions\ActivityPubFormatException;
@@ -46,6 +47,7 @@ class ImportService {
use TArrayTools;
+ use TStringTools;
/** @var ConfigService */
@@ -94,6 +96,7 @@ class ImportService {
*/
public function parseIncomingRequest(ACore $activity) {
$activity->checkOrigin($activity->getId());
+ $activity->setRequestToken($this->uuid());
$interface = AP::$activityPub->getInterfaceForItem($activity);
try {
diff --git a/lib/Service/NoteService.php b/lib/Service/NoteService.php
index c832659c..d0bf47ac 100644
--- a/lib/Service/NoteService.php
+++ b/