summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSean Molenaar <sean@seanmolenaar.eu>2021-06-08 18:05:27 +0200
committerBenjamin Brahmer <info@b-brahmer.de>2021-06-16 11:32:19 +0200
commitfd01e9ad7b60081c1b4e54a42580987f3636f6cd (patch)
treefabc23552e807c9724cf2214f90de94713919098
parentbe45dd9830d04ce0fe967a697ff3c457ba7c302f (diff)
Search: add feed search
Signed-off-by: Sean Molenaar <sean@seanmolenaar.eu>
-rw-r--r--CHANGELOG.md1
-rw-r--r--lib/AppInfo/Application.php28
-rw-r--r--lib/Search/FeedSearchProvider.php79
-rw-r--r--tests/Unit/Search/FeedSearchProviderTest.php130
4 files changed, 212 insertions, 26 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 8fe49f304..4d2c04f9a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,6 +7,7 @@ The format is almost based on [Keep a Changelog](https://keepachangelog.com/en/1
## [16.x.x]
### Changed
+- added feed search (#1402)
### Fixed
- removed reference for deleted repair-steps (#1399)
## [15.x.x]
diff --git a/lib/AppInfo/Application.php b/lib/AppInfo/Application.php
index ea7beeae5..55f9b0ff5 100644
--- a/lib/AppInfo/Application.php
+++ b/lib/AppInfo/Application.php
@@ -19,9 +19,9 @@ use HTMLPurifier;
use HTMLPurifier_Config;
use Favicon\Favicon;
-use OCA\News\Config\LegacyConfig;
use OCA\News\Config\FetcherConfig;
use OCA\News\Hooks\UserDeleteHook;
+use OCA\News\Search\FeedSearchProvider;
use OCA\News\Search\FolderSearchProvider;
use OCP\AppFramework\Bootstrap\IBootContext;
@@ -29,8 +29,6 @@ use OCP\AppFramework\Bootstrap\IBootstrap;
use OCP\AppFramework\Bootstrap\IRegistrationContext;
use OCP\ITempManager;
use OCP\AppFramework\App;
-use OCP\Files\IRootFolder;
-use OCP\Files\Node;
use OCA\News\Fetcher\FeedFetcher;
use OCA\News\Fetcher\Fetcher;
@@ -83,12 +81,12 @@ class Application extends App implements IBootstrap
});
$context->registerSearchProvider(FolderSearchProvider::class);
+ $context->registerSearchProvider(FeedSearchProvider::class);
$context->registerEventListener(BeforeUserDeletedEvent::class, UserDeleteHook::class);
// parameters
$context->registerParameter('exploreDir', __DIR__ . '/../Explore/feeds');
- $context->registerParameter('configFile', 'config.ini');
$context->registerService(HTMLPurifier::class, function (ContainerInterface $c): HTMLPurifier {
$directory = $c->get(ITempManager::class)->getTempBaseDir() . '/news/cache/purifier';
@@ -142,28 +140,6 @@ class Application extends App implements IBootstrap
$favicon->cache(['dir' => $c->get(ITempManager::class)->getTempBaseDir()]);
return $favicon;
});
-
- //TODO: Remove code after 15.1
- $context->registerService('ConfigFolder', function (ContainerInterface $c): ?Node {
- /** @var IRootFolder $fs */
- $fs = $c->get(IRootFolder::class);
- $path = 'news/config';
- if ($fs->nodeExists($path)) {
- return $fs->get($path);
- } else {
- return null;
- }
- });
-
- //TODO: Remove code after 15.1
- $context->registerService(LegacyConfig::class, function (ContainerInterface $c): LegacyConfig {
- $config = new LegacyConfig(
- $c->get('ConfigFolder'),
- $c->get(LoggerInterface::class)
- );
- $config->read($c->get('configFile'), false);
- return $config;
- });
}
public function boot(IBootContext $context): void
diff --git a/lib/Search/FeedSearchProvider.php b/lib/Search/FeedSearchProvider.php
new file mode 100644
index 000000000..bbcd466e4
--- /dev/null
+++ b/lib/Search/FeedSearchProvider.php
@@ -0,0 +1,79 @@
+<?php
+declare(strict_types=1);
+
+namespace OCA\News\Search;
+
+use OCA\News\Service\FeedServiceV2;
+use OCA\News\Service\FolderServiceV2;
+use OCP\IL10N;
+use OCP\IURLGenerator;
+use OCP\IUser;
+use OCP\Search\IProvider;
+use OCP\Search\ISearchQuery;
+use OCP\Search\SearchResult;
+use OCP\Search\SearchResultEntry;
+
+/**
+ * Class FeedSearchProvider
+ *
+ * @package OCA\News\Search
+ */
+class FeedSearchProvider implements IProvider
+{
+ /** @var IL10N */
+ private $l10n;
+
+ /** @var IURLGenerator */
+ private $urlGenerator;
+
+ /** @var FeedServiceV2 */
+ private $service;
+
+ public function __construct(IL10N $l10n, IURLGenerator $urlGenerator, FeedServiceV2 $service)
+ {
+ $this->l10n = $l10n;
+ $this->urlGenerator = $urlGenerator;
+ $this->service = $service;
+ }
+
+ public function getId(): string
+ {
+ return 'news_feed';
+ }
+
+ public function getName(): string
+ {
+ return $this->l10n->t('News feeds');
+ }
+
+ public function getOrder(string $route, array $routeParameters): int
+ {
+ if ($route === 'news.page.index') {
+ // Active app, prefer my results
+ return -1;
+ }
+
+ return 60;
+ }
+
+ public function search(IUser $user, ISearchQuery $query): SearchResult
+ {
+ $list = [];
+ $term = strtolower($query->getTerm());
+
+ foreach ($this->service->findAllForUser($user->getUID()) as $feed) {
+ if (strpos(strtolower($feed->getTitle()), $term) === false) {
+ continue;
+ }
+
+ $list[] = new SearchResultEntry(
+ $this->urlGenerator->imagePath('core', 'filetypes/text.svg'),
+ $feed->getTitle(),
+ $this->l10n->t('Unread articles') . ': ' . $feed->getUnreadCount(),
+ $this->urlGenerator->linkToRoute('news.page.index') . '#/items/feeds/' . $feed->getId()
+ );
+ }
+
+ return SearchResult::complete($this->l10n->t('News'), $list);
+ }
+}
diff --git a/tests/Unit/Search/FeedSearchProviderTest.php b/tests/Unit/Search/FeedSearchProviderTest.php
new file mode 100644
index 000000000..97ec1f984
--- /dev/null
+++ b/tests/Unit/Search/FeedSearchProviderTest.php
@@ -0,0 +1,130 @@
+<?php
+
+namespace OCA\News\Search;
+
+use OCA\News\Db\Feed;
+use OCA\News\Service\FeedServiceV2;
+use OCP\IL10N;
+use OCP\IURLGenerator;
+use OCP\IUser;
+use OCP\Search\ISearchQuery;
+use PHPUnit\Framework\MockObject\MockObject;
+use PHPUnit\Framework\TestCase;
+
+class FeedSearchProviderTest extends TestCase
+{
+
+ /**
+ * @var MockObject|FeedServiceV2
+ */
+ private $folderService;
+
+ /**
+ * @var MockObject|IL10N
+ */
+ private $l10n;
+
+ /**
+ * @var MockObject|IURLGenerator
+ */
+ private $generator;
+
+ /**
+ * @var FeedSearchProvider
+ */
+ private $class;
+
+ protected function setUp(): void
+ {
+ $this->l10n = $this->getMockBuilder(IL10N::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $this->generator = $this->getMockBuilder(IURLGenerator::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $this->folderService = $this->getMockBuilder(FeedServiceV2::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $this->class = new FeedSearchProvider(
+ $this->l10n,
+ $this->generator,
+ $this->folderService
+ );
+ }
+
+ public function testGetId()
+ {
+ $this->assertSame('news_feed', $this->class->getId());
+ }
+
+ public function testGetName()
+ {
+ $this->l10n->expects($this->once())
+ ->method('t')
+ ->with('News feeds')
+ ->willReturnArgument(0);
+
+ $this->assertSame('News feeds', $this->class->getName());
+ }
+
+ public function testGetOrderExternal()
+ {
+ $this->assertSame(60, $this->class->getOrder('contacts.Page.index', []));
+ }
+
+ public function testGetOrderInternal()
+ {
+ $this->assertSame(-1, $this->class->getOrder('news.page.index', []));
+ }
+
+ public function testSearch()
+ {
+ $user = $this->getMockBuilder(IUser::class)
+ ->getMock();
+ $query = $this->getMockBuilder(ISearchQuery::class)
+ ->getMock();
+
+ $user->expects($this->once())
+ ->method('getUID')
+ ->willReturn('user');
+
+ $query->expects($this->once())
+ ->method('getTerm')
+ ->willReturn('Term');
+
+ $folders = [
+ Feed::fromRow(['id' => 1,'title' => 'some_tErm', 'unread_count'=> 1]),
+ Feed::fromRow(['id' => 2,'title' => 'nothing', 'unread_count'=> 1])
+ ];
+
+ $this->folderService->expects($this->once())
+ ->method('findAllForUser')
+ ->with('user')
+ ->willReturn($folders);
+
+ $this->l10n->expects($this->exactly(2))
+ ->method('t')
+ ->withConsecutive(['Unread articles'], ['News'])
+ ->willReturnArgument(0);
+
+ $this->generator->expects($this->once())
+ ->method('imagePath')
+ ->with('core', 'filetypes/text.svg')
+ ->willReturn('folderpath.svg');
+
+ $this->generator->expects($this->once())
+ ->method('linkToRoute')
+ ->with('news.page.index')
+ ->willReturn('/news');
+
+
+ $result = $this->class->search($user, $query)->jsonSerialize();
+ $entry = $result['entries'][0]->jsonSerialize();
+ $this->assertSame('News', $result['name']);
+ $this->assertSame('some_tErm', $entry['title']);
+ $this->assertSame('folderpath.svg', $entry['thumbnailUrl']);
+ $this->assertSame('Unread articles: 1', $entry['subline']);
+ $this->assertSame('/news#/items/feeds/1', $entry['resourceUrl']);
+ }
+}