summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSean Molenaar <sean@seanmolenaar.eu>2021-01-19 12:30:48 +0100
committerSean Molenaar <SMillerDev@users.noreply.github.com>2021-01-30 18:27:06 +0100
commit023c61b88f3bfdc3829606a17fa3bf9deac600fc (patch)
treee17552831645e05366089ef1f3373a03415c8b6d
parent191860fc7210b51032f3026491ed745508209936 (diff)
Mappers: Implement item purging
Signed-off-by: Sean Molenaar <sean@seanmolenaar.eu>
-rw-r--r--CHANGELOG.md1
-rw-r--r--lib/Command/Updater/AfterUpdate.php19
-rw-r--r--lib/Db/ItemMapperV2.php57
-rw-r--r--lib/Service/ItemServiceV2.php21
-rw-r--r--tests/Unit/Command/AfterUpdateTest.php68
5 files changed, 141 insertions, 25 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 1c24f8f1a..2b25b3751 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -12,6 +12,7 @@ The format is almost based on [Keep a Changelog](https://keepachangelog.com/en/1
### Fixed
- Fetch feed after creation (#1058)
+- Implement missing item purger (#1063)
- Update FeedIO Response call and add tests
- Improve Psalm tests and dependency definition
diff --git a/lib/Command/Updater/AfterUpdate.php b/lib/Command/Updater/AfterUpdate.php
index bedc8c9ff..f9e5671f0 100644
--- a/lib/Command/Updater/AfterUpdate.php
+++ b/lib/Command/Updater/AfterUpdate.php
@@ -15,6 +15,7 @@ use OCA\News\Service\ItemServiceV2;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
class AfterUpdate extends Command
@@ -42,14 +43,26 @@ class AfterUpdate extends Command
{
$this->setName('news:updater:after-update')
->setDescription('removes old read articles which are not starred')
- ->addArgument('purge_count', InputArgument::OPTIONAL, 'The amount of items to purge');
+ ->addArgument('purge-count', InputArgument::OPTIONAL, 'The amount of items to purge')
+ ->addOption('purge-unread', null, InputOption::VALUE_NONE, 'If unread items should be purged');
}
protected function execute(InputInterface $input, OutputInterface $output): int
{
- $count = (int) $input->getArgument('purge_count');
+ $count = $input->getArgument('purge-count');
+ $removeUnread = $input->getOption('purge-unread');
- $output->writeln($this->itemService->purgeOverThreshold($count));
+ if ($count !== null) {
+ $count = intval($count);
+ }
+
+ $result = $this->itemService->purgeOverThreshold($count, $removeUnread);
+ if ($result === null) {
+ $output->writeln('No cleanup needed', $output::VERBOSITY_VERBOSE);
+ return 0;
+ }
+
+ $output->writeln('Removed ' . $result . ' item(s)', $output::VERBOSITY_VERBOSE);
return 0;
}
diff --git a/lib/Db/ItemMapperV2.php b/lib/Db/ItemMapperV2.php
index 0c3191540..256621815 100644
--- a/lib/Db/ItemMapperV2.php
+++ b/lib/Db/ItemMapperV2.php
@@ -12,6 +12,7 @@
namespace OCA\News\Db;
+use Doctrine\DBAL\FetchMode;
use OCA\News\Utility\Time;
use OCP\AppFramework\Db\DoesNotExistException;
use OCP\AppFramework\Db\Entity;
@@ -138,20 +139,58 @@ class ItemMapperV2 extends NewsMapperV2
/**
* Delete items from feed that are over the max item threshold
*
- * TODO: Implement
+ * @param int $threshold Deletion threshold
+ * @param bool $removeUnread If unread articles should be removed
*
- * @param int $threshold Deletion threshold
+ * @return int|null Removed items
+ *
+ * @throws \Doctrine\DBAL\Exception|\OCP\DB\Exception
*/
- public function deleteOverThreshold(int $threshold)
+ public function deleteOverThreshold(int $threshold, bool $removeUnread = false): ?int
{
- $builder = $this->db->getQueryBuilder();
+ $feedQb = $this->db->getQueryBuilder();
+ $feedQb->addSelect('feed_id', $feedQb->func()->count('*', 'itemCount'), 'feeds.articles_per_update')
+ ->from($this->tableName, 'items')
+ ->innerJoin('items', FeedMapperV2::TABLE_NAME, 'feeds', 'items.feed_id = feeds.id')
+ ->groupBy('feed_id');
+
+ $feeds = $this->db->executeQuery($feedQb->getSQL())
+ ->fetchAll(FetchMode::ASSOCIATIVE);
+
+ if ($feeds === []) {
+ return null;
+ }
+
+ $rangeQuery = $this->db->getQueryBuilder();
+ $rangeQuery->select('id')
+ ->from($this->tableName)
+ ->where('feed_id = :feedId')
+ ->andWhere('starred = 0')
+ ->orderBy('updated_date', 'DESC');
+
+ if ($removeUnread === false) {
+ $rangeQuery->andWhere('unread = 0');
+ }
+
+ $total_items = [];
+ foreach ($feeds as $feed) {
+ if ($feed['itemCount'] < $threshold) {
+ continue;
+ }
+
+ $rangeQuery->setFirstResult(max($threshold, $feed['articles_per_update']));
+
+ $items = $this->db->executeQuery($rangeQuery->getSQL(), ['feedId' => $feed['feed_id']])
+ ->fetchAll(FetchMode::COLUMN);
+
+ $total_items = array_merge($total_items, $items);
+ }
- $query = $builder->addSelect('COUNT(*)')
- ->from($this->tableName)
- ->groupBy('feed_id')
- ->where('');
+ $deleteQb = $this->db->getQueryBuilder();
+ $deleteQb->delete($this->tableName)
+ ->where('id IN (?)');
- return $this->db->executeQuery($query->getSQL());
+ return $this->db->executeUpdate($deleteQb->getSQL(), [$total_items], [IQueryBuilder::PARAM_INT_ARRAY]);
}
/**
diff --git a/lib/Service/ItemServiceV2.php b/lib/Service/ItemServiceV2.php
index 54cefa197..f13b249b8 100644
--- a/lib/Service/ItemServiceV2.php
+++ b/lib/Service/ItemServiceV2.php
@@ -113,22 +113,25 @@ class ItemServiceV2 extends Service
return $this->mapper->findAllForFeed($feedId);
}
-
-
- public function purgeOverThreshold(int $threshold = null)
+ /**
+ * @param int|null $threshold
+ * @param bool $removeUnread
+ *
+ * @return int|null Amount of deleted items or null if not applicable
+ */
+ public function purgeOverThreshold(int $threshold = null, bool $removeUnread = false): ?int
{
-
- $threshold = (int) $threshold ?? $this->config->getAppValue(
+ $threshold = (int) ($threshold ?? $this->config->getAppValue(
Application::NAME,
'autoPurgeCount',
Application::DEFAULT_SETTINGS['autoPurgeCount']
- );
+ ));
- if ($threshold === 0) {
- return '';
+ if ($threshold <= 0) {
+ return null;
}
- return $this->mapper->deleteOverThreshold($threshold);
+ return $this->mapper->deleteOverThreshold($threshold, $removeUnread);
}
/**
diff --git a/tests/Unit/Command/AfterUpdateTest.php b/tests/Unit/Command/AfterUpdateTest.php
index fbc327ecc..81fd175cf 100644
--- a/tests/Unit/Command/AfterUpdateTest.php
+++ b/tests/Unit/Command/AfterUpdateTest.php
@@ -62,17 +62,77 @@ class AfterUpdateTest extends TestCase
{
$this->consoleInput->expects($this->once())
->method('getArgument')
- ->with('purge_count')
+ ->with('purge-count')
->willReturn('1');
+ $this->consoleInput->expects($this->once())
+ ->method('getOption')
+ ->with('purge-unread')
+ ->willReturn(false);
+
+ $this->service->expects($this->exactly(1))
+ ->method('purgeOverThreshold')
+ ->with('1', false)
+ ->willReturn(1);
+
+ $this->consoleOutput->expects($this->exactly(1))
+ ->method('writeln')
+ ->with('Removed 1 item(s)');
+
+ $result = $this->command->run($this->consoleInput, $this->consoleOutput);
+ $this->assertSame(0, $result);
+ }
+
+ /**
+ * Test a valid call will work
+ */
+ public function testValidEmpty()
+ {
+ $this->consoleInput->expects($this->once())
+ ->method('getArgument')
+ ->with('purge-count')
+ ->willReturn('1');
+ $this->consoleInput->expects($this->once())
+ ->method('getOption')
+ ->with('purge-unread')
+ ->willReturn(false);
+
+
+ $this->service->expects($this->exactly(1))
+ ->method('purgeOverThreshold')
+ ->with('1', false)
+ ->willReturn(null);
+
+ $this->consoleOutput->expects($this->exactly(1))
+ ->method('writeln')
+ ->with('No cleanup needed');
+
+ $result = $this->command->run($this->consoleInput, $this->consoleOutput);
+ $this->assertSame(0, $result);
+ }
+
+ /**
+ * Test a valid call will work
+ */
+ public function testValidEmptyUnread()
+ {
+ $this->consoleInput->expects($this->once())
+ ->method('getArgument')
+ ->with('purge-count')
+ ->willReturn('1');
+ $this->consoleInput->expects($this->once())
+ ->method('getOption')
+ ->with('purge-unread')
+ ->willReturn(true);
+
$this->service->expects($this->exactly(1))
->method('purgeOverThreshold')
- ->with('1')
- ->willReturn('test');
+ ->with('1', true)
+ ->willReturn(null);
$this->consoleOutput->expects($this->exactly(1))
->method('writeln')
- ->with('test');
+ ->with('No cleanup needed');
$result = $this->command->run($this->consoleInput, $this->consoleOutput);
$this->assertSame(0, $result);