mirror of
https://code.mensbeam.com/MensBeam/Arsse.git
synced 2024-12-22 21:22:40 +00:00
More article marking tests, some context tests
Various fixes as a result
This commit is contained in:
parent
c2f60bc5d2
commit
5742d949cc
3 changed files with 182 additions and 14 deletions
|
@ -703,6 +703,16 @@ class Database {
|
||||||
$out = 0;
|
$out = 0;
|
||||||
// wrap this UPDATE and INSERT together into a transaction
|
// wrap this UPDATE and INSERT together into a transaction
|
||||||
$tr = $this->begin();
|
$tr = $this->begin();
|
||||||
|
// if an edition context is specified, make sure it's valid
|
||||||
|
if($context->edition()) {
|
||||||
|
// make sure the edition exists
|
||||||
|
$edition = $this->articleValidateEdition($user, $context->edition);
|
||||||
|
// if the edition is not the latest, make no marks and return
|
||||||
|
if(!$edition['current']) return false;
|
||||||
|
} else if($context->article()) {
|
||||||
|
// otherwise if an article context is specified, make sure it's valid
|
||||||
|
$this->articleValidateId($user, $context->article);
|
||||||
|
}
|
||||||
// execute each query in sequence
|
// execute each query in sequence
|
||||||
foreach($queries as $query) {
|
foreach($queries as $query) {
|
||||||
// first build the query which will select the target articles; we will later turn this into a CTE for the actual query that manipulates the articles
|
// first build the query which will select the target articles; we will later turn this into a CTE for the actual query that manipulates the articles
|
||||||
|
@ -727,33 +737,32 @@ class Database {
|
||||||
or starred is not coalesce((select starred from target_values),starred)
|
or starred is not coalesce((select starred from target_values),starred)
|
||||||
)
|
)
|
||||||
) as to_update
|
) as to_update
|
||||||
FROM arsse_articles
|
FROM arsse_articles"
|
||||||
join subscribed_feeds on feed is subscribed_feeds.id
|
|
||||||
"
|
|
||||||
);
|
);
|
||||||
// common table expression for the affected user
|
// common table expression for the affected user
|
||||||
$q->setCTE("user(user) as (SELECT ?)", "str", $user);
|
$q->setCTE("user(user) as (SELECT ?)", "str", $user);
|
||||||
// common table expression with the values to set
|
// common table expression with the values to set
|
||||||
$q->setCTE("target_values(read,starred) as (select ?,?)", ["bool","bool"], $values);
|
$q->setCTE("target_values(read,starred) as (select ?,?)", ["bool","bool"], $values);
|
||||||
if($context->subscription()) {
|
if($context->edition()) {
|
||||||
|
$q->setWhere("arsse_articles.id is ?", "int", $edition['article']);
|
||||||
|
} else if($context->article()) {
|
||||||
|
$q->setWhere("arsse_articles.id is ?", "int", $context->article);
|
||||||
|
} else if($context->subscription()) {
|
||||||
// if a subscription is specified, make sure it exists
|
// if a subscription is specified, make sure it exists
|
||||||
$id = $this->subscriptionValidateId($user, $context->subscription)['feed'];
|
$id = $this->subscriptionValidateId($user, $context->subscription)['feed'];
|
||||||
// add a basic CTE that will join in only the requested subscription
|
// add a basic CTE that will join in only the requested subscription
|
||||||
$q->setCTE("subscribed_feeds(id,sub) as (SELECT ?,?)", ["int","int"], [$id,$context->subscription]);
|
$q->setCTE("subscribed_feeds(id,sub) as (SELECT ?,?)", ["int","int"], [$id,$context->subscription], "join subscribed_feeds on feed is subscribed_feeds.id");
|
||||||
} else if($context->folder()) {
|
} else if($context->folder()) {
|
||||||
// if a folder is specified, make sure it exists
|
// if a folder is specified, make sure it exists
|
||||||
$this->folderValidateId($user, $context->folder);
|
$this->folderValidateId($user, $context->folder);
|
||||||
// if it does exist, add a common table expression to list it and its children so that we select from the entire subtree
|
// if it does exist, add a common table expression to list it and its children so that we select from the entire subtree
|
||||||
$q->setCTE("folders(folder) as (SELECT ? union select id from arsse_folders join folders on parent is folder)", "int", $context->folder);
|
$q->setCTE("folders(folder) as (SELECT ? union select id from arsse_folders join folders on parent is folder)", "int", $context->folder);
|
||||||
// add another CTE for the subscriptions within the folder
|
// add another CTE for the subscriptions within the folder
|
||||||
$q->setCTE("subscribed_feeds(id,sub) as (SELECT feed,id from arsse_subscriptions join user on user is owner join folders on arsse_subscriptions.folder is folders.folder)");
|
$q->setCTE("subscribed_feeds(id,sub) as (SELECT feed,id from arsse_subscriptions join user on user is owner join folders on arsse_subscriptions.folder is folders.folder)", [], [], "join subscribed_feeds on feed is subscribed_feeds.id");
|
||||||
} else {
|
} else {
|
||||||
// otherwise add a CTE for all the user's subscriptions
|
// otherwise add a CTE for all the user's subscriptions
|
||||||
$q->setCTE("subscribed_feeds(id,sub) as (SELECT feed,id from arsse_subscriptions join user on user is owner)");
|
$q->setCTE("subscribed_feeds(id,sub) as (SELECT feed,id from arsse_subscriptions join user on user is owner)", [], [], "join subscribed_feeds on feed is subscribed_feeds.id");
|
||||||
}
|
}
|
||||||
// filter for specific article or edition
|
|
||||||
if($context->article()) $q->setWhere("arsse_article.id is ?", "int", $context->article);
|
|
||||||
if($context->edition()) $q->setWhere("arsse_article.id is (SELECT article from arsse_editions where id is ?)", "int", $context->edition);
|
|
||||||
// filter based on edition offset
|
// filter based on edition offset
|
||||||
if($context->oldestEdition()) $q->setWhere("edition >= ?", "int", $context->oldestEdition);
|
if($context->oldestEdition()) $q->setWhere("edition >= ?", "int", $context->oldestEdition);
|
||||||
if($context->latestEdition()) $q->setWhere("edition <= ?", "int", $context->latestEdition);
|
if($context->latestEdition()) $q->setWhere("edition <= ?", "int", $context->latestEdition);
|
||||||
|
@ -773,4 +782,38 @@ class Database {
|
||||||
$tr->commit();
|
$tr->commit();
|
||||||
return (bool) $out;
|
return (bool) $out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function articleValidateId(string $user, int $id): array {
|
||||||
|
$out = $this->db->prepare(
|
||||||
|
"SELECT
|
||||||
|
arsse_articles.id as article,
|
||||||
|
(select max(id) from arsse_editions where article is arsse_articles.id) as edition
|
||||||
|
FROM arsse_articles
|
||||||
|
join arsse_feeds on arsse_feeds.id is arsse_articles.feed
|
||||||
|
join arsse_subscriptions on arsse_subscriptions.feed is arsse_feeds.id
|
||||||
|
WHERE
|
||||||
|
arsse_articles.id is ? and arsse_subscriptions.owner is ?",
|
||||||
|
"int", "str"
|
||||||
|
)->run($id, $user)->getRow();
|
||||||
|
if(!$out) throw new Db\ExceptionInput("idMissing", ["action" => $this->caller(), "field" => "article", 'id' => $id]);
|
||||||
|
return $out;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function articleValidateEdition(string $user, int $id): array {
|
||||||
|
$out = $this->db->prepare(
|
||||||
|
"SELECT
|
||||||
|
arsse_editions.id as edition,
|
||||||
|
arsse_editions.article as article,
|
||||||
|
(arsse_editions.id is (select max(id) from arsse_editions where article is arsse_editions.article)) as current
|
||||||
|
FROM arsse_editions
|
||||||
|
join arsse_articles on arsse_editions.article is arsse_articles.id
|
||||||
|
join arsse_feeds on arsse_feeds.id is arsse_articles.feed
|
||||||
|
join arsse_subscriptions on arsse_subscriptions.feed is arsse_feeds.id
|
||||||
|
WHERE
|
||||||
|
edition is ? and arsse_subscriptions.owner is ?",
|
||||||
|
"int", "str"
|
||||||
|
)->run($id, $user)->getRow();
|
||||||
|
if(!$out) throw new Db\ExceptionInput("idMissing", ["action" => $this->caller(), "field" => "edition", 'id' => $id]);
|
||||||
|
return $out;
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -81,6 +81,7 @@ class Query {
|
||||||
array_push($values, $this->offset);
|
array_push($values, $this->offset);
|
||||||
}
|
}
|
||||||
$this->setCTE($tableSpec." as (".$this->buildQueryBody().")", $types, $values);
|
$this->setCTE($tableSpec." as (".$this->buildQueryBody().")", $types, $values);
|
||||||
|
$this->jCTE = [];
|
||||||
$this->qWhere = [];
|
$this->qWhere = [];
|
||||||
$this->tWhere = [];
|
$this->tWhere = [];
|
||||||
$this->vWhere = [];
|
$this->vWhere = [];
|
||||||
|
|
|
@ -83,7 +83,7 @@ trait SeriesArticle {
|
||||||
[8,"john.doe@example.org",11,null],
|
[8,"john.doe@example.org",11,null],
|
||||||
[9,"john.doe@example.org",12,null],
|
[9,"john.doe@example.org",12,null],
|
||||||
[10,"john.doe@example.org",13,null],
|
[10,"john.doe@example.org",13,null],
|
||||||
[11,"john.doe@example.net",1,null],
|
[11,"john.doe@example.net",10,null],
|
||||||
[12,"john.doe@example.net",2,9],
|
[12,"john.doe@example.net",2,9],
|
||||||
[13,"john.doe@example.net",3,8],
|
[13,"john.doe@example.net",3,8],
|
||||||
[14,"john.doe@example.net",4,7],
|
[14,"john.doe@example.net",4,7],
|
||||||
|
@ -163,11 +163,10 @@ trait SeriesArticle {
|
||||||
["john.doe@example.org",103,0,1,'2000-01-03 03:00:00'],
|
["john.doe@example.org",103,0,1,'2000-01-03 03:00:00'],
|
||||||
["john.doe@example.org",104,1,1,'2000-01-04 04:00:00'],
|
["john.doe@example.org",104,1,1,'2000-01-04 04:00:00'],
|
||||||
["john.doe@example.org",105,0,0,'2000-01-05 05:00:00'],
|
["john.doe@example.org",105,0,0,'2000-01-05 05:00:00'],
|
||||||
["john.doe@example.net", 1,0,0,'2017-01-01 00:00:00'],
|
["john.doe@example.net", 19,0,0,'2017-01-01 00:00:00'],
|
||||||
["john.doe@example.net", 2,1,0,'2017-01-01 00:00:00'],
|
["john.doe@example.net", 20,1,0,'2017-01-01 00:00:00'],
|
||||||
["john.doe@example.net", 3,0,1,'2017-01-01 00:00:00'],
|
["john.doe@example.net", 3,0,1,'2017-01-01 00:00:00'],
|
||||||
["john.doe@example.net", 4,1,1,'2017-01-01 00:00:00'],
|
["john.doe@example.net", 4,1,1,'2017-01-01 00:00:00'],
|
||||||
|
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
|
@ -422,6 +421,131 @@ trait SeriesArticle {
|
||||||
$this->compareExpectations($state);
|
$this->compareExpectations($state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function testMarkAllArticlesUnreadAndStarred() {
|
||||||
|
Data::$db->articleMark($this->user, ['read'=>false,'starred'=>true]);
|
||||||
|
$now = $this->dateTransform(time(), "sql");
|
||||||
|
$state = $this->primeExpectations($this->data, [
|
||||||
|
'arsse_marks' => ["owner","article","read","starred","modified"],
|
||||||
|
]);
|
||||||
|
$state['arsse_marks']['rows'][8][3] = 1;
|
||||||
|
$state['arsse_marks']['rows'][8][4] = $now;
|
||||||
|
$state['arsse_marks']['rows'][9][2] = 0;
|
||||||
|
$state['arsse_marks']['rows'][9][3] = 1;
|
||||||
|
$state['arsse_marks']['rows'][9][4] = $now;
|
||||||
|
$state['arsse_marks']['rows'][11][2] = 0;
|
||||||
|
$state['arsse_marks']['rows'][11][4] = $now;
|
||||||
|
$state['arsse_marks']['rows'][] = [$this->user,5,0,1,$now];
|
||||||
|
$state['arsse_marks']['rows'][] = [$this->user,6,0,1,$now];
|
||||||
|
$state['arsse_marks']['rows'][] = [$this->user,7,0,1,$now];
|
||||||
|
$state['arsse_marks']['rows'][] = [$this->user,8,0,1,$now];
|
||||||
|
$this->compareExpectations($state);
|
||||||
|
}
|
||||||
|
|
||||||
|
function testMarkAllArticlesReadAndUnstarred() {
|
||||||
|
Data::$db->articleMark($this->user, ['read'=>true,'starred'=>false]);
|
||||||
|
$now = $this->dateTransform(time(), "sql");
|
||||||
|
$state = $this->primeExpectations($this->data, [
|
||||||
|
'arsse_marks' => ["owner","article","read","starred","modified"],
|
||||||
|
]);
|
||||||
|
$state['arsse_marks']['rows'][8][2] = 1;
|
||||||
|
$state['arsse_marks']['rows'][8][4] = $now;
|
||||||
|
$state['arsse_marks']['rows'][10][2] = 1;
|
||||||
|
$state['arsse_marks']['rows'][10][3] = 0;
|
||||||
|
$state['arsse_marks']['rows'][10][4] = $now;
|
||||||
|
$state['arsse_marks']['rows'][11][3] = 0;
|
||||||
|
$state['arsse_marks']['rows'][11][4] = $now;
|
||||||
|
$state['arsse_marks']['rows'][] = [$this->user,5,1,0,$now];
|
||||||
|
$state['arsse_marks']['rows'][] = [$this->user,6,1,0,$now];
|
||||||
|
$state['arsse_marks']['rows'][] = [$this->user,7,1,0,$now];
|
||||||
|
$state['arsse_marks']['rows'][] = [$this->user,8,1,0,$now];
|
||||||
|
$this->compareExpectations($state);
|
||||||
|
}
|
||||||
|
|
||||||
|
function testMarkATreeFolder() {
|
||||||
|
Data::$db->articleMark($this->user, ['read'=>true], (new Context)->folder(7));
|
||||||
|
$now = $this->dateTransform(time(), "sql");
|
||||||
|
$state = $this->primeExpectations($this->data, [
|
||||||
|
'arsse_marks' => ["owner","article","read","starred","modified"],
|
||||||
|
]);
|
||||||
|
$state['arsse_marks']['rows'][] = [$this->user,5,1,0,$now];
|
||||||
|
$state['arsse_marks']['rows'][] = [$this->user,6,1,0,$now];
|
||||||
|
$state['arsse_marks']['rows'][] = [$this->user,7,1,0,$now];
|
||||||
|
$state['arsse_marks']['rows'][] = [$this->user,8,1,0,$now];
|
||||||
|
$this->compareExpectations($state);
|
||||||
|
}
|
||||||
|
|
||||||
|
function testMarkALeafFolder() {
|
||||||
|
Data::$db->articleMark($this->user, ['read'=>true], (new Context)->folder(8));
|
||||||
|
$now = $this->dateTransform(time(), "sql");
|
||||||
|
$state = $this->primeExpectations($this->data, [
|
||||||
|
'arsse_marks' => ["owner","article","read","starred","modified"],
|
||||||
|
]);
|
||||||
|
$state['arsse_marks']['rows'][] = [$this->user,5,1,0,$now];
|
||||||
|
$state['arsse_marks']['rows'][] = [$this->user,6,1,0,$now];
|
||||||
|
$this->compareExpectations($state);
|
||||||
|
}
|
||||||
|
|
||||||
|
function testMarkAMissingFolder() {
|
||||||
|
$this->assertException("idMissing", "Db", "ExceptionInput");
|
||||||
|
Data::$db->articleMark($this->user, ['read'=>true], (new Context)->folder(42));
|
||||||
|
}
|
||||||
|
|
||||||
|
function testMarkASubscription() {
|
||||||
|
Data::$db->articleMark($this->user, ['read'=>true], (new Context)->subscription(13));
|
||||||
|
$now = $this->dateTransform(time(), "sql");
|
||||||
|
$state = $this->primeExpectations($this->data, [
|
||||||
|
'arsse_marks' => ["owner","article","read","starred","modified"],
|
||||||
|
]);
|
||||||
|
$state['arsse_marks']['rows'][] = [$this->user,5,1,0,$now];
|
||||||
|
$state['arsse_marks']['rows'][] = [$this->user,6,1,0,$now];
|
||||||
|
$this->compareExpectations($state);
|
||||||
|
}
|
||||||
|
|
||||||
|
function testMarkAMissingSubscription() {
|
||||||
|
$this->assertException("idMissing", "Db", "ExceptionInput");
|
||||||
|
Data::$db->articleMark($this->user, ['read'=>true], (new Context)->folder(2112));
|
||||||
|
}
|
||||||
|
|
||||||
|
function testMarkAnArticle() {
|
||||||
|
Data::$db->articleMark($this->user, ['starred'=>true], (new Context)->article(20));
|
||||||
|
$now = $this->dateTransform(time(), "sql");
|
||||||
|
$state = $this->primeExpectations($this->data, [
|
||||||
|
'arsse_marks' => ["owner","article","read","starred","modified"],
|
||||||
|
]);
|
||||||
|
$state['arsse_marks']['rows'][9][3] = 1;
|
||||||
|
$state['arsse_marks']['rows'][9][4] = $now;
|
||||||
|
$this->compareExpectations($state);
|
||||||
|
}
|
||||||
|
|
||||||
|
function testMarkAMissingArticle() {
|
||||||
|
$this->assertException("idMissing", "Db", "ExceptionInput");
|
||||||
|
Data::$db->articleMark($this->user, ['starred'=>true], (new Context)->article(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
function testMarkAnEdition() {
|
||||||
|
Data::$db->articleMark($this->user, ['starred'=>true], (new Context)->edition(1001));
|
||||||
|
$now = $this->dateTransform(time(), "sql");
|
||||||
|
$state = $this->primeExpectations($this->data, [
|
||||||
|
'arsse_marks' => ["owner","article","read","starred","modified"],
|
||||||
|
]);
|
||||||
|
$state['arsse_marks']['rows'][9][3] = 1;
|
||||||
|
$state['arsse_marks']['rows'][9][4] = $now;
|
||||||
|
$this->compareExpectations($state);
|
||||||
|
}
|
||||||
|
|
||||||
|
function testMarkAStaleEdition() {
|
||||||
|
Data::$db->articleMark($this->user, ['starred'=>true], (new Context)->edition(20)); // no changes occur
|
||||||
|
$state = $this->primeExpectations($this->data, [
|
||||||
|
'arsse_marks' => ["owner","article","read","starred","modified"],
|
||||||
|
]);
|
||||||
|
$this->compareExpectations($state);
|
||||||
|
}
|
||||||
|
|
||||||
|
function testMarkAMissingEdition() {
|
||||||
|
$this->assertException("idMissing", "Db", "ExceptionInput");
|
||||||
|
Data::$db->articleMark($this->user, ['starred'=>true], (new Context)->edition(2));
|
||||||
|
}
|
||||||
|
|
||||||
protected function compareIds(array $exp, Context $c) {
|
protected function compareIds(array $exp, Context $c) {
|
||||||
$ids = array_column($ids = Data::$db->articleList($this->user, $c)->getAll(), "id");
|
$ids = array_column($ids = Data::$db->articleList($this->user, $c)->getAll(), "id");
|
||||||
sort($ids);
|
sort($ids);
|
||||||
|
|
Loading…
Reference in a new issue