diff options
Diffstat (limited to 'lib/Service')
-rw-r--r-- | lib/Service/Exceptions/ServiceConflictException.php (renamed from lib/Service/ServiceConflictException.php) | 2 | ||||
-rw-r--r-- | lib/Service/Exceptions/ServiceException.php (renamed from lib/Service/ServiceException.php) | 2 | ||||
-rw-r--r-- | lib/Service/Exceptions/ServiceNotFoundException.php (renamed from lib/Service/ServiceNotFoundException.php) | 2 | ||||
-rw-r--r-- | lib/Service/Exceptions/ServiceValidationException.php (renamed from lib/Service/ServiceValidationException.php) | 2 | ||||
-rw-r--r-- | lib/Service/FeedService.php | 61 | ||||
-rw-r--r-- | lib/Service/FeedServiceV2.php | 336 | ||||
-rw-r--r-- | lib/Service/FolderService.php | 97 | ||||
-rw-r--r-- | lib/Service/FolderServiceV2.php | 102 | ||||
-rw-r--r-- | lib/Service/ItemService.php | 30 | ||||
-rw-r--r-- | lib/Service/ItemServiceV2.php | 104 | ||||
-rw-r--r-- | lib/Service/Service.php | 70 | ||||
-rw-r--r-- | lib/Service/StatusService.php | 6 | ||||
-rw-r--r-- | lib/Service/UpdaterService.php | 71 |
13 files changed, 797 insertions, 88 deletions
diff --git a/lib/Service/ServiceConflictException.php b/lib/Service/Exceptions/ServiceConflictException.php index 95955eecb..4a1a80801 100644 --- a/lib/Service/ServiceConflictException.php +++ b/lib/Service/Exceptions/ServiceConflictException.php @@ -11,7 +11,7 @@ * @copyright 2012-2014 Bernhard Posselt */ -namespace OCA\News\Service; +namespace OCA\News\Service\Exceptions; class ServiceConflictException extends ServiceException { diff --git a/lib/Service/ServiceException.php b/lib/Service/Exceptions/ServiceException.php index ef1aa1102..7ee53bef9 100644 --- a/lib/Service/ServiceException.php +++ b/lib/Service/Exceptions/ServiceException.php @@ -11,7 +11,7 @@ * @copyright 2012-2014 Bernhard Posselt */ -namespace OCA\News\Service; +namespace OCA\News\Service\Exceptions; class ServiceException extends \Exception { diff --git a/lib/Service/ServiceNotFoundException.php b/lib/Service/Exceptions/ServiceNotFoundException.php index 65ba092d7..6a9bae192 100644 --- a/lib/Service/ServiceNotFoundException.php +++ b/lib/Service/Exceptions/ServiceNotFoundException.php @@ -11,7 +11,7 @@ * @copyright 2012-2014 Bernhard Posselt */ -namespace OCA\News\Service; +namespace OCA\News\Service\Exceptions; class ServiceNotFoundException extends ServiceException { diff --git a/lib/Service/ServiceValidationException.php b/lib/Service/Exceptions/ServiceValidationException.php index 20485642b..8d1bf09c8 100644 --- a/lib/Service/ServiceValidationException.php +++ b/lib/Service/Exceptions/ServiceValidationException.php @@ -11,7 +11,7 @@ * @copyright 2012-2014 Bernhard Posselt */ -namespace OCA\News\Service; +namespace OCA\News\Service\Exceptions; class ServiceValidationException extends ServiceException { diff --git a/lib/Service/FeedService.php b/lib/Service/FeedService.php index 6d57c8027..55807b45a 100644 --- a/lib/Service/FeedService.php +++ b/lib/Service/FeedService.php @@ -18,7 +18,9 @@ use HTMLPurifier; use OCA\News\AppInfo\Application; use OCP\IConfig; -use OCP\ILogger; +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; @@ -28,14 +30,20 @@ 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 $logger; private $l10n; private $timeFactory; private $autoPurgeMinimumInterval; @@ -43,18 +51,19 @@ class FeedService extends Service private $loggerParams; public function __construct( - FeedMapper $feedMapper, + FeedMapper $legacyFeedMapper, Fetcher $feedFetcher, - ItemMapper $itemMapper, - ILogger $logger, + ItemMapper $legacyItemMapper, + LoggerInterface $logger, IL10N $l10n, Time $timeFactory, IConfig $config, HTMLPurifier $purifier ) { - parent::__construct($feedMapper); + parent::__construct($legacyFeedMapper, $logger); $this->feedFetcher = $feedFetcher; - $this->itemMapper = $itemMapper; + $this->feedMapper = $legacyFeedMapper; + $this->itemMapper = $legacyItemMapper; $this->logger = $logger; $this->l10n = $l10n; $this->timeFactory = $timeFactory; @@ -64,7 +73,6 @@ class FeedService extends Service Application::DEFAULT_SETTINGS['autoPurgeMinimumInterval'] ); $this->purifier = $purifier; - $this->feedMapper = $feedMapper; $this->loggerParams = ['app' => Application::NAME]; } @@ -75,7 +83,7 @@ class FeedService extends Service * * @return Feed[] */ - public function findAll($userId) + public function findAllForUser($userId): array { return $this->feedMapper->findAllFromUser($userId); } @@ -88,7 +96,7 @@ class FeedService extends Service */ public function findAllFromAllUsers() { - return $this->feedMapper->findAll(); + return $this->findAll(); } @@ -202,17 +210,17 @@ class FeedService extends Service /** * Updates a single feed * - * @param int $feedId the id of the feed that should be updated * @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($feedId, $userId, $forceUpdate = false) + public function update(string $userId, int $feedId, $forceUpdate = false) { /** @var Feed $existingFeed */ - $existingFeed = $this->find($feedId, $userId); + $existingFeed = $this->find($userId, $feedId); if ($existingFeed->getPreventUpdate() === true) { return $existingFeed; @@ -316,7 +324,7 @@ class FeedService extends Service $this->feedMapper->update($existingFeed); - return $this->find($feedId, $userId); + return $this->find($userId, $feedId); } /** @@ -333,7 +341,7 @@ class FeedService extends Service $urlHash = md5($url); // build assoc array for fast access - $feeds = $this->findAll($userId); + $feeds = $this->findAllForUser($userId); $feedsDict = []; foreach ($feeds as $feed) { $feedsDict[$feed->getLink()] = $feed; @@ -402,9 +410,9 @@ class FeedService extends Service * * @throws ServiceNotFoundException when feed does not exist */ - public function markDeleted($feedId, $userId) + public function markDeleted(int $feedId, string $userId) { - $feed = $this->find($feedId, $userId); + $feed = $this->find($userId, $feedId); $feed->setDeletedAt($this->timeFactory->getTime()); $this->feedMapper->update($feed); } @@ -418,9 +426,9 @@ class FeedService extends Service * * @throws ServiceNotFoundException when feed does not exist */ - public function unmarkDeleted($feedId, $userId) + public function unmarkDeleted(int $feedId, string $userId) { - $feed = $this->find($feedId, $userId); + $feed = $this->find($userId, $feedId); $feed->setDeletedAt(0); $this->feedMapper->update($feed); } @@ -463,9 +471,9 @@ class FeedService extends Service } /** - * @param string $feedId ID of the feed. + * @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.: + * @param array $diff An array containing the fields to update, e.g.: * <code> * [ * 'ordering' => 1, @@ -479,9 +487,9 @@ class FeedService extends Service * @throws ServiceNotFoundException if feed does not exist * @return Feed The patched feed */ - public function patch($feedId, $userId, $diff = []) + public function patch(int $feedId, string $userId, array $diff = []) { - $feed = $this->find($feedId, $userId); + $feed = $this->find($userId, $feedId); foreach ($diff as $attribute => $value) { $method = 'set' . ucfirst($attribute); @@ -494,9 +502,14 @@ class FeedService extends Service $feed->setHttpEtag(''); $feed->setHttpLastModified(0); $this->feedMapper->update($feed); - return $this->update($feedId, $userId, true); + return $this->update($userId, $feedId, true); } return $this->feedMapper->update($feed); } + + public function findAll(): array + { + return $this->feedMapper->findAll(); + } } diff --git a/lib/Service/FeedServiceV2.php b/lib/Service/FeedServiceV2.php new file mode 100644 index 000000000..58217a1ce --- /dev/null +++ b/lib/Service/FeedServiceV2.php @@ -0,0 +1,336 @@ +<?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\Db\FeedMapperV2; +use OCA\News\Fetcher\FeedFetcher; +use OCA\News\Service\Exceptions\ServiceConflictException; +use OCA\News\Service\Exceptions\ServiceNotFoundException; +use OCP\AppFramework\Db\Entity; +use OCP\AppFramework\Db\MultipleObjectsReturnedException; +use OCP\ILogger; +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\Config\Config; +use OCA\News\Utility\Time; +use Psr\Log\LoggerInterface; + +/** + * Class FeedService + * + * @package OCA\News\Service + */ +class FeedServiceV2 extends Service +{ + /** + * Class to fetch feeds. + * @var FeedFetcher + */ + protected $feedFetcher; + /** + * Items service. + * + * @var ItemServiceV2 + */ + protected $itemService; + /** + * HTML Purifier + * @var HTMLPurifier + */ + protected $purifier; + + /** + * FeedService constructor. + * + * @param FeedMapperV2 $mapper DB layer for feeds + * @param FeedFetcher $feedFetcher FeedIO interface + * @param ItemServiceV2 $itemService Service to manage items + * @param HTMLPurifier $purifier HTML Purifier + * @param LoggerInterface $logger Logger + */ + public function __construct( + FeedMapperV2 $mapper, + FeedFetcher $feedFetcher, + ItemServiceV2 $itemService, + HTMLPurifier $purifier, + LoggerInterface $logger + ) { + parent::__construct($mapper, $logger); + + $this->feedFetcher = $feedFetcher; + $this->itemService = $itemService; + $this->purifier = $purifier; + } + + /** + * Finds all feeds of a user + * + * @param string $userId the name of the user + * + * @return Feed[] + */ + public function findAllForUser(string $userId): array + { + return $this->mapper->findAllFromUser($userId); + } + + /** + * 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 $id + * + * @return Feed[] + */ + public function findAllFromFolder(int $id): array + { + return $this->mapper->findAllFromFolder($id); + } + + /** + * Finds all feeds of a user and all items in it + * + * @param string $userId the name of the user + * + * @return Feed[] + */ + public function findAllForUserRecursive(string $userId): array + { + $feeds = $this->mapper->findAllFromUser($userId); + + foreach ($feeds as &$feed) { + $items = $this->itemService->findAllForFeed($feed->getId()); + $feed->items = $items; + } + return $feeds; + } + + /** + * Finds all feeds + * + * @return Feed[] + */ + public function findAll(): array + { + return $this->mapper->findAll(); + } + + /** + * Check if a feed exists for a user + * + * @param string $userID the name of the user + * @param string $url the feed URL + * + * @return bool + */ + public function existsForUser(string $userID, string $url): bool + { + try { + $this->mapper->findByURL($userID, $url); + return true; + } catch (DoesNotExistException $e) { + return false; + } + } + + + /** + * Creates a new feed + * + * @param string $userId Feed owner + * @param string $feedUrl Feed URL + * @param int $folderId Target folder, defaults to root + * @param string|null $title The OPML feed title + * @param string|null $user Basic auth username, if set + * @param string|null $password Basic auth password if username is set + * + * @return Feed the newly created feed + * + * @throws ServiceConflictException The feed already exists + * @throws ServiceNotFoundException The url points to an invalid feed + */ + public function create( + string $userId, + string $feedUrl, + int $folderId = 0, + bool $full_text = false, + ?string $title = null, + ?string $user = null, + ?string $password = null + ): Feed { + if ($this->existsForUser($userId, $feedUrl)) { + throw new ServiceConflictException('Feed with this URL exists'); + } + + try { + /** + * @var Feed $feed + * @var Item[] $items + */ + list($feed, $items) = $this->feedFetcher->fetch($feedUrl, true, $full_text, false, $user, $password); + if ($feed === null) { + throw new ServiceNotFoundException('Failed to fetch feed'); + } + + $feed->setFolderId($folderId) + ->setUserId($userId) + ->setArticlesPerUpdate(count($items)); + + if (!is_null($title)) { + $feed->setTitle($title); + } + + if (!is_null($user)) { + $feed->setBasicAuthUser($user) + ->setBasicAuthUser($password); + } + + $feed = $this->mapper->insert($feed); + + return $feed; + } catch (ReadErrorException $ex) { + $this->logger->debug($ex->getMessage()); + throw new ServiceNotFoundException($ex->getMessage()); + } + } + + + /** + * Update a feed + * + * @param Feed $feed Feed item + * @param bool $force update even if the article exists already + * + * @return Feed|Entity Database feed entity + */ + public function fetch(Feed $feed, bool $force = false) + { + if ($feed->getPreventUpdate() === true) { + return $feed; + } + + // for backwards compability it can be that the location is not set + // yet, if so use the url + $location = $feed->getLocation() ?? $feed->getUrl(); + + try { + /** + * @var Feed $feed + * @var Item[] $items + */ + list($fetchedFeed, $items) = $this->feedFetcher->fetch( + $location, + false, + $feed->getHttpLastModified(), + $feed->getFullTextEnabled(), + $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()); + $feed->setHttpEtag($fetchedFeed->getHttpEtag()); + $feed->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()); + + $item->setTitle($item->getTitle()); + $item->setUrl($item->getUrl()); + $item->setAuthor($item->getAuthor()); + $item->setSearchIndex($item->getSearchIndex()); + $item->setRtl($item->getRtl()); + $item->setLastModified($item->getLastModified()); + $item->setPubDate($item->getPubDate()); + $item->setUpdatedDate($item->getUpdatedDate()); + $item->setEnclosureMime($item->getEnclosureMime()); + $item->setEnclosureLink($item->getEnclosureLink()); + $item->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); + } + + public function delete(string $user, int $id) + { + $feed = $this->mapper->findFromUser($user, $id); + $this->mapper->delete($feed); + } + + public function purgeDeleted() + { + $this->mapper->purgeDeleted(); + } + + public function fetchAll() + { + return $this->mapper->findAll(); + } +} diff --git a/lib/Service/FolderService.php b/lib/Service/FolderService.php index 35eb77f95..ed95f81f4 100644 --- a/lib/Service/FolderService.php +++ b/lib/Service/FolderService.php @@ -15,11 +15,23 @@ namespace OCA\News\Service; use OCA\News\AppInfo\Application; use OCP\IConfig; +use OCA\News\Service\Exceptions\ServiceConflictException; +use OCA\News\Service\Exceptions\ServiceException; +use OCA\News\Service\Exceptions\ServiceNotFoundException; +use OCA\News\Service\Exceptions\ServiceValidationException; +use OCP\AppFramework\Db\Entity; use OCP\IL10N; use OCA\News\Db\Folder; use OCA\News\Db\FolderMapper; use OCA\News\Utility\Time; +use Psr\Log\LoggerInterface; +/** + * Class LegacyFolderService + * + * @package OCA\News\Service + * @deprecated use FolderServiceV2 + */ class FolderService extends Service { @@ -32,35 +44,37 @@ class FolderService extends Service FolderMapper $folderMapper, IL10N $l10n, Time $timeFactory, - IConfig $config + IConfig $config, + LoggerInterface $logger ) { - parent::__construct($folderMapper); - $this->l10n = $l10n; - $this->timeFactory = $timeFactory; + parent::__construct($folderMapper, $logger); + $this->l10n = $l10n; + $this->timeFactory = $timeFactory; + $this->folderMapper = $folderMapper; $this->autoPurgeMinimumInterval = $config->getAppValue( Application::NAME, 'autoPurgeMinimumInterval', Application::DEFAULT_SETTINGS['autoPurgeMinimumInterval'] ); - $this->folderMapper = $folderMapper; } /** - * Returns all folders of a user + * Finds all folders of a user + * + * @param string $userId the name of the user * - * @param string $userId the name of the user - * @return array of folders + * @return Folder[] */ - public function findAll($userId) + public function findAllForUser(string $userId): array { return $this->folderMapper->findAllFromUser($userId); } - private function validateFolder($folderName, $userId) + private function validateFolder(string $folderName, string $userId) { - $existingFolders = - $this->folderMapper->findByName($folderName, $userId); + $existingFolders + = $this->folderMapper->findByName($folderName, $userId); if (count($existingFolders) > 0) { throw new ServiceConflictException( $this->l10n->t('Can not add folder: Exists already') @@ -78,15 +92,16 @@ class FolderService extends Service /** * Creates a new folder * - * @param string $folderName the name of the folder - * @param string $userId the name of the user for whom it should be created - * @param int $parentId the parent folder id, deprecated we don't nest + * @param string $folderName the name of the folder + * @param string $userId the name of the user for whom it should be created + * @param int $parentId the parent folder id, deprecated we don't nest * folders - * @throws ServiceConflictException if name exists already + * + * @return Folder|Entity the newly created folder * @throws ServiceValidationException if the folder has invalid parameters - * @return Folder the newly created folder + * @throws ServiceConflictException if name exists already */ - public function create($folderName, $userId, $parentId = 0) + public function create(string $folderName, string $userId, int $parentId = 0) { $this->validateFolder($folderName, $userId); @@ -103,9 +118,9 @@ class FolderService extends Service /** * @throws ServiceException if the folder does not exist */ - public function open($folderId, $opened, $userId) + public function open(int $folderId, bool $opened, string $userId) { - $folder = $this->find($folderId, $userId); + $folder = $this->find($userId, $folderId); $folder->setOpened($opened); $this->folderMapper->update($folder); } @@ -114,19 +129,20 @@ class FolderService extends Service /** * Renames a folder * - * @param int $folderId the id of the folder that should be deleted - * @param string $folderName the new name of the folder - * @param string $userId the name of the user for security reasons - * @throws ServiceConflictException if name exists already + * @param int $folderId the id of the folder that should be deleted + * @param string $folderName the new name of the folder + * @param string $userId the name of the user for security reasons + * + * @return Folder the updated folder * @throws ServiceValidationException if the folder has invalid parameters * @throws ServiceNotFoundException if the folder does not exist - * @return Folder the updated folder + * @throws ServiceConflictException if name exists already */ - public function rename($folderId, $folderName, $userId) + public function rename(int $folderId, string $folderName, string $userId) { $this->validateFolder($folderName, $userId); - $folder = $this->find($folderId, $userId); + $folder = $this->find($userId, $folderId); $folder->setName($folderName); return $this->folderMapper->update($folder); @@ -136,13 +152,14 @@ class FolderService extends Service /** * Use this to mark a folder as deleted. That way it can be un-deleted * - * @param int $folderId the id of the folder that should be deleted - * @param string $userId the name of the user for security reasons + * @param int $folderId the id of the folder that should be deleted + * @param string $userId the name of the user for security reasons + * * @throws ServiceNotFoundException when folder does not exist */ - public function markDeleted($folderId, $userId) + public function markDeleted(int $folderId, string $userId) { - $folder = $this->find($folderId, $userId); + $folder = $this->find($userId, $folderId); $folder->setDeletedAt($this->timeFactory->getTime()); $this->folderMapper->update($folder); } @@ -151,13 +168,14 @@ class FolderService extends Service /** * Use this to restore a folder * - * @param int $folderId the id of the folder that should be restored - * @param string $userId the name of the user for security reasons + * @param int $folderId the id of the folder that should be restored + * @param string $userId the name of the user for security reasons + * * @throws ServiceNotFoundException when folder does not exist */ - public function unmarkDeleted($folderId, $userId) + public function unmarkDeleted(int $folderId, string $userId) { - $folder = $this->find($folderId, $userId); + $folder = $this->find($userId, $folderId); $folder->setDeletedAt(0); $this->folderMapper->update($folder); } @@ -171,7 +189,7 @@ class FolderService extends Service * entries in a given interval to give the user a chance to undo the * deletion */ - public function purgeDeleted($userId = null, $useInterval = true) + public function purgeDeleted(?string $userId = null, bool $useInterval = true) { $deleteOlderThan = null; @@ -193,8 +211,13 @@ class FolderService extends Service * * @param string $userId the name of the user */ - public function deleteUser($userId) + public function deleteUser(string $userId) { $this->folderMapper->deleteUser($userId); } + + public function findAll(): array + { + return $this->mapper->findAll(); + } } diff --git a/lib/Service/FolderServiceV2.php b/lib/Service/FolderServiceV2.php new file mode 100644 index 000000000..0e15ddde5 --- /dev/null +++ b/lib/Service/FolderServiceV2.php @@ -0,0 +1,102 @@ +<?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\Feed; +use OCA\News\Db\FeedMapperV2; +use OCA\News\Db\Folder; +use OCA\News\Db\FolderMapperV2; +use Psr\Log\LoggerInterface; + +/** + * Class FolderService + * + * @package OCA\News\Service + |