Browse Source

More sub soft-delete fixes

redup
J. King 1 year ago
parent
commit
de6760d5d7
  1. 40
      lib/Database.php
  2. 22
      tests/cases/Database/SeriesArticle.php
  3. 25
      tests/cases/Database/SeriesFolder.php
  4. 15
      tests/cases/Database/SeriesIcon.php
  5. 48
      tests/cases/Database/SeriesLabel.php

40
lib/Database.php

@ -566,7 +566,7 @@ class Database {
coalesce(feeds,0) as feeds coalesce(feeds,0) as feeds
from arsse_folders 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 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"], ["str", "strict int"],
[$user, $parent] [$user, $parent]
); );
@ -1139,7 +1139,7 @@ class Database {
return V::normalize($out, V::T_DATE | V::M_NULL, "sql"); 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 string $user The user who owns the subscription
* @param integer $id The identifier of the subscription whose rules are to be evaluated * @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 * @param string $user The user whose subscription icons are to be retrieved
*/ */
public function iconList(string $user): Db\Result { 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 /** Deletes orphaned icons from the database
@ -1571,7 +1571,7 @@ class Database {
select select
$outColumns $outColumns
from arsse_articles 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 arsse_article_contents on arsse_article_contents.id = arsse_articles.id
left join folder_data on arsse_subscriptions.folder = folder_data.id left join folder_data on arsse_subscriptions.folder = folder_data.id
left join arsse_enclosures on arsse_enclosures.article = arsse_articles.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 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 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 * @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 = [ $data = [
'read' => $data['read'] ?? null, 'read' => $data['read'] ?? null,
'starred' => $data['starred'] ?? null, 'starred' => $data['starred'] ?? null,
@ -2011,7 +2011,7 @@ class Database {
coalesce(sum(abs(\"read\" - 1)),0) as unread, coalesce(sum(abs(\"read\" - 1)),0) as unread,
coalesce(sum(\"read\"),0) as \"read\" coalesce(sum(\"read\"),0) as \"read\"
FROM ( 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", ) as starred_data",
"str" "str"
)->run($user)->getRow(); )->run($user)->getRow();
@ -2148,7 +2148,7 @@ class Database {
join arsse_articles on arsse_articles.id = arsse_editions.article join arsse_articles on arsse_articles.id = arsse_editions.article
join arsse_subscriptions on arsse_subscriptions.id = arsse_articles.subscription 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 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"] ["int", "str"]
)->run($id, $user)->getRow(); )->run($id, $user)->getRow();
if (!$out) { 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 cast(coalesce(marked, 0) as $integerType) as \"read\" -- this cast is required for MySQL for unclear reasons
from arsse_labels from arsse_labels
left join ( 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 ) as label_stats on label_stats.label = arsse_labels.id
left join ( left join (
SELECT SELECT
@ -2221,7 +2227,7 @@ class Database {
from arsse_articles from arsse_articles
join arsse_subscriptions on arsse_subscriptions.id = arsse_articles.subscription join arsse_subscriptions on arsse_subscriptions.id = arsse_articles.subscription
join arsse_label_members on arsse_label_members.article = arsse_articles.id 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 group by label
) as mark_stats on mark_stats.label = arsse_labels.id ) as mark_stats on mark_stats.label = arsse_labels.id
WHERE owner = ? WHERE owner = ?
@ -2275,7 +2281,13 @@ class Database {
coalesce(marked, 0) as \"read\" coalesce(marked, 0) as \"read\"
FROM arsse_labels FROM arsse_labels
left join ( 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 ) as label_stats on label_stats.label = arsse_labels.id
left join ( left join (
SELECT SELECT
@ -2285,7 +2297,7 @@ class Database {
from arsse_articles from arsse_articles
join arsse_subscriptions on arsse_subscriptions.id = arsse_articles.subscription join arsse_subscriptions on arsse_subscriptions.id = arsse_articles.subscription
join arsse_label_members on arsse_label_members.article = arsse_articles.id 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 group by label
) as mark_stats on mark_stats.label = arsse_labels.id ) as mark_stats on mark_stats.label = arsse_labels.id
WHERE $field = ? and owner = ?", WHERE $field = ? and owner = ?",
@ -2374,7 +2386,7 @@ class Database {
if (!sizeof($articles)) { if (!sizeof($articles)) {
if ($mode == self::ASSOC_REPLACE) { if ($mode == self::ASSOC_REPLACE) {
// replacing with an empty set means setting everything to zero // 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 { } else {
// adding or removing is a no-op // adding or removing is a no-op
return 0; return 0;
@ -2384,7 +2396,7 @@ class Database {
} }
// prepare up to three queries: removing requires one, adding two, and replacing three // prepare up to three queries: removing requires one, adding two, and replacing three
[$inClause, $inTypes, $inValues] = $this->generateIn($articles, "int"); [$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]; $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)"; $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]; $insertT = ["int", "str", "int", $inTypes];

22
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, ''], [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, ''], [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, ''], [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' => [ 'arsse_article_contents' => [
@ -208,7 +208,6 @@ trait SeriesArticle {
[ 802,802], [ 802,802],
[ 902,802], [ 902,802],
[ 999,999], [ 999,999],
[9999,999],
], ],
], ],
'arsse_enclosures' => [ 'arsse_enclosures' => [
@ -250,14 +249,15 @@ trait SeriesArticle {
'arsse_label_members' => [ 'arsse_label_members' => [
'columns' => ["label", "article", "assigned", "modified"], 'columns' => ["label", "article", "assigned", "modified"],
'rows' => [ 'rows' => [
[1, 1,1,'2000-01-01 00:00:00'], [1, 1,1,'2000-01-01 00:00:00'],
[2, 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'], [1, 19,1,'2000-01-01 00:00:00'],
[2,20,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'], [1, 5,0,'2000-01-01 00:00:00'],
[2, 5,1,'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, 7,0,'2000-01-01 00:00:00'],
[4, 8,1,'2015-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 { public function testMarkAnEditionOfADeletedSubscription(): void {
$this->assertException("subjectMissing", "Db", "ExceptionInput"); $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 { public function testMarkByOldestEdition(): void {

25
tests/cases/Database/SeriesFolder.php

@ -42,19 +42,20 @@ trait SeriesFolder {
], ],
], ],
'arsse_subscriptions' => [ 'arsse_subscriptions' => [
'columns' => ["id", "owner", "url", "title", "folder"], 'columns' => ["id", "owner", "url", "title", "folder", "deleted"],
'rows' => [ 'rows' => [
[1, "john.doe@example.com","http://example.com/1", "Feed 1", null], [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], [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], [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], [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], [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], [6, "john.doe@example.com", "http://example.com/10", "Feed 10", 5, 0],
[7, "jane.doe@example.com","http://example.com/1", "Feed 1", null], [101, "john.doe@example.com", "http://example.com/101", "Feed 101", 1, 1],
[8, "jane.doe@example.com","http://example.com/10", "Feed 10",null], [7, "jane.doe@example.com", "http://example.com/1", "Feed 1", null, 0],
[9, "jane.doe@example.com","http://example.com/2", "Feed 2", 4], [8, "jane.doe@example.com", "http://example.com/10", "Feed 10", null, 0],
[10,"jane.doe@example.com","http://example.com/3", "Feed 3", 4], [9, "jane.doe@example.com", "http://example.com/2", "Feed 2", 4, 0],
[11,"jane.doe@example.com","http://example.com/4", "Feed 4", 4], [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],
], ],
], ],
]; ];

15
tests/cases/Database/SeriesIcon.php

@ -31,14 +31,15 @@ trait SeriesIcon {
], ],
], ],
'arsse_subscriptions' => [ 'arsse_subscriptions' => [
'columns' => ["id", "owner", "url", "title", "icon"], 'columns' => ["id", "owner", "url", "title", "icon", "deleted"],
'rows' => [ 'rows' => [
[1,'john.doe@example.com',"http://localhost:8000/Feed/Matching/3", "Ook", 1], [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], [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], [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], [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], [5,'john.doe@example.com',"http://localhost:8000/Feed/Parsing/Valid", "Ooook", 2, 0],
[6,'jane.doe@example.com',"http://localhost:8000/Feed/Parsing/Valid", "Ooook", 2], [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],
], ],
], ],
]; ];

48
tests/cases/Database/SeriesLabel.php

@ -40,22 +40,23 @@ trait SeriesLabel {
], ],
], ],
'arsse_subscriptions' => [ 'arsse_subscriptions' => [
'columns' => ["id", "owner", "url", "folder"], 'columns' => ["id", "owner", "url", "folder", "deleted"],
'rows' => [ 'rows' => [
[1, "john.doe@example.com","http://example.com/1",null], [1, "john.doe@example.com", "http://example.com/1", null, 0],
[2, "john.doe@example.com","http://example.com/2",null], [2, "john.doe@example.com", "http://example.com/2", null, 0],
[3, "john.doe@example.com","http://example.com/3",1], [3, "john.doe@example.com", "http://example.com/3", 1, 0],
[4, "john.doe@example.com","http://example.com/4",6], [4, "john.doe@example.com", "http://example.com/4", 6, 0],
[5, "john.doe@example.com","http://example.com/10",5], [5, "john.doe@example.com", "http://example.com/10" ,5, 0],
[6, "jane.doe@example.com","http://example.com/1",null], [6, "jane.doe@example.com", "http://example.com/1", null, 0],
[7, "jane.doe@example.com","http://example.com/10",null], [7, "jane.doe@example.com", "http://example.com/10", null, 0],
[8, "john.doe@example.org","http://example.com/11",null], [8, "john.doe@example.org", "http://example.com/11", null, 0],
[9, "john.doe@example.org","http://example.com/12",null], [9, "john.doe@example.org", "http://example.com/12", null, 0],
[10,"john.doe@example.org","http://example.com/13",null], [10, "john.doe@example.org", "http://example.com/13", null, 0],
[11,"john.doe@example.net","http://example.com/10",null], [11, "john.doe@example.net", "http://example.com/10", null, 0],
[12,"john.doe@example.net","http://example.com/2",9], [12, "john.doe@example.net", "http://example.com/2", 9, 0],
[13,"john.doe@example.net","http://example.com/3",8], [13, "john.doe@example.net", "http://example.com/3", 8, 0],
[14,"john.doe@example.net","http://example.com/4",7], [14, "john.doe@example.net", "http://example.com/4", 7, 0],
[16, "john.doe@example.com", "http://example.com/16", null, 1],
], ],
], ],
'arsse_articles' => [ '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, ''], [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, ''], [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, ''], [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' => [ 'arsse_article_contents' => [
@ -204,13 +206,15 @@ trait SeriesLabel {
'arsse_label_members' => [ 'arsse_label_members' => [
'columns' => ["label", "article", "assigned"], 'columns' => ["label", "article", "assigned"],
'rows' => [ 'rows' => [
[1, 1,1], [1, 1,1],
[2, 1,1], [2, 1,1],
[1,19,1], [1, 19,1],
[2,20,1], [2, 20,1],
[1, 5,0], [1, 5,0],
[2, 5,1], [2, 5,1],
[2, 8,1], [2, 8,1],
[1,999,1],
[2,999,1],
], ],
], ],
]; ];

Loading…
Cancel
Save