mirror of
https://github.com/chylex/Nextcloud-News.git
synced 2025-04-26 05:15:46 +02:00
Remove PHPunit integration tests
Signed-off-by: Sean Molenaar <sean@seanmolenaar.eu>
This commit is contained in:
parent
27bd540580
commit
05377d023e
CHANGELOG.mdphpunit.xml
lib
Command/Updater
Controller
EntityApiSerializer.phpFeedApiController.phpFeedController.phpFolderController.phpItemController.php
Db
Fetcher
Hooks
Service
tests/Unit
@ -1,10 +1,13 @@
|
||||
# Changelog
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is almost based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), older entries don't fully match.
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
### Changed
|
||||
- Remove outdated feed DB code
|
||||
- add background & hover for entries
|
||||
|
||||
## [15.1.1] - 2020-12-27
|
||||
|
||||
### Changed
|
||||
|
@ -51,7 +51,7 @@ class UpdateFeed extends Command
|
||||
$feedId = $input->getArgument('feed-id');
|
||||
$userId = $input->getArgument('user-id');
|
||||
try {
|
||||
$feed = $this->feedService->findForUser($userId, $feedId);
|
||||
$feed = $this->feedService->find($userId, $feedId);
|
||||
$updated_feed = $this->feedService->fetch($feed);
|
||||
} catch (\Exception $e) {
|
||||
$output->writeln(
|
||||
|
@ -1,76 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* Nextcloud - News
|
||||
*
|
||||
* This file is licensed under the Affero General Public License version 3 or
|
||||
* later. See the COPYING file.
|
||||
*
|
||||
* @author Bernhard Posselt <dev@bernhard-posselt.com>
|
||||
* @copyright 2012-2014 Bernhard Posselt
|
||||
*/
|
||||
|
||||
namespace OCA\News\Controller;
|
||||
|
||||
use \OCA\News\Db\IAPI;
|
||||
|
||||
/**
|
||||
* Class EntityApiSerializer
|
||||
*
|
||||
* @package OCA\News\Controller
|
||||
* @deprecated use ApiPayloadTrait
|
||||
*/
|
||||
class EntityApiSerializer
|
||||
{
|
||||
|
||||
private $level;
|
||||
|
||||
public function __construct($level)
|
||||
{
|
||||
$this->level = $level;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Call toAPI() method on all entities. Works on
|
||||
*
|
||||
* @param mixed $data :
|
||||
* * Entity
|
||||
* * Entity[]
|
||||
* * array('level' => Entity[])
|
||||
* * Response
|
||||
* @return array|mixed
|
||||
*/
|
||||
public function serialize($data)
|
||||
{
|
||||
|
||||
if ($data instanceof IAPI) {
|
||||
return [$this->level => [$data->toAPI()]];
|
||||
}
|
||||
|
||||
if (is_array($data) && array_key_exists($this->level, $data)) {
|
||||
$data[$this->level] = $this->convert($data[$this->level]);
|
||||
} elseif (is_array($data)) {
|
||||
$data = [$this->level => $this->convert($data)];
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
|
||||
private function convert(array $entities)
|
||||
{
|
||||
$converted = [];
|
||||
|
||||
foreach ($entities as $entity) {
|
||||
if ($entity instanceof IAPI) {
|
||||
$converted[] = $entity->toAPI();
|
||||
|
||||
// break if it contains anything else than entities
|
||||
} else {
|
||||
return $entities;
|
||||
}
|
||||
}
|
||||
|
||||
return $converted;
|
||||
}
|
||||
}
|
@ -25,10 +25,8 @@ use \OCP\IRequest;
|
||||
use \OCP\IUserSession;
|
||||
use \OCP\AppFramework\Http;
|
||||
|
||||
use \OCA\News\Service\FeedService;
|
||||
use \OCA\News\Service\ItemService;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use function GuzzleHttp\Psr7\uri_for;
|
||||
|
||||
class FeedApiController extends ApiController
|
||||
{
|
||||
@ -45,12 +43,6 @@ class FeedApiController extends ApiController
|
||||
*/
|
||||
private $feedService;
|
||||
|
||||
/**
|
||||
* TODO: Remove
|
||||
* @var FeedService
|
||||
*/
|
||||
private $oldFeedService;
|
||||
|
||||
/**
|
||||
* @var LoggerInterface
|
||||
*/
|
||||
@ -64,14 +56,12 @@ class FeedApiController extends ApiController
|
||||
public function __construct(
|
||||
IRequest $request,
|
||||
?IUserSession $userSession,
|
||||
FeedService $oldFeedService,
|
||||
FeedServiceV2 $feedService,
|
||||
ItemService $oldItemService,
|
||||
LoggerInterface $logger
|
||||
) {
|
||||
parent::__construct($request, $userSession);
|
||||
$this->feedService = $feedService;
|
||||
$this->oldFeedService = $oldFeedService;
|
||||
$this->oldItemService = $oldItemService;
|
||||
$this->logger = $logger;
|
||||
}
|
||||
@ -189,11 +179,9 @@ class FeedApiController extends ApiController
|
||||
}
|
||||
|
||||
try {
|
||||
$this->oldFeedService->patch(
|
||||
$feedId,
|
||||
$this->getUserId(),
|
||||
['folderId' => $folderId]
|
||||
);
|
||||
$feed = $this->feedService->find($this->getUserId(), $feedId);
|
||||
$feed->setFolderId($folderId);
|
||||
$this->feedService->update($this->getUserId(), $feed);
|
||||
} catch (ServiceNotFoundException $ex) {
|
||||
return $this->error($ex, Http::STATUS_NOT_FOUND);
|
||||
}
|
||||
@ -215,11 +203,9 @@ class FeedApiController extends ApiController
|
||||
public function rename(int $feedId, string $feedTitle)
|
||||
{
|
||||
try {
|
||||
$this->oldFeedService->patch(
|
||||
$feedId,
|
||||
$this->getUserId(),
|
||||
['title' => $feedTitle]
|
||||
);
|
||||
$feed = $this->feedService->find($this->getUserId(), $feedId);
|
||||
$feed->setTitle($feedTitle);
|
||||
$this->feedService->update($this->getUserId(), $feed);
|
||||
} catch (ServiceNotFoundException $ex) {
|
||||
return $this->error($ex, Http::STATUS_NOT_FOUND);
|
||||
}
|
||||
|
@ -15,14 +15,15 @@ namespace OCA\News\Controller;
|
||||
|
||||
use OCA\News\Service\Exceptions\ServiceConflictException;
|
||||
use OCA\News\Service\Exceptions\ServiceNotFoundException;
|
||||
use OCA\News\Service\FeedServiceV2;
|
||||
use OCA\News\Service\FolderServiceV2;
|
||||
use OCA\News\Service\ImportService;
|
||||
use OCP\AppFramework\Http\JSONResponse;
|
||||
use OCP\IRequest;
|
||||
use OCP\IConfig;
|
||||
use OCP\AppFramework\Http;
|
||||
|
||||
use OCA\News\Service\ItemService;
|
||||
use OCA\News\Service\FeedService;
|
||||
use OCA\News\Db\FeedType;
|
||||
use OCP\IUserSession;
|
||||
|
||||
@ -30,7 +31,9 @@ class FeedController extends Controller
|
||||
{
|
||||
use JSONHttpErrorTrait;
|
||||
|
||||
//TODO: Remove
|
||||
/**
|
||||
* @var FeedServiceV2
|
||||
*/
|
||||
private $feedService;
|
||||
//TODO: Remove
|
||||
private $itemService;
|
||||
@ -38,6 +41,10 @@ class FeedController extends Controller
|
||||
* @var FolderServiceV2
|
||||
*/
|
||||
private $folderService;
|
||||
/**
|
||||
* @var ImportService
|
||||
*/
|
||||
private $importService;
|
||||
/**
|
||||
* @var IConfig
|
||||
*/
|
||||
@ -46,8 +53,9 @@ class FeedController extends Controller
|
||||
public function __construct(
|
||||
IRequest $request,
|
||||
FolderServiceV2 $folderService,
|
||||
FeedService $feedService,
|
||||
FeedServiceV2 $feedService,
|
||||
ItemService $itemService,
|
||||
ImportService $importService,
|
||||
IConfig $settings,
|
||||
?IUserSession $userSession
|
||||
) {
|
||||
@ -55,6 +63,7 @@ class FeedController extends Controller
|
||||
$this->folderService = $folderService;
|
||||
$this->feedService = $feedService;
|
||||
$this->itemService = $itemService;
|
||||
$this->importService = $importService;
|
||||
$this->settings = $settings;
|
||||
}
|
||||
|
||||
@ -74,12 +83,13 @@ class FeedController extends Controller
|
||||
];
|
||||
|
||||
try {
|
||||
$params['newestItemId'] =
|
||||
$this->itemService->getNewestItemId($this->getUserId());
|
||||
$id = $this->itemService->getNewestItemId($this->getUserId());
|
||||
|
||||
// An exception occurs if there is a newest item. If there is none,
|
||||
// simply ignore it and do not add the newestItemId
|
||||
$params['newestItemId'] = $id;
|
||||
} catch (ServiceNotFoundException $ex) {
|
||||
//NO-OP
|
||||
}
|
||||
|
||||
return $params;
|
||||
@ -102,24 +112,22 @@ class FeedController extends Controller
|
||||
'lastViewedFeedType'
|
||||
);
|
||||
|
||||
// cast from null to int is 0
|
||||
if ($feedType !== null) {
|
||||
$feedType = (int) $feedType;
|
||||
}
|
||||
|
||||
// check if feed or folder exists
|
||||
try {
|
||||
if ($feedType === FeedType::FOLDER) {
|
||||
if ($feedId === 0) {
|
||||
$feedId = null;
|
||||
}
|
||||
$this->folderService->find($this->getUserId(), $feedId);
|
||||
} elseif ($feedType === FeedType::FEED) {
|
||||
$this->feedService->find($this->getUserId(), $feedId);
|
||||
if ($feedType === null) {
|
||||
throw new ServiceNotFoundException('First launch');
|
||||
}
|
||||
|
||||
// if its the first launch, those values will be null
|
||||
} elseif ($feedType === null) {
|
||||
throw new ServiceNotFoundException('');
|
||||
$feedType = intval($feedType);
|
||||
switch ($feedType) {
|
||||
case FeedType::FOLDER:
|
||||
$this->folderService->find($this->getUserId(), $feedId);
|
||||
break;
|
||||
case FeedType::FEED:
|
||||
$this->feedService->find($this->getUserId(), $feedId);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} catch (ServiceNotFoundException $ex) {
|
||||
$feedId = 0;
|
||||
@ -162,9 +170,10 @@ class FeedController extends Controller
|
||||
$this->feedService->purgeDeleted($this->getUserId(), false);
|
||||
|
||||
$feed = $this->feedService->create(
|
||||
$this->getUserId(),
|
||||
$url,
|
||||
$parentFolderId,
|
||||
$this->getUserId(),
|
||||
false,
|
||||
$title,
|
||||
$user,
|
||||
$password
|
||||
@ -172,12 +181,12 @@ class FeedController extends Controller
|
||||
$params = ['feeds' => [$feed]];
|
||||
|
||||
try {
|
||||
$params['newestItemId'] =
|
||||
$this->itemService->getNewestItemId($this->getUserId());
|
||||
|
||||
$id = $this->itemService->getNewestItemId($this->getUserId());
|
||||
// An exception occurs if there is a newest item. If there is none,
|
||||
// simply ignore it and do not add the newestItemId
|
||||
$params['newestItemId'] = $id;
|
||||
} catch (ServiceNotFoundException $ex) {
|
||||
//NO-OP
|
||||
}
|
||||
|
||||
return $params;
|
||||
@ -199,7 +208,9 @@ class FeedController extends Controller
|
||||
public function delete(int $feedId)
|
||||
{
|
||||
try {
|
||||
$this->feedService->markDeleted($feedId, $this->getUserId());
|
||||
$feed = $this->feedService->find($this->getUserId(), $feedId);
|
||||
$feed->setDeletedAt(time());
|
||||
$this->feedService->update($this->getUserId(), $feed);
|
||||
} catch (ServiceNotFoundException $ex) {
|
||||
return $this->error($ex, Http::STATUS_NOT_FOUND);
|
||||
}
|
||||
@ -218,7 +229,8 @@ class FeedController extends Controller
|
||||
public function update(int $feedId)
|
||||
{
|
||||
try {
|
||||
$feed = $this->feedService->update($this->getUserId(), $feedId);
|
||||
$old_feed = $this->feedService->find($this->getUserId(), $feedId);
|
||||
$feed = $this->feedService->fetch($old_feed);
|
||||
|
||||
return [
|
||||
'feeds' => [
|
||||
@ -244,7 +256,7 @@ class FeedController extends Controller
|
||||
*/
|
||||
public function import(array $json): array
|
||||
{
|
||||
$feed = $this->feedService->importArticles($json, $this->getUserId());
|
||||
$feed = $this->importService->importArticles($this->getUserId(), $json);
|
||||
|
||||
$params = [
|
||||
'starred' => $this->itemService->starredCount($this->getUserId())
|
||||
@ -290,7 +302,9 @@ class FeedController extends Controller
|
||||
public function restore(int $feedId)
|
||||
{
|
||||
try {
|
||||
$this->feedService->unmarkDeleted($feedId, $this->getUserId());
|
||||
$feed = $this->feedService->find($this->getUserId(), $feedId);
|
||||
$feed->setDeletedAt(null);
|
||||
$this->feedService->update($this->getUserId(), $feed);
|
||||
} catch (ServiceNotFoundException $ex) {
|
||||
return $this->error($ex, Http::STATUS_NOT_FOUND);
|
||||
}
|
||||
@ -320,24 +334,32 @@ class FeedController extends Controller
|
||||
?int $folderId = null,
|
||||
?string $title = null
|
||||
) {
|
||||
$attributes = [
|
||||
'pinned' => $pinned,
|
||||
'fullTextEnabled' => $fullTextEnabled,
|
||||
'updateMode' => $updateMode,
|
||||
'ordering' => $ordering,
|
||||
'title' => $title,
|
||||
'folderId' => $folderId === 0 ? null : $folderId
|
||||
];
|
||||
try {
|
||||
$feed = $this->feedService->find($this->getUserId(), $feedId);
|
||||
} catch (ServiceNotFoundException $ex) {
|
||||
return $this->error($ex, Http::STATUS_NOT_FOUND);
|
||||
}
|
||||
|
||||
$diff = array_filter(
|
||||
$attributes,
|
||||
function ($value) {
|
||||
return $value !== null;
|
||||
}
|
||||
);
|
||||
$fId = $folderId === 0 ? null : $folderId;
|
||||
$feed->setFolderId($fId);
|
||||
if ($pinned !== null) {
|
||||
$feed->setPinned($pinned);
|
||||
}
|
||||
if ($fullTextEnabled !== null) {
|
||||
$feed->setFullTextEnabled($fullTextEnabled);
|
||||
}
|
||||
if ($updateMode !== null) {
|
||||
$feed->setUpdateMode($updateMode);
|
||||
}
|
||||
if ($ordering !== null) {
|
||||
$feed->setOrdering($ordering);
|
||||
}
|
||||
if ($title !== null) {
|
||||
$feed->setTitle($title);
|
||||
}
|
||||
|
||||
try {
|
||||
$this->feedService->patch($feedId, $this->getUserId(), $diff);
|
||||
$this->feedService->update($this->getUserId(), $feed);
|
||||
} catch (ServiceNotFoundException $ex) {
|
||||
return $this->error($ex, Http::STATUS_NOT_FOUND);
|
||||
}
|
||||
|
@ -14,12 +14,12 @@
|
||||
namespace OCA\News\Controller;
|
||||
|
||||
use OCA\News\Service\Exceptions\ServiceException;
|
||||
use OCA\News\Service\FeedServiceV2;
|
||||
use OCP\AppFramework\Http\JSONResponse;
|
||||
use \OCP\IRequest;
|
||||
use \OCP\AppFramework\Http;
|
||||
|
||||
use \OCA\News\Service\FolderServiceV2;
|
||||
use \OCA\News\Service\FeedService;
|
||||
use \OCA\News\Service\ItemService;
|
||||
use \OCA\News\Service\Exceptions\ServiceNotFoundException;
|
||||
use \OCA\News\Service\Exceptions\ServiceConflictException;
|
||||
@ -33,7 +33,9 @@ class FolderController extends Controller
|
||||
* @var FolderServiceV2
|
||||
*/
|
||||
private $folderService;
|
||||
//TODO: Remove
|
||||
/**
|
||||
* @var FeedServiceV2
|
||||
*/
|
||||
private $feedService;
|
||||
//TODO: Remove
|
||||
private $itemService;
|
||||
@ -41,7 +43,7 @@ class FolderController extends Controller
|
||||
public function __construct(
|
||||
IRequest $request,
|
||||
FolderServiceV2 $folderService,
|
||||
FeedService $feedService,
|
||||
FeedServiceV2 $feedService,
|
||||
ItemService $itemService,
|
||||
?IUserSession $userSession
|
||||
) {
|
||||
|
@ -13,6 +13,7 @@
|
||||
|
||||
namespace OCA\News\Controller;
|
||||
|
||||
use OCA\News\Service\FeedServiceV2;
|
||||
use \OCP\IRequest;
|
||||
use \OCP\IConfig;
|
||||
use \OCP\AppFramework\Http;
|
||||
@ -20,7 +21,6 @@ use \OCP\AppFramework\Http;
|
||||
use \OCA\News\Service\Exceptions\ServiceException;
|
||||
use \OCA\News\Service\Exceptions\ServiceNotFoundException;
|
||||
use \OCA\News\Service\ItemService;
|
||||
use \OCA\News\Service\FeedService;
|
||||
use OCP\IUserSession;
|
||||
|
||||
class ItemController extends Controller
|
||||
@ -28,12 +28,18 @@ class ItemController extends Controller
|
||||
use JSONHttpErrorTrait;
|
||||
|
||||
private $itemService;
|
||||
/**
|
||||
* @var FeedServiceV2
|
||||
*/
|
||||
private $feedService;
|
||||
/**
|
||||
* @var IConfig
|
||||
*/
|
||||
private $settings;
|
||||
|
||||
public function __construct(
|
||||
IRequest $request,
|
||||
FeedService $feedService,
|
||||
FeedServiceV2 $feedService,
|
||||
ItemService $itemService,
|
||||
IConfig $settings,
|
||||
?IUserSession $userSession
|
||||
|
@ -25,6 +25,16 @@ class Feed extends Entity implements IAPI, \JsonSerializable
|
||||
{
|
||||
use EntityJSONSerializer;
|
||||
|
||||
/**
|
||||
* Silently import new items
|
||||
*/
|
||||
const UPDATE_MODE_SILENT = 0;
|
||||
|
||||
/**
|
||||
* Mark new items as unread.
|
||||
*/
|
||||
const UPDATE_MODE_NORMAL = 1;
|
||||
|
||||
/** @var string */
|
||||
protected $userId = '';
|
||||
/** @var string */
|
||||
|
@ -1,202 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* Nextcloud - News
|
||||
*
|
||||
* This file is licensed under the Affero General Public License version 3 or
|
||||
* later. See the COPYING file.
|
||||
*
|
||||
* @author Alessandro Cosentino <cosenal@gmail.com>
|
||||
* @author Bernhard Posselt <dev@bernhard-posselt.com>
|
||||
* @copyright 2012 Alessandro Cosentino
|
||||
* @copyright 2012-2014 Bernhard Posselt
|
||||
*/
|
||||
|
||||
namespace OCA\News\Db;
|
||||
|
||||
use OCA\News\Utility\Time;
|
||||
use OCP\AppFramework\Db\DoesNotExistException;
|
||||
use OCP\AppFramework\Db\MultipleObjectsReturnedException;
|
||||
use OCP\IDBConnection;
|
||||
use OCP\AppFramework\Db\Entity;
|
||||
|
||||
/**
|
||||
* Class LegacyFeedMapper
|
||||
*
|
||||
* @package OCA\News\Db
|
||||
* @deprecated use FeedMapper
|
||||
*/
|
||||
class FeedMapper extends NewsMapper
|
||||
{
|
||||
const TABLE_NAME = 'news_feeds';
|
||||
|
||||
public function __construct(IDBConnection $db, Time $time)
|
||||
{
|
||||
parent::__construct($db, $time, Feed::class);
|
||||
}
|
||||
|
||||
|
||||
public function find(string $userId, int $id)
|
||||
{
|
||||
$sql = 'SELECT `feeds`.*, `item_numbers`.`unread_count` ' .
|
||||
'FROM `*PREFIX*news_feeds` `feeds` ' .
|
||||
'JOIN ( ' .
|
||||
'SELECT `feeds`.`id`, COUNT(`items`.`id`) AS `unread_count` ' .
|
||||
'FROM `*PREFIX*news_feeds` `feeds` ' .
|
||||
'LEFT JOIN `*PREFIX*news_items` `items` ' .
|
||||
'ON `feeds`.`id` = `items`.`feed_id` ' .
|
||||
// WARNING: this is a desperate attempt at making this query
|
||||
// work because prepared statements dont work. This is a
|
||||
// POSSIBLE SQL INJECTION RISK WHEN MODIFIED WITHOUT THOUGHT.
|
||||
// think twice when changing this
|
||||
'AND `items`.`unread` = ? ' .
|
||||
'WHERE `feeds`.`id` = ? ' .
|
||||
'AND `feeds`.`user_id` = ? ' .
|
||||
'GROUP BY `feeds`.`id` ' .
|
||||
') `item_numbers` ' .
|
||||
'ON `item_numbers`.`id` = `feeds`.`id` ';
|
||||
$params = [true, $id, $userId];
|
||||
|
||||
return $this->findEntity($sql, $params);
|
||||
}
|
||||
|
||||
|
||||
public function findAllFromUser(string $userId): array
|
||||
{
|
||||
$sql = 'SELECT `feeds`.*, `item_numbers`.`unread_count` ' .
|
||||
'FROM `*PREFIX*news_feeds` `feeds` ' .
|
||||
'JOIN ( ' .
|
||||
'SELECT `feeds`.`id`, COUNT(`items`.`id`) AS `unread_count` ' .
|
||||
'FROM `*PREFIX*news_feeds` `feeds` ' .
|
||||
'LEFT OUTER JOIN `*PREFIX*news_folders` `folders` ' .
|
||||
'ON `feeds`.`folder_id` = `folders`.`id` ' .
|
||||
'LEFT JOIN `*PREFIX*news_items` `items` ' .
|
||||
'ON `feeds`.`id` = `items`.`feed_id` ' .
|
||||
// WARNING: this is a desperate attempt at making this query
|
||||
// work because prepared statements dont work. This is a
|
||||
// POSSIBLE SQL INJECTION RISK WHEN MODIFIED WITHOUT THOUGHT.
|
||||
// think twice when changing this
|
||||
'AND `items`.`unread` = ? ' .
|
||||
'WHERE `feeds`.`user_id` = ? ' .
|
||||
'AND (`feeds`.`folder_id` IS NULL ' .
|
||||
'OR `folders`.`deleted_at` = 0 ' .
|
||||
') ' .
|
||||
'AND `feeds`.`deleted_at` = 0 ' .
|
||||
'GROUP BY `feeds`.`id` ' .
|
||||
') `item_numbers` ' .
|
||||
'ON `item_numbers`.`id` = `feeds`.`id` ';
|
||||
$params = [true, $userId];
|
||||
|
||||
return $this->findEntities($sql, $params);
|
||||
}
|
||||
|
||||
|
||||
public function findAll(): array
|
||||
{
|
||||
$sql = 'SELECT `feeds`.*, `item_numbers`.`unread_count` ' .
|
||||
'FROM `*PREFIX*news_feeds` `feeds` ' .
|
||||
'JOIN ( ' .
|
||||
'SELECT `feeds`.`id`, COUNT(`items`.`id`) AS `unread_count` ' .
|
||||
'FROM `*PREFIX*news_feeds` `feeds` ' .
|
||||
'LEFT OUTER JOIN `*PREFIX*news_folders` `folders` ' .
|
||||
'ON `feeds`.`folder_id` = `folders`.`id` ' .
|
||||
'LEFT JOIN `*PREFIX*news_items` `items` ' .
|
||||
'ON `feeds`.`id` = `items`.`feed_id` ' .
|
||||
// WARNING: this is a desperate attempt at making this query
|
||||
// work because prepared statements dont work. This is a
|
||||
// POSSIBLE SQL INJECTION RISK WHEN MODIFIED WITHOUT THOUGHT.
|
||||
// think twice when changing this
|
||||
'AND `items`.`unread` = ? ' .
|
||||
'WHERE (`feeds`.`folder_id` IS NULL ' .
|
||||
'OR `folders`.`deleted_at` = 0 ' .
|
||||
') ' .
|
||||
'AND `feeds`.`deleted_at` = 0 ' .
|
||||
'GROUP BY `feeds`.`id` ' .
|
||||
') `item_numbers` ' .
|
||||
'ON `item_numbers`.`id` = `feeds`.`id` ';
|
||||
|
||||
return $this->findEntities($sql, [true]);
|
||||
}
|
||||
|
||||
|
||||
public function findByUrlHash($hash, $userId)
|
||||
{
|
||||
$sql = 'SELECT `feeds`.*, `item_numbers`.`unread_count` ' .
|
||||
'FROM `*PREFIX*news_feeds` `feeds` ' .
|
||||
'JOIN ( ' .
|
||||
'SELECT `feeds`.`id`, COUNT(`items`.`id`) AS `unread_count` ' .
|
||||
'FROM `*PREFIX*news_feeds` `feeds` ' .
|
||||
'LEFT JOIN `*PREFIX*news_items` `items` ' .
|
||||
'ON `feeds`.`id` = `items`.`feed_id` ' .
|
||||
// WARNING: this is a desperate attempt at making this query
|
||||
// work because prepared statements dont work. This is a
|
||||
// POSSIBLE SQL INJECTION RISK WHEN MODIFIED WITHOUT THOUGHT.
|
||||
// think twice when changing this
|
||||
'AND `items`.`unread` = ? ' .
|
||||
'WHERE `feeds`.`url_hash` = ? ' .
|
||||
'AND `feeds`.`user_id` = ? ' .
|
||||
'GROUP BY `feeds`.`id` ' .
|
||||
') `item_numbers` ' .
|
||||
'ON `item_numbers`.`id` = `feeds`.`id` ';
|
||||
$params = [true, $hash, $userId];
|
||||
|
||||
return $this->findEntity($sql, $params);
|
||||
}
|
||||
|
||||
|
||||
public function delete(Entity $entity): Entity
|
||||
{
|
||||
// someone please slap me for doing this manually :P
|
||||
// we needz CASCADE + FKs please
|
||||
$sql = 'DELETE FROM `*PREFIX*news_items` WHERE `feed_id` = ?';
|
||||
$params = [$entity->getId()];
|
||||
$this->execute($sql, $params);
|
||||
|
||||
return parent::delete($entity);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param int $deleteOlderThan if given gets all entries with a delete date
|
||||
* older than that timestamp
|
||||
* @param string $userId if given returns only entries from the given user
|
||||
* @return array with the database rows
|
||||
*/
|
||||
public function getToDelete($deleteOlderThan = null, $userId = null)
|
||||
{
|
||||
$sql = 'SELECT * FROM `*PREFIX*news_feeds` ' .
|
||||
'WHERE `deleted_at` > 0 ';
|
||||
$params = [];
|
||||
|
||||
// sometimes we want to delete all entries
|
||||
if ($deleteOlderThan !== null) {
|
||||
$sql .= 'AND `deleted_at` < ? ';
|
||||
$params[] = $deleteOlderThan;
|
||||
}
|
||||
|
||||
// we need to sometimes only delete feeds of a user
|
||||
if ($userId !== null) {
|
||||
$sql .= 'AND `user_id` = ?';
|
||||
$params[] = $userId;
|
||||
}
|
||||
|
||||
return $this->findEntities($sql, $params);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Deletes all feeds of a user, delete items first since the user_id
|
||||
* is not defined in there
|
||||
*
|
||||
* @param string $userId the name of the user
|
||||
*/
|
||||
public function deleteUser($userId)
|
||||
{
|
||||
$sql = 'DELETE FROM `*PREFIX*news_feeds` WHERE `user_id` = ?';
|
||||
$this->execute($sql, [$userId]);
|
||||
}
|
||||
|
||||
public function findFromUser(string $userId, int $id): Entity
|
||||
{
|
||||
return $this->find($userId, $id);
|
||||
}
|
||||
}
|
@ -52,7 +52,7 @@ class FeedMapperV2 extends NewsMapperV2
|
||||
{
|
||||
$builder = $this->db->getQueryBuilder();
|
||||
$builder->select('feeds.*', $builder->func()->count('items.id', 'unreadCount'))
|
||||
->from($this->tableName, 'feeds')
|
||||
->from(static::TABLE_NAME, 'feeds')
|
||||
->leftJoin(
|
||||
'feeds',
|
||||
ItemMapperV2::TABLE_NAME,
|
||||
@ -82,8 +82,8 @@ class FeedMapperV2 extends NewsMapperV2
|
||||
public function findFromUser(string $userId, int $id): Entity
|
||||
{
|
||||
$builder = $this->db->getQueryBuilder();
|
||||
$builder->addSelect('*')
|
||||
->from($this->tableName)
|
||||
$builder->select('*')
|
||||
->from(static::TABLE_NAME)
|
||||
->where('user_id = :user_id')
|
||||
->andWhere('id = :id')
|
||||
->setParameter(':user_id', $userId)
|
||||
@ -101,7 +101,7 @@ class FeedMapperV2 extends NewsMapperV2
|
||||
{
|
||||
$builder = $this->db->getQueryBuilder();
|
||||
$builder->select('*')
|
||||
->from($this->tableName)
|
||||
->from(static::TABLE_NAME)
|
||||
->where('deleted_at = 0');
|
||||
|
||||
return $this->findEntities($builder);
|
||||
@ -121,8 +121,8 @@ class FeedMapperV2 extends NewsMapperV2
|
||||
public function findByURL(string $userId, string $url): Entity
|
||||
{
|
||||
$builder = $this->db->getQueryBuilder();
|
||||
$builder->addSelect('*')
|
||||
->from($this->tableName)
|
||||
$builder->select('*')
|
||||
->from(static::TABLE_NAME)
|
||||
->where('user_id = :user_id')
|
||||
->andWhere('url = :url')
|
||||
->setParameter(':user_id', $userId)
|
||||
@ -141,8 +141,8 @@ class FeedMapperV2 extends NewsMapperV2
|
||||
public function findAllFromFolder(?int $id): array
|
||||
{
|
||||
$builder = $this->db->getQueryBuilder();
|
||||
$builder->addSelect('*')
|
||||
->from($this->tableName);
|
||||
$builder->select('*')
|
||||
->from(static::TABLE_NAME);
|
||||
|
||||
if (is_null($id)) {
|
||||
$builder->where('folder_id IS NULL');
|
||||
|
@ -17,6 +17,7 @@ use Exception;
|
||||
use OCA\News\Utility\Time;
|
||||
use OCP\AppFramework\Db\DoesNotExistException;
|
||||
use OCP\AppFramework\Db\Entity;
|
||||
use OCP\AppFramework\Db\Mapper;
|
||||
use OCP\AppFramework\Db\MultipleObjectsReturnedException;
|
||||
use OCP\DB\QueryBuilder\IQueryBuilder;
|
||||
use OCP\IDBConnection;
|
||||
@ -27,13 +28,25 @@ use OCP\IDBConnection;
|
||||
* @package OCA\News\Db
|
||||
* @deprecated use ItemMapper
|
||||
*/
|
||||
class ItemMapper extends NewsMapper
|
||||
class ItemMapper extends Mapper
|
||||
{
|
||||
|
||||
const TABLE_NAME = 'news_items';
|
||||
/**
|
||||
* @var Time
|
||||
*/
|
||||
private $time;
|
||||
|
||||
/**
|
||||
* NewsMapper constructor.
|
||||
*
|
||||
* @param IDBConnection $db Database connection
|
||||
* @param Time $time Time class
|
||||
*/
|
||||
public function __construct(IDBConnection $db, Time $time)
|
||||
{
|
||||
parent::__construct($db, $time, Item::class);
|
||||
parent::__construct($db, static::TABLE_NAME, Item::class);
|
||||
$this->time = $time;
|
||||
}
|
||||
|
||||
private function makeSelectQuery(
|
||||
@ -107,7 +120,7 @@ class ItemMapper extends NewsMapper
|
||||
/**
|
||||
* @param int $id
|
||||
* @param string $userId
|
||||
* @return \OCA\News\Db\Item
|
||||
* @return \OCA\News\Db\Item|Entity
|
||||
*/
|
||||
public function find(string $userId, int $id)
|
||||
{
|
||||
@ -332,7 +345,15 @@ class ItemMapper extends NewsMapper
|
||||
return $this->findEntities($sql, $params);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $guidHash
|
||||
* @param $feedId
|
||||
* @param $userId
|
||||
*
|
||||
* @return Entity|Item
|
||||
* @throws DoesNotExistException
|
||||
* @throws MultipleObjectsReturnedException
|
||||
*/
|
||||
public function findByGuidHash($guidHash, $feedId, $userId)
|
||||
{
|
||||
$sql = $this->makeSelectQuery(
|
||||
@ -411,23 +432,6 @@ class ItemMapper extends NewsMapper
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Deletes all items of a user
|
||||
*
|
||||
* @param string $userId the name of the user
|
||||
*/
|
||||
public function deleteUser($userId)
|
||||
{
|
||||
$sql = 'DELETE FROM `*PREFIX*news_items` ' .
|
||||
'WHERE `feed_id` IN (' .
|
||||
'SELECT `feeds`.`id` FROM `*PREFIX*news_feeds` `feeds` ' .
|
||||
'WHERE `feeds`.`user_id` = ?' .
|
||||
')';
|
||||
|
||||
$this->execute($sql, [$userId]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns a list of ids and userid of all items
|
||||
*/
|
||||
@ -492,29 +496,74 @@ class ItemMapper extends NewsMapper
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* NO-OP
|
||||
*
|
||||
* @param string $userId
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function findAllFromUser(string $userId): array
|
||||
public function update(Entity $entity): Entity
|
||||
{
|
||||
return [];
|
||||
$entity->setLastModified($this->time->getMicroTime());
|
||||
return parent::update($entity);
|
||||
}
|
||||
|
||||
public function findFromUser(string $userId, int $id): Entity
|
||||
public function insert(Entity $entity): Entity
|
||||
{
|
||||
return $this->find($id, $userId);
|
||||
$entity->setLastModified($this->time->getMicroTime());
|
||||
return parent::insert($entity);
|
||||
}
|
||||
|
||||
/**
|
||||
* NO-OP
|
||||
* @return array
|
||||
* Remove deleted items.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function findAll(): array
|
||||
public function purgeDeleted(): void
|
||||
{
|
||||
return [];
|
||||
$builder = $this->db->getQueryBuilder();
|
||||
$builder->delete($this->tableName)
|
||||
->where('deleted_at != 0')
|
||||
->execute();
|
||||
}
|
||||
/**
|
||||
* Performs a SELECT query with all arguments appened to the WHERE clause
|
||||
* The SELECT will be performed on the current table and take the entity
|
||||
* that is related for transforming the properties into column names
|
||||
*
|
||||
* Important: This method does not filter marked as deleted rows!
|
||||
*
|
||||
* @param array $search an assoc array from property to filter value
|
||||
* @param int|null $limit Output limit
|
||||
* @param int|null $offset Output offset
|
||||
*
|
||||
* @depreacted Legacy function
|
||||
*
|
||||
* @return Entity[]
|
||||
*/
|
||||
public function where(array $search = [], ?int $limit = null, ?int $offset = null)
|
||||
{
|
||||
$entity = new $this->entityClass();
|
||||
|
||||
// turn keys into sql query filter, e.g. feedId -> feed_id = :feedId
|
||||
$filter = array_map(
|
||||
function ($property) use ($entity) {
|
||||
// check if the property actually exists on the entity to prevent
|
||||
// accidental Sql injection
|
||||
if (!property_exists($entity, $property)) {
|
||||
$msg = 'Property ' . $property . ' does not exist on '
|
||||
. $this->entityClass;
|
||||
throw new \BadFunctionCallException($msg);
|
||||
}
|
||||
|
||||
$column = $entity->propertyToColumn($property);
|
||||
return $column . ' = :' . $property;
|
||||
},
|
||||
array_keys($search)
|
||||
);
|
||||
|
||||
$andStatement = implode(' AND ', $filter);
|
||||
|
||||
$sql = 'SELECT * FROM `' . $this->getTableName() . '`';
|
||||
|
||||
if (count($search) > 0) {
|
||||
$sql .= 'WHERE ' . $andStatement;
|
||||
}
|
||||
|
||||
return $this->findEntities($sql, $search, $limit, $offset);
|
||||
}
|
||||
}
|
||||
|
@ -120,6 +120,11 @@ class ItemMapperV2 extends NewsMapperV2
|
||||
return $this->findEntity($builder);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $feedId
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function findAllForFeed(int $feedId): array
|
||||
{
|
||||
$builder = $this->db->getQueryBuilder();
|
||||
|
@ -1,158 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* Nextcloud - News
|
||||
*
|
||||
* This file is licensed under the Affero General Public License version 3 or
|
||||
* later. See the COPYING file.
|
||||
*
|
||||
* @author Alessandro Cosentino <cosenal@gmail.com>
|
||||
* @author Bernhard Posselt <dev@bernhard-posselt.com>
|
||||
* @copyright 2012 Alessandro Cosentino
|
||||
* @copyright 2012-2014 Bernhard Posselt
|
||||
*/
|
||||
|
||||
namespace OCA\News\Db;
|
||||
|
||||
use OCA\News\Utility\Time;
|
||||
use OCP\AppFramework\Db\DoesNotExistException;
|
||||
use OCP\AppFramework\Db\MultipleObjectsReturnedException;
|
||||
use OCP\AppFramework\Db\QBMapper;
|
||||
use OCP\IDBConnection;
|
||||
use OCP\AppFramework\Db\Mapper;
|
||||
use OCP\AppFramework\Db\Entity;
|
||||
|
||||
/**
|
||||
* Class NewsMapper
|
||||
*
|
||||
* @package OCA\News\Db
|
||||
*/
|
||||
abstract class NewsMapper extends Mapper
|
||||
{
|
||||
const TABLE_NAME = '';
|
||||
|
||||
/**
|
||||
* @var Time
|
||||
*/
|
||||
private $time;
|
||||
|
||||
/**
|
||||
* NewsMapper constructor.
|
||||
*
|
||||
* @param IDBConnection $db Database connection
|
||||
* @param Time $time Time class
|
||||
* @param string $entity Entity class
|
||||
*/
|
||||
public function __construct(
|
||||
IDBConnection $db,
|
||||
Time $time,
|
||||
string $entity
|
||||
) {
|
||||
parent::__construct($db, static::TABLE_NAME, $entity);
|
||||
$this->time = $time;
|
||||
}
|
||||
|
||||
public function update(Entity $entity): Entity
|
||||
{
|
||||
$entity->setLastModified($this->time->getMicroTime());
|
||||
return parent::update($entity);
|
||||
}
|
||||
|
||||
public function insert(Entity $entity): Entity
|
||||
{
|
||||
$entity->setLastModified($this->time->getMicroTime());
|
||||
return parent::insert($entity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove deleted items.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function purgeDeleted(): void
|
||||
{
|
||||
$builder = $this->db->getQueryBuilder();
|
||||
$builder->delete($this->tableName)
|
||||
->where('deleted_at != 0')
|
||||
->execute();
|
||||
}
|
||||
|
||||
abstract public function find(string $userId, int $id);
|
||||
|
||||
/**
|
||||
* Find all items.
|
||||
*
|
||||
* @return Entity[]
|
||||
*/
|
||||
abstract public function findAll(): array;
|
||||
|
||||
/**
|
||||
* Find all items for a user.
|
||||
*
|
||||
* @param string $userId ID of the user
|
||||
*
|
||||
* @return Entity[]
|
||||
*/
|
||||
abstract public function findAllFromUser(string $userId): array;
|
||||
|
||||
/**
|
||||
* Find item for a user.
|
||||
*
|
||||
* @param string $userId ID of the user
|
||||
* @param int $id ID of the item
|
||||
*
|
||||
* @return Feed
|
||||
*
|
||||
* @throws DoesNotExistException The item is not found
|
||||
* @throws MultipleObjectsReturnedException Multiple items found
|
||||
*/
|
||||
abstract public function findFromUser(string $userId, int $id): Entity;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Performs a SELECT query with all arguments appened to the WHERE clause
|
||||
* The SELECT will be performed on the current table and take the entity
|
||||
* that is related for transforming the properties into column names
|
||||
*
|
||||
* Important: This method does not filter marked as deleted rows!
|
||||
*
|
||||
* @param array $search an assoc array from property to filter value
|
||||
* @param int|null $limit Output limit
|
||||
* @param int|null $offset Output offset
|
||||
*
|
||||
* @depreacted Legacy function
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function where(array $search = [], ?int $limit = null, ?int $offset = null)
|
||||
{
|
||||
$entity = new $this->entityClass();
|
||||
|
||||
// turn keys into sql query filter, e.g. feedId -> feed_id = :feedId
|
||||
$filter = array_map(
|
||||
function ($property) use ($entity) {
|
||||
// check if the property actually exists on the entity to prevent
|
||||
// accidental Sql injection
|
||||
if (!property_exists($entity, $property)) {
|
||||
$msg = 'Property ' . $property . ' does not exist on '
|
||||
. $this->entityClass;
|
||||
throw new \BadFunctionCallException($msg);
|
||||
}
|
||||
|
||||
$column = $entity->propertyToColumn($property);
|
||||
return $column . ' = :' . $property;
|
||||
},
|
||||
array_keys($search)
|
||||
);
|
||||
|
||||
$andStatement = implode(' AND ', $filter);
|
||||
|
||||
$sql = 'SELECT * FROM `' . $this->getTableName() . '`';
|
||||
|
||||
if (count($search) > 0) {
|
||||
$sql .= 'WHERE ' . $andStatement;
|
||||
}
|
||||
|
||||
return $this->findEntities($sql, $search, $limit, $offset);
|
||||
}
|
||||
}
|
@ -14,6 +14,8 @@
|
||||
namespace OCA\News\Fetcher;
|
||||
|
||||
use FeedIo\Reader\ReadErrorException;
|
||||
use OCA\News\Db\Feed;
|
||||
use OCA\News\Db\Item;
|
||||
|
||||
interface IFeedFetcher
|
||||
{
|
||||
@ -29,7 +31,7 @@ interface IFeedFetcher
|
||||
* @param string|null $user if given, basic auth is set for this feed
|
||||
* @param string|null $password if given, basic auth is set for this feed. Ignored if user is empty
|
||||
*
|
||||
* @return array an array containing the new feed and its items, first
|
||||
* @return <Feed, Item[]> an array containing the new feed and its items, first
|
||||
* element being the Feed and second element being an array of Items
|
||||
*
|
||||
* @throws ReadErrorException if the Feed-IO fetcher encounters a problem
|
||||
|
@ -14,9 +14,9 @@
|
||||
namespace OCA\News\Hooks;
|
||||
|
||||
use OCA\News\AppInfo\Application;
|
||||
use OCA\News\Service\ItemService;
|
||||
use OCA\News\Service\FeedService;
|
||||
use OCA\News\Service\FeedServiceV2;
|
||||
use OCA\News\Service\FolderServiceV2;
|
||||
use OCA\News\Service\ItemServiceV2;
|
||||
use OCP\EventDispatcher\Event;
|
||||
use OCP\EventDispatcher\IEventListener;
|
||||
use OCP\User\Events\BeforeUserDeletedEvent;
|
||||
@ -37,8 +37,8 @@ class UserDeleteHook implements IEventListener
|
||||
$container = $app->getContainer();
|
||||
|
||||
// order is important!
|
||||
$container->get(ItemService::class)->deleteUser($userId);
|
||||
$container->get(FeedService::class)->deleteUser($userId);
|
||||
$container->get(ItemServiceV2::class)->deleteUser($userId);
|
||||
$container->get(FeedServiceV2::class)->deleteUser($userId);
|
||||
$container->get(FolderServiceV2::class)->deleteUser($userId);
|
||||
}
|
||||
}
|
||||
|
@ -1,521 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* Nextcloud - News
|
||||
*
|
||||
* This file is licensed under the Affero General Public License version 3 or
|
||||
* later. See the COPYING file.
|
||||
*
|
||||
* @author Alessandro Cosentino <cosenal@gmail.com>
|
||||
* @author Bernhard Posselt <dev@bernhard-posselt.com>
|
||||
* @copyright 2012 Alessandro Cosentino
|
||||
* @copyright 2012-2014 Bernhard Posselt
|
||||
*/
|
||||
|
||||
namespace OCA\News\Service;
|
||||
|
||||
use FeedIo\Reader\ReadErrorException;
|
||||
use HTMLPurifier;
|
||||
|
||||
use OCA\News\AppInfo\Application;
|
||||
use OCP\IConfig;
|
||||
use OCA\News\Service\Exceptions\ServiceConflictException;
|
||||
use OCA\News\Service\Exceptions\ServiceNotFoundException;
|
||||
use OCP\AppFramework\Db\Entity;
|
||||
use OCP\IL10N;
|
||||
use OCP\AppFramework\Db\DoesNotExistException;
|
||||
|
||||
use OCA\News\Db\Feed;
|
||||
use OCA\News\Db\Item;
|
||||
use OCA\News\Db\FeedMapper;
|
||||
use OCA\News\Db\ItemMapper;
|
||||
use OCA\News\Fetcher\Fetcher;
|
||||
use OCA\News\Utility\Time;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
/**
|
||||
* Class LegacyFeedService
|
||||
*
|
||||
* @package OCA\News\Service
|
||||
* @deprecated use FeedServiceV2
|
||||
*/
|
||||
class FeedService extends Service
|
||||
{
|
||||
|
||||
private $feedFetcher;
|
||||
private $itemMapper;
|
||||
private $feedMapper;
|
||||
private $l10n;
|
||||
private $timeFactory;
|
||||
private $autoPurgeMinimumInterval;
|
||||
private $purifier;
|
||||
private $loggerParams;
|
||||
|
||||
public function __construct(
|
||||
FeedMapper $legacyFeedMapper,
|
||||
Fetcher $feedFetcher,
|
||||
ItemMapper $legacyItemMapper,
|
||||
LoggerInterface $logger,
|
||||
IL10N $l10n,
|
||||
Time $timeFactory,
|
||||
IConfig $config,
|
||||
HTMLPurifier $purifier
|
||||
) {
|
||||
parent::__construct($legacyFeedMapper, $logger);
|
||||
$this->feedFetcher = $feedFetcher;
|
||||
$this->feedMapper = $legacyFeedMapper;
|
||||
$this->itemMapper = $legacyItemMapper;
|
||||
$this->logger = $logger;
|
||||
$this->l10n = $l10n;
|
||||
$this->timeFactory = $timeFactory;
|
||||
$this->autoPurgeMinimumInterval = $config->getAppValue(
|
||||
Application::NAME,
|
||||
'autoPurgeMinimumInterval',
|
||||
Application::DEFAULT_SETTINGS['autoPurgeMinimumInterval']
|
||||
);
|
||||
$this->purifier = $purifier;
|
||||
$this->loggerParams = ['app' => Application::NAME];
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds all feeds of a user
|
||||
*
|
||||
* @param string $userId the name of the user
|
||||
*
|
||||
* @return Feed[]
|
||||
*/
|
||||
public function findAllForUser($userId, array $params = []): array
|
||||
{
|
||||
return $this->feedMapper->findAllFromUser($userId);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Finds all feeds from all users
|
||||
*
|
||||
* @return array of feeds
|
||||
*/
|
||||
public function findAllFromAllUsers()
|
||||
{
|
||||
return $this->findAll();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new feed
|
||||
*
|
||||
* @param string $feedUrl the url to the feed
|
||||
* @param int|null $folderId the folder where it should be put into, null for root
|
||||
* folder
|
||||
* @param string $userId for which user the feed should be created
|
||||
* @param string|null $title if given, this is used for the opml feed title
|
||||
* @param string|null $user if given, basic auth is set for this feed
|
||||
* @param string|null $password if given, basic auth is set for this
|
||||
* feed. Ignored if user is null or an empty string
|
||||
*
|
||||
* @return Feed the newly created feed
|
||||
* @throws ServiceConflictException if the feed exists already
|
||||
* @throws ServiceNotFoundException if the url points to an invalid feed
|
||||
*/
|
||||
public function create(
|
||||
string $feedUrl,
|
||||
?int $folderId,
|
||||
string $userId,
|
||||
string $title = null,
|
||||
string $user = null,
|
||||
string $password = null
|
||||
) {
|
||||
// first try if the feed exists already
|
||||
try {
|
||||
/**
|
||||
* @var Feed $feed
|
||||
* @var Item[] $items
|
||||
*/
|
||||
list($feed, $items) = $this->feedFetcher->fetch($feedUrl, true, null, false, $user, $password);
|
||||
// try again if feed exists depending on the reported link
|
||||
if ($feed === null) {
|
||||
throw new ServiceNotFoundException($this->l10n->t('Can not add feed: Unable to parse feed'));
|
||||
}
|
||||
try {
|
||||
$hash = $feed->getUrlHash();
|
||||
$this->feedMapper->findByUrlHash($hash, $userId);
|
||||
throw new ServiceConflictException(
|
||||
$this->l10n->t('Can not add feed: Exists already')
|
||||
);
|
||||
} catch (DoesNotExistException $ex) {
|
||||
// If no matching feed was found everything was ok
|
||||
}
|
||||
|
||||
// insert feed
|
||||
$itemCount = count($items);
|
||||
$feed->setBasicAuthUser($user);
|
||||
$feed->setBasicAuthPassword($password);
|
||||
$feed->setFolderId($folderId);
|
||||
$feed->setUserId($userId);
|
||||
$feed->setArticlesPerUpdate($itemCount);
|
||||
|
||||
if (!empty($title)) {
|
||||
$feed->setTitle($title);
|
||||
}
|
||||
|
||||
$feed = $this->feedMapper->insert($feed);
|
||||
|
||||
// insert items in reverse order because the first one is usually
|
||||
// the newest item
|
||||
$unreadCount = 0;
|
||||
foreach (array_reverse($items) as $item) {
|
||||
$item->setFeedId($feed->getId());
|
||||
|
||||
// check if item exists (guidhash is the same)
|
||||
// and ignore it if it does
|
||||
try {
|
||||
$this->itemMapper->findByGuidHash(
|
||||
$item->getGuidHash(),
|
||||
$item->getFeedId(),
|
||||
$userId
|
||||
);
|
||||
continue;
|
||||
} catch (DoesNotExistException $ex) {
|
||||
$unreadCount += 1;
|
||||
$item->setBody($this->purifier->purify($item->getBody()));
|
||||
$this->itemMapper->insert($item);
|
||||
}
|
||||
}
|
||||
|
||||
// set unread count
|
||||
$feed->setUnreadCount($unreadCount);
|
||||
|
||||
return $feed;
|
||||
} catch (ReadErrorException $ex) {
|
||||
$this->logger->debug($ex->getMessage(), $this->loggerParams);
|
||||
throw new ServiceNotFoundException($ex->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Runs all the feed updates
|
||||
*/
|
||||
public function updateAll()
|
||||
{
|
||||
// TODO: this method is not covered by any tests
|
||||
$feeds = $this->feedMapper->findAll();
|
||||
foreach ($feeds as $feed) {
|
||||
try {
|
||||
$this->update($feed->getId(), $feed->getUserId());
|
||||
} catch (\Exception $ex) {
|
||||
// something is really wrong here, log it
|
||||
$this->logger->error(
|
||||
'Unexpected error when updating feed ' . $ex->getMessage(),
|
||||
$this->loggerParams
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Updates a single feed
|
||||
*
|
||||
* @param string $userId the id of the user
|
||||
* @param int $feedId the id of the feed that should be updated
|
||||
* @param bool $forceUpdate update even if the article exists already
|
||||
*
|
||||
* @throws ServiceNotFoundException if the feed does not exist
|
||||
* @return Feed the updated feed entity
|
||||
*/
|
||||
public function update(string $userId, int $feedId, $forceUpdate = false)
|
||||
{
|
||||
/** @var Feed $existingFeed */
|
||||
$existingFeed = $this->find($userId, $feedId);
|
||||
|
||||
if ($existingFeed->getPreventUpdate() === true) {
|
||||
return $existingFeed;
|
||||
}
|
||||
|
||||
// for backwards compability it can be that the location is not set
|
||||
// yet, if so use the url
|
||||
$location = $existingFeed->getLocation();
|
||||
if (!$location) {
|
||||
$location = $existingFeed->getUrl();
|
||||
}
|
||||
|
||||
try {
|
||||
list($fetchedFeed, $items) = $this->feedFetcher->fetch(
|
||||
$location,
|
||||
false,
|
||||
$existingFeed->getHttpLastModified(),
|
||||
$existingFeed->getFullTextEnabled(),
|
||||
$existingFeed->getBasicAuthUser(),
|
||||
$existingFeed->getBasicAuthPassword()
|
||||
);
|
||||
|
||||
// if there is no feed it means that no update took place
|
||||
if (!$fetchedFeed) {
|
||||
return $existingFeed;
|
||||
}
|
||||
|
||||
// update number of articles on every feed update
|
||||
$itemCount = count($items);
|
||||
|
||||
// this is needed to adjust to updates that add more items
|
||||
// than when the feed was created. You can't update the count
|
||||
// if it's lower because it may be due to the caching headers
|
||||
// that were sent as the request and it might cause unwanted
|
||||
// deletion and reappearing of feeds
|
||||
if ($itemCount > $existingFeed->getArticlesPerUpdate()) {
|
||||
$existingFeed->setArticlesPerUpdate($itemCount);
|
||||
}
|
||||
|
||||
$existingFeed->setHttpLastModified(
|
||||
$fetchedFeed->getHttpLastModified()
|
||||
);
|
||||
$existingFeed->setHttpEtag($fetchedFeed->getHttpEtag());
|
||||
$existingFeed->setLocation($fetchedFeed->getLocation());
|
||||
|
||||
// insert items in reverse order because the first one is
|
||||
// usually the newest item
|
||||
for ($i = $itemCount - 1; $i >= 0; $i--) {
|
||||
$item = $items[$i];
|
||||
$item->setFeedId($existingFeed->getId());
|
||||
|
||||
try {
|
||||
$dbItem = $this->itemMapper->findByGuidHash(
|
||||
$item->getGuidHash(),
|
||||
$feedId,
|
||||
$userId
|
||||
);
|
||||
|
||||
// in case of update
|
||||
if ($forceUpdate
|
||||
|| $item->getUpdatedDate() > $dbItem->getUpdatedDate()
|
||||
) {
|
||||
$dbItem->setTitle($item->getTitle());
|
||||
$dbItem->setUrl($item->getUrl());
|
||||
$dbItem->setAuthor($item->getAuthor());
|
||||
$dbItem->setSearchIndex($item->getSearchIndex());
|
||||
$dbItem->setRtl($item->getRtl());
|
||||
$dbItem->setLastModified($item->getLastModified());
|
||||
$dbItem->setPubDate($item->getPubDate());
|
||||
$dbItem->setUpdatedDate($item->getUpdatedDate());
|
||||
$dbItem->setEnclosureMime($item->getEnclosureMime());
|
||||
$dbItem->setEnclosureLink($item->getEnclosureLink());
|
||||
$dbItem->setBody(
|
||||
$this->purifier->purify($item->getBody())
|
||||
);
|
||||
|
||||
// update modes: 0 nothing, 1 set unread
|
||||
if ($existingFeed->getUpdateMode() === 1) {
|
||||
$dbItem->setUnread(true);
|
||||
}
|
||||
|
||||
$this->itemMapper->update($dbItem);
|
||||
}
|
||||
} catch (DoesNotExistException $ex) {
|
||||
$item->setBody(
|
||||
$this->purifier->purify($item->getBody())
|
||||
);
|
||||
$this->itemMapper->insert($item);
|
||||
}
|
||||
}
|
||||
|
||||
// mark feed as successfully updated
|
||||
$existingFeed->setUpdateErrorCount(0);
|
||||
$existingFeed->setLastUpdateError('');
|
||||
} catch (ReadErrorException $ex) {
|
||||
$existingFeed->setUpdateErrorCount(
|
||||
$existingFeed->getUpdateErrorCount() + 1
|
||||
);
|
||||
$existingFeed->setLastUpdateError($ex->getMessage());
|
||||
}
|
||||
|
||||
$this->feedMapper->update($existingFeed);
|
||||
|
||||
return $this->find($userId, $feedId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Import articles
|
||||
*
|
||||
* @param array $json the array with json
|
||||
* @param string $userId the username
|
||||
*
|
||||
* @return Feed if one had to be created for nonexistent feeds
|
||||
*/
|
||||
public function importArticles($json, $userId)
|
||||
{
|
||||
$url = 'http://nextcloud/nofeed';
|
||||
$urlHash = md5($url);
|
||||
|
||||
// build assoc array for fast access
|
||||
$feeds = $this->findAllForUser($userId);
|
||||
$feedsDict = [];
|
||||
foreach ($feeds as $feed) {
|
||||
$feedsDict[$feed->getLink()] = $feed;
|
||||
}
|
||||
|
||||
$createdFeed = false;
|
||||
|
||||
// loop over all items and get the corresponding feed
|
||||
// if the feed does not exist, create a separate feed for them
|
||||
foreach ($json as $entry) {
|
||||
$item = Item::fromImport($entry);
|
||||
$feedLink = $entry['feedLink']; // this is not set on the item yet
|
||||
|
||||
if (array_key_exists($feedLink, $feedsDict)) {
|
||||
$feed = $feedsDict[$feedLink];
|
||||
$item->setFeedId($feed->getId());
|
||||
} elseif (array_key_exists($url, $feedsDict)) {
|
||||
$feed = $feedsDict[$url];
|
||||
$item->setFeedId($feed->getId());
|
||||
} else {
|
||||
$createdFeed = true;
|
||||
$feed = new Feed();
|
||||
$feed->setUserId($userId);
|
||||
$feed->setLink($url);
|
||||
$feed->setUrl($url);
|
||||
$feed->setTitle($this->l10n->t('Articles without feed'));
|
||||
$feed->setAdded($this->timeFactory->getTime());
|
||||
$feed->setFolderId(null);
|
||||
$feed->setPreventUpdate(true);
|
||||
/** @var Feed $feed */
|
||||
$feed = $this->feedMapper->insert($feed);
|
||||
|
||||
$item->setFeedId($feed->getId());
|
||||
$feedsDict[$feed->getLink()] = $feed;
|
||||
}
|
||||
|
||||
try {
|
||||
// if item exists, copy the status
|
||||
$existingItem = $this->itemMapper->findByGuidHash(
|
||||
$item->getGuidHash(),
|
||||
$feed->getId(),
|
||||
$userId
|
||||
);
|
||||
$existingItem->setStatus($item->getStatus());
|
||||
$this->itemMapper->update($existingItem);
|
||||
} catch (DoesNotExistException $ex) {
|
||||
$item->setBody($this->purifier->purify($item->getBody()));
|
||||
$item->generateSearchIndex();
|
||||
$this->itemMapper->insert($item);
|
||||
}
|
||||
}
|
||||
|
||||
if ($createdFeed) {
|
||||
return $this->feedMapper->findByUrlHash($urlHash, $userId);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Use this to mark a feed as deleted. That way it can be un-deleted
|
||||
*
|
||||
* @param int $feedId the id of the feed that should be deleted
|
||||
* @param string $userId the name of the user for security reasons
|
||||
*
|
||||
* @throws ServiceNotFoundException when feed does not exist
|
||||
*/
|
||||
public function markDeleted(int $feedId, string $userId)
|
||||
{
|
||||
$feed = $this->find($userId, $feedId);
|
||||
$feed->setDeletedAt($this->timeFactory->getTime());
|
||||
$this->feedMapper->update($feed);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Use this to undo a feed deletion
|
||||
*
|
||||
* @param int $feedId the id of the feed that should be restored
|
||||
* @param string $userId the name of the user for security reasons
|
||||
*
|
||||
* @throws ServiceNotFoundException when feed does not exist
|
||||
*/
|
||||
public function unmarkDeleted(int $feedId, string $userId)
|
||||
{
|
||||
$feed = $this->find($userId, $feedId);
|
||||
$feed->setDeletedAt(0);
|
||||
$this->feedMapper->update($feed);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Deletes all deleted feeds
|
||||
*
|
||||
* @param string $userId if given it purges only feeds of that user
|
||||
* @param boolean $useInterval defaults to true, if true it only purges
|
||||
* entries in a given interval to give the user a chance to undo the
|
||||
* deletion
|
||||
*/
|
||||
public function purgeDeleted($userId = null, $useInterval = true)
|
||||
{
|
||||
$deleteOlderThan = null;
|
||||
|
||||
if ($useInterval) {
|
||||
$now = $this->timeFactory->getTime();
|
||||
$deleteOlderThan = $now - $this->autoPurgeMinimumInterval;
|
||||
}
|
||||
|
||||
$toDelete = $this->feedMapper->getToDelete($deleteOlderThan, $userId);
|
||||
|
||||
foreach ($toDelete as $feed) {
|
||||
$this->feedMapper->delete($feed);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Deletes all feeds of a user, delete items first since the user_id
|
||||
* is not defined in there
|
||||
*
|
||||
* @param string $userId the name of the user
|
||||
*/
|
||||
public function deleteUser($userId)
|
||||
{
|
||||
$this->feedMapper->deleteUser($userId);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $feedId ID of the feed.
|
||||
* @param string $userId ID of the user.
|
||||
* @param array $diff An array containing the fields to update, e.g.:
|
||||
* <code>
|
||||
* [
|
||||
* 'ordering' => 1,
|
||||
* 'fullTextEnabled' => true,
|
||||
* 'pinned' => true,
|
||||
* 'updateMode' => 0,
|
||||
* 'title' => 'title'
|
||||
* ]
|
||||
* </code>
|
||||
*
|
||||
* @throws ServiceNotFoundException if feed does not exist
|
||||
* @return Feed The patched feed
|
||||
*/
|
||||
public function patch(int $feedId, string $userId, array $diff = [])
|
||||
{
|
||||
$feed = $this->find($userId, $feedId);
|
||||
|
||||
foreach ($diff as $attribute => $value) {
|
||||
$method = 'set' . ucfirst($attribute);
|
||||
$feed->$method($value);
|
||||
}
|
||||
|
||||
// special feed updates
|
||||
if (array_key_exists('fullTextEnabled', $diff)) {
|
||||
// disable caching for the next update
|
||||
$feed->setHttpEtag('');
|
||||
$feed->setHttpLastModified(0);
|
||||
$this->feedMapper->update($feed);
|
||||
return $this->update($userId, $feedId, true);
|
||||
}
|
||||
|
||||
return $this->feedMapper->update($feed);
|
||||
}
|
||||
|
||||
public function findAll(): array
|
||||
{
|
||||
return $this->feedMapper->findAll();
|
||||
}
|
||||
}
|
@ -29,7 +29,6 @@ use OCP\AppFramework\Db\DoesNotExistException;
|
||||
|
||||
use OCA\News\Db\Feed;
|
||||
use OCA\News\Db\Item;
|
||||
use OCA\News\Db\FeedMapper;
|
||||
use OCA\News\Db\ItemMapper;
|
||||
use OCA\News\Fetcher\Fetcher;
|
||||
use OCA\News\Config\Config;
|
||||
@ -104,22 +103,6 @@ class FeedServiceV2 extends Service
|
||||
return $this->mapper->findAllFromUser($userId, $params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds a feed of a user
|
||||
*
|
||||
* @param string $userId the name of the user
|
||||
* @param string $id the id of the feed
|
||||
*
|
||||
* @return Feed
|
||||
*
|
||||
* @throws DoesNotExistException
|
||||
* @throws MultipleObjectsReturnedException
|
||||
*/
|
||||
public function findForUser(string $userId, string $id): Feed
|
||||
{
|
||||
return $this->mapper->findFromUser($userId, $id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int|null $id
|
||||
*
|
||||
@ -139,6 +122,7 @@ class FeedServiceV2 extends Service
|
||||
*/
|
||||
public function findAllForUserRecursive(string $userId): array
|
||||
{
|
||||
/** @var Feed[] $feeds */
|
||||
$feeds = $this->mapper->findAllFromUser($userId);
|
||||
|
||||
foreach ($feeds as &$feed) {
|
||||
@ -167,12 +151,24 @@ class FeedServiceV2 extends Service
|
||||
* @return bool
|
||||
*/
|
||||
public function existsForUser(string $userID, string $url): bool
|
||||
{
|
||||
return $this->findByURL($userID, $url) !== null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a feed exists for a user
|
||||
*
|
||||
* @param string $userID the name of the user
|
||||
* @param string $url the feed URL
|
||||
*
|
||||
* @return Entity|Feed|null
|
||||
*/
|
||||
public function findByURL(string $userID, string $url): ?Entity
|
||||
{
|
||||
try {
|
||||
$this->mapper->findByURL($userID, $url);
|
||||
return true;
|
||||
return $this->mapper->findByURL($userID, $url);
|
||||
} catch (DoesNotExistException $e) {
|
||||
return false;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@ -274,58 +270,59 @@ class FeedServiceV2 extends Service
|
||||
$feed->getBasicAuthUser(),
|
||||
$feed->getBasicAuthPassword()
|
||||
);
|
||||
|
||||
// if there is no feed it means that no update took place
|
||||
if (!$fetchedFeed) {
|
||||
return $feed;
|
||||
}
|
||||
|
||||
// update number of articles on every feed update
|
||||
$itemCount = count($items);
|
||||
|
||||
// this is needed to adjust to updates that add more items
|
||||
// than when the feed was created. You can't update the count
|
||||
// if it's lower because it may be due to the caching headers
|
||||
// that were sent as the request and it might cause unwanted
|
||||
// deletion and reappearing of feeds
|
||||
if ($itemCount > $feed->getArticlesPerUpdate()) {
|
||||
$feed->setArticlesPerUpdate($itemCount);
|
||||
}
|
||||
|
||||
$feed->setHttpLastModified($fetchedFeed->getHttpLastModified())
|
||||
->setHttpEtag($fetchedFeed->getHttpEtag())
|
||||
->setLocation($fetchedFeed->getLocation());
|
||||
|
||||
// insert items in reverse order because the first one is
|
||||
// usually the newest item
|
||||
for ($i = $itemCount - 1; $i >= 0; $i--) {
|
||||
$item = $items[$i];
|
||||
$item->setFeedId($feed->getId())
|
||||
->setBody($this->purifier->purify($item->getBody()));
|
||||
|
||||
// update modes: 0 nothing, 1 set unread
|
||||
if ($feed->getUpdateMode() === 1) {
|
||||
$item->setUnread(true);
|
||||
}
|
||||
|
||||
$this->itemService->insertOrUpdate($item);
|
||||
}
|
||||
|
||||
// mark feed as successfully updated
|
||||
$feed->setUpdateErrorCount(0);
|
||||
$feed->setLastUpdateError(null);
|
||||
} catch (ReadErrorException $ex) {
|
||||
$feed->setUpdateErrorCount($feed->getUpdateErrorCount() + 1);
|
||||
$feed->setLastUpdateError($ex->getMessage());
|
||||
|
||||
return $this->mapper->update($feed);
|
||||
}
|
||||
|
||||
return $this->mapper->update($feed);
|
||||
}
|
||||
// if there is no feed it means that no update took place
|
||||
if (!$fetchedFeed) {
|
||||
return $feed;
|
||||
}
|
||||
|
||||
public function delete(string $user, int $id): void
|
||||
{
|
||||
$feed = $this->mapper->findFromUser($user, $id);
|
||||
$this->mapper->delete($feed);
|
||||
// update number of articles on every feed update
|
||||
$itemCount = count($items);
|
||||
|
||||
// this is needed to adjust to updates that add more items
|
||||
// than when the feed was created. You can't update the count
|
||||
// if it's lower because it may be due to the caching headers
|
||||
// that were sent as the request and it might cause unwanted
|
||||
// deletion and reappearing of feeds
|
||||
if ($itemCount > $feed->getArticlesPerUpdate()) {
|
||||
$feed->setArticlesPerUpdate($itemCount);
|
||||
}
|
||||
|
||||
$feed->setHttpLastModified($fetchedFeed->getHttpLastModified())
|
||||
->setHttpEtag($fetchedFeed->getHttpEtag())
|
||||
->setLocation($fetchedFeed->getLocation());
|
||||
|
||||
foreach (array_reverse($items) as &$item) {
|
||||
$item->setFeedId($feed->getId())
|
||||
->setBody($this->purifier->purify($item->getBody()));
|
||||
|
||||
// update modes: 0 nothing, 1 set unread
|
||||
if ($feed->getUpdateMode() === Feed::UPDATE_MODE_NORMAL) {
|
||||
$item->setUnread(true);
|
||||
}
|
||||
|
||||
$item = $this->itemService->insertOrUpdate($item);
|
||||
}
|
||||
|
||||
|
||||
// mark feed as successfully updated
|
||||
$feed->setUpdateErrorCount(0);
|
||||
$feed->setLastUpdateError(null);
|
||||
|
||||
$unreadCount = 0;
|
||||
array_map(function (Item $item) use (&$unreadCount) {
|
||||
if ($item->isUnread()) {
|
||||
$unreadCount++;
|
||||
}
|
||||
}, $items);
|
||||
|
||||
return $this->mapper->update($feed)->setUnreadCount($unreadCount);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -341,6 +338,11 @@ class FeedServiceV2 extends Service
|
||||
$this->mapper->purgeDeleted($userID, $minTimestamp);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch all feeds.
|
||||
*
|
||||
* @see FeedServiceV2::fetch()
|
||||
*/
|
||||
public function fetchAll(): void
|
||||
{
|
||||
foreach ($this->findAll() as $feed) {
|
||||
|
@ -63,28 +63,6 @@ class FolderServiceV2 extends Service
|
||||
return $this->mapper->findAllFromUser($userId, $params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds a folder of a user
|
||||
*
|
||||
* @param string $userId The name/ID of the user
|
||||
* @param int|null $folderId ID of the folder
|
||||
*
|
||||
* @return Folder
|
||||
*
|
||||
* @throws ServiceConflictException
|
||||
* @throws ServiceNotFoundException
|
||||
*/
|
||||
public function findForUser(string $userId, ?int $folderId): Entity
|
||||
{
|
||||
try {
|
||||
return $this->mapper->findFromUser($userId, $folderId);
|
||||
} catch (DoesNotExistException $e) {
|
||||
throw new ServiceNotFoundException('Folder not found');
|
||||
} catch (MultipleObjectsReturnedException $e) {
|
||||
throw new ServiceConflictException('Multiple folders found');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find all folders and it's feeds.
|
||||
*
|
||||
@ -133,23 +111,6 @@ class FolderServiceV2 extends Service
|
||||
return $this->mapper->insert($folder);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a feed.
|
||||
*
|
||||
* @param string $userId Folder owner
|
||||
* @param int $folderId Folder ID
|
||||
*
|
||||
* @return Folder
|
||||
* @throws ServiceConflictException
|
||||
* @throws ServiceNotFoundException
|
||||
*/
|
||||
public function delete(string $userId, int $folderId): Entity
|
||||
{
|
||||
$folder = $this->findForUser($userId, $folderId);
|
||||
|
||||
return $this->mapper->delete($folder);
|
||||
}
|
||||
|
||||
/**
|
||||
* Purge all deleted folders.
|
||||
*
|
||||
@ -174,8 +135,9 @@ class FolderServiceV2 extends Service
|
||||
*/
|
||||
public function rename(string $userId, int $folderId, string $newName): Entity
|
||||
{
|
||||
$folder = $this->findForUser($userId, $folderId);
|
||||
$folder = $this->find($userId, $folderId);
|
||||
$folder->setName($newName);
|
||||
|
||||
return $this->mapper->update($folder);
|
||||
}
|
||||
|
||||
@ -192,7 +154,7 @@ class FolderServiceV2 extends Service
|
||||
*/
|
||||
public function markDelete(string $userId, int $folderId, bool $mark): Entity
|
||||
{
|
||||
$folder = $this->findForUser($userId, $folderId);
|
||||
$folder = $this->find($userId, $folderId);
|
||||
$time = $mark ? $this->timeFactory->getTime() : 0;
|
||||
$folder->setDeletedAt($time);
|
||||
|
||||
@ -212,21 +174,8 @@ class FolderServiceV2 extends Service
|
||||
*/
|
||||
public function open(string $userId, ?int $folderId, bool $open): Entity
|
||||
{
|
||||
$folder = $this->findForUser($userId, $folderId);
|
||||
$folder = $this->find($userId, $folderId);
|
||||
$folder->setOpened($open);
|
||||
return $this->mapper->update($folder);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete all folders of a user
|
||||
*
|
||||
* @param string $userId User ID/name
|
||||
*/
|
||||
public function deleteUser(string $userId): void
|
||||
{
|
||||
$folders = $this->findAllForUser($userId);
|
||||
foreach ($folders as $folder) {
|
||||
$this->mapper->delete($folder);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
125
lib/Service/ImportService.php
Normal file
125
lib/Service/ImportService.php
Normal file
@ -0,0 +1,125 @@
|
||||
<?php
|
||||
/**
|
||||
* Nextcloud - News
|
||||
*
|
||||
* This file is licensed under the Affero General Public License version 3 or
|
||||
* later. See the COPYING file.
|
||||
*
|
||||
* @author Alessandro Cosentino <cosenal@gmail.com>
|
||||
* @author Bernhard Posselt <dev@bernhard-posselt.com>
|
||||
* @copyright 2012 Alessandro Cosentino
|
||||
* @copyright 2012-2014 Bernhard Posselt
|
||||
*/
|
||||
|
||||
namespace OCA\News\Service;
|
||||
|
||||
use \OCA\News\Db\Item;
|
||||
use \OCA\News\Db\Feed;
|
||||
|
||||
use \Psr\Log\LoggerInterface;
|
||||
use \HTMLPurifier;
|
||||
|
||||
/**
|
||||
* Class ImportService
|
||||
*
|
||||
* @package OCA\News\Service
|
||||
*/
|
||||
class ImportService
|
||||
{
|
||||
/**
|
||||
* Items service.
|
||||
*
|
||||
* @var ItemServiceV2
|
||||
*/
|
||||
protected $itemService;
|
||||
/**
|
||||
* Feeds service.
|
||||
*
|
||||
* @var FeedServiceV2
|
||||
*/
|
||||
protected $feedService;
|
||||
/**
|
||||
* @var LoggerInterface
|
||||
*/
|
||||
protected $logger;
|
||||
/**
|
||||
* @var HTMLPurifier
|
||||
*/
|
||||
protected $purifier;
|
||||
|
||||
/**
|
||||
* FeedService constructor.
|
||||
*
|
||||
* @param FeedServiceV2 $feedService Service for feeds
|
||||
* @param ItemServiceV2 $itemService Service to manage items
|
||||
* @param HTMLPurifier $purifier HTML Purifier
|
||||
* @param LoggerInterface $logger Logger
|
||||
*/
|
||||
public function __construct(
|
||||
FeedServiceV2 $feedService,
|
||||
ItemServiceV2 $itemService,
|
||||
HTMLPurifier $purifier,
|
||||
LoggerInterface $logger
|
||||
) {
|
||||
$this->itemService = $itemService;
|
||||
$this->feedService = $feedService;
|
||||
$this->purifier = $purifier;
|
||||
$this->logger = $logger;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $userId
|
||||
* @param array $json
|
||||
*
|
||||
* @return array|null
|
||||
*/
|
||||
public function importArticles(string $userId, array $json)
|
||||
{
|
||||
$url = 'http://nextcloud/nofeed';
|
||||
|
||||
// build assoc array for fast access
|
||||
$feeds = $this->feedService->findAllForUser($userId);
|
||||
$feedsDict = [];
|
||||
foreach ($feeds as $feed) {
|
||||
$feedsDict[$feed->getLink()] = $feed;
|
||||
}
|
||||
|
||||
$createdFeed = false;
|
||||
|
||||
// loop over all items and get the corresponding feed
|
||||
// if the feed does not exist, create a separate feed for them
|
||||
foreach ($json as $entry) {
|
||||
$item = Item::fromImport($entry);
|
||||
$feedLink = $entry['feedLink']; // this is not set on the item yet
|
||||
|
||||
if (array_key_exists($feedLink, $feedsDict)) {
|
||||
$feed = $feedsDict[$feedLink];
|
||||
} else {
|
||||
$createdFeed = true;
|
||||
$feed = new Feed();
|
||||
$feed->setUserId($userId)
|
||||
->setUrlHash(md5($url))
|
||||
->setLink($url)
|
||||
->setUrl($url)
|
||||
->setTitle('Articles without feed')
|
||||
->setAdded(time())
|
||||
->setFolderId(null)
|
||||
->setPreventUpdate(true);
|
||||
|
||||
$feed = $this->feedService->insert($feed);
|
||||
$feedsDict[$feed->getLink()] = $feed;
|
||||
}
|
||||
|
||||
$item->setFeedId($feed->getId())
|
||||
->setBody($this->purifier->purify($item->getBody()))
|
||||
->generateSearchIndex();
|
||||
$this->itemService->insertOrUpdate($item);
|
||||
}
|
||||
|
||||
if (!$createdFeed) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $this->feedService->findByURL($userId, $url);
|
||||
}
|
||||
}
|
@ -15,6 +15,7 @@ namespace OCA\News\Service;
|
||||
|
||||
use OCA\News\AppInfo\Application;
|
||||
use OCA\News\Db\Item;
|
||||
use OCA\News\Db\ItemMapperV2;
|
||||
use OCA\News\Service\Exceptions\ServiceNotFoundException;
|
||||
use OCP\AppFramework\Db\Entity;
|
||||
use OCP\IConfig;
|
||||
@ -34,12 +35,22 @@ use Psr\Log\LoggerInterface;
|
||||
class ItemService extends Service
|
||||
{
|
||||
|
||||
/**
|
||||
* @var IConfig
|
||||
*/
|
||||
private $config;
|
||||
/**
|
||||
* @var Time
|
||||
*/
|
||||
private $timeFactory;
|
||||
private $itemMapper;
|
||||
/**
|
||||
* @var ItemMapper
|
||||
*/
|
||||
private $oldItemMapper;
|
||||
|
||||
public function __construct(
|
||||
ItemMapper $itemMapper,
|
||||
ItemMapperV2 $itemMapper,
|
||||
ItemMapper $oldItemMapper,
|
||||
Time $timeFactory,
|
||||
IConfig $config,
|
||||
LoggerInterface $logger
|
||||
@ -47,7 +58,7 @@ class ItemService extends Service
|
||||
parent::__construct($itemMapper, $logger);
|
||||
$this->config = $config;
|
||||
$this->timeFactory = $timeFactory;
|
||||
$this->itemMapper = $itemMapper;
|
||||
$this->oldItemMapper = $oldItemMapper;
|
||||
}
|
||||
|
||||
|
||||
@ -68,21 +79,21 @@ class ItemService extends Service
|
||||
{
|
||||
switch ($type) {
|
||||
case FeedType::FEED:
|
||||
return $this->itemMapper->findAllNewFeed(
|
||||
return $this->oldItemMapper->findAllNewFeed(
|
||||
$id,
|
||||
$updatedSince,
|
||||
$showAll,
|
||||
$userId
|
||||
);
|
||||
case FeedType::FOLDER:
|
||||
return $this->itemMapper->findAllNewFolder(
|
||||
return $this->oldItemMapper->findAllNewFolder(
|
||||
$id,
|
||||
$updatedSince,
|
||||
$showAll,
|
||||
$userId
|
||||
);
|
||||
default:
|
||||
return $this->itemMapper->findAllNew(
|
||||
return $this->oldItemMapper->findAllNew(
|
||||
$updatedSince,
|
||||
$type,
|
||||
$showAll,
|
||||
@ -120,7 +131,7 @@ class ItemService extends Service
|
||||
) {
|
||||
switch ($type) {
|
||||
case FeedType::FEED:
|
||||
return $this->itemMapper->findAllFeed(
|
||||
return $this->oldItemMapper->findAllFeed(
|
||||
$id,
|
||||
$limit,
|
||||
$offset,
|
||||
@ -130,7 +141,7 @@ class ItemService extends Service
|
||||
$search
|
||||
);
|
||||
case FeedType::FOLDER:
|
||||
return $this->itemMapper->findAllFolder(
|
||||
return $this->oldItemMapper->findAllFolder(
|
||||
$id,
|
||||
$limit,
|
||||
$offset,
|
||||
@ -140,7 +151,7 @@ class ItemService extends Service
|
||||
$search
|
||||
);
|
||||
default:
|
||||
return $this->itemMapper->findAllItems(
|
||||
return $this->oldItemMapper->findAllItems(
|
||||
$limit,
|
||||
$offset,
|
||||
$type,
|
||||
@ -154,7 +165,7 @@ class ItemService extends Service
|
||||
|
||||
public function findAllForUser(string $userId, array $params = []): array
|
||||
{
|
||||
return $this->itemMapper->findAllFromUser($userId);
|
||||
return $this->mapper->findAllFromUser($userId, $params);
|
||||
}
|
||||
|
||||
|
||||
@ -171,18 +182,11 @@ class ItemService extends Service
|
||||
public function star($feedId, $guidHash, $isStarred, $userId)
|
||||
{
|
||||
try {
|
||||
/**
|
||||
* @var Item $item
|
||||
*/
|
||||
$item = $this->itemMapper->findByGuidHash(
|
||||
$guidHash,
|
||||
$feedId,
|
||||
$userId
|
||||
);
|
||||
$item = $this->mapper->findByGuidHash($feedId, $guidHash);
|
||||
|
||||
$item->setStarred($isStarred);
|
||||
|
||||
$this->itemMapper->update($item);
|
||||
$this->mapper->update($item);
|
||||
} catch (DoesNotExistException $ex) {
|
||||
throw new ServiceNotFoundException($ex->getMessage());
|
||||
}
|
||||
@ -202,7 +206,7 @@ class ItemService extends Service
|
||||
{
|
||||
try {
|
||||
$lastModified = $this->timeFactory->getMicroTime();
|
||||
$this->itemMapper->readItem($itemId, $isRead, $lastModified, $userId);
|
||||
$this->oldItemMapper->readItem($itemId, $isRead, $lastModified, $userId);
|
||||
} catch (DoesNotExistException $ex) {
|
||||
throw new ServiceNotFoundException($ex->getMessage());
|
||||
}
|
||||
@ -220,7 +224,7 @@ class ItemService extends Service
|
||||
public function readAll($highestItemId, $userId)
|
||||
{
|
||||
$time = $this->timeFactory->getMicroTime();
|
||||
$this->itemMapper->readAll($highestItemId, $time, $userId);
|
||||
$this->oldItemMapper->readAll($highestItemId, $time, $userId);
|
||||
}
|
||||
|
||||
|
||||
@ -236,7 +240,7 @@ class ItemService extends Service
|
||||
public function readFolder(?int $folderId, $highestItemId, $userId)
|
||||
{
|
||||
$time = $this->timeFactory->getMicroTime();
|
||||
$this->itemMapper->readFolder(
|
||||
$this->oldItemMapper->readFolder(
|
||||
$folderId,
|
||||
$highestItemId,
|
||||
$time,
|
||||
@ -257,7 +261,7 @@ class ItemService extends Service
|
||||
public function readFeed($feedId, $highestItemId, $userId)
|
||||
{
|
||||
$time = $this->timeFactory->getMicroTime();
|
||||
$this->itemMapper->readFeed($feedId, $highestItemId, $time, $userId);
|
||||
$this->oldItemMapper->readFeed($feedId, $highestItemId, $time, $userId);
|
||||
}
|
||||
|
||||
|
||||
@ -275,7 +279,7 @@ class ItemService extends Service
|
||||
Application::DEFAULT_SETTINGS['autoPurgeCount']
|
||||
);
|
||||
if ($count >= 0) {
|
||||
$this->itemMapper->deleteReadOlderThanThreshold($count);
|
||||
$this->oldItemMapper->deleteReadOlderThanThreshold($count);
|
||||
}
|
||||
}
|
||||
|
||||
@ -290,7 +294,7 @@ class ItemService extends Service
|
||||
public function getNewestItemId($userId)
|
||||
{
|
||||
try {
|
||||
return $this->itemMapper->getNewestItemId($userId);
|
||||
return $this->oldItemMapper->getNewestItemId($userId);
|
||||
} catch (DoesNotExistException $ex) {
|
||||
throw new ServiceNotFoundException($ex->getMessage());
|
||||
}
|
||||
@ -305,7 +309,7 @@ class ItemService extends Service
|
||||
*/
|
||||
public function starredCount($userId)
|
||||
{
|
||||
return $this->itemMapper->starredCount($userId);
|
||||
return $this->oldItemMapper->starredCount($userId);
|
||||
}
|
||||
|
||||
|
||||
@ -315,18 +319,7 @@ class ItemService extends Service
|
||||
*/
|
||||
public function getUnreadOrStarred($userId)
|
||||
{
|
||||
return $this->itemMapper->findAllUnreadOrStarred($userId);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Deletes all items of a user
|
||||
*
|
||||
* @param string $userId the name of the user
|
||||
*/
|
||||
public function deleteUser($userId)
|
||||
{
|
||||
$this->itemMapper->deleteUser($userId);
|
||||
return $this->oldItemMapper->findAllUnreadOrStarred($userId);
|
||||
}
|
||||
|
||||
|
||||
@ -335,7 +328,7 @@ class ItemService extends Service
|
||||
*/
|
||||
public function generateSearchIndices()
|
||||
{
|
||||
$this->itemMapper->updateSearchIndices();
|
||||
$this->oldItemMapper->updateSearchIndices();
|
||||
}
|
||||
|
||||
public function findAll(): array
|
||||
|
@ -16,6 +16,7 @@ use OCA\News\AppInfo\Application;
|
||||
use OCA\News\Db\Item;
|
||||
use OCA\News\Db\ItemMapperV2;
|
||||
use OCP\AppFramework\Db\DoesNotExistException;
|
||||
use OCP\AppFramework\Db\Entity;
|
||||
use OCP\IConfig;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
@ -76,8 +77,10 @@ class ItemServiceV2 extends Service
|
||||
* Insert an item or update.
|
||||
*
|
||||
* @param Item $item
|
||||
*
|
||||
* @return Entity|Item The updated/inserted item
|
||||
*/
|
||||
public function insertOrUpdate(Item $item)
|
||||
public function insertOrUpdate(Item $item): Entity
|
||||
{
|
||||
try {
|
||||
$db_item = $this->mapper->findByGuidHash($item->getFeedId(), $item->getGuidHash());
|
||||
@ -94,17 +97,24 @@ class ItemServiceV2 extends Service
|
||||
$item->resetUpdatedFields();
|
||||
}
|
||||
|
||||
$this->mapper->update($item);
|
||||
return $this->mapper->update($item);
|
||||
} catch (DoesNotExistException $exception) {
|
||||
$this->mapper->insert($item);
|
||||
return $this->mapper->insert($item);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $feedId
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function findAllForFeed(int $feedId): array
|
||||
{
|
||||
return $this->mapper->findAllForFeed($feedId);
|
||||
}
|
||||
|
||||
|
||||
|
||||
public function purgeOverThreshold(int $threshold = null)
|
||||
{
|
||||
|
||||
@ -120,4 +130,13 @@ class ItemServiceV2 extends Service
|
||||
|
||||
return $this->mapper->deleteOverThreshold($threshold);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $feedId
|
||||
* @param string $guidHash
|
||||
*/
|
||||
public function findForGuidHash(int $feedId, string $guidHash)
|
||||
{
|
||||
return $this->mapper->findByGuidHash($feedId, $guidHash);
|
||||
}
|
||||
}
|
||||
|
@ -29,11 +29,6 @@ class OpmlService
|
||||
*/
|
||||
private $feedService;
|
||||
|
||||
/**
|
||||
* @var ItemService
|
||||
*/
|
||||
private $itemService;
|
||||
|
||||
/**
|
||||
* @var OPMLExporter
|
||||
*/
|
||||
@ -42,12 +37,10 @@ class OpmlService
|
||||
public function __construct(
|
||||
FolderServiceV2 $folderService,
|
||||
FeedServiceV2 $feedService,
|
||||
ItemServiceV2 $itemService,
|
||||
OPMLExporter $exporter
|
||||
) {
|
||||
$this->folderService = $folderService;
|
||||
$this->feedService = $feedService;
|
||||
$this->itemService = $itemService;
|
||||
$this->exporter = $exporter;
|
||||
}
|
||||
|
||||
|
@ -43,7 +43,7 @@ abstract class Service
|
||||
* @param NewsMapperV2 $mapper
|
||||
* @param LoggerInterface $logger
|
||||
*/
|
||||
public function __construct($mapper, LoggerInterface $logger)
|
||||
public function __construct(NewsMapperV2 $mapper, LoggerInterface $logger)
|
||||
{
|
||||
$this->mapper = $mapper;
|
||||
$this->logger = $logger;
|
||||
@ -76,11 +76,40 @@ abstract class Service
|
||||
* @throws ServiceNotFoundException if the entity does not exist, or there
|
||||
* are more than one of it
|
||||
*/
|
||||
public function delete(string $userId, int $id)
|
||||
public function delete(string $userId, int $id): Entity
|
||||
{
|
||||
$entity = $this->find($userId, $id);
|
||||
|
||||
$this->mapper->delete($entity);
|
||||
return $this->mapper->delete($entity);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Insert an entity
|
||||
*
|
||||
* @param Entity $entity The entity to insert
|
||||
*
|
||||
* @return Entity The inserted entity
|
||||
*/
|
||||
public function insert(Entity $entity): Entity
|
||||
{
|
||||
return $this->mapper->insert($entity);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Update an entity
|
||||
*
|
||||
* @param string $userId the name of the user for security reasons
|
||||
* @param Entity $entity the entity
|
||||
*
|
||||
* @throws ServiceNotFoundException if the entity does not exist, or there
|
||||
* are more than one of it
|
||||
*/
|
||||
public function update(string $userId, Entity $entity): Entity
|
||||
{
|
||||
$this->find($userId, $entity->getId());
|
||||
return $this->mapper->update($entity);
|
||||
}
|
||||
|
||||
|
||||
@ -104,4 +133,17 @@ abstract class Service
|
||||
throw new ServiceNotFoundException($ex->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete all items of a user
|
||||
*
|
||||
* @param string $userId User ID/name
|
||||
*/
|
||||
public function deleteUser(string $userId): void
|
||||
{
|
||||
$items = $this->findAllForUser($userId);
|
||||
foreach ($items as $item) {
|
||||
$this->mapper->delete($item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -28,12 +28,11 @@ class StatusService
|
||||
|
||||
public function __construct(
|
||||
IConfig $settings,
|
||||
IDBConnection $connection,
|
||||
string $AppName
|
||||
IDBConnection $connection
|
||||
) {
|
||||
$this->settings = $settings;
|
||||
$this->appName = $AppName;
|
||||
$this->connection = $connection;
|
||||
$this->appName = Application::NAME;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -11,6 +11,7 @@
|
||||
<file>./lib/AppInfo/Application.php</file>
|
||||
<file>./lib/Controller/JSONHttpErrorTrait.php</file>
|
||||
<file>./lib/**Exception.php</file>
|
||||
<file>./lib/Migration/**.php</file>
|
||||
</exclude>
|
||||
</whitelist>
|
||||
</filter>
|
||||
|
@ -74,7 +74,7 @@ class UpdateFeedTest extends TestCase
|
||||
->method('getLastUpdateError');
|
||||
|
||||
$this->service->expects($this->exactly(1))
|
||||
->method('findForUser')
|
||||
->method('find')
|
||||
->with('admin', '1')
|
||||
->willReturn($feed);
|
||||
|
||||
@ -108,7 +108,7 @@ class UpdateFeedTest extends TestCase
|
||||
->willReturn('Problem');
|
||||
|
||||
$this->service->expects($this->exactly(1))
|
||||
->method('findForUser')
|
||||
->method('find')
|
||||
->with('admin', '1')
|
||||
->willReturn($feed);
|
||||
|
||||
@ -140,7 +140,7 @@ class UpdateFeedTest extends TestCase
|
||||
$feed = $this->createMock(Feed::class);
|
||||
|
||||
$this->service->expects($this->exactly(1))
|
||||
->method('findForUser')
|
||||
->method('find')
|
||||
->with('admin', '1')
|
||||
->willReturn($feed);
|
||||
|
||||
|
@ -1,144 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* Nextcloud - News
|
||||
*
|
||||
* This file is licensed under the Affero General Public License version 3 or
|
||||
* later. See the COPYING file.
|
||||
*
|
||||
* @author Alessandro Cosentino <cosenal@gmail.com>
|
||||
* @author Bernhard Posselt <dev@bernhard-posselt.com>
|
||||
* @copyright 2012 Alessandro Cosentino
|
||||
* @copyright 2012-2014 Bernhard Posselt
|
||||
*/
|
||||
|
||||
namespace OCA\News\Tests\Unit\Controller;
|
||||
|
||||
use OCA\News\Controller\EntityApiSerializer;
|
||||
use \OCP\AppFramework\Http\Response;
|
||||
use \OCP\AppFramework\Db\Entity;
|
||||
|
||||
use \OCA\News\Db\Item;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class TestEntity extends Entity
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
class EntityApiSerializerTest extends TestCase
|
||||
{
|
||||
|
||||
|
||||
public function testSerializeSingle()
|
||||
{
|
||||
$item = new Item();
|
||||
$item->setUnread(true);
|
||||
$item->setId(3);
|
||||
$item->setGuid('guid');
|
||||
$item->setGuidHash('guidhash');
|
||||
$item->setFeedId(123);
|
||||
|
||||
$serializer = new EntityApiSerializer('items');
|
||||
$result = $serializer->serialize($item);
|
||||
|
||||
$this->assertTrue($result['items'][0]['unread']);
|
||||
}
|
||||
|
||||
|
||||
public function testSerializeMultiple()
|
||||
{
|
||||
$item = new Item();
|
||||
$item->setUnread(true);
|
||||
$item->setId(3);
|
||||
$item->setGuid('guid');
|
||||
$item->setGuidHash('guidhash');
|
||||
$item->setFeedId(123);
|
||||
|
||||
$item2 = new Item();
|
||||
$item2->setUnread(false);
|
||||
$item2->setId(5);
|
||||
$item2->setGuid('guid');
|
||||
$item2->setGuidHash('guidhash');
|
||||
$item2->setFeedId(123);
|
||||
|
||||
$serializer = new EntityApiSerializer('items');
|
||||
|
||||
$result = $serializer->serialize([$item, $item2]);
|
||||
|
||||
$this->assertTrue($result['items'][0]['unread']);
|
||||
$this->assertFalse($result['items'][1]['unread']);
|
||||
}
|
||||
|
||||
|
||||
public function testResponseNoChange()
|
||||
{
|
||||
$response = new Response();
|
||||
$serializer = new EntityApiSerializer('items');
|
||||
|
||||
$result = $serializer->serialize($response);
|
||||
|
||||
$this->assertEquals($response, $result);
|
||||
}
|
||||
|
||||
|
||||
public function testCompleteArraysTransformed()
|
||||
{
|
||||
$item = new Item();
|
||||
$item->setUnread(true);
|
||||
$item->setId(3);
|
||||
$item->setGuid('guid');
|
||||
$item->setGuidHash('guidhash');
|
||||
$item->setFeedId(123);
|
||||
|
||||
$item2 = new Item();
|
||||
$item2->setUnread(false);
|
||||
$item2->setId(5);
|
||||
$item2->setGuid('guid');
|
||||
$item2->setGuidHash('guidhash');
|
||||
$item2->setFeedId(123);
|
||||
|
||||
$serializer = new EntityApiSerializer('items');
|
||||
|
||||
$in = [
|
||||
'items' => [$item, $item2],
|
||||
'test' => 1
|
||||
];
|
||||
|
||||
$result = $serializer->serialize($in);
|
||||
|
||||
$this->assertTrue($result['items'][0]['unread']);
|
||||
$this->assertFalse($result['items'][1]['unread']);
|
||||
$this->assertEquals(1, $result['test']);
|
||||
}
|
||||
|
||||
|
||||
public function testNoEntityNoChange()
|
||||
{
|
||||
$serializer = new EntityApiSerializer('items');
|
||||
|
||||
$in = [
|
||||
'items' => ['hi', '2'],
|
||||
'test' => 1
|
||||
];
|
||||
|
||||
$result = $serializer->serialize($in);
|
||||
|
||||
$this->assertEquals('hi', $result['items'][0]);
|
||||
$this->assertEquals('2', $result['items'][1]);
|
||||
$this->assertEquals(1, $result['test']);
|
||||
}
|
||||
|
||||
|
||||
public function testEntitiesNoChange()
|
||||
{
|
||||
$serializer = new EntityApiSerializer('items');
|
||||
|
||||
$in = [
|
||||
'items' => [new TestEntity()]
|
||||
];
|
||||
|
||||
$result = $serializer->serialize($in);
|
||||
|
||||
$this->assertEquals($in, $result);
|
||||
}
|
||||
}
|
@ -15,18 +15,15 @@
|
||||
|
||||
namespace OCA\News\Tests\Unit\Controller;
|
||||
|
||||
use Exception;
|
||||
use OCA\News\Controller\FeedApiController;
|
||||
use OCA\News\Service\FeedService;
|
||||
use OCA\News\Service\FeedServiceV2;
|
||||
use OCA\News\Service\ItemService;
|
||||
use OCA\News\Service\ItemServiceV2;
|
||||
use OCA\News\Utility\PsrLogger;
|
||||
use \OCP\AppFramework\Http;
|
||||
|
||||
use \OCA\News\Service\Exceptions\ServiceNotFoundException;
|
||||
use \OCA\News\Service\Exceptions\ServiceConflictException;
|
||||
use \OCA\News\Db\Feed;
|
||||
use OCP\ILogger;
|
||||
use OCP\IRequest;
|
||||
use OCP\IUser;
|
||||
use OCP\IUserSession;
|
||||
@ -36,10 +33,6 @@ use Psr\Log\LoggerInterface;
|
||||
|
||||
class FeedApiControllerTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @var \PHPUnit\Framework\MockObject\MockObject|FeedService
|
||||
*/
|
||||
private $oldFeedService;
|
||||
|
||||
/**
|
||||
* @var \PHPUnit\Framework\MockObject\MockObject|FeedServiceV2
|
||||
@ -57,7 +50,10 @@ class FeedApiControllerTest extends TestCase
|
||||
private $logger;
|
||||
|
||||
private $class;
|
||||
private $user;
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $userID = '123';
|
||||
private $msg;
|
||||
|
||||
protected function setUp(): void
|
||||
@ -72,18 +68,15 @@ class FeedApiControllerTest extends TestCase
|
||||
$userSession = $this->getMockBuilder(IUserSession::class)
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
$this->user = $this->getMockBuilder(IUser::class)
|
||||
$user = $this->getMockBuilder(IUser::class)
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
$userSession->expects($this->any())
|
||||
->method('getUser')
|
||||
->will($this->returnValue($this->user));
|
||||
$this->user->expects($this->any())
|
||||
->will($this->returnValue($user));
|
||||
$user->expects($this->any())
|
||||
->method('getUID')
|
||||
->will($this->returnValue('123'));
|
||||
$this->oldFeedService = $this->getMockBuilder(FeedService::class)
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
->will($this->returnValue($this->userID));
|
||||
$this->feedService = $this->getMockBuilder(FeedServiceV2::class)
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
@ -93,7 +86,6 @@ class FeedApiControllerTest extends TestCase
|
||||
$this->class = new FeedApiController(
|
||||
$request,
|
||||
$userSession,
|
||||
$this->oldFeedService,
|
||||
$this->feedService,
|
||||
$this->itemService,
|
||||
$this->logger
|
||||
@ -110,25 +102,26 @@ class FeedApiControllerTest extends TestCase
|
||||
|
||||
$this->itemService->expects($this->once())
|
||||
->method('starredCount')
|
||||
->with($this->equalTo($this->user->getUID()))
|
||||
->with($this->equalTo($this->userID))
|
||||
->will($this->returnValue($starredCount));
|
||||
$this->itemService->expects($this->once())
|
||||
->method('getNewestItemId')
|
||||
->with($this->equalTo($this->user->getUID()))
|
||||
->with($this->equalTo($this->userID))
|
||||
->will($this->returnValue($newestItemId));
|
||||
$this->feedService->expects($this->once())
|
||||
->method('findAllForUser')
|
||||
->with($this->equalTo($this->user->getUID()))
|
||||
->with($this->equalTo($this->userID))
|
||||
->will($this->returnValue($feeds));
|
||||
|
||||
$response = $this->class->index();
|
||||
|
||||
$this->assertEquals(
|
||||
[
|
||||
'feeds' => [$feeds[0]->toAPI()],
|
||||
'starredCount' => $starredCount,
|
||||
'newestItemId' => $newestItemId
|
||||
], $response
|
||||
'feeds' => [$feeds[0]->toAPI()],
|
||||
'starredCount' => $starredCount,
|
||||
'newestItemId' => $newestItemId
|
||||
],
|
||||
$response
|
||||
);
|
||||
}
|
||||
|
||||
@ -140,24 +133,25 @@ class FeedApiControllerTest extends TestCase
|
||||
|
||||
$this->itemService->expects($this->once())
|
||||
->method('starredCount')
|
||||
->with($this->equalTo($this->user->getUID()))
|
||||
->with($this->equalTo($this->userID))
|
||||
->will($this->returnValue($starredCount));
|
||||
$this->itemService->expects($this->once())
|
||||
->method('getNewestItemId')
|
||||
->with($this->equalTo($this->user->getUID()))
|
||||
->with($this->equalTo($this->userID))
|
||||
->will($this->throwException(new ServiceNotFoundException('')));
|
||||
$this->feedService->expects($this->once())
|
||||
->method('findAllForUser')
|
||||
->with($this->equalTo($this->user->getUID()))
|
||||
->with($this->equalTo($this->userID))
|
||||
->will($this->returnValue($feeds));
|
||||
|
||||
$response = $this->class->index();
|
||||
|
||||
$this->assertEquals(
|
||||
[
|
||||
'feeds' => [$feeds[0]->toAPI()],
|
||||
'starredCount' => $starredCount,
|
||||
], $response
|
||||
'feeds' => [$feeds[0]->toAPI()],
|
||||
'starredCount' => $starredCount,
|
||||
],
|
||||
$response
|
||||
);
|
||||
}
|
||||
|
||||
@ -167,7 +161,7 @@ class FeedApiControllerTest extends TestCase
|
||||
$this->feedService->expects($this->once())
|
||||
->method('delete')
|
||||
->with(
|
||||
$this->equalTo($this->user->getUID()),
|
||||
$this->equalTo($this->userID),
|
||||
$this->equalTo(2)
|
||||
);
|
||||
|
||||
@ -202,7 +196,7 @@ class FeedApiControllerTest extends TestCase
|
||||
|
||||
$this->feedService->expects($this->once())
|
||||
->method('create')
|
||||
->with($this->user->getUID(), 'url', 3)
|
||||
->with($this->userID, 'url', 3)
|
||||
->will($this->returnValue($feeds[0]));
|
||||
$this->itemService->expects($this->once())
|
||||
->method('getNewestItemId')
|
||||
@ -229,7 +223,7 @@ class FeedApiControllerTest extends TestCase
|
||||
|
||||
$this->feedService->expects($this->once())
|
||||
->method('create')
|
||||
->with($this->user->getUID(), 'ho', 3)
|
||||
->with($this->userID, 'ho', 3)
|
||||
->will($this->returnValue($feeds[0]));
|
||||
$this->itemService->expects($this->once())
|
||||
->method('getNewestItemId')
|
||||
@ -239,8 +233,9 @@ class FeedApiControllerTest extends TestCase
|
||||
|
||||
$this->assertEquals(
|
||||
[
|
||||
'feeds' => [$feeds[0]->toAPI()]
|
||||
], $response
|
||||
'feeds' => [$feeds[0]->toAPI()]
|
||||
],
|
||||
$response
|
||||
);
|
||||
}
|
||||
|
||||
@ -288,7 +283,7 @@ class FeedApiControllerTest extends TestCase
|
||||
->with(
|
||||
$this->equalTo(3),
|
||||
$this->equalTo(30),
|
||||
$this->equalTo($this->user->getUID())
|
||||
$this->equalTo($this->userID)
|
||||
);
|
||||
|
||||
$this->class->read(3, 30);
|
||||
@ -297,13 +292,18 @@ class FeedApiControllerTest extends TestCase
|
||||
|
||||
public function testMove()
|
||||
{
|
||||
$this->oldFeedService->expects($this->once())
|
||||
->method('patch')
|
||||
->with(
|
||||
$this->equalTo(3),
|
||||
$this->equalTo($this->user->getUID()),
|
||||
$this->equalTo(['folderId' => 30])
|
||||
);
|
||||
$feed = $this->getMockBuilder(Feed::class)->getMock();
|
||||
$feed->expects($this->once())
|
||||
->method('setFolderId')
|
||||
->with(30)
|
||||
->will($this->returnSelf());
|
||||
$this->feedService->expects($this->once())
|
||||
->method('find')
|
||||
->with($this->userID, 3)
|
||||
->will($this->returnValue($feed));
|
||||
$this->feedService->expects($this->once())
|
||||
->method('update')
|
||||
->with($this->userID, $feed);
|
||||
|
||||
$this->class->move(3, 30);
|
||||
}
|
||||
@ -311,8 +311,8 @@ class FeedApiControllerTest extends TestCase
|
||||
|
||||
public function testMoveDoesNotExist()
|
||||
{
|
||||
$this->oldFeedService->expects($this->once())
|
||||
->method('patch')
|
||||
$this->feedService->expects($this->once())
|
||||
->method('update')
|
||||
->will(
|
||||
$this->throwException(new ServiceNotFoundException($this->msg))
|
||||
);
|
||||
@ -327,18 +327,20 @@ class FeedApiControllerTest extends TestCase
|
||||
|
||||
public function testRename()
|
||||
{
|
||||
$feedId = 3;
|
||||
$feedTitle = 'test';
|
||||
$feed = $this->getMockBuilder(Feed::class)->getMock();
|
||||
$feed->expects($this->once())
|
||||
->method('setTitle')
|
||||
->with('test')
|
||||
->will($this->returnSelf());
|
||||
$this->feedService->expects($this->once())
|
||||
->method('find')
|
||||
->with($this->userID, 3)
|
||||
->will($this->returnValue($feed));
|
||||
$this->feedService->expects($this->once())
|
||||
->method('update')
|
||||
->with($this->userID, $feed);
|
||||
|
||||
$this->oldFeedService->expects($this->once())
|
||||
->method('patch')
|
||||
->with(
|
||||
$this->equalTo($feedId),
|
||||
$this->equalTo($this->user->getUID()),
|
||||
$this->equalTo(['title' => $feedTitle])
|
||||
);
|
||||
|
||||
$this->class->rename($feedId, $feedTitle);
|
||||
$this->class->rename(3, 'test');
|
||||
}
|
||||
|
||||
|
||||
@ -347,13 +349,9 @@ class FeedApiControllerTest extends TestCase
|
||||
$feedId = 3;
|
||||
$feedTitle = 'test';
|
||||
|
||||
$this->oldFeedService->expects($this->once())
|
||||
->method('patch')
|
||||
->with(
|
||||
$this->equalTo($feedId),
|
||||
$this->equalTo($this->user->getUID()),
|
||||
$this->equalTo(['title' => $feedTitle])
|
||||
)
|
||||
$this->feedService->expects($this->once())
|
||||
->method('find')
|
||||
->with($this->userID, 3)
|
||||
->will($this->throwException(new ServiceNotFoundException('hi')));
|
||||
|
||||
$result = $this->class->rename($feedId, $feedTitle);
|
||||
@ -365,7 +363,7 @@ class FeedApiControllerTest extends TestCase
|
||||
}
|
||||
|
||||
|
||||
public function testfromAllUsers()
|
||||
public function testFromAllUsers()
|
||||
{
|
||||
$feed = new Feed();
|
||||
$feed->setUrl(3);
|
||||
@ -405,7 +403,7 @@ class FeedApiControllerTest extends TestCase
|
||||
$userId = 'hi';
|
||||
$this->feedService->expects($this->once())
|
||||
->method('find')
|
||||
->will($this->throwException(new \Exception($this->msg)));
|
||||
->will($this->throwException(new Exception($this->msg)));
|
||||
|
||||
$this->logger->expects($this->once())
|
||||
->method('debug')
|
||||
|
@ -14,8 +14,10 @@
|
||||
namespace OCA\News\Tests\Unit\Controller;
|
||||
|
||||
use OCA\News\Controller\FeedController;
|
||||
use OCA\News\Service\FeedService;
|
||||
use OCA\News\Db\Folder;
|
||||
use OCA\News\Service\FeedServiceV2;
|
||||
use OCA\News\Service\FolderServiceV2;
|
||||
use OCA\News\Service\ImportService;
|
||||
use OCA\News\Service\ItemService;
|
||||
use OCP\AppFramework\Http;
|
||||
|
||||
@ -45,10 +47,13 @@ class FeedControllerTest extends TestCase
|
||||
*/
|
||||
private $folderService;
|
||||
/**
|
||||
* TODO: Remove
|
||||
* @var MockObject|FeedService
|
||||
* @var MockObject|FeedServiceV2
|
||||
*/
|
||||
private $feedService;
|
||||
/**
|
||||
* @var MockObject|ImportService
|
||||
*/
|
||||
private $importService;
|
||||
/**
|
||||
* TODO: Remove
|
||||
* @var MockObject|ItemService
|
||||
@ -86,7 +91,11 @@ class FeedControllerTest extends TestCase
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
$this->feedService = $this
|
||||
->getMockBuilder(FeedService::class)
|
||||
->getMockBuilder(FeedServiceV2::class)
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
$this->importService = $this
|
||||
->getMockBuilder(ImportService::class)
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
$this->folderService = $this
|
||||
@ -110,6 +119,7 @@ class FeedControllerTest extends TestCase
|
||||
$this->folderService,
|
||||
$this->feedService,
|
||||
$this->itemService,
|
||||
$this->importService,
|
||||
$this->settings,
|
||||
$this->userSession
|
||||
);
|
||||
@ -136,11 +146,11 @@ class FeedControllerTest extends TestCase
|
||||
->will($this->returnValue($result['feeds']));
|
||||
$this->itemService->expects($this->once())
|
||||
->method('getNewestItemId')
|
||||
->with($this->equalTo($this->uid))
|
||||
->with($this->uid)
|
||||
->will($this->throwException(new ServiceNotFoundException('')));
|
||||
$this->itemService->expects($this->once())
|
||||
->method('starredCount')
|
||||
->with($this->equalTo($this->uid))
|
||||
->with($this->uid)
|
||||
->will($this->returnValue($result['starred']));
|
||||
|
||||
$response = $this->class->index();
|
||||
@ -160,15 +170,15 @@ class FeedControllerTest extends TestCase
|
||||
];
|
||||
$this->feedService->expects($this->once())
|
||||
->method('findAllForUser')
|
||||
->with($this->equalTo($this->uid))
|
||||
->with($this->uid)
|
||||
->will($this->returnValue($result['feeds']));
|
||||
$this->itemService->expects($this->once())
|
||||
->method('getNewestItemId')
|
||||
->with($this->equalTo($this->uid))
|
||||
->with($this->uid)
|
||||
->will($this->returnValue($result['newestItemId']));
|
||||
$this->itemService->expects($this->once())
|
||||
->method('starredCount')
|
||||
->with($this->equalTo($this->uid))
|
||||
->with($this->uid)
|
||||
->will($this->returnValue($result['starred']));
|
||||
|
||||
$response = $this->class->index();
|
||||
@ -229,6 +239,32 @@ class FeedControllerTest extends TestCase
|
||||
}
|
||||
|
||||
|
||||
public function testActiveFolder()
|
||||
{
|
||||
$type = FeedType::FOLDER;
|
||||
$folder = new Folder();
|
||||
$folder->setId(3);
|
||||
|
||||
$result = [
|
||||
'activeFeed' => [
|
||||
'id' => 3,
|
||||
'type' => 1
|
||||
]
|
||||
];
|
||||
|
||||
$this->folderService->expects($this->once())
|
||||
->method('find')
|
||||
->with($this->uid, 3)
|
||||
->will($this->returnValue($folder));
|
||||
|
||||
$this->activeInitMocks(3, $type);
|
||||
|
||||
$response = $this->class->active();
|
||||
|
||||
$this->assertEquals($result, $response);
|
||||
}
|
||||
|
||||
|
||||
public function testActiveFolderDoesNotExist()
|
||||
{
|
||||
$id = 3;
|
||||
@ -276,15 +312,10 @@ class FeedControllerTest extends TestCase
|
||||
->will($this->returnValue($result['newestItemId']));
|
||||
$this->feedService->expects($this->once())
|
||||
->method('purgeDeleted')
|
||||
->with($this->equalTo($this->uid), $this->equalTo(false));
|
||||
->with($this->uid, false);
|
||||
$this->feedService->expects($this->once())
|
||||
->method('create')
|
||||
->with(
|
||||
$this->equalTo('hi'),
|
||||
$this->equalTo(4),
|
||||
$this->equalTo($this->uid),
|
||||
$this->equalTo('yo')
|
||||
)
|
||||
->with($this->uid, 'hi', 4, false, 'yo')
|
||||
->will($this->returnValue($result['feeds'][0]));
|
||||
|
||||
$response = $this->class->create('hi', 4, 'yo');
|
||||
@ -293,13 +324,37 @@ class FeedControllerTest extends TestCase
|
||||
}
|
||||
|
||||
|
||||
public function testCreateOldFolderId()
|
||||
{
|
||||
$result = [
|
||||
'feeds' => [new Feed()],
|
||||
'newestItemId' => 3
|
||||
];
|
||||
|
||||
$this->itemService->expects($this->once())
|
||||
->method('getNewestItemId')
|
||||
->will($this->returnValue($result['newestItemId']));
|
||||
$this->feedService->expects($this->once())
|
||||
->method('purgeDeleted')
|
||||
->with($this->uid, false);
|
||||
$this->feedService->expects($this->once())
|
||||
->method('create')
|
||||
->with($this->uid, 'hi', null, false, 'yo')
|
||||
->will($this->returnValue($result['feeds'][0]));
|
||||
|
||||
$response = $this->class->create('hi', 0, 'yo');
|
||||
|
||||
$this->assertEquals($result, $response);
|
||||
}
|
||||
|
||||
|
||||
public function testCreateNoItems()
|
||||
{
|
||||
$result = ['feeds' => [new Feed()]];
|
||||
|
||||
$this->feedService->expects($this->once())
|
||||
->method('purgeDeleted')
|
||||
->with($this->equalTo($this->uid), $this->equalTo(false));
|
||||
->with($this->uid, false);
|
||||
|
||||
$this->itemService->expects($this->once())
|
||||
->method('getNewestItemId')
|
||||
@ -307,12 +362,7 @@ class FeedControllerTest extends TestCase
|
||||
|
||||
$this->feedService->expects($this->once())
|
||||
->method('create')
|
||||
->with(
|
||||
$this->equalTo('hi'),
|
||||
$this->equalTo(4),
|
||||
$this->equalTo($this->uid),
|
||||
$this->equalTo('yo')
|
||||
)
|
||||
->with($this->uid, 'hi', 4, false, 'yo')
|
||||
->will($this->returnValue($result['feeds'][0]));
|
||||
|
||||
$response = $this->class->create('hi', 4, 'yo');
|
||||
@ -327,7 +377,7 @@ class FeedControllerTest extends TestCase
|
||||
$ex = new ServiceNotFoundException($msg);
|
||||
$this->feedService->expects($this->once())
|
||||
->method('purgeDeleted')
|
||||
->with($this->equalTo($this->uid), $this->equalTo(false));
|
||||
->with($this->uid, false);
|
||||
$this->feedService->expects($this->once())
|
||||
->method('create')
|
||||
->will($this->throwException($ex));
|
||||
@ -348,7 +398,7 @@ class FeedControllerTest extends TestCase
|
||||
$ex = new ServiceConflictException($msg);
|
||||
$this->feedService->expects($this->once())
|
||||
->method('purgeDeleted')
|
||||
->with($this->equalTo($this->uid), $this->equalTo(false));
|
||||
->with($this->uid, false);
|
||||
$this->feedService->expects($this->once())
|
||||
->method('create')
|
||||
->will($this->throwException($ex));
|
||||
@ -363,9 +413,17 @@ class FeedControllerTest extends TestCase
|
||||
|
||||
public function testDelete()
|
||||
{
|
||||
$feed = $this->getMockBuilder(Feed::class)
|
||||
->getMock();
|
||||
$feed->expects($this->once())
|
||||
->method('setDeletedAt');
|
||||
$this->feedService->expects($this->once())
|
||||
->method('markDeleted')
|
||||
->with($this->equalTo(4));
|
||||
->method('find')
|
||||
->with('jack', 4)
|
||||
->willReturn($feed);
|
||||
$this->feedService->expects($this->once())
|
||||
->method('update')
|
||||
->with('jack', $feed);
|
||||
|
||||
$this->class->delete(4);
|
||||
}
|
||||
@ -376,7 +434,7 @@ class FeedControllerTest extends TestCase
|
||||
$msg = 'hehe';
|
||||
|
||||
$this->feedService->expects($this->once())
|
||||
->method('markDeleted')
|
||||
->method('find')
|
||||
->will($this->throwException(new ServiceNotFoundException($msg)));
|
||||
|
||||
$response = $this->class->delete(4);
|
||||
@ -402,8 +460,13 @@ class FeedControllerTest extends TestCase
|
||||
];
|
||||
|
||||
$this->feedService->expects($this->once())
|
||||
->method('update')
|
||||
->with($this->equalTo($this->uid), $this->equalTo(4))
|
||||
->method('find')
|
||||
->with($this->uid, 4)
|
||||
->will($this->returnValue($feed));
|
||||
|
||||
$this->feedService->expects($this->once())
|
||||
->method('fetch')
|
||||
->with($feed)
|
||||
->will($this->returnValue($feed));
|
||||
|
||||
$response = $this->class->update(4);
|
||||
@ -415,8 +478,8 @@ class FeedControllerTest extends TestCase
|
||||
public function testUpdateReturnsJSONError()
|
||||
{
|
||||
$this->feedService->expects($this->once())
|
||||
->method('update')
|
||||
->with($this->equalTo($this->uid), $this->equalTo(4))
|
||||
->method('find')
|
||||
->with($this->uid, 4)
|
||||
->will($this->throwException(new ServiceNotFoundException('NO!')));
|
||||
|
||||
$response = $this->class->update(4);
|
||||
@ -436,17 +499,14 @@ class FeedControllerTest extends TestCase
|
||||
'feeds' => [$feed]
|
||||
];
|
||||
|
||||
$this->feedService->expects($this->once())
|
||||
$this->importService->expects($this->once())
|
||||
->method('importArticles')
|
||||
->with(
|
||||
$this->equalTo(['json']),
|
||||
$this->equalTo($this->uid)
|
||||
)
|
||||
->with($this->uid, ['json'],)
|
||||
->will($this->returnValue($feed));
|
||||
|
||||
$this->itemService->expects($this->once())
|
||||
->method('starredCount')
|
||||
->with($this->equalTo($this->uid))
|
||||
->with($this->uid)
|
||||
->will($this->returnValue(3));
|
||||
|
||||
$response = $this->class->import(['json']);
|
||||
@ -457,17 +517,14 @@ class FeedControllerTest extends TestCase
|
||||
|
||||
public function testImportCreatesNoAdditionalFeed()
|
||||
{
|
||||
$this->feedService->expects($this->once())
|
||||
$this->importService->expects($this->once())
|
||||
->method('importArticles')
|
||||
->with(
|
||||
$this->equalTo(['json']),
|
||||
$this->equalTo($this->uid)
|
||||
)
|
||||
->with($this->uid, ['json'])
|
||||
->will($this->returnValue(null));
|
||||
|
||||
$this->itemService->expects($this->once())
|
||||
->method('starredCount')
|
||||
->with($this->equalTo($this->uid))
|
||||
->with($this->uid)
|
||||
->will($this->returnValue(3));
|
||||
|
||||
$response = $this->class->import(['json']);
|
||||
@ -489,7 +546,7 @@ class FeedControllerTest extends TestCase
|
||||
|
||||
$this->itemService->expects($this->once())
|
||||
->method('readFeed')
|
||||
->with($this->equalTo(4), $this->equalTo(5), $this->uid);
|
||||
->with(4, 5, $this->uid);
|
||||
|
||||
$response = $this->class->read(4, 5);
|
||||
$this->assertEquals($expected, $response);
|
||||
@ -498,9 +555,21 @@ class FeedControllerTest extends TestCase
|
||||
|
||||
public function testRestore()
|
||||
{
|
||||
$feed = $this->getMockBuilder(Feed::class)
|
||||
->getMock();
|
||||
|
||||
$feed->expects($this->once())
|
||||
->method('setDeletedAt')
|
||||
->with(null);
|
||||
|
||||
$this->feedService->expects($this->once())
|
||||
->method('unmarkDeleted')
|
||||
->with($this->equalTo(4));
|
||||
->method('find')
|
||||
->with($this->uid, 4)
|
||||
->willReturn($feed);
|
||||
|
||||
$this->feedService->expects($this->once())
|
||||
->method('update')
|
||||
->with($this->uid, $feed);
|
||||
|
||||
$this->class->restore(4);
|
||||
}
|
||||
@ -511,7 +580,8 @@ class FeedControllerTest extends TestCase
|
||||
$msg = 'hehe';
|
||||
|
||||
$this->feedService->expects($this->once())
|
||||
->method('unmarkDeleted')
|
||||
->method('find')
|
||||
->with($this->uid, 4)
|
||||
->will($this->throwException(new ServiceNotFoundException($msg)));
|
||||
|
||||
$response = $this->class->restore(4);
|
||||
@ -523,17 +593,46 @@ class FeedControllerTest extends TestCase
|
||||
|
||||
public function testPatch()
|
||||
{
|
||||
$expected = [
|
||||
'pinned' => true,
|
||||
'fullTextEnabled' => true,
|
||||
'updateMode' => 1
|
||||
];
|
||||
$this->feedService->expects($this->once())
|
||||
->method('patch')
|
||||
->with(4, $this->uid, $expected)
|
||||
->will($this->returnValue(1));
|
||||
$feed = $this->getMockBuilder(Feed::class)
|
||||
->getMock();
|
||||
|
||||
$this->class->patch(4, true, true, 1);
|
||||
$feed->expects($this->once())
|
||||
->method('setFolderId')
|
||||
->with(null);
|
||||
|
||||
$feed->expects($this->once())
|
||||
->method('setPinned')
|
||||
->with(true);
|
||||
|
||||
$feed->expects($this->once())
|
||||
->method('setFullTextEnabled')
|
||||
->with(false);
|
||||
|
||||
|
||||
$feed->expects($this->once())
|
||||
->method('setUpdateMode')
|
||||
->with(1);
|
||||
|
||||
|
||||
$feed->expects($this->never())
|
||||
->method('setOrdering')
|
||||
->with(true);
|
||||
|
||||
|
||||
$feed->expects($this->never())
|
||||
->method('setTitle')
|
||||
->with(true);
|
||||
|
||||
$this->feedService->expects($this->once())
|
||||
->method('find')
|
||||
->with($this->uid, 4)
|
||||
->will($this->returnValue($feed));
|
||||
|
||||
$this->feedService->expects($this->once())
|
||||
->method('update')
|
||||
->with($this->uid, $feed);
|
||||
|
||||
$this->class->patch(4, true, false, 1);
|
||||
}
|
||||
|
||||
public function testPatchDoesNotExist()
|
||||
@ -541,7 +640,8 @@ class FeedControllerTest extends TestCase
|
||||
$msg = 'hehe';
|
||||
|
||||
$this->feedService->expects($this->once())
|
||||
->method('patch')
|
||||
->method('find')
|
||||
->with($this->uid, 4)
|
||||
->will($this->throwException(new ServiceNotFoundException($msg)));
|
||||
|
||||
$response = $this->class->patch(4, 2);
|
||||
@ -551,5 +651,54 @@ class FeedControllerTest extends TestCase
|
||||
$this->assertEquals($response->getStatus(), Http::STATUS_NOT_FOUND);
|
||||
}
|
||||
|
||||
public function testPatchDoesNotExistOnUpdate()
|
||||
{
|
||||
$feed = $this->getMockBuilder(Feed::class)
|
||||
->getMock();
|
||||
|
||||
$feed->expects($this->once())
|
||||
->method('setFolderId')
|
||||
->with(1);
|
||||
|
||||
$feed->expects($this->once())
|
||||
->method('setPinned')
|
||||
->with(true);
|
||||
|
||||
$feed->expects($this->once())
|
||||
->method('setFullTextEnabled')
|
||||
->with(false);
|
||||
|
||||
|
||||
$feed->expects($this->once())
|
||||
->method('setUpdateMode')
|
||||
->with(1);
|
||||
|
||||
|
||||
$feed->expects($this->once())
|
||||
->method('setOrdering')
|
||||
->with(1);
|
||||
|
||||
|
||||
$feed->expects($this->once())
|
||||
->method('setTitle')
|
||||
->with('title');
|
||||
|
||||
$this->feedService->expects($this->once())
|
||||
->method('find')
|
||||
->with($this->uid, 4)
|
||||
->will($this->returnValue($feed));
|
||||
|
||||
$this->feedService->expects($this->once())
|
||||
->method('update')
|
||||
->with($this->uid, $feed)
|
||||
->will($this->throwException(new ServiceNotFoundException('test')));
|
||||
|
||||
$response = $this->class->patch(4, 2, false, 1, 1, 1, 'title');
|
||||
$params = json_decode($response->render(), true);
|
||||
|
||||
$this->assertEquals('test', $params['message']);
|
||||
$this->assertEquals($response->getStatus(), Http::STATUS_NOT_FOUND);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -14,7 +14,7 @@
|
||||
namespace OCA\News\Tests\Unit\Controller;
|
||||
|
||||
use OCA\News\Controller\FolderController;
|
||||
use OCA\News\Service\FeedService;
|
||||
use OCA\News\Service\FeedServiceV2;
|
||||
use OCA\News\Service\FolderServiceV2;
|
||||
use OCA\News\Service\ItemService;
|
||||
use \OCP\AppFramework\Http;
|
||||
@ -39,6 +39,9 @@ class FolderControllerTest extends TestCase
|
||||
*/
|
||||
private $folderService;
|
||||
private $itemService;
|
||||
/**
|
||||
* @var MockObject|FeedServiceV2
|
||||
*/
|
||||
private $feedService;
|
||||
/**
|
||||
* @var MockObject|IUser
|
||||
@ -60,7 +63,7 @@ class FolderControllerTest extends TestCase
|
||||
$this->folderService = $this->getMockBuilder(FolderServiceV2::class)
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
$this->feedService = $this->getMockBuilder(FeedService::class)
|
||||
$this->feedService = $this->getMockBuilder(FeedServiceV2::class)
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
$this->itemService = $this->getMockBuilder(ItemService::class)
|
||||
|
@ -14,7 +14,7 @@
|
||||
namespace OCA\News\Tests\Unit\Controller;
|
||||
|
||||
use OCA\News\Controller\ItemController;
|
||||
use OCA\News\Service\FeedService;
|
||||
use OCA\News\Service\FeedServiceV2;
|
||||
use OCA\News\Service\ItemService;
|
||||
use \OCP\AppFramework\Http;
|
||||
|
||||
@ -34,9 +34,21 @@ class ItemControllerTest extends TestCase
|
||||
{
|
||||
|
||||
private $appName;
|
||||
/**
|
||||
* @var \PHPUnit\Framework\MockObject\MockObject|IConfig
|
||||
*/
|
||||
private $settings;
|
||||
/**
|
||||
* @var \PHPUnit\Framework\MockObject\MockObject|ItemService
|
||||
*/
|
||||
private $itemService;
|
||||
/**
|
||||
* @var \PHPUnit\Framework\MockObject\MockObject|FeedServiceV2
|
||||
*/
|
||||
private $feedService;
|
||||
/**
|
||||
* @var \PHPUnit\Framework\MockObject\MockObject|IRequest
|
||||
*/
|
||||
private $request;
|
||||
/**
|
||||
* @var \PHPUnit\Framework\MockObject\MockObject|IUser
|
||||
@ -64,7 +76,7 @@ class ItemControllerTest extends TestCase
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
$this->feedService =
|
||||
$this->getMockBuilder(FeedService::class)
|
||||
$this->getMockBuilder(FeedServiceV2::class)
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
$this->request = $this->getMockBuilder(IRequest::class)
|
||||
|
451
tests/Unit/Db/FeedMapperTest.php
Normal file
451
tests/Unit/Db/FeedMapperTest.php
Normal file
@ -0,0 +1,451 @@
|
||||
<?php
|
||||
/**
|
||||
* Nextcloud - News
|
||||
*
|
||||
* This file is licensed under the Affero General Public License version 3 or
|
||||
* later. See the COPYING file.
|
||||
*
|
||||
* @author Alessandro Cosentino <cosenal@gmail.com>
|
||||
* @author Bernhard Posselt <dev@bernhard-posselt.com>
|
||||
* @copyright 2012 Alessandro Cosentino
|
||||
* @copyright 2012-2014 Bernhard Posselt
|
||||
*/
|
||||
|
||||
namespace OCA\News\Tests\Unit\Db;
|
||||
|
||||
use OCA\News\Db\Feed;
|
||||
use OCA\News\Db\FeedMapperV2;
|
||||
use OCA\News\Db\Folder;
|
||||
use OCA\News\Utility\Time;
|
||||
use OCP\AppFramework\Db\DoesNotExistException;
|
||||
use OCP\AppFramework\Db\MultipleObjectsReturnedException;
|
||||
use OCP\DB\QueryBuilder\IFunctionBuilder;
|
||||
|
||||
class FeedMapperTest extends MapperTestUtility
|
||||
{
|
||||
/** @var FeedMapperV2 */
|
||||
private $class;
|
||||
/** @var Feeds[] */
|
||||
private $feeds;
|
||||
|
||||
/**
|
||||
* @covers \OCA\News\Db\FeedMapperV2::__construct
|
||||
*/
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->class = new FeedMapperV2($this->db, new Time());
|
||||
|
||||
// create mock folders
|
||||
$feed1 = new Feed();
|
||||
$feed1->setId(4);
|
||||
$feed1->resetUpdatedFields();
|
||||
$feed2 = new Feed();
|
||||
$feed2->setId(5);
|
||||
$feed2->resetUpdatedFields();
|
||||
|
||||
$this->feeds = [$feed1, $feed2];
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers \OCA\News\Db\FeedMapperV2::__construct
|
||||
*/
|
||||
public function testSetUpSuccess(): void
|
||||
{
|
||||
$this->assertEquals('news_feeds', $this->class->getTableName());
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers \OCA\News\Db\FeedMapperV2::findAllFromUser
|
||||
*/
|
||||
public function testFindAllFromUser()
|
||||
{
|
||||
$this->db->expects($this->once())
|
||||
->method('getQueryBuilder')
|
||||
->willReturn($this->builder);
|
||||
|
||||
$funcbuilder = $this->getMockBuilder(IFunctionBuilder::class)
|
||||
->getMock();
|
||||
|
||||
$funcbuilder->expects($this->once())
|
||||
->method('count')
|
||||
->with('items.id', 'unreadCount')
|
||||
->will($this->returnValue('COUNT_FUNC'));
|
||||
|
||||
$this->builder->expects($this->once())
|
||||
->method('func')
|
||||
->will($this->returnValue($funcbuilder));
|
||||
|
||||
$this->builder->expects($this->once())
|
||||
->method('select')
|
||||
->with('feeds.*', 'COUNT_FUNC')
|
||||
->will($this->returnSelf());
|
||||
|
||||
$this->builder->expects($this->once())
|
||||
->method('from')
|
||||
->with('news_feeds', 'feeds')
|
||||
->will($this->returnSelf());
|
||||
|
||||
$this->builder->expects($this->once())
|
||||
->method('leftJoin')
|
||||
->with('feeds', 'news_items', 'items', 'items.feed_id = feeds.id AND items.unread = :unread')
|
||||
->will($this->returnSelf());
|
||||
|
||||
$this->builder->expects($this->once())
|
||||
->method('where')
|
||||
->with('feeds.user_id = :user_id')
|
||||
->will($this->returnSelf());
|
||||
|
||||
$this->builder->expects($this->once())
|
||||
->method('andWhere')
|
||||
->with('feeds.deleted_at = 0')
|
||||
->will($this->returnSelf());
|
||||
|
||||
$this->builder->expects($this->once())
|
||||
->method('groupby')
|
||||
->with('feeds.id')
|
||||
->will($this->returnSelf());
|
||||
|
||||
$this->builder->expects($this->exactly(2))
|
||||
->method('setParameter')
|
||||
->withConsecutive([':unread', true], [':user_id', 'jack'])
|
||||
->will($this->returnSelf());
|
||||
|
||||
$this->builder->expects($this->once())
|
||||
->method('execute')
|
||||
->will($this->returnValue($this->cursor));
|
||||
|
||||
$this->cursor->expects($this->exactly(3))
|
||||
->method('fetch')
|
||||
->willReturnOnConsecutiveCalls(
|
||||
['id' => 4],
|
||||
['id' => 5],
|
||||
null
|
||||
);
|
||||
|
||||
$result = $this->class->findAllFromUser('jack', []);
|
||||
$this->assertEquals($this->feeds, $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers \OCA\News\Db\FeedMapperV2::findFromUser
|
||||
*/
|
||||
public function testFindFromUser()
|
||||
{
|
||||
$this->db->expects($this->once())
|
||||
->method('getQueryBuilder')
|
||||
->willReturn($this->builder);
|
||||
|
||||
$this->builder->expects($this->once())
|
||||
->method('select')
|
||||
->with('*')
|
||||
->will($this->returnSelf());
|
||||
|
||||
$this->builder->expects($this->once())
|
||||
->method('from')
|
||||
->with('news_feeds')
|
||||
->will($this->returnSelf());
|
||||
|
||||
$this->builder->expects($this->once())
|
||||
->method('where')
|
||||
->with('user_id = :user_id')
|
||||
->will($this->returnSelf());
|
||||
|
||||
$this->builder->expects($this->exactly(1))
|
||||
->method('andWhere')
|
||||
->withConsecutive(['id = :id'])
|
||||
->will($this->returnSelf());
|
||||
|
||||
$this->builder->expects($this->exactly(2))
|
||||
->method('setParameter')
|
||||
->withConsecutive([':user_id', 'jack'], [':id', 1])
|
||||
->will($this->returnSelf());
|
||||
|
||||
$this->builder->expects($this->once())
|
||||
->method('execute')
|
||||
->will($this->returnValue($this->cursor));
|
||||
|
||||
$this->cursor->expects($this->exactly(2))
|
||||
->method('fetch')
|
||||
->willReturnOnConsecutiveCalls(
|
||||
['id' => 4],
|
||||
false
|
||||
);
|
||||
|
||||
$result = $this->class->findFromUser('jack', 1);
|
||||
$this->assertEquals($this->feeds[0], $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers \OCA\News\Db\FeedMapperV2::findFromUser
|
||||
*/
|
||||
public function testFindFromUserEmpty()
|
||||
{
|
||||
$this->db->expects($this->once())
|
||||
->method('getQueryBuilder')
|
||||
->willReturn($this->builder);
|
||||
|
||||
$this->builder->expects($this->once())
|
||||
->method('select')
|
||||
->with('*')
|
||||
->will($this->returnSelf());
|
||||
|
||||
$this->builder->expects($this->once())
|
||||
->method('from')
|
||||
->with('news_feeds')
|
||||
->will($this->returnSelf());
|
||||
|
||||
$this->builder->expects($this->once())
|
||||
->method('where')
|
||||
->with('user_id = :user_id')
|
||||
->will($this->returnSelf());
|
||||
|
||||
$this->builder->expects($this->exactly(1))
|
||||
->method('andWhere')
|
||||
->withConsecutive(['id = :id'])
|
||||
->will($this->returnSelf());
|
||||
|
||||
$this->builder->expects($this->exactly(2))
|
||||
->method('setParameter')
|
||||
->withConsecutive([':user_id', 'jack'], [':id', 1])
|
||||
->will($this->returnSelf());
|
||||
|
||||
$this->builder->expects($this->once())
|
||||
->method('execute')
|
||||
->will($this->returnValue($this->cursor));
|
||||
|
||||
$this->cursor->expects($this->exactly(1))
|
||||
->method('fetch')
|
||||
->willReturnOnConsecutiveCalls(
|
||||
false
|
||||
);
|
||||
|
||||
$this->expectException(DoesNotExistException::class);
|
||||
$this->class->findFromUser('jack', 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers \OCA\News\Db\FeedMapperV2::findByURL
|
||||
*/
|
||||
public function testFindByUrl()
|
||||
{
|
||||
$this->db->expects($this->once())
|
||||
->method('getQueryBuilder')
|
||||
->willReturn($this->builder);
|
||||
|
||||
$this->builder->expects($this->once())
|
||||
->method('select')
|
||||
->with('*')
|
||||
->will($this->returnSelf());
|
||||
|
||||
$this->builder->expects($this->once())
|
||||
->method('from')
|
||||
->with('news_feeds')
|
||||
->will($this->returnSelf());
|
||||
|
||||
$this->builder->expects($this->once())
|
||||
->method('where')
|
||||
->with('user_id = :user_id')
|
||||
->will($this->returnSelf());
|
||||
|
||||
$this->builder->expects($this->exactly(1))
|
||||
->method('andWhere')
|
||||
->withConsecutive(['url = :url'])
|
||||
->will($this->returnSelf());
|
||||
|
||||
$this->builder->expects($this->exactly(2))
|
||||
->method('setParameter')
|
||||
->withConsecutive([':user_id', 'jack'], [':url', 'https://url.com'])
|
||||
->will($this->returnSelf());
|
||||
|
||||
$this->builder->expects($this->once())
|
||||
->method('execute')
|
||||
->will($this->returnValue($this->cursor));
|
||||
|
||||
$this->cursor->expects($this->exactly(2))
|
||||
->method('fetch')
|
||||
->willReturnOnConsecutiveCalls(
|
||||
['id' => 4],
|
||||
false
|
||||
);
|
||||
|
||||
$result = $this->class->findByURL('jack', 'https://url.com');
|
||||
$this->assertEquals($this->feeds[0], $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers \OCA\News\Db\FeedMapperV2::findFromUser
|
||||
*/
|
||||
public function testFindFromUserDuplicate()
|
||||
{
|
||||
|
||||
$this->db->expects($this->once())
|
||||
->method('getQueryBuilder')
|
||||
->willReturn($this->builder);
|
||||
|
||||
$this->builder->expects($this->once())
|
||||
->method('select')
|
||||
->with('*')
|
||||
->will($this->returnSelf());
|
||||
|
||||
$this->builder->expects($this->once())
|
||||
->method('from')
|
||||
->with('news_feeds')
|
||||
->will($this->returnSelf());
|
||||
|
||||
$this->builder->expects($this->once())
|
||||
->method('where')
|
||||
->with('user_id = :user_id')
|
||||
->will($this->returnSelf());
|
||||
|
||||
$this->builder->expects($this->exactly(1))
|
||||
->method('andWhere')
|
||||
->withConsecutive(['id = :id'])
|
||||
->will($this->returnSelf());
|
||||
|
||||
$this->builder->expects($this->exactly(2))
|
||||
->method('setParameter')
|
||||
->withConsecutive([':user_id', 'jack'], [':id', 1])
|
||||
->will($this->returnSelf());
|
||||
|
||||
$this->builder->expects($this->once())
|
||||
->method('execute')
|
||||
->will($this->returnValue($this->cursor));
|
||||
|
||||
$this->cursor->expects($this->exactly(2))
|
||||
->method('fetch')
|
||||
->willReturnOnConsecutiveCalls(
|
||||
['id' => 1],
|
||||
['id' => 2]
|
||||
);
|
||||
|
||||
$this->expectException(MultipleObjectsReturnedException::class);
|
||||
$this->class->findFromUser('jack', 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers \OCA\News\Db\FeedMapperV2::findAll
|
||||
*/
|
||||
public function testFindAll()
|
||||
{
|
||||
$this->db->expects($this->once())
|
||||
->method('getQueryBuilder')
|
||||
->willReturn($this->builder);
|
||||
|
||||
$this->builder->expects($this->once())
|
||||
->method('select')
|
||||
->with('*')
|
||||
->will($this->returnSelf());
|
||||
|
||||
$this->builder->expects($this->once())
|
||||
->method('from')
|
||||
->with('news_feeds')
|
||||
->will($this->returnSelf());
|
||||
|
||||
$this->builder->expects($this->once())
|
||||
->method('where')
|
||||
->with('deleted_at = 0')
|
||||
->will($this->returnSelf());
|
||||
|
||||
$this->builder->expects($this->once())
|
||||
->method('execute')
|
||||
->will($this->returnValue($this->cursor));
|
||||
|
||||
$this->cursor->expects($this->exactly(3))
|
||||
->method('fetch')
|
||||
->willReturnOnConsecutiveCalls(
|
||||
['id' => 4],
|
||||
['id' => 5],
|
||||
null
|
||||
);
|
||||
|
||||
$result = $this->class->findAll();
|
||||
$this->assertEquals($this->feeds, $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers \OCA\News\Db\FeedMapperV2::findAllFromFolder
|
||||
*/
|
||||
public function testFindAllFromFolder()
|
||||
{
|
||||
$this->db->expects($this->once())
|
||||
->method('getQueryBuilder')
|
||||
->willReturn($this->builder);
|
||||
|
||||
$this->builder->expects($this->once())
|
||||
->method('select')
|
||||
->with('*')
|
||||
->will($this->returnSelf());
|
||||
|
||||
$this->builder->expects($this->once())
|
||||
->method('from')
|
||||
->with('news_feeds')
|
||||
->will($this->returnSelf());
|
||||
|
||||
$this->builder->expects($this->once())
|
||||
->method('where')
|
||||
->with('folder_id = :folder_id')
|
||||
->will($this->returnSelf());
|
||||
|
||||
$this->builder->expects($this->exactly(1))
|
||||
->method('setParameter')
|
||||
->withConsecutive([':folder_id', 1])
|
||||
->will($this->returnSelf());
|
||||
|
||||
$this->builder->expects($this->once())
|
||||
->method('execute')
|
||||
->will($this->returnValue($this->cursor));
|
||||
|
||||
$this->cursor->expects($this->exactly(3))
|
||||
->method('fetch')
|
||||
->willReturnOnConsecutiveCalls(
|
||||
['id' => 4],
|
||||
['id' => 5],
|
||||
null
|
||||
);
|
||||
|
||||
$result = $this->class->findAllFromFolder(1);
|
||||
$this->assertEquals($this->feeds, $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers \OCA\News\Db\FeedMapperV2::findAllFromFolder
|
||||
*/
|
||||
public function testFindAllFromRootFolder()
|
||||
{
|
||||
$this->db->expects($this->once())
|
||||
->method('getQueryBuilder')
|
||||
->willReturn($this->builder);
|
||||
|
||||
$this->builder->expects($this->once())
|
||||
->method('select')
|
||||
->with('*')
|
||||
->will($this->returnSelf());
|
||||
|
||||
$this->builder->expects($this->once())
|
||||
->method('from')
|
||||
->with('news_feeds')
|
||||
->will($this->returnSelf());
|
||||
|
||||
$this->builder->expects($this->once())
|
||||
->method('where')
|
||||
->with('folder_id IS NULL')
|
||||
->will($this->returnSelf());
|
||||
|
||||
$this->builder->expects($this->once())
|
||||
->method('execute')
|
||||
->will($this->returnValue($this->cursor));
|
||||
|
||||
$this->cursor->expects($this->exactly(3))
|
||||
->method('fetch')
|
||||
->willReturnOnConsecutiveCalls(
|
||||
['id' => 4],
|
||||
['id' => 5],
|
||||
null
|
||||
);
|
||||
|
||||
$result = $this->class->findAllFromFolder(null);
|
||||
$this->assertEquals($this->feeds, $result);
|
||||
}
|
||||
}
|
270
tests/Unit/Db/NewsMapperTest.php
Normal file
270
tests/Unit/Db/NewsMapperTest.php
Normal file
@ -0,0 +1,270 @@
|
||||
<?php
|
||||
/**
|
||||
* Nextcloud - News
|
||||
*
|
||||
* This file is licensed under the Affero General Public License version 3 or
|
||||
* later. See the COPYING file.
|
||||
*
|
||||
* @author Alessandro Cosentino <cosenal@gmail.com>
|
||||
* @author Bernhard Posselt <dev@bernhard-posselt.com>
|
||||
* @copyright 2012 Alessandro Cosentino
|
||||
* @copyright 2012-2014 Bernhard Posselt
|
||||
*/
|
||||
|
||||
namespace OCA\News\Tests\Unit\Db;
|
||||
|
||||
use OCA\News\Db\Feed;
|
||||
use OCA\News\Db\FeedMapperV2;
|
||||
use OCA\News\Db\Folder;
|
||||
use OCA\News\Db\NewsMapperV2;
|
||||
use OCA\News\Utility\Time;
|
||||
use OCP\AppFramework\Db\DoesNotExistException;
|
||||
use OCP\AppFramework\Db\MultipleObjectsReturnedException;
|
||||
use OCP\DB\QueryBuilder\IFunctionBuilder;
|
||||
use OCP\DB\QueryBuilder\IQueryBuilder;
|
||||
use OCP\IDBConnection;
|
||||
use Test\TestCase;
|
||||
|
||||
abstract class TmpNewsMapper extends NewsMapperV2 {
|
||||
const TABLE_NAME = 'NAME';
|
||||
}
|
||||
|
||||
class NewsMapperTest extends TestCase
|
||||
{
|
||||
/** @var IDBConnection */
|
||||
private $db;
|
||||
/** @var Time */
|
||||
private $time;
|
||||
/** @var NewsMapperV2 */
|
||||
private $class;
|
||||
|
||||
/**
|
||||
* @covers \OCA\News\Db\NewsMapperV2::__construct
|
||||
*/
|
||||
protected function setUp(): void
|
||||
{
|
||||
$this->db = $this->getMockBuilder(IDBConnection::class)
|
||||
->getMock();
|
||||
$this->time = $this->getMockBuilder(Time::class)
|
||||
->getMock();
|
||||
|
||||
$this->class = $this->getMockBuilder(TmpNewsMapper::class)
|
||||
->setConstructorArgs([$this->db, $this->time, 'entity'])
|
||||
->getMockForAbstractClass();
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers \OCA\News\Db\NewsMapperV2::__construct
|
||||
*/
|
||||
public function testSetUpSuccess(): void
|
||||
{
|
||||
$this->assertEquals('NAME', $this->class->getTableName());
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers \OCA\News\Db\NewsMapperV2::update
|
||||
*/
|
||||
public function testUpdateNoChange()
|
||||
{
|
||||
$feed = $this->getMockBuilder(Feed::class)
|
||||
->getMock();
|
||||
|
||||
$this->time->expects($this->never())
|
||||
->method('getMicroTime')
|
||||
->willReturn('1');
|
||||
|
||||
$feed->expects($this->never())
|
||||
->method('setLastModified')
|
||||
->with('1');
|
||||
|
||||
$feed->expects($this->exactly(2))
|
||||
->method('getUpdatedFields')
|
||||
->willReturn([]);
|
||||
|
||||
$result = $this->class->update($feed);
|
||||
$this->assertEquals($feed, $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers \OCA\News\Db\NewsMapperV2::update
|
||||
*/
|
||||
public function testUpdateChange()
|
||||
{
|
||||
$this->expectException('InvalidArgumentException');
|
||||
|
||||
$feed = $this->getMockBuilder(Feed::class)
|
||||
->getMock();
|
||||
|
||||
$this->time->expects($this->once())
|
||||
->method('getMicroTime')
|
||||
->willReturn('1');
|
||||
|
||||
$feed->expects($this->once())
|
||||
->method('setLastModified')
|
||||
->with('1');
|
||||
|
||||
$feed->expects($this->exactly(2))
|
||||
->method('getUpdatedFields')
|
||||
->willReturn(['a' => 'b']);
|
||||
|
||||
$result = $this->class->update($feed);
|
||||
$this->assertEquals($feed, $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers \OCA\News\Db\NewsMapperV2::insert
|
||||
*/
|
||||
public function testInsert()
|
||||
{
|
||||
$feed = $this->getMockBuilder(Feed::class)
|
||||
->getMock();
|
||||
$qb = $this->getMockBuilder(IQueryBuilder::class)
|
||||
->getMock();
|
||||
|
||||
$this->time->expects($this->once())
|
||||
->method('getMicroTime')
|
||||
->willReturn('1');
|
||||
|
||||
$this->db->expects($this->once())
|
||||
->method('getQueryBuilder')
|
||||
->willReturn($qb);
|
||||
|
||||
$feed->expects($this->once())
|
||||
->method('setLastModified')
|
||||
->with('1');
|
||||
|
||||
$feed->expects($this->once())
|
||||
->method('getUpdatedFields')
|
||||
->willReturn([]);
|
||||
|
||||
$result = $this->class->insert($feed);
|
||||
$this->assertEquals($feed, $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers \OCA\News\Db\NewsMapperV2::purgeDeleted
|
||||
*/
|
||||
public function testPurgeEmptyAll()
|
||||
{
|
||||
$qb = $this->getMockBuilder(IQueryBuilder::class)
|
||||
->getMock();
|
||||
|
||||
$this->db->expects($this->once())
|
||||
->method('getQueryBuilder')
|
||||
->willReturn($qb);
|
||||
|
||||
$qb->expects($this->once())
|
||||
->method('delete')
|
||||
->with('NAME')
|
||||
->will($this->returnSelf());
|
||||
|
||||
$qb->expects($this->once())
|
||||
->method('andWhere')
|
||||
->with('deleted_at != 0')
|
||||
->will($this->returnSelf());
|
||||
|
||||
$qb->expects($this->once())
|
||||
->method('execute');
|
||||
|
||||
$result = $this->class->purgeDeleted(null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers \OCA\News\Db\NewsMapperV2::purgeDeleted
|
||||
*/
|
||||
public function testPurgeUser()
|
||||
{
|
||||
$qb = $this->getMockBuilder(IQueryBuilder::class)
|
||||
->getMock();
|
||||
|
||||
$this->db->expects($this->once())
|
||||
->method('getQueryBuilder')
|
||||
->willReturn($qb);
|
||||
|
||||
$qb->expects($this->once())
|
||||
->method('delete')
|
||||
->with('NAME')
|
||||
->will($this->returnSelf());
|
||||
|
||||
$qb->expects($this->exactly(2))
|
||||
->method('andWhere')
|
||||
->withConsecutive(['deleted_at != 0'], ['user_id = :user_id'])
|
||||
->will($this->returnSelf());
|
||||
|
||||
$qb->expects($this->once())
|
||||
->method('setParameter')
|
||||
->with(':user_id', 'jack')
|
||||
->will($this->returnSelf());
|
||||
|
||||
$qb->expects($this->once())
|
||||
->method('execute');
|
||||
|
||||
$result = $this->class->purgeDeleted('jack', null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers \OCA\News\Db\NewsMapperV2::purgeDeleted
|
||||
*/
|
||||
public function testPurgeTime()
|
||||
{
|
||||
$qb = $this->getMockBuilder(IQueryBuilder::class)
|
||||
->getMock();
|
||||
|
||||
$this->db->expects($this->once())
|
||||
->method('getQueryBuilder')
|
||||
->willReturn($qb);
|
||||
|
||||
$qb->expects($this->once())
|
||||
->method('delete')
|
||||
->with('NAME')
|
||||
->will($this->returnSelf());
|
||||
|
||||
$qb->expects($this->exactly(2))
|
||||
->method('andWhere')
|
||||
->withConsecutive(['deleted_at != 0'], ['deleted_at < :deleted_at'])
|
||||
->will($this->returnSelf());
|
||||
|
||||
$qb->expects($this->once())
|
||||
->method('setParameter')
|
||||
->with(':deleted_at', 1)
|
||||
->will($this->returnSelf());
|
||||
|
||||
$qb->expects($this->once())
|
||||
->method('execute');
|
||||
|
||||
$result = $this->class->purgeDeleted(null, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers \OCA\News\Db\NewsMapperV2::purgeDeleted
|
||||
*/
|
||||
public function testPurgeBoth()
|
||||
{
|
||||
$qb = $this->getMockBuilder(IQueryBuilder::class)
|
||||
->getMock();
|
||||
|
||||
$this->db->expects($this->once())
|
||||
->method('getQueryBuilder')
|
||||
->willReturn($qb);
|
||||
|
||||
$qb->expects($this->once())
|
||||
->method('delete')
|
||||
->with('NAME')
|
||||
->will($this->returnSelf());
|
||||
|
||||
$qb->expects($this->exactly(3))
|
||||
->method('andWhere')
|
||||
->withConsecutive(['deleted_at != 0'], ['user_id = :user_id'], ['deleted_at < :deleted_at'])
|
||||
->will($this->returnSelf());
|
||||
|
||||
$qb->expects($this->exactly(2))
|
||||
->method('setParameter')
|
||||
->withConsecutive([':user_id', 'jack'], [':deleted_at', 1])
|
||||
->will($this->returnSelf());
|
||||
|
||||
$qb->expects($this->once())
|
||||
->method('execute');
|
||||
|
||||
$result = $this->class->purgeDeleted('jack', 1);
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -132,45 +132,6 @@ class FolderServiceTest extends TestCase
|
||||
$this->assertEquals($result[0]->feeds, $feeds);
|
||||
}
|
||||
|
||||
public function testFindForUser()
|
||||
{
|
||||
$return = new Folder();
|
||||
$this->mapper->expects($this->once())
|
||||
->method('findFromUser')
|
||||
->with('jack', 1)
|
||||
->will($this->returnValue($return));
|
||||
|
||||
$result = $this->class->findForUser('jack', 1);
|
||||
|
||||
$this->assertEquals($return, $result);
|
||||
}
|
||||
|
||||
public function testFindForUserEmpty()
|
||||
{
|
||||
$this->expectException(ServiceNotFoundException::class);
|
||||
$this->expectExceptionMessage('Folder not found');
|
||||
|
||||
$this->mapper->expects($this->once())
|
||||
->method('findFromUser')
|
||||
->with('jack', 1)
|
||||
->will($this->throwException(new DoesNotExistException('')));
|
||||
|
||||
$this->class->findForUser('jack', 1);
|
||||
}
|
||||
|
||||
public function testFindForUserDupe()
|
||||
{
|
||||
$this->expectException(ServiceConflictException::class);
|
||||
$this->expectExceptionMessage('Multiple folders found');
|
||||
|
||||
$this->mapper->expects($this->once())
|
||||
->method('findFromUser')
|
||||
->with('jack', 1)
|
||||
->will($this->throwException(new MultipleObjectsReturnedException('')));
|
||||
|
||||
$this->class->findForUser('jack', 1);
|
||||
}
|
||||
|
||||
|
||||
public function testCreate()
|
||||
{
|
||||
|
232
tests/Unit/Service/ImportServiceTest.php
Normal file
232
tests/Unit/Service/ImportServiceTest.php
Normal file
@ -0,0 +1,232 @@
|
||||
<?php
|
||||
/**
|
||||
* Nextcloud - News
|
||||
*
|
||||
* This file is licensed under the Affero General Public License version 3 or
|
||||
* later. See the COPYING file.
|
||||
*
|
||||
* @author Alessandro Cosentino <cosenal@gmail.com>
|
||||
* @author Bernhard Posselt <dev@bernhard-posselt.com>
|
||||
* @copyright 2012 Alessandro Cosentino
|
||||
* @copyright 2012-2014 Bernhard Posselt
|
||||
*/
|
||||
|
||||
|
||||
namespace OCA\News\Tests\Unit\Service;
|
||||
|
||||
use FeedIo\Explorer;
|
||||
use FeedIo\Reader\ReadErrorException;
|
||||
|
||||
use OC\L10N\L10N;
|
||||
use OCA\News\Db\FeedMapperV2;
|
||||
use OCA\News\Fetcher\FeedFetcher;
|
||||
use OCA\News\Service\Exceptions\ServiceConflictException;
|
||||
use OCA\News\Service\Exceptions\ServiceNotFoundException;
|
||||
use OCA\News\Service\FeedServiceV2;
|
||||
use OCA\News\Service\ImportService;
|
||||
use OCA\News\Service\ItemServiceV2;
|
||||
use OCA\News\Utility\Time;
|
||||
use OCP\AppFramework\Db\DoesNotExistException;
|
||||
|
||||
use OCA\News\Db\Feed;
|
||||
use OCA\News\Db\Item;
|
||||
use OCP\IConfig;
|
||||
use OCP\IL10N;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
|
||||
class ImportServiceTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @var \PHPUnit\Framework\MockObject\MockObject|ItemServiceV2
|
||||
*/
|
||||
private $itemService;
|
||||
|
||||
/**
|
||||
* @var \PHPUnit\Framework\MockObject\MockObject|FeedServiceV2
|
||||
*/
|
||||
private $feedService;
|
||||
|
||||
/** @var ImportService */
|
||||
private $class;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $uid;
|
||||
|
||||
/**
|
||||
* @var \PHPUnit\Framework\MockObject\MockObject|LoggerInterface
|
||||
*/
|
||||
private $logger;
|
||||
|
||||
/**
|
||||
* @var \PHPUnit\Framework\MockObject\MockObject|\HTMLPurifier
|
||||
*/
|
||||
private $purifier;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
$this->logger = $this->getMockBuilder(LoggerInterface::class)
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
$this->itemService = $this
|
||||
->getMockBuilder(ItemServiceV2::class)
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
$this->feedService = $this
|
||||
->getMockBuilder(FeedServiceV2::class)
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
$this->purifier = $this
|
||||
->getMockBuilder(\HTMLPurifier::class)
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
|
||||
$this->time = 333333;
|
||||
|
||||
$this->class = new ImportService(
|
||||
$this->feedService,
|
||||
$this->itemService,
|
||||
$this->purifier,
|
||||
$this->logger
|
||||
);
|
||||
$this->uid = 'jack';
|
||||
}
|
||||
|
||||
|
||||
public function testImportArticles()
|
||||
{
|
||||
$url = 'http://nextcloud/nofeed';
|
||||
|
||||
$feed = new Feed();
|
||||
$feed->setId(3);
|
||||
$feed->setUserId($this->uid);
|
||||
$feed->setUrl($url);
|
||||
$feed->setLink($url);
|
||||
$feed->setTitle('Articles without feed');
|
||||
$feed->setAdded($this->time);
|
||||
$feed->setFolderId(0);
|
||||
$feed->setPreventUpdate(true);
|
||||
|
||||
$feeds = [$feed];
|
||||
|
||||
$item = new Item();
|
||||
$item->setFeedId(3);
|
||||
$item->setAuthor('john');
|
||||
$item->setGuid('s');
|
||||
$item->setGuidHash('03c7c0ace395d80182db07ae2c30f034');
|
||||
$item->setTitle('hey');
|
||||
$item->setPubDate(333);
|
||||
$item->setBody('come over');
|
||||
$item->setEnclosureMime('mime');
|
||||
$item->setEnclosureLink('lin');
|
||||
$item->setUnread(true);
|
||||
$item->setStarred(false);
|
||||
$item->generateSearchIndex();
|
||||
|
||||
$json = $item->toExport(['feed3' => $feed]);
|
||||
|
||||
$items = [$json];
|
||||
|
||||
$this->feedService->expects($this->once())
|
||||
->method('findAllForUser')
|
||||
->with($this->equalTo($this->uid))
|
||||
->will($this->returnValue($feeds));
|
||||
|
||||
$this->itemService->expects($this->once())
|
||||
->method('insertOrUpdate')
|
||||
->with($item);
|
||||
|
||||
$this->purifier->expects($this->once())
|
||||
->method('purify')
|
||||
->with($this->equalTo($item->getBody()))
|
||||
->will($this->returnValue($item->getBody()));
|
||||
|
||||
$result = $this->class->importArticles($this->uid, $items);
|
||||
|
||||
$this->assertEquals(null, $result);
|
||||
}
|
||||
|
||||
|
||||
public function testImportArticlesCreatesOwnFeedWhenNotFound()
|
||||
{
|
||||
$url = 'http://nextcloud/args';
|
||||
|
||||
$feed = new Feed();
|
||||
$feed->setId(3);
|
||||
$feed->setUserId($this->uid);
|
||||
$feed->setUrl($url);
|
||||
$feed->setLink($url);
|
||||
$feed->setTitle('Articles without feed');
|
||||
$feed->setAdded($this->time);
|
||||
$feed->setFolderId(0);
|
||||
$feed->setPreventUpdate(true);
|
||||
|
||||
$feeds = [$feed];
|
||||
|
||||
$item = new Item();
|
||||
$item->setFeedId(3);
|
||||
$item->setAuthor('john');
|
||||
$item->setGuid('s');
|
||||
$item->setGuidHash('03c7c0ace395d80182db07ae2c30f034');
|
||||
$item->setTitle('hey');
|
||||
$item->setPubDate(333);
|
||||
$item->setBody('come over');
|
||||
$item->setEnclosureMime('mime');
|
||||
$item->setEnclosureLink('lin');
|
||||
$item->setUnread(true);
|
||||
$item->setStarred(false);
|
||||
$item->generateSearchIndex();
|
||||
|
||||
$json = $item->toExport(['feed3' => $feed]);
|
||||
$json2 = $json;
|
||||
// believe it or not this copies stuff :D
|
||||
$json2['feedLink'] = 'http://test.com';
|
||||
|
||||
$items = [$json, $json2];
|
||||
|
||||
$insertFeed = new Feed();
|
||||
$insertFeed->setLink('http://nextcloud/nofeed');
|
||||
$insertFeed->setUrl('http://nextcloud/nofeed');
|
||||
$insertFeed->setUserId($this->uid);
|
||||
$insertFeed->setTitle('Articles without feed');
|
||||
$insertFeed->setAdded($this->time);
|
||||
$insertFeed->setPreventUpdate(true);
|
||||
$insertFeed->setFolderId(null);
|
||||
|
||||
$this->feedService->expects($this->once())
|
||||
->method('findAllForUser')
|
||||
->with($this->equalTo($this->uid))
|
||||
->will($this->returnValue($feeds));
|
||||
$this->feedService->expects($this->once())
|
||||
->method('insert')
|
||||
->will(
|
||||
$this->returnCallback(
|
||||
function () use ($insertFeed) {
|
||||
$insertFeed->setId(3);
|
||||
return $insertFeed;
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
$this->itemService->expects($this->exactly(2))
|
||||
->method('insertOrUpdate')
|
||||
->withConsecutive([$item]);
|
||||
$this->purifier->expects($this->exactly(2))
|
||||
->method('purify')
|
||||
->with($this->equalTo($item->getBody()))
|
||||
->will($this->returnValue($item->getBody()));
|
||||
|
||||
$this->feedService->expects($this->once())
|
||||
->method('findByUrl')
|
||||
->will($this->returnValue($feed));
|
||||
|
||||
$result = $this->class->importArticles($this->uid, $items);
|
||||
|
||||
$this->assertEquals($feed, $result);
|
||||
}
|
||||
|
||||
}
|
@ -15,6 +15,7 @@ namespace OCA\News\Tests\Unit\Service;
|
||||
|
||||
use OC\Log;
|
||||
use OCA\News\Db\ItemMapper;
|
||||
use OCA\News\Db\ItemMapperV2;
|
||||
use OCA\News\Service\ItemService;
|
||||
use OCA\News\Service\Exceptions\ServiceNotFoundException;
|
||||
use OCA\News\Utility\PsrLogger;
|
||||
@ -35,6 +36,11 @@ class ItemServiceTest extends TestCase
|
||||
/**
|
||||
* @var \PHPUnit\Framework\MockObject\MockObject|ItemMapper
|
||||
*/
|
||||
private $oldItemMapper;
|
||||
|
||||
/**
|
||||
* @var \PHPUnit\Framework\MockObject\MockObject|ItemMapperV2
|
||||
*/
|
||||
private $mapper;
|
||||
/**
|
||||
* @var ItemService
|
||||
@ -79,7 +85,10 @@ class ItemServiceTest extends TestCase
|
||||
$this->timeFactory->expects($this->any())
|
||||
->method('getMicroTime')
|
||||
->will($this->returnValue($this->time));
|
||||
$this->mapper = $this->getMockBuilder(ItemMapper::class)
|
||||
$this->mapper = $this->getMockBuilder(ItemMapperV2::class)
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
$this->oldItemMapper = $this->getMockBuilder(ItemMapper::class)
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
$this->config = $this->getMockBuilder(IConfig::class)
|
||||
@ -92,6 +101,7 @@ class ItemServiceTest extends TestCase
|
||||
|
||||
$this->itemService = new ItemService(
|
||||
$this->mapper,
|
||||
$this->oldItemMapper,
|
||||
$this->timeFactory,
|
||||
$this->config,
|
||||
$this->logger
|
||||
@ -109,7 +119,7 @@ class ItemServiceTest extends TestCase
|
||||
public function testFindAllNewFeed()
|
||||
{
|
||||
$type = FeedType::FEED;
|
||||
$this->mapper->expects($this->once())
|
||||
$this->oldItemMapper->expects($this->once())
|
||||
->method('findAllNewFeed')
|
||||
->with(
|
||||
$this->equalTo(3),
|
||||
@ -127,7 +137,7 @@ class ItemServiceTest extends TestCase
|
||||
public function testFindAllNewFolder()
|
||||
{
|
||||
$type = FeedType::FOLDER;
|
||||
$this->mapper->expects($this->once())
|
||||
$this->oldItemMapper->expects($this->once())
|
||||
->method('findAllNewFolder')
|
||||
->with(
|
||||
$this->equalTo(3),
|
||||
@ -145,7 +155,7 @@ class ItemServiceTest extends TestCase
|
||||
public function testFindAllNew()
|
||||
{
|
||||
$type = FeedType::STARRED;
|
||||
$this->mapper->expects($this->once())
|
||||
$this->oldItemMapper->expects($this->once())
|
||||
->method('findAllNew')
|
||||
->with(
|
||||
$this->equalTo(20333),
|
||||
@ -166,7 +176,7 @@ class ItemServiceTest extends TestCase
|
||||
public function testFindAllFeed()
|
||||
{
|
||||
$type = FeedType::FEED;
|
||||
$this->mapper->expects($this->once())
|
||||
$this->oldItemMapper->expects($this->once())
|
||||
->method('findAllFeed')
|
||||
->with(
|
||||
$this->equalTo(3),
|
||||
@ -190,7 +200,7 @@ class ItemServiceTest extends TestCase
|
||||
public function testFindAllFolder()
|
||||
{
|
||||
$type = FeedType::FOLDER;
|
||||
$this->mapper->expects($this->once())
|
||||
$this->oldItemMapper->expects($this->once())
|
||||
->method('findAllFolder')
|
||||
->with(
|
||||
$this->equalTo(3),
|
||||
@ -214,7 +224,7 @@ class ItemServiceTest extends TestCase
|
||||
public function testFindAll()
|
||||
{
|
||||
$type = FeedType::STARRED;
|
||||
$this->mapper->expects($this->once())
|
||||
$this->oldItemMapper->expects($this->once())
|
||||
->method('findAllItems')
|
||||
->with(
|
||||
$this->equalTo(20),
|
||||
@ -240,7 +250,7 @@ class ItemServiceTest extends TestCase
|
||||
$type = FeedType::STARRED;
|
||||
$search = ['test'];
|
||||
|
||||
$this->mapper->expects($this->once())
|
||||
$this->oldItemMapper->expects($this->once())
|
||||
->method('findAllItems')
|
||||
->with(
|
||||
$this->equalTo(20),
|
||||
@ -269,22 +279,16 @@ class ItemServiceTest extends TestCase
|
||||
$guidHash = md5('hihi');
|
||||
|
||||
$item = new Item();
|
||||
$item->setStatus(128);
|
||||
$item->setId($itemId);
|
||||
$item->setStarred(false);
|
||||
|
||||
$expectedItem = new Item();
|
||||
$expectedItem->setStatus(128);
|
||||
$expectedItem->setStarred(true);
|
||||
$expectedItem->setId($itemId);
|
||||
|
||||
$this->mapper->expects($this->once())
|
||||
->method('findByGuidHash')
|
||||
->with(
|
||||
$this->equalTo($guidHash),
|
||||
$this->equalTo($feedId),
|
||||
$this->equalTo('jack')
|
||||
)
|
||||
->with($feedId, $guidHash)
|
||||
->will($this->returnValue($item));
|
||||
|
||||
$this->mapper->expects($this->once())
|
||||
@ -316,11 +320,7 @@ class ItemServiceTest extends TestCase
|
||||
|
||||
$this->mapper->expects($this->once())
|
||||
->method('findByGuidHash')
|
||||
->with(
|
||||
$this->equalTo($guidHash),
|
||||
$this->equalTo($feedId),
|
||||
$this->equalTo('jack')
|
||||
)
|
||||
->with($feedId, $guidHash)
|
||||
->will($this->returnValue($item));
|
||||
|
||||
$this->mapper->expects($this->once())
|
||||
@ -346,7 +346,7 @@ class ItemServiceTest extends TestCase
|
||||
$expectedItem->setId($itemId);
|
||||
$expectedItem->setLastModified($this->time);
|
||||
|
||||
$this->mapper->expects($this->once())
|
||||
$this->oldItemMapper->expects($this->once())
|
||||
->method('readItem')
|
||||
->with(
|
||||
$this->equalTo($itemId),
|
||||
@ -364,7 +364,7 @@ class ItemServiceTest extends TestCase
|
||||
{
|
||||
|
||||
$this->expectException(ServiceNotFoundException::class);
|
||||
$this->mapper->expects($this->once())
|
||||
$this->oldItemMapper->expects($this->once())
|
||||
->method('readItem')
|
||||
->will($this->throwException(new DoesNotExistException('')));
|
||||
|
||||
@ -387,7 +387,7 @@ class ItemServiceTest extends TestCase
|
||||
{
|
||||
$highestItemId = 6;
|
||||
|
||||
$this->mapper->expects($this->once())
|
||||
$this->oldItemMapper->expects($this->once())
|
||||
->method('readAll')
|
||||
->with(
|
||||
$this->equalTo($highestItemId),
|
||||
@ -404,7 +404,7 @@ class ItemServiceTest extends TestCase
|
||||
$folderId = 3;
|
||||
$highestItemId = 6;
|
||||
|
||||
$this->mapper->expects($this->once())
|
||||
$this->oldItemMapper->expects($this->once())
|
||||
->method('readFolder')
|
||||
->with(
|
||||
$this->equalTo($folderId),
|
||||
@ -422,7 +422,7 @@ class ItemServiceTest extends TestCase
|
||||
$feedId = 3;
|
||||
$highestItemId = 6;
|
||||
|
||||
$this->mapper->expects($this->once())
|
||||
$this->oldItemMapper->expects($this->once())
|
||||
->method('readFeed')
|
||||
->with(
|
||||
$this->equalTo($feedId),
|
||||
@ -441,7 +441,7 @@ class ItemServiceTest extends TestCase
|
||||
->method('getAppValue')
|
||||
->with('news', 'autoPurgeCount')
|
||||
->will($this->returnValue(2));
|
||||
$this->mapper->expects($this->once())
|
||||
$this->oldItemMapper->expects($this->once())
|
||||
->method('deleteReadOlderThanThreshold')
|
||||
->with($this->equalTo(2));
|
||||
|
||||
@ -454,7 +454,7 @@ class ItemServiceTest extends TestCase
|
||||
->method('getAppValue')
|
||||
->with('news', 'autoPurgeCount')
|
||||
->will($this->returnValue(-1));
|
||||
$this->mapper->expects($this->never())
|
||||
$this->oldItemMapper->expects($this->never())
|
||||
->method('deleteReadOlderThanThreshold');
|
||||
|
||||
$this->itemService->autoPurgeOld();
|
||||
@ -463,7 +463,7 @@ class ItemServiceTest extends TestCase
|
||||
|
||||
public function testGetNewestItemId()
|
||||
{
|
||||
$this->mapper->expects($this->once())
|
||||
$this->oldItemMapper->expects($this->once())
|
||||
->method('getNewestItemId')
|
||||
->with($this->equalTo('jack'))
|
||||
->will($this->returnValue(12));
|
||||
@ -475,7 +475,7 @@ class ItemServiceTest extends TestCase
|
||||
|
||||
public function testGetNewestItemIdDoesNotExist()
|
||||
{
|
||||
$this->mapper->expects($this->once())
|
||||
$this->oldItemMapper->expects($this->once())
|
||||
->method('getNewestItemId')
|
||||
->with($this->equalTo('jack'))
|
||||
->will(
|
||||
@ -493,7 +493,7 @@ class ItemServiceTest extends TestCase
|
||||
{
|
||||
$star = 18;
|
||||
|
||||
$this->mapper->expects($this->once())
|
||||
$this->oldItemMapper->expects($this->once())
|
||||
->method('starredCount')
|
||||
->with($this->equalTo('jack'))
|
||||
->will($this->returnValue($star));
|
||||
@ -508,7 +508,7 @@ class ItemServiceTest extends TestCase
|
||||
{
|
||||
$star = 18;
|
||||
|
||||
$this->mapper->expects($this->once())
|
||||
$this->oldItemMapper->expects($this->once())
|
||||
->method('findAllUnreadOrStarred')
|
||||
->with($this->equalTo('jack'))
|
||||
->will($this->returnValue($star));
|
||||
@ -519,15 +519,5 @@ class ItemServiceTest extends TestCase
|
||||
}
|
||||
|
||||
|
||||
public function testDeleteUser()
|
||||
{
|
||||
$this->mapper->expects($this->once())
|
||||
->method('deleteUser')
|
||||
->will($this->returnValue('jack'));
|
||||
|
||||
$this->itemService->deleteUser('jack');
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
143
tests/Unit/Service/OPMLServiceTest.php
Normal file
143
tests/Unit/Service/OPMLServiceTest.php
Normal file
@ -0,0 +1,143 @@
|
||||
<?php
|
||||
/**
|
||||
* Nextcloud - News
|
||||
*
|
||||
* This file is licensed under the Affero General Public License version 3 or
|
||||
* later. See the COPYING file.
|
||||
*
|
||||
* @author Alessandro Cosentino <cosenal@gmail.com>
|
||||
* @author Bernhard Posselt <dev@bernhard-posselt.com>
|
||||
* @copyright 2012 Alessandro Cosentino
|
||||
* @copyright 2012-2014 Bernhard Posselt
|
||||
*/
|
||||
|
||||
|
||||
namespace OCA\News\Tests\Unit\Service;
|
||||
|
||||
use FeedIo\Explorer;
|
||||
use FeedIo\Reader\ReadErrorException;
|
||||
|
||||
use OC\L10N\L10N;
|
||||
use OCA\News\Db\FeedMapperV2;
|
||||
use OCA\News\Db\Folder;
|
||||
use OCA\News\Fetcher\FeedFetcher;
|
||||
use OCA\News\Service\Exceptions\ServiceConflictException;
|
||||
use OCA\News\Service\Exceptions\ServiceNotFoundException;
|
||||
use OCA\News\Service\FeedServiceV2;
|
||||
use OCA\News\Service\FolderServiceV2;
|
||||
use OCA\News\Service\ImportService;
|
||||
use OCA\News\Service\ItemServiceV2;
|
||||
use OCA\News\Service\OpmlService;
|
||||
use OCA\News\Utility\OPMLExporter;
|
||||
use OCA\News\Utility\Time;
|
||||
use OCP\AppFramework\Db\DoesNotExistException;
|
||||
|
||||
use OCA\News\Db\Feed;
|
||||
use OCA\News\Db\Item;
|
||||
use OCP\IConfig;
|
||||
use OCP\IL10N;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
|
||||
class OPMLServiceTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @var \PHPUnit\Framework\MockObject\MockObject|FolderServiceV2
|
||||
*/
|
||||
private $folderService;
|
||||
|
||||
/**
|
||||
* @var \PHPUnit\Framework\MockObject\MockObject|FeedServiceV2
|
||||
*/
|
||||
private $feedService;
|
||||
|
||||
/**
|
||||
* @var \PHPUnit\Framework\MockObject\MockObject|OPMLExporter
|
||||
*/
|
||||
private $exporter;
|
||||
|
||||
/** @var OpmlService */
|
||||
private $class;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $uid;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
$this->exporter = $this->getMockBuilder(OPMLExporter::class)
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
$this->folderService = $this
|
||||
->getMockBuilder(FolderServiceV2::class)
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
$this->feedService = $this
|
||||
->getMockBuilder(FeedServiceV2::class)
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
|
||||
$this->time = 333333;
|
||||
|
||||
$this->class = new OpmlService(
|
||||
$this->folderService,
|
||||
$this->feedService,
|
||||
$this->exporter
|
||||
);
|
||||
$this->uid = 'jack';
|
||||
}
|
||||
|
||||
public function testExportEmpty()
|
||||
{
|
||||
$this->feedService->expects($this->once())
|
||||
->method('findAllForUser')
|
||||
->will($this->returnValue([]));
|
||||
$this->folderService->expects($this->once())
|
||||
->method('findAllForUser')
|
||||
->will($this->returnValue([]));
|
||||
|
||||
$domdoc = $this->getMockBuilder(\DOMDocument::class)
|
||||
->getMock();
|
||||
|
||||
$this->exporter->expects($this->once())
|
||||
->method('build')
|
||||
->with([], [])
|
||||
->will($this->returnValue($domdoc));
|
||||
|
||||
$domdoc->expects($this->once())
|
||||
->method('saveXML')
|
||||
->will($this->returnValue('doc'));
|
||||
|
||||
$this->assertEquals('doc', $this->class->export('jack'));
|
||||
}
|
||||
|
||||
public function testExportSuccess()
|
||||
{
|
||||
$feed = Feed::fromParams(['id' => 1]);
|
||||
$folder = Folder::fromParams(['id' => 1]);
|
||||
$this->feedService->expects($this->once())
|
||||
->method('findAllForUser')
|
||||
->will($this->returnValue([$feed]));
|
||||
$this->folderService->expects($this->once())
|
||||
->method('findAllForUser')
|
||||
->will($this->returnValue([$folder]));
|
||||
|
||||
$domdoc = $this->getMockBuilder(\DOMDocument::class)
|
||||
->getMock();
|
||||
|
||||
$this->exporter->expects($this->once())
|
||||
->method('build')
|
||||
->with([$folder], [$feed])
|
||||
->will($this->returnValue($domdoc));
|
||||
|
||||
$domdoc->expects($this->once())
|
||||
->method('saveXML')
|
||||
->will($this->returnValue('doc'));
|
||||
|
||||
$this->assertEquals('doc', $this->class->export('jack'));
|
||||
}
|
||||
|
||||
}
|
@ -15,6 +15,7 @@ namespace OCA\News\Tests\Unit\Service;
|
||||
|
||||
use OCA\News\Db\Feed;
|
||||
use OCA\News\Db\ItemMapper;
|
||||
use OCA\News\Db\ItemMapperV2;
|
||||
use OCA\News\Service\Exceptions\ServiceNotFoundException;
|
||||
use OCA\News\Service\Service;
|
||||
use \OCP\AppFramework\Db\DoesNotExistException;
|
||||
@ -24,41 +25,24 @@ use \OCA\News\Db\Folder;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
|
||||
class TestLegacyService extends Service
|
||||
{
|
||||
public function __construct($mapper, $logger)
|
||||
{
|
||||
parent::__construct($mapper, $logger);
|
||||
}
|
||||
|
||||
public function findAllForUser(string $userId, array $params = []): array
|
||||
{
|
||||
// TODO: Implement findAllForUser() method.
|
||||
}
|
||||
|
||||
public function findAll(): array
|
||||
{
|
||||
// TODO: Implement findAll() method.
|
||||
}
|
||||
}
|
||||
|
||||
class ServiceTest extends TestCase
|
||||
{
|
||||
|
||||
protected $mapper;
|
||||
protected $logger;
|
||||
protected $newsService;
|
||||
protected $class;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
$this->mapper = $this->getMockBuilder(ItemMapper::class)
|
||||
$this->mapper = $this->getMockBuilder(ItemMapperV2::class)
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
$this->logger = $this->getMockBuilder(LoggerInterface::class)
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
$this->newsService = new TestLegacyService($this->mapper, $this->logger);
|
||||
$this->class = $this->getMockBuilder(Service::class)
|
||||
->setConstructorArgs([$this->mapper, $this->logger])
|
||||
->getMockForAbstractClass();
|
||||
}
|
||||
|
||||
|
||||
@ -77,7 +61,19 @@ class ServiceTest extends TestCase
|
||||
->with($this->equalTo($user), $this->equalTo($id))
|
||||
->will($this->returnValue($folder));
|
||||
|
||||
$this->newsService->delete($user, $id);
|
||||
$this->class->delete($user, $id);
|
||||
}
|
||||
|
||||
|
||||
public function testInsert()
|
||||
{
|
||||
$folder = new Folder();
|
||||
|
||||
$this->mapper->expects($this->once())
|
||||
->method('insert')
|
||||
->with($this->equalTo($folder));
|
||||
|
||||
$this->class->insert($folder);
|
||||
}
|
||||
|
||||
|
||||
@ -91,7 +87,7 @@ class ServiceTest extends TestCase
|
||||
->with($this->equalTo($user), $this->equalTo($id))
|
||||
->will($this->returnValue(new Feed()));
|
||||
|
||||
$this->newsService->find($user, $id);
|
||||
$this->class->find($user, $id);
|
||||
}
|
||||
|
||||
|
||||
@ -104,7 +100,7 @@ class ServiceTest extends TestCase
|
||||
->will($this->throwException($ex));
|
||||
|
||||
$this->expectException(ServiceNotFoundException::class);
|
||||
$this->newsService->find('', 1);
|
||||
$this->class->find('', 1);
|
||||
}
|
||||
|
||||
|
||||
@ -117,7 +113,25 @@ class ServiceTest extends TestCase
|
||||
->will($this->throwException($ex));
|
||||
|
||||
$this->expectException(ServiceNotFoundException::class);
|
||||
$this->newsService->find('', 1);
|
||||
$this->class->find('', 1);
|
||||
}
|
||||
|
||||
|
||||
public function testDeleteUser()
|
||||
{
|
||||
$feed1 = Feed::fromParams(['id' => 1]);
|
||||
$feed2 = Feed::fromParams(['id' => 2]);
|
||||
|
||||
$this->class->expects($this->once())
|
||||
->method('findAllForUser')
|
||||
->with('')
|
||||
->willReturn([$feed1, $feed2]);
|
||||
|
||||
$this->mapper->expects($this->exactly(2))
|
||||
->method('delete')
|
||||
->withConsecutive([$feed1], [$feed2]);
|
||||
|
||||
$this->class->deleteUser('');
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -45,12 +45,9 @@ class StatusServiceTest extends TestCase
|
||||
$this->connection = $this->getMockBuilder(IDBConnection::class)
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
$this->service = new StatusService($this->settings, $this->connection, 'news');
|
||||
$this->service = new StatusService($this->settings, $this->connection);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers \OCA\News\Service\StatusService::getStatus
|
||||
*/
|
||||
public function testGetStatus()
|
||||
{
|
||||
$this->settings->expects($this->exactly(3))
|
||||
@ -81,9 +78,6 @@ class StatusServiceTest extends TestCase
|
||||
$this->assertEquals($expected, $response);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers \OCA\News\Service\StatusService::getStatus
|
||||
*/
|
||||
public function testGetStatusNoCorrectCronAjax()
|
||||
{
|
||||
$this->settings->expects($this->exactly(3))
|
||||
@ -114,9 +108,6 @@ class StatusServiceTest extends TestCase
|
||||
$this->assertEquals($expected, $response);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers \OCA\News\Service\StatusService::getStatus
|
||||
*/
|
||||
public function testGetStatusNoCorrectCronTurnedOff()
|
||||
{
|
||||
$this->settings->expects($this->exactly(3))
|
||||
@ -147,9 +138,6 @@ class StatusServiceTest extends TestCase
|
||||
$this->assertEquals($expected, $response);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers \OCA\News\Service\StatusService::getStatus
|
||||
*/
|
||||
public function testGetStatusReportsNon4ByteText()
|
||||
{
|
||||
$this->settings->expects($this->exactly(3))
|
||||
@ -180,9 +168,6 @@ class StatusServiceTest extends TestCase
|
||||
$this->assertEquals($expected, $response);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers \OCA\News\Service\StatusService::isCronProperlyConfigured
|
||||
*/
|
||||
public function testIsProperlyConfiguredNone()
|
||||
{
|
||||
$this->settings->expects($this->exactly(2))
|
||||
@ -200,9 +185,6 @@ class StatusServiceTest extends TestCase
|
||||
$this->assertFalse($response);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers \OCA\News\Service\StatusService::isCronProperlyConfigured
|
||||
*/
|
||||
public function testIsProperlyConfiguredModeCronNoSystem()
|
||||
{
|
||||
$this->settings->expects($this->exactly(2))
|
||||
@ -220,9 +202,6 @@ class StatusServiceTest extends TestCase
|
||||
$this->assertTrue($response);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers \OCA\News\Service\StatusService::isCronProperlyConfigured
|
||||
*/
|
||||
public function testIsProperlyConfiguredModeCron()
|
||||
{
|
||||
$this->settings->expects($this->exactly(2))
|
||||
|
Loading…
Reference in New Issue
Block a user