summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorDevlin Junker <devlin.junker@gmail.com>2023-08-05 19:16:39 -0700
committerBenjamin Brahmer <info@b-brahmer.de>2023-08-09 11:08:04 +0200
commit923f986e67413ac548cc98d6d59fa01de9681035 (patch)
treea3d1fb38fd28388686b0c394d4824af30b959fd7 /lib
parent450047ef4be0d39ba8a5e5e5ac0d6e87b7203ebb (diff)
upmerged from master
Signed-off-by: Devlin Junker <devlin.junker@gmail.com>
Diffstat (limited to 'lib')
-rw-r--r--lib/AppInfo/Application.php3
-rw-r--r--lib/Config/FetcherConfig.php6
-rw-r--r--lib/Controller/PageController.php1
-rw-r--r--lib/Db/Feed.php8
-rw-r--r--lib/Db/ItemMapperV2.php7
-rwxr-xr-xlib/Fetcher/FeedFetcher.php67
-rw-r--r--lib/Fetcher/Fetcher.php7
-rw-r--r--lib/Fetcher/IFeedFetcher.php4
-rw-r--r--lib/Migration/RemoveUnusedJob.php50
-rw-r--r--lib/Scraper/Scraper.php7
-rw-r--r--lib/Search/FeedSearchProvider.php6
-rw-r--r--lib/Search/FolderSearchProvider.php4
-rw-r--r--lib/Search/ItemSearchProvider.php109
-rw-r--r--lib/Service/FeedServiceV2.php57
-rw-r--r--lib/Service/StatusService.php27
-rw-r--r--lib/Settings/AdminSettings.php14
16 files changed, 317 insertions, 60 deletions
diff --git a/lib/AppInfo/Application.php b/lib/AppInfo/Application.php
index 950d44383..bc5e1b476 100644
--- a/lib/AppInfo/Application.php
+++ b/lib/AppInfo/Application.php
@@ -23,6 +23,7 @@ use OCA\News\Config\FetcherConfig;
use OCA\News\Hooks\UserDeleteHook;
use OCA\News\Search\FeedSearchProvider;
use OCA\News\Search\FolderSearchProvider;
+use OCA\News\Search\ItemSearchProvider;
use OCP\AppFramework\Bootstrap\IBootContext;
use OCP\AppFramework\Bootstrap\IBootstrap;
@@ -82,6 +83,8 @@ class Application extends App implements IBootstrap
$context->registerSearchProvider(FolderSearchProvider::class);
$context->registerSearchProvider(FeedSearchProvider::class);
+ $context->registerSearchProvider(ItemSearchProvider::class);
+
$context->registerEventListener(BeforeUserDeletedEvent::class, UserDeleteHook::class);
diff --git a/lib/Config/FetcherConfig.php b/lib/Config/FetcherConfig.php
index ce2e7db8d..797dae49e 100644
--- a/lib/Config/FetcherConfig.php
+++ b/lib/Config/FetcherConfig.php
@@ -103,7 +103,11 @@ class FetcherConfig
{
$config = [
'timeout' => $this->client_timeout,
- 'headers' => ['User-Agent' => static::DEFAULT_USER_AGENT, 'Accept' => static::DEFAULT_ACCEPT],
+ 'headers' => [
+ 'User-Agent' => static::DEFAULT_USER_AGENT,
+ 'Accept' => static::DEFAULT_ACCEPT,
+ 'Accept-Encoding' => 'gzip, deflate',
+ ],
];
if (!is_null($this->proxy)) {
diff --git a/lib/Controller/PageController.php b/lib/Controller/PageController.php
index abdd3f2f7..41d0e7f89 100644
--- a/lib/Controller/PageController.php
+++ b/lib/Controller/PageController.php
@@ -96,6 +96,7 @@ class PageController extends Controller
$csp->addAllowedImageDomain('*')
->addAllowedMediaDomain('*')
->addAllowedConnectDomain('*')// chrome breaks on audio elements
+ ->allowEvalScript(true)
->addAllowedFrameDomain('https://youtube.com')
->addAllowedFrameDomain('https://www.youtube.com')
->addAllowedFrameDomain('https://player.vimeo.com')
diff --git a/lib/Db/Feed.php b/lib/Db/Feed.php
index 3c371087b..d949ea5f5 100644
--- a/lib/Db/Feed.php
+++ b/lib/Db/Feed.php
@@ -326,13 +326,16 @@ class Feed extends Entity implements IAPI, \JsonSerializable
'basicAuthPassword'
]);
+ if (is_null($this->link)) {
+ return $serialized;
+ }
+
$url = parse_url($this->link, PHP_URL_HOST);
// strip leading www. to avoid css class confusion
if (strpos($url, 'www.') === 0) {
$url = substr($url, 4);
}
-
$serialized['cssClass'] = 'custom-' . str_replace('.', '-', $url);
return $serialized;
@@ -488,6 +491,9 @@ class Feed extends Entity implements IAPI, \JsonSerializable
*/
public function setLink(?string $link = null): Feed
{
+ if (is_null($link)) {
+ return $this;
+ }
$link = trim($link);
if (strpos($link, 'http') === 0 && $this->link !== $link) {
$this->link = $link;
diff --git a/lib/Db/ItemMapperV2.php b/lib/Db/ItemMapperV2.php
index 704a8214d..972295ee3 100644
--- a/lib/Db/ItemMapperV2.php
+++ b/lib/Db/ItemMapperV2.php
@@ -285,12 +285,15 @@ class ItemMapperV2 extends NewsMapperV2
return intval($value['id']);
}, $this->db->executeQuery($idBuilder->getSQL(), $idBuilder->getParameters())->fetchAll());
+ $time = new Time();
$builder = $this->db->getQueryBuilder();
$builder->update(self::TABLE_NAME)
->set('unread', $builder->createParameter('unread'))
+ ->set('last_modified', $builder->createParameter('last_modified'))
->andWhere('id IN (:idList)')
->setParameter('idList', $idList, IQueryBuilder::PARAM_INT_ARRAY)
- ->setParameter('unread', false, IQueryBuilder::PARAM_BOOL);
+ ->setParameter('unread', false, IQueryBuilder::PARAM_BOOL)
+ ->setParameter('last_modified', $time->getMicroTime(), IQueryBuilder::PARAM_STR);
return $this->db->executeStatement(
$builder->getSQL(),
@@ -311,7 +314,7 @@ class ItemMapperV2 extends NewsMapperV2
{
$builder = $this->db->getQueryBuilder();
- $builder->select('items.*')
+ $builder->select('items.id')
->from($this->tableName, 'items')
->innerJoin('items', FeedMapperV2::TABLE_NAME, 'feeds', 'items.feed_id = feeds.id')
->where('feeds.user_id = :userId')
diff --git a/lib/Fetcher/FeedFetcher.php b/lib/Fetcher/FeedFetcher.php
index 86e0edd18..60d798889 100755
--- a/lib/Fetcher/FeedFetcher.php
+++ b/lib/Fetcher/FeedFetcher.php
@@ -31,6 +31,7 @@ use OCA\News\Db\Item;
use OCA\News\Db\Feed;
use OCA\News\Utility\Time;
use OCA\News\Scraper\Scraper;
+use OCA\News\Config\FetcherConfig;
use Psr\Log\LoggerInterface;
use SimpleXMLElement;
@@ -113,15 +114,21 @@ class FeedFetcher implements IFeedFetcher
string $url,
bool $fullTextEnabled,
?string $user,
- ?string $password
+ ?string $password,
+ ?string $httpLastModified
): array {
$url2 = new Net_URL2($url);
if (!is_null($user) && trim($user) !== '') {
$url2->setUserinfo(rawurlencode($user), rawurlencode($password));
}
+ if (!is_null($httpLastModified) && trim($httpLastModified) !== '') {
+ $lastModified = new DateTime($httpLastModified);
+ } else {
+ $lastModified = null;
+ }
$url = $url2->getNormalizedURL();
$this->reader->resetFilters();
- $resource = $this->reader->read($url);
+ $resource = $this->reader->read($url, null, $lastModified);
$location = $resource->getUrl();
$parsedFeed = $resource->getFeed();
@@ -301,22 +308,24 @@ class FeedFetcher implements IFeedFetcher
}
// purification is done in the service layer
- $body = mb_convert_encoding(
- $body,
- 'HTML-ENTITIES',
- mb_detect_encoding($body)
- );
- if (strpos($body, 'CDATA') !== false) {
- libxml_use_internal_errors(true);
- $data = simplexml_load_string(
- "<?xml version=\"1.0\"?><item>$body</item>",
- SimpleXMLElement::class,
- LIBXML_NOCDATA
+ if (!is_null($body)) {
+ $body = mb_convert_encoding(
+ $body,
+ 'HTML-ENTITIES',
+ mb_detect_encoding($body)
);
- if ($data !== false && libxml_get_last_error() === false) {
- $body = (string) $data;
+ if (strpos($body, 'CDATA') !== false) {
+ libxml_use_internal_errors(true);
+ $data = simplexml_load_string(
+ "<?xml version=\"1.0\"?><item>$body</item>",
+ SimpleXMLElement::class,
+ LIBXML_NOCDATA
+ );
+ if ($data !== false && libxml_get_last_error() === false) {
+ $body = (string) $data;
+ }
+ libxml_clear_errors();
}
- libxml_clear_errors();
}
$item->setBody($body);
@@ -350,9 +359,9 @@ class FeedFetcher implements IFeedFetcher
* @param FeedInterface $feed Feed to check for a logo
* @param string $url Original URL for the feed
*
- * @return string|mixed|bool
+ * @return string|null
*/
- protected function getFavicon(FeedInterface $feed, string $url)
+ protected function getFavicon(FeedInterface $feed, string $url): ?string
{
$favicon = null;
// trim the string because authors do funny things
@@ -362,15 +371,21 @@ class FeedFetcher implements IFeedFetcher
$favicon = trim($feed_logo);
}
- ini_set('user_agent', 'NextCloud-News/1.0');
+ ini_set('user_agent', FetcherConfig::DEFAULT_USER_AGENT);
$base_url = new Net_URL2($url);
$base_url->setPath("");
$base_url = $base_url->getNormalizedURL();
+ // Return if the URL is empty
+ if ($base_url === null || trim($base_url) === '') {
+ return null;
+ }
+
// check if feed has a logo entry
- if (is_null($favicon) || $favicon === '') {
- return $this->faviconFactory->get($base_url);
+ if ($favicon === null || $favicon === '') {
+ $return = $this->faviconFactory->get($base_url);
+ return is_string($return) ? $return : null;
}
// logo will be saved in the tmp folder provided by Nextcloud, file is named as md5 of the url
@@ -392,7 +407,7 @@ class FeedFetcher implements IFeedFetcher
[
'sink' => $favicon_path,
'headers' => [
- 'User-Agent' => 'NextCloud-News/1.0',
+ 'User-Agent' => FetcherConfig::DEFAULT_USER_AGENT,
'Accept' => 'image/*',
'If-Modified-Since' => date(DateTime::RFC7231, $last_modified)
]
@@ -422,16 +437,18 @@ class FeedFetcher implements IFeedFetcher
// check if file is actually an image
if (!$is_image) {
- return $this->faviconFactory->get($base_url);
+ $return = $this->faviconFactory->get($base_url);
+ return is_string($return) ? $return : null;
}
list($width, $height, $type, $attr) = getimagesize($favicon_path);
// check if image is square else fall back to favicon
if ($width !== $height) {
- return $this->faviconFactory->get($base_url);
+ $return = $this->faviconFactory->get($base_url);
+ return is_string($return) ? $return : null;
}
- return $favicon;
+ return is_string($favicon) ? $favicon : null;
}
/**
diff --git a/lib/Fetcher/Fetcher.php b/lib/Fetcher/Fetcher.php
index 8c755bc85..7d4690a6e 100644
--- a/lib/Fetcher/Fetcher.php
+++ b/lib/Fetcher/Fetcher.php
@@ -47,6 +47,7 @@ class Fetcher
* @param bool $fullTextEnabled If true use a scraper to download the full article
* @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
+ * @param string|null $httpLastModified if given, will be used when sending a request to servers
*
* @throws ReadErrorException if FeedIO fails
* @return array an array containing the new feed and its items, first
@@ -56,7 +57,8 @@ class Fetcher
string $url,
bool $fullTextEnabled = false,
?string $user = null,
- ?string $password = null
+ ?string $password = null,
+ ?string $httpLastModified = null
): array {
foreach ($this->fetchers as $fetcher) {
if (!$fetcher->canHandle($url)) {
@@ -66,7 +68,8 @@ class Fetcher
$url,
$fullTextEnabled,
$user,
- $password
+ $password,
+ $httpLastModified
);
}
diff --git a/lib/Fetcher/IFeedFetcher.php b/lib/Fetcher/IFeedFetcher.php
index 45e0915f0..7f2bbe31c 100644
--- a/lib/Fetcher/IFeedFetcher.php
+++ b/lib/Fetcher/IFeedFetcher.php
@@ -27,6 +27,7 @@ interface IFeedFetcher
* @param bool $fullTextEnabled If true use a scraper to download the full article
* @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
+ * @param string|null $httpLastModified if given, will be used when sending a request to servers
*
* @return array<Feed, Item[]> an array containing the new feed and its items, first
* element being the Feed and second element being an array of Items
@@ -37,7 +38,8 @@ interface IFeedFetcher
string $url,
bool $fullTextEnabled,
?string $user,
- ?string $password
+ ?string $password,
+ ?string $httpLastModified
): array;
/**
diff --git a/lib/Migration/RemoveUnusedJob.php b/lib/Migration/RemoveUnusedJob.php
new file mode 100644
index 000000000..cb5c5fecc
--- /dev/null
+++ b/lib/Migration/RemoveUnusedJob.php
@@ -0,0 +1,50 @@
+<?php
+namespace OCA\News\Migration;
+
+use OCP\Migration\IOutput;
+use OCP\Migration\IRepairStep;
+use Psr\Log\LoggerInterface;
+use OCP\BackgroundJob\IJobList;
+
+class RemoveUnusedJob implements IRepairStep
+{
+
+ /**
+ * @var LoggerInterface
+ */
+ protected $logger;
+
+ /**
+ * @var IJobList
+ */
+ protected $joblist;
+
+ public function __construct(LoggerInterface $logger, IJobList $jobList)
+ {
+
+ $this->logger = $logger;
+ $this->joblist = $jobList;
+ }
+
+ /**
+ * Returns the step's name
+ */
+ public function getName()
+ {
+ return 'Remove the unused News update job';
+ }
+
+ /**
+ * @param IOutput $output
+ */
+ public function run(IOutput $output)
+ {
+ if ($this->joblist->has("OCA\News\Cron\Updater", null)) {
+ $output->info("Job exists, attempting to remove");
+ $this->joblist->remove("OCA\News\Cron\Updater");
+ $output->info("Job removed");
+ } else {
+ $output->info("Job does not exist, all good");
+ }
+ }
+}
diff --git a/lib/Scraper/Scraper.php b/lib/Scraper/Scraper.php
index 5deac358e..998c4464c 100644
--- a/lib/Scraper/Scraper.php
+++ b/lib/Scraper/Scraper.php
@@ -14,6 +14,7 @@ namespace OCA\News\Scraper;
use fivefilters\Readability\Readability;
use fivefilters\Readability\Configuration;
use fivefilters\Readability\ParseException;
+use League\Uri\Exceptions\SyntaxError;
use Psr\Log\LoggerInterface;
class Scraper implements IScraper
@@ -74,10 +75,14 @@ class Scraper implements IScraper
try {
$this->readability->parse($content);
- } catch (ParseException $e) {
+ } catch (ParseException | SyntaxError $e) {
$this->logger->error('Unable to parse content from {url}', [
'url' => $url,
]);
+ $this->logger->debug('Error during parsing of {url} ran into {error}', [
+ 'url' => $url,
+ 'error' => $e,
+ ]);
}
return true;
}
diff --git a/lib/Search/FeedSearchProvider.php b/lib/Search/FeedSearchProvider.php
index bbcd466e4..36b21eaba 100644
--- a/lib/Search/FeedSearchProvider.php
+++ b/lib/Search/FeedSearchProvider.php
@@ -4,7 +4,7 @@ declare(strict_types=1);
namespace OCA\News\Search;
use OCA\News\Service\FeedServiceV2;
-use OCA\News\Service\FolderServiceV2;
+use OCA\News\AppInfo\Application;
use OCP\IL10N;
use OCP\IURLGenerator;
use OCP\IUser;
@@ -48,7 +48,7 @@ class FeedSearchProvider implements IProvider
public function getOrder(string $route, array $routeParameters): int
{
- if ($route === 'news.page.index') {
+ if (strpos($route, Application::NAME . '.') === 0) {
// Active app, prefer my results
return -1;
}
@@ -67,7 +67,7 @@ class FeedSearchProvider implements IProvider
}
$list[] = new SearchResultEntry(
- $this->urlGenerator->imagePath('core', 'filetypes/text.svg'),
+ $this->urlGenerator->imagePath('core', 'rss.svg'),
$feed->getTitle(),
$this->l10n->t('Unread articles') . ': ' . $feed->getUnreadCount(),
$this->urlGenerator->linkToRoute('news.page.index') . '#/items/feeds/' . $feed->getId()
diff --git a/lib/Search/FolderSearchProvider.php b/lib/Search/FolderSearchProvider.php
index 24439d73d..7f6783c68 100644
--- a/lib/Search/FolderSearchProvider.php
+++ b/lib/Search/FolderSearchProvider.php
@@ -49,9 +49,9 @@ class FolderSearchProvider implements IProvider
public function getOrder(string $route, array $routeParameters): int
{
- if ($route === 'news.page.index') {
+ if (strpos($route, Application::NAME . '.') === 0) {
// Active app, prefer my results
- return -1;
+ return 0;
}
return 55;
diff --git a/lib/Search/ItemSearchProvider.php b/lib/Search/ItemSearchProvider.php
new file mode 100644
index 000000000..29b4bf209
--- /dev/null
+++ b/lib/Search/ItemSearchProvider.php
@@ -0,0 +1,109 @@
+<?php
+declare(strict_types=1);
+
+namespace OCA\News\Search;
+
+use OCA\News\Service\ItemServiceV2;
+use OCA\News\AppInfo\Application;
+use OCA\News\Db\ListType;
+use OCP\IL10N;
+use OCP\IURLGenerator;
+use OCP\IUser;
+use OCP\Search\IProvider;
+use OCP\Search\ISearchQuery;
+use OCP\Search\SearchResult;
+use OCP\Search\SearchResultEntry;
+
+/**
+ * Class ItemSearchProvider
+ *
+ * @package OCA\News\Search
+ */
+class ItemSearchProvider implements IProvider
+{
+ /** @var IL10N */
+ private $l10n;
+
+ /** @var IURLGenerator */
+ private $urlGenerator;
+
+ /** @var ItemServiceV2 */
+ private $service;
+
+ public function __construct(IL10N $l10n, IURLGenerator $urlGenerator, ItemServiceV2 $service)
+ {
+ $this->l10n = $l10n;
+ $this->urlGenerator = $urlGenerator;
+ $this->service = $service;
+ }
+
+ public function getId(): string
+ {
+ return 'news_item';
+ }
+
+ public function getName(): string
+ {
+ return $this->l10n->t('News articles');
+ }
+
+ public function getOrder(string $route, array $routeParameters): int
+ {
+ if (strpos($route, Application::NAME . '.') === 0) {
+ // Active app, prefer my results
+ return 1;
+ }
+
+ return 65;
+ }
+
+ private function stripTruncate(string $string, int $length = 50): string
+ {
+ $string = strip_tags(trim($string));
+
+ if (strlen($string) > $length) {
+ $string = wordwrap($string, $length);
+ $string = explode("\n", $string, 2);
+ $string = $string[0];
+ }
+
+ return $string;
+ }
+
+ public function search(IUser $user, ISearchQuery $query): SearchResult
+ {
+ $list = [];
+ $offset = (int) ($query->getCursor() ?? 0);
+ $limit = $query->getLimit();
+
+ $search_result = $this->service->findAllWithFilters(
+ $user->getUID(),
+ ListType::ALL_ITEMS,
+ $limit,
+ $offset,
+ false,
+ [$query->getTerm()]
+ );
+
+ $last = end($search_result);
+ if ($last === false) {
+ return SearchResult::complete(
+ $this->l10n->t('News'),
+ []
+ );
+ }
+
+ $icon = $this->urlGenerator->imagePath('core', 'filetypes/text.svg');
+
+ foreach ($search_result as $item) {
+ $list[] = new SearchResultEntry(
+ $icon,
+ $item->getTitle(),
+ $this->stripTruncate($item->getBody(), 50),
+ $this->urlGenerator->linkToRoute('news.page.index') . '#/items/feeds/' . $item->getFeedId()
+ );
+ }
+
+ return SearchResult::paginated($this->l10n->t('News'), $list, $last->getId());
+ }
+}
diff --git a/lib/Service/FeedServiceV2.php b/lib/Service/FeedServiceV2.php
index 3e02b3971..16ca9a60a 100644
--- a/lib/Service/FeedServiceV2.php
+++ b/lib/Service/FeedServiceV2.php
@@ -13,6 +13,7 @@
namespace OCA\News\Service;
+use DateTime;
use FeedIo\Explorer;
use FeedIo\Reader\ReadErrorException;
use HTMLPurifier;
@@ -37,6 +38,7 @@ class FeedServiceV2 extends Service
{
/**
* Class to fetch feeds.
+ *
* @var FeedFetcher
*/
protected $feedFetcher;
@@ -48,11 +50,13 @@ class FeedServiceV2 extends Service
protected $itemService;
/**
* HTML Purifier
+ *
* @var HTMLPurifier
*/
protected $purifier;
/**
* Feed Explorer
+ *
* @var Explorer
*/
protected $explorer;
@@ -109,7 +113,7 @@ class FeedServiceV2 extends Service
/**
* Finds all feeds of a user and all items in it
*
- * @param string $userId the name of the user
+ * @param string $userId the name of the user
*
* @return Feed[]
*/
@@ -169,13 +173,14 @@ class FeedServiceV2 extends Service
/**
* Creates a new feed
*
- * @param string $userId Feed owner
- * @param string $feedUrl Feed URL
- * @param int|null $folderId Target folder, defaults to root
- * @param bool $full_text Scrape the feed for full text
- * @param string|null $title The feed title
- * @param string|null $user Basic auth username, if set
- * @param string|null $password Basic auth password if username is set
+ * @param string $userId Feed owner
+ * @param string $feedUrl Feed URL
+ * @param int|null $folderId Target folder, defaults to root
+ * @param bool $full_text Scrape the feed for full text
+ * @param string|null $title The feed title
+ * @param string|null $user Basic auth username, if set
+ * @param string|null $password Basic auth password if username is set
+ * @param string|null $httpLastModified timestamp send when fetching the feed
*
* @return Feed|Entity
*
@@ -190,14 +195,16 @@ class FeedServiceV2 extends Service
?string $title = null,
?string $user = null,
?string $password = null,
- bool $full_discover = true
+ bool $full_discover = true,
+ ?string $httpLastModified = null
): Entity {
+ $httpLastModified ??= (new DateTime("-1 year"))->format(DateTime::RSS);
try {
/**
* @var Feed $feed
* @var Item[] $items
*/
- list($feed, $items) = $this->feedFetcher->fetch($feedUrl, $full_text, $user, $password);
+ list($feed, $items) = $this->feedFetcher->fetch($feedUrl, $full_text, $user, $password, $httpLastModified);
} catch (ReadErrorException $ex) {
$this->logger->debug($ex->getMessage());
if ($full_discover === false) {
@@ -209,7 +216,13 @@ class FeedServiceV2 extends Service
$feedUrl = array_shift($feeds);
}
try {
- list($feed, $items) = $this->feedFetcher->fetch($feedUrl, $full_text, $user, $password);
+ list($feed, $items) = $this->feedFetcher->fetch(
+ $feedUrl,
+ $full_text,
+ $user,
+ $password,
+ $httpLastModified
+ );
} catch (ReadErrorException $ex) {
throw new ServiceNotFoundException($ex->getMessage());
}
@@ -234,7 +247,7 @@ class FeedServiceV2 extends Service
if (!is_null($user)) {
$feed->setBasicAuthUser($user)
- ->setBasicAuthPassword($password);
+ ->setBasicAuthPassword($password);
}
return $this->mapper->insert($feed);
@@ -267,7 +280,8 @@ class FeedServiceV2 extends Service
$location,
$feed->getFullTextEnabled(),
$feed->getBasicAuthUser(),
- $feed->getBasicAuthPassword()
+ $feed->getBasicAuthPassword(),
+ $feed->getHttpLastModified()
);
} catch (ReadErrorException $ex) {
$feed->setUpdateErrorCount($feed->getUpdateErrorCount() + 1);
@@ -294,11 +308,11 @@ class FeedServiceV2 extends Service
}
$feed->setHttpLastModified($fetchedFeed->getHttpLastModified())
- ->setLocation($fetchedFeed->getLocation());
+ ->setLocation($fetchedFeed->getLocation());
foreach (array_reverse($items) as &$item) {
$item->setFeedId($feed->getId())
- ->setBody($this->purifier->purify($item->getBody()));
+ ->setBody($this->purifier->purify($item->getBody()));
// update modes: 0 nothing, 1 set unread
if ($feed->getUpdateMode() === Feed::UPDATE_MODE_NORMAL) {
@@ -314,11 +328,14 @@ class FeedServiceV2 extends Service
$feed->setLastUpdateError(null);
$unreadCount = 0;
- array_map(function (Item $item) use (&$unreadCount): void {
- if ($item->isUnread()) {
- $unreadCount++;
- }
- }, $items);
+ array_map(
+ function (Item $item) use (&$unreadCount): void {
+ if ($item->isUnread()) {
+ $unreadCount++;
+ }
+ },
+ $items
+ );
return $this->mapper->update($feed)->setUnreadCount($unreadCount);
}
diff --git a/lib/Service/StatusService.php b/lib/Service/StatusService.php
index a15f30c76..69a621e3c 100644
--- a/lib/Service/StatusService.php
+++ b/lib/Service/StatusService.php
@@ -16,6 +16,9 @@ namespace OCA\News\Service;
use OCA\News\AppInfo\Application;
use OCP\IConfig;
use OCP\IDBConnection;
+use OCP\BackgroundJob\IJobList;
+use OCP\Util;
+use OCA\News\Cron\UpdaterJob;
class StatusService
{
@@ -25,14 +28,18 @@ class StatusService
private $appName;
/** @var IDBConnection */
private $connection;
+ /** @var IJobList */
+ private $jobList;
public function __construct(
IConfig $settings,
- IDBConnection $connection
+ IDBConnection $connection,
+ IJobList $jobList
) {
$this->settings = $settings;
$this->connection = $connection;
$this->appName = Application::NAME;
+ $this->jobList = $jobList;
}
/**
@@ -76,4 +83,22 @@ class StatusService
]
];
}
+
+ /**
+ * Get last update time
+ */
+ public function getUpdateTime(): int
+ {
+
+ $time = 0;
+
+ [$major, $minor, $micro] = Util::getVersion();
+
+ if ($major >= 26) {
+ $myJobList = $this->jobList->getJobsIterator(UpdaterJob::class, 1, 0);
+ $time = $myJobList->current()->getLastRun();
+ }
+
+ return $time;
+ }
}
diff --git a/lib/Settings/AdminSettings.php b/lib/Settings/AdminSettings.php
index c29b5d46c..5e4e83920 100644
--- a/lib/Settings/AdminSettings.php
+++ b/lib/Settings/AdminSettings.php
@@ -3,6 +3,7 @@
namespace OCA\News\Settings;
use OCA\News\AppInfo\Application;
+use OCA\News\Service\StatusService;
use OCP\AppFramework\Http\TemplateResponse;
use OCP\IConfig;
use OCP\Settings\ISettings;
@@ -17,11 +18,14 @@ class AdminSettings implements ISettings
private $config;
/** @var IInitialState */
private $initialState;
+ /** @var StatusService */
+ private $service;
- public function __construct(IConfig $config, IInitialState $initialState)
+ public function __construct(IConfig $config, IInitialState $initialState, StatusService $service)
{
$this->config = $config;
$this->initialState = $initialState;
+ $this->service = $service;
}
public function getForm()
@@ -33,6 +37,14 @@ class AdminSettings implements ISettings
(string)Application::DEFAULT_SETTINGS[$setting]
));
}
+
+ if ($this->service->isCronProperlyConfigured()) {
+ $lastUpdate = $this->service->getUpdateTime();
+ } else {
+ $lastUpdate = 0;
+ }
+
+ $this->initialState->provideInitialState("lastCron", $lastUpdate);
return new TemplateResponse(Application::NAME, 'admin', []);
}