Search: add feed search
Signed-off-by: Sean Molenaar <sean@seanmolenaar.eu>
This commit is contained in:
parent
be45dd9830
commit
fd01e9ad7b
|
@ -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]
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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']);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue