diff --git a/lib/Database.php b/lib/Database.php index eaa6b3b..bc2b5aa 100644 --- a/lib/Database.php +++ b/lib/Database.php @@ -566,7 +566,7 @@ class Database { coalesce(feeds,0) as feeds from arsse_folders left join (select parent,count(id) as children from arsse_folders group by parent) as child_stats on child_stats.parent = arsse_folders.id - left join (select folder,count(id) as feeds from arsse_subscriptions group by folder) as sub_stats on sub_stats.folder = arsse_folders.id", + left join (select folder,count(id) as feeds from arsse_subscriptions where deleted = 0 group by folder) as sub_stats on sub_stats.folder = arsse_folders.id", ["str", "strict int"], [$user, $parent] ); @@ -1139,7 +1139,7 @@ class Database { return V::normalize($out, V::T_DATE | V::M_NULL, "sql"); } - /** Evalutes the filter rules specified for a subscription against every article associated with the subscription's feed + /** Evalutes the filter rules specified for a subscription against every article associated with the subscription * * @param string $user The user who owns the subscription * @param integer $id The identifier of the subscription whose rules are to be evaluated @@ -1458,7 +1458,7 @@ class Database { * @param string $user The user whose subscription icons are to be retrieved */ public function iconList(string $user): Db\Result { - return $this->db->prepare("SELECT distinct i.id, i.url, i.type, i.data from arsse_icons as i join arsse_subscriptions as s on s.icon = i.id where s.owner = ?", "str")->run($user); + return $this->db->prepare("SELECT distinct i.id, i.url, i.type, i.data from arsse_icons as i join arsse_subscriptions as s on s.icon = i.id where s.owner = ? and s.deleted = 0", "str")->run($user); } /** Deletes orphaned icons from the database @@ -1571,7 +1571,7 @@ class Database { select $outColumns from arsse_articles - join arsse_subscriptions on arsse_subscriptions.id = arsse_articles.subscription and arsse_subscriptions.owner = ? and deleted = 0 + join arsse_subscriptions on arsse_subscriptions.id = arsse_articles.subscription and arsse_subscriptions.owner = ? and arsse_subscriptions.deleted = 0 left join arsse_article_contents on arsse_article_contents.id = arsse_articles.id left join folder_data on arsse_subscriptions.folder = folder_data.id left join arsse_enclosures on arsse_enclosures.article = arsse_articles.id @@ -1884,10 +1884,10 @@ class Database { * * @param string $user The user who owns the articles to be modified * @param array $data An associative array of properties to modify. Anything not specified will remain unchanged - * @param Context|UnionContext $context The query context to match articles against + * @param Context $context The query context to match articles against * @param bool $updateTimestamp Whether to also update the timestamp. This should only be false if a mark is changed as a result of an automated action not taken by the user */ - public function articleMark(string $user, array $data, RootContext $context = null, bool $updateTimestamp = true): int { + public function articleMark(string $user, array $data, Context $context = null, bool $updateTimestamp = true): int { $data = [ 'read' => $data['read'] ?? null, 'starred' => $data['starred'] ?? null, @@ -2011,7 +2011,7 @@ class Database { coalesce(sum(abs(\"read\" - 1)),0) as unread, coalesce(sum(\"read\"),0) as \"read\" FROM ( - select \"read\" from arsse_articles where starred = 1 and hidden <> 1 and subscription in (select id from arsse_subscriptions where owner = ?) + select \"read\" from arsse_articles where starred = 1 and hidden <> 1 and subscription in (select id from arsse_subscriptions where owner = ? and deleted = 0) ) as starred_data", "str" )->run($user)->getRow(); @@ -2148,7 +2148,7 @@ class Database { join arsse_articles on arsse_articles.id = arsse_editions.article join arsse_subscriptions on arsse_subscriptions.id = arsse_articles.subscription join (select article, max(id) as edition from arsse_editions group by article) as edition_stats on edition_stats.article = arsse_editions.article - where arsse_editions.id = ? and arsse_subscriptions.owner = ?", + where arsse_editions.id = ? and arsse_subscriptions.owner = ? and arsse_subscriptions.deleted = 0", ["int", "str"] )->run($id, $user)->getRow(); if (!$out) { @@ -2211,7 +2211,13 @@ class Database { cast(coalesce(marked, 0) as $integerType) as \"read\" -- this cast is required for MySQL for unclear reasons from arsse_labels left join ( - SELECT label, sum(assigned) as articles from arsse_label_members group by label + SELECT + label, + sum(assigned) as articles + from arsse_label_members + join arsse_articles on arsse_articles.id = arsse_label_members.article + join arsse_subscriptions on arsse_articles.subscription = arsse_subscriptions.id and arsse_subscriptions.deleted = 0 + group by label ) as label_stats on label_stats.label = arsse_labels.id left join ( SELECT @@ -2221,7 +2227,7 @@ class Database { from arsse_articles join arsse_subscriptions on arsse_subscriptions.id = arsse_articles.subscription join arsse_label_members on arsse_label_members.article = arsse_articles.id - where arsse_subscriptions.owner = ? + where arsse_subscriptions.owner = ? and arsse_subscriptions.deleted = 0 group by label ) as mark_stats on mark_stats.label = arsse_labels.id WHERE owner = ? @@ -2275,7 +2281,13 @@ class Database { coalesce(marked, 0) as \"read\" FROM arsse_labels left join ( - SELECT label, sum(assigned) as articles from arsse_label_members group by label + SELECT + label, + sum(assigned) as articles + from arsse_label_members + join arsse_articles on arsse_articles.id = arsse_label_members.article + join arsse_subscriptions on arsse_articles.subscription = arsse_subscriptions.id and arsse_subscriptions.deleted = 0 + group by label ) as label_stats on label_stats.label = arsse_labels.id left join ( SELECT @@ -2285,7 +2297,7 @@ class Database { from arsse_articles join arsse_subscriptions on arsse_subscriptions.id = arsse_articles.subscription join arsse_label_members on arsse_label_members.article = arsse_articles.id - where arsse_subscriptions.owner = ? + where arsse_subscriptions.owner = ? and arsse_subscriptions.deleted = 0 group by label ) as mark_stats on mark_stats.label = arsse_labels.id WHERE $field = ? and owner = ?", @@ -2374,7 +2386,7 @@ class Database { if (!sizeof($articles)) { if ($mode == self::ASSOC_REPLACE) { // replacing with an empty set means setting everything to zero - return $this->db->prepare("UPDATE arsse_label_members set assigned = 0, modified = CURRENT_TIMESTAMP where label = ? and assigned = 1", "int")->run($id)->changes(); + return $this->db->prepare("UPDATE arsse_label_members set assigned = 0, modified = CURRENT_TIMESTAMP where label = ? and assigned = 1 and article not in (select id from arsse_articles where subscription in (select id from arsse_subscriptions where deleted = 1))", "int")->run($id)->changes(); } else { // adding or removing is a no-op return 0; @@ -2384,7 +2396,7 @@ class Database { } // prepare up to three queries: removing requires one, adding two, and replacing three [$inClause, $inTypes, $inValues] = $this->generateIn($articles, "int"); - $updateQ = "UPDATE arsse_label_members set assigned = ?, modified = CURRENT_TIMESTAMP where label = ? and assigned <> ? and article %in% ($inClause)"; + $updateQ = "UPDATE arsse_label_members set assigned = ?, modified = CURRENT_TIMESTAMP where label = ? and assigned <> ? and article %in% ($inClause) and article not in (select id from arsse_articles where subscription in (select id from arsse_subscriptions where deleted = 1))"; $updateT = ["bool", "int", "bool", $inTypes]; $insertQ = "INSERT INTO arsse_label_members(label,article) SELECT ?,a.id from arsse_articles as a join arsse_subscriptions as s on a.subscription = s.id where s.owner = ? and a.id not in (select article from arsse_label_members where label = ?) and a.id in ($inClause)"; $insertT = ["int", "str", "int", $inTypes]; diff --git a/tests/cases/Database/SeriesArticle.php b/tests/cases/Database/SeriesArticle.php index 1c1a8ca..5588424 100644 --- a/tests/cases/Database/SeriesArticle.php +++ b/tests/cases/Database/SeriesArticle.php @@ -129,7 +129,7 @@ trait SeriesArticle { [208,14,null, null, null, null, null, null, "", "", "", "2010-01-01 00:00:00",0,0,0,null, ''], [801,15,'http://example.com/1','Article title 1','', '2000-01-01 00:00:00','2000-01-01 00:00:01','e433653cef2e572eee4215fa299a4a5af9137b2cefd6283c85bd69a32915beda','f5cb8bfc1c7396dc9816af212a3e2ac5221585c2a00bf7ccb6aabd95dcfcd6a6','fb0bc8f8cb08913dc5a497db700e327f1d34e4987402687d494a5891f24714d4','18fdd4fa93d693128c43b004399e5c9cea6c261ddfa002518d3669f55d8c2207','2000-01-01 01:00:00',0,0,0,null, ''], [802,15,'http://example.com/2','Article title 2','', '2000-01-02 00:00:00','2000-01-02 00:00:02','5be8a5a46ecd52ed132191c8d27fb1af6b3d4edc00234c5d9f8f0e10562ed3b7','0e86d2de822a174fe3c44a466953e63ca1f1a58a19cbf475fce0855d4e3d5153','13075894189c47ffcfafd1dfe7fbb539f7c74a69d35a399b3abf8518952714f9','2abd0a8cba83b8214a66c8f0293ba63e467d720540e29ff8ddcdab069d4f1c9e','2000-01-02 02:00:00',0,0,0,null, ''], - [999,16,null, null, null, null, null, null, "", "", "", "2000-01-01 00:00:00",0,0,0,null, ''], + [999,16,null, null, null, null, null, null, "", "", "", "2000-01-01 00:00:00",0,1,0,null, ''], ], ], 'arsse_article_contents' => [ @@ -208,7 +208,6 @@ trait SeriesArticle { [ 802,802], [ 902,802], [ 999,999], - [9999,999], ], ], 'arsse_enclosures' => [ @@ -250,14 +249,15 @@ trait SeriesArticle { 'arsse_label_members' => [ 'columns' => ["label", "article", "assigned", "modified"], 'rows' => [ - [1, 1,1,'2000-01-01 00:00:00'], - [2, 1,1,'2000-01-01 00:00:00'], - [1,19,1,'2000-01-01 00:00:00'], - [2,20,1,'2000-01-01 00:00:00'], - [1, 5,0,'2000-01-01 00:00:00'], - [2, 5,1,'2000-01-01 00:00:00'], - [4, 7,0,'2000-01-01 00:00:00'], - [4, 8,1,'2015-01-01 00:00:00'], + [1, 1,1,'2000-01-01 00:00:00'], + [2, 1,1,'2000-01-01 00:00:00'], + [1, 19,1,'2000-01-01 00:00:00'], + [2, 20,1,'2000-01-01 00:00:00'], + [1, 5,0,'2000-01-01 00:00:00'], + [2, 5,1,'2000-01-01 00:00:00'], + [4, 7,0,'2000-01-01 00:00:00'], + [4, 8,1,'2015-01-01 00:00:00'], + [1,999,1,'2000-01-01 00:00:00'], ], ], ]; @@ -889,7 +889,7 @@ trait SeriesArticle { public function testMarkAnEditionOfADeletedSubscription(): void { $this->assertException("subjectMissing", "Db", "ExceptionInput"); - Arsse::$db->articleMark("john.doe@example.com", ['starred' => true], (new Context)->edition(9999)); + Arsse::$db->articleMark("john.doe@example.com", ['starred' => false], (new Context)->edition(999)); } public function testMarkByOldestEdition(): void { diff --git a/tests/cases/Database/SeriesFolder.php b/tests/cases/Database/SeriesFolder.php index 0158257..8c65c25 100644 --- a/tests/cases/Database/SeriesFolder.php +++ b/tests/cases/Database/SeriesFolder.php @@ -42,19 +42,20 @@ trait SeriesFolder { ], ], 'arsse_subscriptions' => [ - 'columns' => ["id", "owner", "url", "title", "folder"], + 'columns' => ["id", "owner", "url", "title", "folder", "deleted"], 'rows' => [ - [1, "john.doe@example.com","http://example.com/1", "Feed 1", null], - [2, "john.doe@example.com","http://example.com/2", "Feed 2", null], - [3, "john.doe@example.com","http://example.com/3", "Feed 3", 1], - [4, "john.doe@example.com","http://example.com/4", "Feed 4", 6], - [5, "john.doe@example.com","http://example.com/5", "Feed 5", 5], - [6, "john.doe@example.com","http://example.com/10", "Feed 10", 5], - [7, "jane.doe@example.com","http://example.com/1", "Feed 1", null], - [8, "jane.doe@example.com","http://example.com/10", "Feed 10",null], - [9, "jane.doe@example.com","http://example.com/2", "Feed 2", 4], - [10,"jane.doe@example.com","http://example.com/3", "Feed 3", 4], - [11,"jane.doe@example.com","http://example.com/4", "Feed 4", 4], + [1, "john.doe@example.com", "http://example.com/1", "Feed 1", null, 0], + [2, "john.doe@example.com", "http://example.com/2", "Feed 2", null, 0], + [3, "john.doe@example.com", "http://example.com/3", "Feed 3", 1, 0], + [4, "john.doe@example.com", "http://example.com/4", "Feed 4", 6, 0], + [5, "john.doe@example.com", "http://example.com/5", "Feed 5", 5, 0], + [6, "john.doe@example.com", "http://example.com/10", "Feed 10", 5, 0], + [101, "john.doe@example.com", "http://example.com/101", "Feed 101", 1, 1], + [7, "jane.doe@example.com", "http://example.com/1", "Feed 1", null, 0], + [8, "jane.doe@example.com", "http://example.com/10", "Feed 10", null, 0], + [9, "jane.doe@example.com", "http://example.com/2", "Feed 2", 4, 0], + [10, "jane.doe@example.com", "http://example.com/3", "Feed 3", 4, 0], + [11, "jane.doe@example.com", "http://example.com/4", "Feed 4", 4, 0], ], ], ]; diff --git a/tests/cases/Database/SeriesIcon.php b/tests/cases/Database/SeriesIcon.php index 4f32241..f2169c6 100644 --- a/tests/cases/Database/SeriesIcon.php +++ b/tests/cases/Database/SeriesIcon.php @@ -31,14 +31,15 @@ trait SeriesIcon { ], ], 'arsse_subscriptions' => [ - 'columns' => ["id", "owner", "url", "title", "icon"], + 'columns' => ["id", "owner", "url", "title", "icon", "deleted"], 'rows' => [ - [1,'john.doe@example.com',"http://localhost:8000/Feed/Matching/3", "Ook", 1], - [2,'john.doe@example.com',"http://localhost:8000/Feed/Matching/1", "Eek", 2], - [3,'john.doe@example.com',"http://localhost:8000/Feed/Fetching/Error?code=404", "Ack", 3], - [4,'john.doe@example.com',"http://localhost:8000/Feed/NextFetch/NotModified?t=".time(), "Ooook", null], - [5,'john.doe@example.com',"http://localhost:8000/Feed/Parsing/Valid", "Ooook", 2], - [6,'jane.doe@example.com',"http://localhost:8000/Feed/Parsing/Valid", "Ooook", 2], + [1,'john.doe@example.com',"http://localhost:8000/Feed/Matching/3", "Ook", 1, 0], + [2,'john.doe@example.com',"http://localhost:8000/Feed/Matching/1", "Eek", 2, 0], + [3,'john.doe@example.com',"http://localhost:8000/Feed/Fetching/Error?code=404", "Ack", 3, 0], + [4,'john.doe@example.com',"http://localhost:8000/Feed/NextFetch/NotModified?t=".time(), "Ooook", null, 0], + [5,'john.doe@example.com',"http://localhost:8000/Feed/Parsing/Valid", "Ooook", 2, 0], + [6,'john.doe@example.com',"http://localhost:8000/Feed/Discovery/Valid", "Aaack", 4, 1], + [7,'jane.doe@example.com',"http://localhost:8000/Feed/Parsing/Valid", "Ooook", 2, 0], ], ], ]; diff --git a/tests/cases/Database/SeriesLabel.php b/tests/cases/Database/SeriesLabel.php index 735cd9c..c14c621 100644 --- a/tests/cases/Database/SeriesLabel.php +++ b/tests/cases/Database/SeriesLabel.php @@ -40,22 +40,23 @@ trait SeriesLabel { ], ], 'arsse_subscriptions' => [ - 'columns' => ["id", "owner", "url", "folder"], + 'columns' => ["id", "owner", "url", "folder", "deleted"], 'rows' => [ - [1, "john.doe@example.com","http://example.com/1",null], - [2, "john.doe@example.com","http://example.com/2",null], - [3, "john.doe@example.com","http://example.com/3",1], - [4, "john.doe@example.com","http://example.com/4",6], - [5, "john.doe@example.com","http://example.com/10",5], - [6, "jane.doe@example.com","http://example.com/1",null], - [7, "jane.doe@example.com","http://example.com/10",null], - [8, "john.doe@example.org","http://example.com/11",null], - [9, "john.doe@example.org","http://example.com/12",null], - [10,"john.doe@example.org","http://example.com/13",null], - [11,"john.doe@example.net","http://example.com/10",null], - [12,"john.doe@example.net","http://example.com/2",9], - [13,"john.doe@example.net","http://example.com/3",8], - [14,"john.doe@example.net","http://example.com/4",7], + [1, "john.doe@example.com", "http://example.com/1", null, 0], + [2, "john.doe@example.com", "http://example.com/2", null, 0], + [3, "john.doe@example.com", "http://example.com/3", 1, 0], + [4, "john.doe@example.com", "http://example.com/4", 6, 0], + [5, "john.doe@example.com", "http://example.com/10" ,5, 0], + [6, "jane.doe@example.com", "http://example.com/1", null, 0], + [7, "jane.doe@example.com", "http://example.com/10", null, 0], + [8, "john.doe@example.org", "http://example.com/11", null, 0], + [9, "john.doe@example.org", "http://example.com/12", null, 0], + [10, "john.doe@example.org", "http://example.com/13", null, 0], + [11, "john.doe@example.net", "http://example.com/10", null, 0], + [12, "john.doe@example.net", "http://example.com/2", 9, 0], + [13, "john.doe@example.net", "http://example.com/3", 8, 0], + [14, "john.doe@example.net", "http://example.com/4", 7, 0], + [16, "john.doe@example.com", "http://example.com/16", null, 1], ], ], 'arsse_articles' => [ @@ -92,6 +93,7 @@ trait SeriesLabel { [206,13,null, null, "Jane Doe",null, null, null, "", "", "", "2010-01-01 00:00:00",0,0,0,null, ''], [207,14,null, null, "Jane Doe",null, null, null, "", "", "", "2000-01-01 00:00:00",0,0,0,null, ''], [208,14,null, null, null, null, null, null, "", "", "", "2010-01-01 00:00:00",0,0,0,null, ''], + [999,16,null, null, null, null, null, null, "", "", "", "2000-01-01 00:00:00",1,1,0,null, ''], ], ], 'arsse_article_contents' => [ @@ -204,13 +206,15 @@ trait SeriesLabel { 'arsse_label_members' => [ 'columns' => ["label", "article", "assigned"], 'rows' => [ - [1, 1,1], - [2, 1,1], - [1,19,1], - [2,20,1], - [1, 5,0], - [2, 5,1], - [2, 8,1], + [1, 1,1], + [2, 1,1], + [1, 19,1], + [2, 20,1], + [1, 5,0], + [2, 5,1], + [2, 8,1], + [1,999,1], + [2,999,1], ], ], ];