mirror of
https://github.com/chylex/Nextcloud-News.git
synced 2025-04-09 19:15:42 +02:00
✨ NewsItem: add share functions (mapper + service)
Signed-off-by: Marco Nassabain <marco.nassabain@hotmail.com>
This commit is contained in:
parent
5b09e74f40
commit
527eef0727
lib
545
lib/Db/ItemMapper.php
Normal file
545
lib/Db/ItemMapper.php
Normal file
@ -0,0 +1,545 @@
|
||||
<?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 Exception;
|
||||
use OCA\News\Utility\Time;
|
||||
use OCP\AppFramework\Db\DoesNotExistException;
|
||||
use OCP\AppFramework\Db\Entity;
|
||||
use OCP\AppFramework\Db\MultipleObjectsReturnedException;
|
||||
use OCP\DB\QueryBuilder\IQueryBuilder;
|
||||
use OCP\IDBConnection;
|
||||
|
||||
/**
|
||||
* Class LegacyItemMapper
|
||||
*
|
||||
* @package OCA\News\Db
|
||||
* @deprecated use ItemMapper
|
||||
*/
|
||||
class ItemMapper extends NewsMapper
|
||||
{
|
||||
|
||||
const TABLE_NAME = 'news_items';
|
||||
public function __construct(IDBConnection $db, Time $time)
|
||||
{
|
||||
parent::__construct($db, $time, Item::class);
|
||||
}
|
||||
|
||||
private function makeSelectQuery(
|
||||
$prependTo = '',
|
||||
$oldestFirst = false,
|
||||
$distinctFingerprint = false
|
||||
) {
|
||||
if ($oldestFirst) {
|
||||
$ordering = 'ASC';
|
||||
} else {
|
||||
$ordering = 'DESC';
|
||||
}
|
||||
|
||||
return 'SELECT `items`.* FROM `*PREFIX*news_items` `items` ' .
|
||||
'JOIN `*PREFIX*news_feeds` `feeds` ' .
|
||||
'ON `feeds`.`id` = `items`.`feed_id` ' .
|
||||
'AND `feeds`.`deleted_at` = 0 ' .
|
||||
'AND `feeds`.`user_id` = ? ' .
|
||||
$prependTo .
|
||||
'LEFT OUTER JOIN `*PREFIX*news_folders` `folders` ' .
|
||||
'ON `folders`.`id` = `feeds`.`folder_id` ' .
|
||||
'WHERE `feeds`.`folder_id` IS NULL ' .
|
||||
'OR `folders`.`deleted_at` = 0 ' .
|
||||
'ORDER BY `items`.`id` ' . $ordering;
|
||||
}
|
||||
|
||||
/**
|
||||
* check if type is feed or all items should be shown
|
||||
*
|
||||
* @param bool $showAll
|
||||
* @param int|null $type
|
||||
* @return string
|
||||
*/
|
||||
private function buildStatusQueryPart($showAll, $type = null)
|
||||
{
|
||||
$sql = '';
|
||||
|
||||
if (isset($type) && $type === FeedType::STARRED) {
|
||||
$sql = 'AND `items`.`starred` = ';
|
||||
$sql .= $this->db->quote(true, IQueryBuilder::PARAM_BOOL) . ' ';
|
||||
} elseif (!$showAll || $type === FeedType::UNREAD) {
|
||||
$sql .= 'AND `items`.`unread` = ';
|
||||
$sql .= $this->db->quote(true, IQueryBuilder::PARAM_BOOL) . ' ';
|
||||
}
|
||||
|
||||
return $sql;
|
||||
}
|
||||
|
||||
private function buildSearchQueryPart(array $search = [])
|
||||
{
|
||||
return str_repeat('AND `items`.`search_index` LIKE ? ', count($search));
|
||||
}
|
||||
|
||||
/**
|
||||
* wrap and escape search parameters in a like statement
|
||||
*
|
||||
* @param string[] $search an array of strings that should be searched
|
||||
* @return array with like parameters
|
||||
*/
|
||||
private function buildLikeParameters($search = [])
|
||||
{
|
||||
return array_map(
|
||||
function ($param) {
|
||||
$param = addcslashes($param, '\\_%');
|
||||
return '%' . mb_strtolower($param, 'UTF-8') . '%';
|
||||
},
|
||||
$search
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $id
|
||||
* @param string $userId
|
||||
* @return \OCA\News\Db\Item
|
||||
*/
|
||||
public function find(string $userId, int $id)
|
||||
{
|
||||
$sql = $this->makeSelectQuery('AND `items`.`id` = ? ');
|
||||
return $this->findEntity($sql, [$userId, $id]);
|
||||
}
|
||||
|
||||
public function starredCount(string $userId)
|
||||
{
|
||||
$sql = 'SELECT COUNT(*) AS size FROM `*PREFIX*news_items` `items` ' .
|
||||
'JOIN `*PREFIX*news_feeds` `feeds` ' .
|
||||
'ON `feeds`.`id` = `items`.`feed_id` ' .
|
||||
'AND `feeds`.`deleted_at` = 0 ' .
|
||||
'AND `feeds`.`user_id` = ? ' .
|
||||
'AND `items`.`starred` = ? ' .
|
||||
'LEFT OUTER JOIN `*PREFIX*news_folders` `folders` ' .
|
||||
'ON `folders`.`id` = `feeds`.`folder_id` ' .
|
||||
'WHERE `feeds`.`folder_id` IS NULL ' .
|
||||
'OR `folders`.`deleted_at` = 0';
|
||||
|
||||
$params = [$userId, true];
|
||||
|
||||
$result = $this->execute($sql, $params)->fetch();
|
||||
|
||||
return (int)$result['size'];
|
||||
}
|
||||
|
||||
|
||||
public function readAll(int $highestItemId, $time, string $userId)
|
||||
{
|
||||
$sql = 'UPDATE `*PREFIX*news_items` ' .
|
||||
'SET unread = ? ' .
|
||||
', `last_modified` = ? ' .
|
||||
'WHERE `feed_id` IN (' .
|
||||
'SELECT `id` FROM `*PREFIX*news_feeds` ' .
|
||||
'WHERE `user_id` = ? ' .
|
||||
') ' .
|
||||
'AND `id` <= ?';
|
||||
$params = [false, $time, $userId, $highestItemId];
|
||||
$this->execute($sql, $params);
|
||||
}
|
||||
|
||||
|
||||
public function readFolder(?int $folderId, $highestItemId, $time, $userId)
|
||||
{
|
||||
$folderWhere = is_null($folderId) ? 'IS' : '=';
|
||||
$sql = 'UPDATE `*PREFIX*news_items` ' .
|
||||
'SET unread = ? ' .
|
||||
', `last_modified` = ? ' .
|
||||
'WHERE `feed_id` IN (' .
|
||||
'SELECT `id` FROM `*PREFIX*news_feeds` ' .
|
||||
"WHERE `folder_id` ${folderWhere} ? " .
|
||||
'AND `user_id` = ? ' .
|
||||
') ' .
|
||||
'AND `id` <= ?';
|
||||
$params = [false, $time, $folderId, $userId,
|
||||
$highestItemId];
|
||||
$this->execute($sql, $params);
|
||||
}
|
||||
|
||||
|
||||
public function readFeed($feedId, $highestItemId, $time, $userId)
|
||||
{
|
||||
$sql = 'UPDATE `*PREFIX*news_items` ' .
|
||||
'SET unread = ? ' .
|
||||
', `last_modified` = ? ' .
|
||||
'WHERE `feed_id` = ? ' .
|
||||
'AND `id` <= ? ' .
|
||||
'AND EXISTS (' .
|
||||
'SELECT * FROM `*PREFIX*news_feeds` ' .
|
||||
'WHERE `user_id` = ? ' .
|
||||
'AND `id` = ? ) ';
|
||||
$params = [false, $time, $feedId, $highestItemId,
|
||||
$userId, $feedId];
|
||||
|
||||
$this->execute($sql, $params);
|
||||
}
|
||||
|
||||
|
||||
private function getOperator($oldestFirst)
|
||||
{
|
||||
if ($oldestFirst) {
|
||||
return '>';
|
||||
} else {
|
||||
return '<';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function findAllNew($updatedSince, $type, $showAll, $userId)
|
||||
{
|
||||
$sql = $this->buildStatusQueryPart($showAll, $type);
|
||||
|
||||
$sql .= 'AND `items`.`last_modified` >= ? ';
|
||||
$sql = $this->makeSelectQuery($sql);
|
||||
$params = [$userId, $updatedSince];
|
||||
return $this->findEntities($sql, $params);
|
||||
}
|
||||
|
||||
|
||||
public function findAllNewFolder(?int $id, $updatedSince, $showAll, $userId)
|
||||
{
|
||||
$sql = $this->buildStatusQueryPart($showAll);
|
||||
|
||||
$folderWhere = is_null($id) ? 'IS' : '=';
|
||||
$sql .= "AND `feeds`.`folder_id` ${$folderWhere} ? " .
|
||||
'AND `items`.`last_modified` >= ? ';
|
||||
$sql = $this->makeSelectQuery($sql);
|
||||
$params = [$userId, $id, $updatedSince];
|
||||
return $this->findEntities($sql, $params);
|
||||
}
|
||||
|
||||
|
||||
public function findAllNewFeed($id, $updatedSince, $showAll, $userId)
|
||||
{
|
||||
$sql = $this->buildStatusQueryPart($showAll);
|
||||
|
||||
$sql .= 'AND `items`.`feed_id` = ? ' .
|
||||
'AND `items`.`last_modified` >= ? ';
|
||||
$sql = $this->makeSelectQuery($sql);
|
||||
$params = [$userId, $id, $updatedSince];
|
||||
return $this->findEntities($sql, $params);
|
||||
}
|
||||
|
||||
|
||||
private function findEntitiesIgnoringNegativeLimit($sql, $params, $limit): array
|
||||
{
|
||||
// ignore limit if negative to offer a way to return all feeds
|
||||
if ($limit >= 0) {
|
||||
return $this->findEntities($sql, $params, $limit);
|
||||
} else {
|
||||
return $this->findEntities($sql, $params);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function findAllFeed(
|
||||
$id,
|
||||
$limit,
|
||||
$offset,
|
||||
$showAll,
|
||||
$oldestFirst,
|
||||
$userId,
|
||||
$search = []
|
||||
) {
|
||||
$params = [$userId];
|
||||
$params = array_merge($params, $this->buildLikeParameters($search));
|
||||
$params[] = $id;
|
||||
|
||||
$sql = $this->buildStatusQueryPart($showAll);
|
||||
$sql .= $this->buildSearchQueryPart($search);
|
||||
|
||||
$sql .= 'AND `items`.`feed_id` = ? ';
|
||||
if ($offset !== 0) {
|
||||
$sql .= 'AND `items`.`id` ' .
|
||||
$this->getOperator($oldestFirst) . ' ? ';
|
||||
$params[] = $offset;
|
||||
}
|
||||
$sql = $this->makeSelectQuery($sql, $oldestFirst, $search);
|
||||
return $this->findEntitiesIgnoringNegativeLimit($sql, $params, $limit);
|
||||
}
|
||||
|
||||
|
||||
public function findAllFolder(
|
||||
?int $id,
|
||||
$limit,
|
||||
$offset,
|
||||
$showAll,
|
||||
$oldestFirst,
|
||||
$userId,
|
||||
$search = []
|
||||
) {
|
||||
$params = [$userId];
|
||||
$params = array_merge($params, $this->buildLikeParameters($search));
|
||||
$params[] = $id;
|
||||
|
||||
$sql = $this->buildStatusQueryPart($showAll);
|
||||
$sql .= $this->buildSearchQueryPart($search);
|
||||
|
||||
$folderWhere = is_null($id) ? 'IS' : '=';
|
||||
$sql .= "AND `feeds`.`folder_id` ${folderWhere} ? ";
|
||||
if ($offset !== 0) {
|
||||
$sql .= 'AND `items`.`id` ' . $this->getOperator($oldestFirst) . ' ? ';
|
||||
$params[] = $offset;
|
||||
}
|
||||
$sql = $this->makeSelectQuery($sql, $oldestFirst, $search);
|
||||
return $this->findEntitiesIgnoringNegativeLimit($sql, $params, $limit);
|
||||
}
|
||||
|
||||
|
||||
public function findAllItems(
|
||||
$limit,
|
||||
$offset,
|
||||
$type,
|
||||
$showAll,
|
||||
$oldestFirst,
|
||||
$userId,
|
||||
$search = []
|
||||
): array {
|
||||
$params = [$userId];
|
||||
$params = array_merge($params, $this->buildLikeParameters($search));
|
||||
$sql = $this->buildStatusQueryPart($showAll, $type);
|
||||
$sql .= $this->buildSearchQueryPart($search);
|
||||
|
||||
if ($offset !== 0) {
|
||||
$sql .= 'AND `items`.`id` ' .
|
||||
$this->getOperator($oldestFirst) . ' ? ';
|
||||
$params[] = $offset;
|
||||
}
|
||||
|
||||
$sql = $this->makeSelectQuery($sql, $oldestFirst);
|
||||
|
||||
return $this->findEntitiesIgnoringNegativeLimit($sql, $params, $limit);
|
||||
}
|
||||
|
||||
|
||||
public function findAllUnreadOrStarred($userId)
|
||||
{
|
||||
$params = [$userId, true, true];
|
||||
$sql = 'AND (`items`.`unread` = ? OR `items`.`starred` = ?) ';
|
||||
$sql = $this->makeSelectQuery($sql);
|
||||
return $this->findEntities($sql, $params);
|
||||
}
|
||||
|
||||
|
||||
public function findByGuidHash($guidHash, $feedId, $userId)
|
||||
{
|
||||
$sql = $this->makeSelectQuery(
|
||||
'AND `items`.`guid_hash` = ? ' .
|
||||
'AND `feeds`.`id` = ? '
|
||||
);
|
||||
|
||||
return $this->findEntity($sql, [$userId, $guidHash, $feedId]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Delete all items for feeds that have over $threshold unread and not
|
||||
* starred items
|
||||
*
|
||||
* @param int $threshold the number of items that should be deleted
|
||||
*/
|
||||
public function deleteReadOlderThanThreshold($threshold)
|
||||
{
|
||||
$params = [false, false, $threshold];
|
||||
|
||||
$sql = 'SELECT (COUNT(*) - `feeds`.`articles_per_update`) AS `size`, ' .
|
||||
'`feeds`.`id` AS `feed_id`, `feeds`.`articles_per_update` ' .
|
||||
'FROM `*PREFIX*news_items` `items` ' .
|
||||
'JOIN `*PREFIX*news_feeds` `feeds` ' .
|
||||
'ON `feeds`.`id` = `items`.`feed_id` ' .
|
||||
'AND `items`.`unread` = ? ' .
|
||||
'AND `items`.`starred` = ? ' .
|
||||
'GROUP BY `feeds`.`id`, `feeds`.`articles_per_update` ' .
|
||||
'HAVING COUNT(*) > ?';
|
||||
|
||||
$result = $this->execute($sql, $params);
|
||||
|
||||
while ($row = $result->fetch()) {
|
||||
$size = (int)$row['size'];
|
||||
$limit = $size - $threshold;
|
||||
$feed_id = $row['feed_id'];
|
||||
|
||||
if ($limit > 0) {
|
||||
$params = [false, false, $feed_id, $limit];
|
||||
$sql = 'SELECT `id` FROM `*PREFIX*news_items` ' .
|
||||
'WHERE `unread` = ? ' .
|
||||
'AND `starred` = ? ' .
|
||||
'AND `feed_id` = ? ' .
|
||||
'ORDER BY `id` ASC ' .
|
||||
'LIMIT 1 ' .
|
||||
'OFFSET ? ';
|
||||
}
|
||||
$limit_result = $this->execute($sql, $params);
|
||||
if ($limit_row = $limit_result->fetch()) {
|
||||
$limit_id = (int)$limit_row['id'];
|
||||
$params = [false, false, $feed_id, $limit_id];
|
||||
$sql = 'DELETE FROM `*PREFIX*news_items` ' .
|
||||
'WHERE `unread` = ? ' .
|
||||
'AND `starred` = ? ' .
|
||||
'AND `feed_id` = ? ' .
|
||||
'AND `id` < ? ';
|
||||
$this->execute($sql, $params);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function getNewestItemId($userId)
|
||||
{
|
||||
$sql = 'SELECT MAX(`items`.`id`) AS `max_id` ' .
|
||||
'FROM `*PREFIX*news_items` `items` ' .
|
||||
'JOIN `*PREFIX*news_feeds` `feeds` ' .
|
||||
'ON `feeds`.`id` = `items`.`feed_id` ' .
|
||||
'AND `feeds`.`user_id` = ?';
|
||||
$params = [$userId];
|
||||
|
||||
$result = $this->findOneQuery($sql, $params);
|
||||
|
||||
return (int)$result['max_id'];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
public function findAllIds($limit = null, $offset = null)
|
||||
{
|
||||
$sql = 'SELECT `id` FROM `*PREFIX*news_items`';
|
||||
return $this->execute($sql, [], $limit, $offset)->fetchAll();
|
||||
}
|
||||
|
||||
/**
|
||||
* Update search indices of all items
|
||||
*/
|
||||
public function updateSearchIndices()
|
||||
{
|
||||
// update indices in steps to prevent memory issues on larger systems
|
||||
$step = 1000; // update 1000 items at a time
|
||||
$itemCount = 1;
|
||||
$offset = 0;
|
||||
|
||||
// stop condition if there are no previously fetched items
|
||||
while ($itemCount > 0) {
|
||||
$items = $this->findAllIds($step, $offset);
|
||||
$itemCount = count($items);
|
||||
$this->updateSearchIndex($items);
|
||||
$offset += $step;
|
||||
}
|
||||
}
|
||||
|
||||
private function updateSearchIndex(array $items = [])
|
||||
{
|
||||
foreach ($items as $row) {
|
||||
$sql = 'SELECT * FROM `*PREFIX*news_items` WHERE `id` = ?';
|
||||
$params = [$row['id']];
|
||||
$item = $this->findEntity($sql, $params);
|
||||
$item->generateSearchIndex();
|
||||
$this->update($item);
|
||||
}
|
||||
}
|
||||
|
||||
public function readItem($itemId, $isRead, $lastModified, $userId)
|
||||
{
|
||||
$item = $this->find($userId, $itemId);
|
||||
|
||||
// reading an item should set all of the same items as read, whereas
|
||||
// marking an item as unread should only mark the selected instance
|
||||
// as unread
|
||||
if ($isRead) {
|
||||
$sql = 'UPDATE `*PREFIX*news_items`
|
||||
SET `unread` = ?,
|
||||
`last_modified` = ?
|
||||
WHERE `fingerprint` = ?
|
||||
AND `feed_id` IN (
|
||||
SELECT `f`.`id` FROM `*PREFIX*news_feeds` AS `f`
|
||||
WHERE `f`.`user_id` = ?
|
||||
)';
|
||||
$params = [false, $lastModified, $item->getFingerprint(), $userId];
|
||||
$this->execute($sql, $params);
|
||||
} else {
|
||||
$item->setLastModified($lastModified);
|
||||
$item->setUnread(true);
|
||||
$this->update($item);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* NO-OP
|
||||
*
|
||||
* @param string $userId
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function findAllFromUser(string $userId): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
public function findFromUser(string $userId, int $id): Entity
|
||||
{
|
||||
return $this->find($id, $userId);
|
||||
}
|
||||
|
||||
/**
|
||||
* NO-OP
|
||||
* @return array
|
||||
*/
|
||||
public function findAll(): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
|
||||
public function shareItem($itemId, $shareWithId, $userId)
|
||||
{
|
||||
// find existing item and copy it
|
||||
$item = $this->find($userId, $itemId);
|
||||
|
||||
// copy item
|
||||
$newItem = Item::fromImport($item->jsonSerialize());
|
||||
|
||||
// copy/initialize fields
|
||||
$newItem->setUnread(false);
|
||||
$newItem->setStarred(false);
|
||||
$newItem->setFeedId(null);
|
||||
$newItem->setFingerprint($item->getFingerprint());
|
||||
$newItem->setContentHash($item->getContentHash());
|
||||
$newItem->setSearchIndex($item->getSearchIndex());
|
||||
|
||||
// set share data
|
||||
$newItem->setSharedBy($userId);
|
||||
$newItem->setSharedWith($shareWithId);
|
||||
|
||||
// persist new item
|
||||
$this->insert($newItem);
|
||||
}
|
||||
}
|
355
lib/Service/ItemService.php
Normal file
355
lib/Service/ItemService.php
Normal file
@ -0,0 +1,355 @@
|
||||
<?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\AppInfo\Application;
|
||||
use OCA\News\Db\Item;
|
||||
use OCA\News\Service\Exceptions\ServiceNotFoundException;
|
||||
use OCP\AppFramework\Db\Entity;
|
||||
use OCP\IConfig;
|
||||
use OCP\AppFramework\Db\DoesNotExistException;
|
||||
|
||||
use OCA\News\Db\ItemMapper;
|
||||
use OCA\News\Db\FeedType;
|
||||
use OCA\News\Utility\Time;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
/**
|
||||
* Class LegacyItemService
|
||||
*
|
||||
* @package OCA\News\Service
|
||||
* @deprecated use ItemServiceV2
|
||||
*/
|
||||
class ItemService extends Service
|
||||
{
|
||||
|
||||
private $config;
|
||||
private $timeFactory;
|
||||
private $itemMapper;
|
||||
|
||||
public function __construct(
|
||||
ItemMapper $itemMapper,
|
||||
Time $timeFactory,
|
||||
IConfig $config,
|
||||
LoggerInterface $logger
|
||||
) {
|
||||
parent::__construct($itemMapper, $logger);
|
||||
$this->config = $config;
|
||||
$this->timeFactory = $timeFactory;
|
||||
$this->itemMapper = $itemMapper;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns all new items
|
||||
*
|
||||
* @param int|null $id the id of the feed, 0 for starred or all items
|
||||
* @param int $type the type of the feed
|
||||
* @param int $updatedSince a timestamp with the last modification date
|
||||
* returns only items with a >= modified
|
||||
* timestamp
|
||||
* @param boolean $showAll if unread items should also be returned
|
||||
* @param string $userId the name of the user
|
||||
*
|
||||
* @return array of items
|
||||
*/
|
||||
public function findAllNew(?int $id, $type, $updatedSince, $showAll, $userId)
|
||||
{
|
||||
switch ($type) {
|
||||
case FeedType::FEED:
|
||||
return $this->itemMapper->findAllNewFeed(
|
||||
$id,
|
||||
$updatedSince,
|
||||
$showAll,
|
||||
$userId
|
||||
);
|
||||
case FeedType::FOLDER:
|
||||
return $this->itemMapper->findAllNewFolder(
|
||||
$id,
|
||||
$updatedSince,
|
||||
$showAll,
|
||||
$userId
|
||||
);
|
||||
default:
|
||||
return $this->itemMapper->findAllNew(
|
||||
$updatedSince,
|
||||
$type,
|
||||
$showAll,
|
||||
$userId
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns all items
|
||||
*
|
||||
* @param int|null $id the id of the feed, 0 for starred or all items
|
||||
* @param int $type the type of the feed
|
||||
* @param int $limit how many items should be returned
|
||||
* @param int $offset the offset
|
||||
* @param boolean $showAll if unread items should also be returned
|
||||
* @param boolean $oldestFirst if it should be ordered by oldest first
|
||||
* @param string $userId the name of the user
|
||||
* @param string[] $search an array of keywords that the result should
|
||||
* contain in either the author, title, link
|
||||
* or body
|
||||
*
|
||||
* @return array of items
|
||||
*/
|
||||
public function findAllItems(
|
||||
?int $id,
|
||||
$type,
|
||||
$limit,
|
||||
$offset,
|
||||
$showAll,
|
||||
$oldestFirst,
|
||||
$userId,
|
||||
$search = []
|
||||
) {
|
||||
switch ($type) {
|
||||
case FeedType::FEED:
|
||||
return $this->itemMapper->findAllFeed(
|
||||
$id,
|
||||
$limit,
|
||||
$offset,
|
||||
$showAll,
|
||||
$oldestFirst,
|
||||
$userId,
|
||||
$search
|
||||
);
|
||||
case FeedType::FOLDER:
|
||||
return $this->itemMapper->findAllFolder(
|
||||
$id,
|
||||
$limit,
|
||||
$offset,
|
||||
$showAll,
|
||||
$oldestFirst,
|
||||
$userId,
|
||||
$search
|
||||
);
|
||||
default:
|
||||
return $this->itemMapper->findAllItems(
|
||||
$limit,
|
||||
$offset,
|
||||
$type,
|
||||
$showAll,
|
||||
$oldestFirst,
|
||||
$userId,
|
||||
$search
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public function findAllForUser(string $userId, array $params = []): array
|
||||
{
|
||||
return $this->itemMapper->findAllFromUser($userId);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Star or unstar an item
|
||||
*
|
||||
* @param int $feedId the id of the item's feed that should be starred
|
||||
* @param string $guidHash the guidHash of the item that should be starred
|
||||
* @param boolean $isStarred if true the item will be marked as starred,
|
||||
* if false unstar
|
||||
* @param string $userId the name of the user for security reasons
|
||||
* @throws ServiceNotFoundException if the item does not exist
|
||||
*/
|
||||
public function star($feedId, $guidHash, $isStarred, $userId)
|
||||
{
|
||||
try {
|
||||
/**
|
||||
* @var Item $item
|
||||
*/
|
||||
$item = $this->itemMapper->findByGuidHash(
|
||||
$guidHash,
|
||||
$feedId,
|
||||
$userId
|
||||
);
|
||||
|
||||
$item->setStarred($isStarred);
|
||||
|
||||
$this->itemMapper->update($item);
|
||||
} catch (DoesNotExistException $ex) {
|
||||
throw new ServiceNotFoundException($ex->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Read or unread an item
|
||||
*
|
||||
* @param int $itemId the id of the item that should be read
|
||||
* @param boolean $isRead if true the item will be marked as read,
|
||||
* if false unread
|
||||
* @param string $userId the name of the user for security reasons
|
||||
* @throws ServiceNotFoundException if the item does not exist
|
||||
*/
|
||||
public function read($itemId, $isRead, $userId)
|
||||
{
|
||||
try {
|
||||
$lastModified = $this->timeFactory->getMicroTime();
|
||||
$this->itemMapper->readItem($itemId, $isRead, $lastModified, $userId);
|
||||
} catch (DoesNotExistException $ex) {
|
||||
throw new ServiceNotFoundException($ex->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set all items read
|
||||
*
|
||||
* @param int $highestItemId all items below that are marked read. This is
|
||||
* used to prevent marking items as read that
|
||||
* the users hasn't seen yet
|
||||
* @param string $userId the name of the user
|
||||
*/
|
||||
public function readAll($highestItemId, $userId)
|
||||
{
|
||||
$time = $this->timeFactory->getMicroTime();
|
||||
$this->itemMapper->readAll($highestItemId, $time, $userId);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set a folder read
|
||||
*
|
||||
* @param int|null $folderId the id of the folder that should be marked read
|
||||
* @param int $highestItemId all items below that are marked read. This is
|
||||
* used to prevent marking items as read that
|
||||
* the users hasn't seen yet
|
||||
* @param string $userId the name of the user
|
||||
*/
|
||||
public function readFolder(?int $folderId, $highestItemId, $userId)
|
||||
{
|
||||
$time = $this->timeFactory->getMicroTime();
|
||||
$this->itemMapper->readFolder(
|
||||
$folderId,
|
||||
$highestItemId,
|
||||
$time,
|
||||
$userId
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set a feed read
|
||||
*
|
||||
* @param int $feedId the id of the feed that should be marked read
|
||||
* @param int $highestItemId all items below that are marked read. This is
|
||||
* used to prevent marking items as read that
|
||||
* the users hasn't seen yet
|
||||
* @param string $userId the name of the user
|
||||
*/
|
||||
public function readFeed($feedId, $highestItemId, $userId)
|
||||
{
|
||||
$time = $this->timeFactory->getMicroTime();
|
||||
$this->itemMapper->readFeed($feedId, $highestItemId, $time, $userId);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This method deletes all unread feeds that are not starred and over the
|
||||
* count of $this->autoPurgeCount starting by the oldest. This is to clean
|
||||
* up the database so that old entries don't spam your db. As criteria for
|
||||
* old, the id is taken
|
||||
*/
|
||||
public function autoPurgeOld()
|
||||
{
|
||||
$count = $this->config->getAppValue(
|
||||
Application::NAME,
|
||||
'autoPurgeCount',
|
||||
Application::DEFAULT_SETTINGS['autoPurgeCount']
|
||||
);
|
||||
if ($count >= 0) {
|
||||
$this->itemMapper->deleteReadOlderThanThreshold($count);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the newest item id, use this for marking feeds read
|
||||
*
|
||||
* @param string $userId the name of the user
|
||||
* @throws ServiceNotFoundException if there is no newest item
|
||||
* @return int
|
||||
*/
|
||||
public function getNewestItemId($userId)
|
||||
{
|
||||
try {
|
||||
return $this->itemMapper->getNewestItemId($userId);
|
||||
} catch (DoesNotExistException $ex) {
|
||||
throw new ServiceNotFoundException($ex->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the starred count
|
||||
*
|
||||
* @param string $userId the name of the user
|
||||
* @return int the count
|
||||
*/
|
||||
public function starredCount($userId)
|
||||
{
|
||||
return $this->itemMapper->starredCount($userId);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $userId from which user the items should be taken
|
||||
* @return array of items which are starred or unread
|
||||
*/
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Regenerates the search index for all items
|
||||
*/
|
||||
public function generateSearchIndices()
|
||||
{
|
||||
$this->itemMapper->updateSearchIndices();
|
||||
}
|
||||
|
||||
public function findAll(): array
|
||||
{
|
||||
return $this->mapper->findAll();
|
||||
}
|
||||
|
||||
|
||||
public function shareItem($itemId, $shareWithId, $userId)
|
||||
{
|
||||
try {
|
||||
$this->itemMapper->shareItem($itemId, $shareWithId, $userId);
|
||||
} catch (DoesNotExistException $ex) {
|
||||
throw new ServiceNotFoundException($ex->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user