mirror of
https://code.mensbeam.com/MensBeam/Arsse.git
synced 2024-12-22 13:12:41 +00:00
Add article selection by tag
This commit is contained in:
parent
e6f70527cf
commit
5de1844f6d
4 changed files with 160 additions and 89 deletions
|
@ -12,6 +12,8 @@ use JKingWeb\Arsse\Misc\Date;
|
|||
class ExclusionContext {
|
||||
public $folder;
|
||||
public $folderShallow;
|
||||
public $tag;
|
||||
public $tagName;
|
||||
public $subscription;
|
||||
public $edition;
|
||||
public $article;
|
||||
|
@ -101,6 +103,14 @@ class ExclusionContext {
|
|||
return $this->act(__FUNCTION__, func_num_args(), $spec);
|
||||
}
|
||||
|
||||
public function tag(int $spec = null) {
|
||||
return $this->act(__FUNCTION__, func_num_args(), $spec);
|
||||
}
|
||||
|
||||
public function tagName(string $spec = null) {
|
||||
return $this->act(__FUNCTION__, func_num_args(), $spec);
|
||||
}
|
||||
|
||||
public function subscription(int $spec = null) {
|
||||
return $this->act(__FUNCTION__, func_num_args(), $spec);
|
||||
}
|
||||
|
|
|
@ -1325,6 +1325,21 @@ class Database {
|
|||
$q->setWhereNot("arsse_articles.id in (select article from labelled where label_name = ?)", "str", $context->not->labelName);
|
||||
}
|
||||
}
|
||||
if ($context->tag() || $context->not->tag() || $context->tagName() || $context->not->tagName()) {
|
||||
$q->setCTE("tagged(id,name,subscription)","SELECT arsse_tags.id, arsse_tags.name, arsse_tag_members.subscription FROM arsse_tag_members join arsse_tags on arsse_tags.id = arsse_tag_members.tag WHERE arsse_tags.owner = ? and assigned = 1", "str", $user);
|
||||
if ($context->tag()) {
|
||||
$q->setWhere("arsse_subscriptions.id in (select subscription from tagged where id = ?)", "int", $context->tag);
|
||||
}
|
||||
if ($context->not->tag()) {
|
||||
$q->setWhereNot("arsse_subscriptions.id in (select subscription from tagged where id = ?)", "int", $context->not->tag);
|
||||
}
|
||||
if ($context->tagName()) {
|
||||
$q->setWhere("arsse_subscriptions.id in (select subscription from tagged where name = ?)", "str", $context->tagName);
|
||||
}
|
||||
if ($context->not->tagName()) {
|
||||
$q->setWhereNot("arsse_subscriptions.id in (select subscription from tagged where name = ?)", "str", $context->not->tagName);
|
||||
}
|
||||
}
|
||||
if ($context->folder()) {
|
||||
// add a common table expression to list the folder and its children so that we select from the entire subtree
|
||||
$q->setCTE("folders(folder)", "SELECT ? union select id from arsse_folders join folders on parent = folder", "int", $context->folder);
|
||||
|
|
|
@ -28,25 +28,6 @@ trait SeriesArticle {
|
|||
["john.doe@example.net", "", "John Doe"],
|
||||
],
|
||||
],
|
||||
'arsse_folders' => [
|
||||
'columns' => [
|
||||
'id' => "int",
|
||||
'owner' => "str",
|
||||
'parent' => "int",
|
||||
'name' => "str",
|
||||
],
|
||||
'rows' => [
|
||||
[1, "john.doe@example.com", null, "Technology"],
|
||||
[2, "john.doe@example.com", 1, "Software"],
|
||||
[3, "john.doe@example.com", 1, "Rocketry"],
|
||||
[4, "jane.doe@example.com", null, "Politics"],
|
||||
[5, "john.doe@example.com", null, "Politics"],
|
||||
[6, "john.doe@example.com", 2, "Politics"],
|
||||
[7, "john.doe@example.net", null, "Technology"],
|
||||
[8, "john.doe@example.net", 7, "Software"],
|
||||
[9, "john.doe@example.net", null, "Politics"],
|
||||
]
|
||||
],
|
||||
'arsse_feeds' => [
|
||||
'columns' => [
|
||||
'id' => "int",
|
||||
|
@ -69,6 +50,42 @@ trait SeriesArticle {
|
|||
[13,"http://example.com/13", "Feed 13"],
|
||||
]
|
||||
],
|
||||
'arsse_folders' => [
|
||||
'columns' => [
|
||||
'id' => "int",
|
||||
'owner' => "str",
|
||||
'parent' => "int",
|
||||
'name' => "str",
|
||||
],
|
||||
'rows' => [
|
||||
[1, "john.doe@example.com", null, "Technology"],
|
||||
[2, "john.doe@example.com", 1, "Software"],
|
||||
[3, "john.doe@example.com", 1, "Rocketry"],
|
||||
[4, "jane.doe@example.com", null, "Politics"],
|
||||
[5, "john.doe@example.com", null, "Politics"],
|
||||
[6, "john.doe@example.com", 2, "Politics"],
|
||||
[7, "john.doe@example.net", null, "Technology"],
|
||||
[8, "john.doe@example.net", 7, "Software"],
|
||||
[9, "john.doe@example.net", null, "Politics"],
|
||||
]
|
||||
],
|
||||
'arsse_tags' => [
|
||||
'columns' => [
|
||||
'id' => "int",
|
||||
'owner' => "str",
|
||||
'name' => "str",
|
||||
],
|
||||
'rows' => [
|
||||
[1, "john.doe@example.com", "Technology"],
|
||||
[2, "john.doe@example.com", "Software"],
|
||||
[3, "john.doe@example.com", "Rocketry"],
|
||||
[4, "jane.doe@example.com", "Politics"],
|
||||
[5, "john.doe@example.com", "Politics"],
|
||||
[6, "john.doe@example.net", "Technology"],
|
||||
[7, "john.doe@example.net", "Software"],
|
||||
[8, "john.doe@example.net", "Politics"],
|
||||
]
|
||||
],
|
||||
'arsse_subscriptions' => [
|
||||
'columns' => [
|
||||
'id' => "int",
|
||||
|
@ -94,6 +111,25 @@ trait SeriesArticle {
|
|||
[14,"john.doe@example.net",4, 7,null],
|
||||
]
|
||||
],
|
||||
'arsse_tag_members' => [
|
||||
'columns' => [
|
||||
'tag' => "int",
|
||||
'subscription' => "int",
|
||||
'assigned' => "bool",
|
||||
],
|
||||
'rows' => [
|
||||
[1,3,1],
|
||||
[1,4,1],
|
||||
[2,4,1],
|
||||
[5,1,0],
|
||||
[5,4,1],
|
||||
[5,5,1],
|
||||
[6,13,1],
|
||||
[6,14,1],
|
||||
[7,13,1],
|
||||
[8,12,1],
|
||||
],
|
||||
],
|
||||
'arsse_articles' => [
|
||||
'columns' => [
|
||||
'id' => "int",
|
||||
|
@ -387,76 +423,84 @@ trait SeriesArticle {
|
|||
|
||||
public function provideContextMatches() {
|
||||
return [
|
||||
"Blank context" => [new Context, [1,2,3,4,5,6,7,8,19,20]],
|
||||
"Folder tree" => [(new Context)->folder(1), [5,6,7,8]],
|
||||
"Leaf folder" => [(new Context)->folder(6), [7,8]],
|
||||
"Root folder only" => [(new Context)->folderShallow(0), [1,2,3,4]],
|
||||
"Shallow folder" => [(new Context)->folderShallow(1), [5,6]],
|
||||
"Subscription" => [(new Context)->subscription(5), [19,20]],
|
||||
"Unread" => [(new Context)->subscription(5)->unread(true), [20]],
|
||||
"Read" => [(new Context)->subscription(5)->unread(false), [19]],
|
||||
"Starred" => [(new Context)->starred(true), [1,20]],
|
||||
"Unstarred" => [(new Context)->starred(false), [2,3,4,5,6,7,8,19]],
|
||||
"Starred and Read" => [(new Context)->starred(true)->unread(false), [1]],
|
||||
"Starred and Read in subscription" => [(new Context)->starred(true)->unread(false)->subscription(5), []],
|
||||
"Annotated" => [(new Context)->annotated(true), [2]],
|
||||
"Not annotated" => [(new Context)->annotated(false), [1,3,4,5,6,7,8,19,20]],
|
||||
"Labelled" => [(new Context)->labelled(true), [1,5,8,19,20]],
|
||||
"Not labelled" => [(new Context)->labelled(false), [2,3,4,6,7]],
|
||||
"Not after edition 999" => [(new Context)->subscription(5)->latestEdition(999), [19]],
|
||||
"Not after edition 19" => [(new Context)->subscription(5)->latestEdition(19), [19]],
|
||||
"Not before edition 999" => [(new Context)->subscription(5)->oldestEdition(999), [20]],
|
||||
"Not before edition 1001" => [(new Context)->subscription(5)->oldestEdition(1001), [20]],
|
||||
"Not after article 3" => [(new Context)->latestArticle(3), [1,2,3]],
|
||||
"Not before article 19" => [(new Context)->oldestArticle(19), [19,20]],
|
||||
"Modified by author since 2005" => [(new Context)->modifiedSince("2005-01-01T00:00:00Z"), [2,4,6,8,20]],
|
||||
"Modified by author since 2010" => [(new Context)->modifiedSince("2010-01-01T00:00:00Z"), [2,4,6,8,20]],
|
||||
"Not modified by author since 2005" => [(new Context)->notModifiedSince("2005-01-01T00:00:00Z"), [1,3,5,7,19]],
|
||||
"Not modified by author since 2000" => [(new Context)->notModifiedSince("2000-01-01T00:00:00Z"), [1,3,5,7,19]],
|
||||
"Marked or labelled since 2014" => [(new Context)->markedSince("2014-01-01T00:00:00Z"), [8,19]],
|
||||
"Marked or labelled since 2010" => [(new Context)->markedSince("2010-01-01T00:00:00Z"), [2,4,6,8,19,20]],
|
||||
"Not marked or labelled since 2014" => [(new Context)->notMarkedSince("2014-01-01T00:00:00Z"), [1,2,3,4,5,6,7,20]],
|
||||
"Not marked or labelled since 2005" => [(new Context)->notMarkedSince("2005-01-01T00:00:00Z"), [1,3,5,7]],
|
||||
"Marked or labelled between 2000 and 2015" => [(new Context)->markedSince("2000-01-01T00:00:00Z")->notMarkedSince("2015-12-31T23:59:59Z"), [1,2,3,4,5,6,7,8,20]],
|
||||
"Marked or labelled in 2010" => [(new Context)->markedSince("2010-01-01T00:00:00Z")->notMarkedSince("2010-12-31T23:59:59Z"), [2,4,6,20]],
|
||||
"Paged results" => [(new Context)->limit(2)->oldestEdition(4), [4,5]],
|
||||
"Reversed paged results" => [(new Context)->limit(2)->latestEdition(7)->reverse(true), [7,6]],
|
||||
"With label ID 1" => [(new Context)->label(1), [1,19]],
|
||||
"With label ID 2" => [(new Context)->label(2), [1,5,20]],
|
||||
"With label 'Interesting'" => [(new Context)->labelName("Interesting"), [1,19]],
|
||||
"With label 'Fascinating'" => [(new Context)->labelName("Fascinating"), [1,5,20]],
|
||||
"Article ID 20" => [(new Context)->article(20), [20]],
|
||||
"Edition ID 1001" => [(new Context)->edition(1001), [20]],
|
||||
"Multiple articles" => [(new Context)->articles([1,20,50]), [1,20]],
|
||||
"Multiple starred articles" => [(new Context)->articles([1,2,3])->starred(true), [1]],
|
||||
"Multiple unstarred articles" => [(new Context)->articles([1,2,3])->starred(false), [2,3]],
|
||||
"Multiple articles" => [(new Context)->articles([1,20,50]), [1,20]],
|
||||
"Multiple editions" => [(new Context)->editions([1,1001,50]), [1,20]],
|
||||
"150 articles" => [(new Context)->articles(range(1, Database::LIMIT_SET_SIZE * 3)), [1,2,3,4,5,6,7,8,19,20]],
|
||||
"Search title or content 1" => [(new Context)->searchTerms(["Article"]), [1,2,3]],
|
||||
"Search title or content 2" => [(new Context)->searchTerms(["one", "first"]), [1]],
|
||||
"Search title or content 3" => [(new Context)->searchTerms(["one first"]), []],
|
||||
"Search title 1" => [(new Context)->titleTerms(["two"]), [2]],
|
||||
"Search title 2" => [(new Context)->titleTerms(["title two"]), [2]],
|
||||
"Search title 3" => [(new Context)->titleTerms(["two", "title"]), [2]],
|
||||
"Search title 4" => [(new Context)->titleTerms(["two title"]), []],
|
||||
"Search note 1" => [(new Context)->annotationTerms(["some"]), [2]],
|
||||
"Search note 2" => [(new Context)->annotationTerms(["some Note"]), [2]],
|
||||
"Search note 3" => [(new Context)->annotationTerms(["note", "some"]), [2]],
|
||||
"Search note 4" => [(new Context)->annotationTerms(["some", "sauce"]), []],
|
||||
"Search author 1" => [(new Context)->authorTerms(["doe"]), [4,5,6,7]],
|
||||
"Search author 2" => [(new Context)->authorTerms(["jane doe"]), [6,7]],
|
||||
"Search author 3" => [(new Context)->authorTerms(["doe", "jane"]), [6,7]],
|
||||
"Search author 4" => [(new Context)->authorTerms(["doe jane"]), []],
|
||||
"Folder tree 1 excluding subscription 4" => [(new Context)->not->subscription(4)->folder(1), [5,6]],
|
||||
"Folder tree 1 excluding articles 7 and 8" => [(new Context)->folder(1)->not->articles([7,8]), [5,6]],
|
||||
"Folder tree 1 excluding no articles" => [(new Context)->folder(1)->not->articles([]), [5,6,7,8]],
|
||||
"Marked or labelled between 2000 and 2015 excluding in 2010" => [(new Context)->markedSince("2000-01-01T00:00:00Z")->notMarkedSince("2015-12-31T23:59:59")->not->markedSince("2010-01-01T00:00:00Z")->not->notMarkedSince("2010-12-31T23:59:59Z"), [1,3,5,7,8]],
|
||||
"Search with exclusion" => [(new Context)->searchTerms(["Article"])->not->searchTerms(["one", "two"]), [3]],
|
||||
"Excluded folder tree" => [(new Context)->not->folder(1), [1,2,3,4,19,20]],
|
||||
"Excluding label ID 2" => [(new Context)->not->label(2), [2,3,4,6,7,8,19]],
|
||||
"Excluding label 'Fascinating'" => [(new Context)->not->labelName("Fascinating"), [2,3,4,6,7,8,19]],
|
||||
"Search 501 terms" => [(new Context)->searchTerms(array_merge(range(1,500),[str_repeat("a", 1000)])), []],
|
||||
'Blank context' => [new Context, [1,2,3,4,5,6,7,8,19,20]],
|
||||
'Folder tree' => [(new Context)->folder(1), [5,6,7,8]],
|
||||
'Leaf folder' => [(new Context)->folder(6), [7,8]],
|
||||
'Root folder only' => [(new Context)->folderShallow(0), [1,2,3,4]],
|
||||
'Shallow folder' => [(new Context)->folderShallow(1), [5,6]],
|
||||
'Subscription' => [(new Context)->subscription(5), [19,20]],
|
||||
'Unread' => [(new Context)->subscription(5)->unread(true), [20]],
|
||||
'Read' => [(new Context)->subscription(5)->unread(false), [19]],
|
||||
'Starred' => [(new Context)->starred(true), [1,20]],
|
||||
'Unstarred' => [(new Context)->starred(false), [2,3,4,5,6,7,8,19]],
|
||||
'Starred and Read' => [(new Context)->starred(true)->unread(false), [1]],
|
||||
'Starred and Read in subscription' => [(new Context)->starred(true)->unread(false)->subscription(5), []],
|
||||
'Annotated' => [(new Context)->annotated(true), [2]],
|
||||
'Not annotated' => [(new Context)->annotated(false), [1,3,4,5,6,7,8,19,20]],
|
||||
'Labelled' => [(new Context)->labelled(true), [1,5,8,19,20]],
|
||||
'Not labelled' => [(new Context)->labelled(false), [2,3,4,6,7]],
|
||||
'Not after edition 999' => [(new Context)->subscription(5)->latestEdition(999), [19]],
|
||||
'Not after edition 19' => [(new Context)->subscription(5)->latestEdition(19), [19]],
|
||||
'Not before edition 999' => [(new Context)->subscription(5)->oldestEdition(999), [20]],
|
||||
'Not before edition 1001' => [(new Context)->subscription(5)->oldestEdition(1001), [20]],
|
||||
'Not after article 3' => [(new Context)->latestArticle(3), [1,2,3]],
|
||||
'Not before article 19' => [(new Context)->oldestArticle(19), [19,20]],
|
||||
'Modified by author since 2005' => [(new Context)->modifiedSince("2005-01-01T00:00:00Z"), [2,4,6,8,20]],
|
||||
'Modified by author since 2010' => [(new Context)->modifiedSince("2010-01-01T00:00:00Z"), [2,4,6,8,20]],
|
||||
'Not modified by author since 2005' => [(new Context)->notModifiedSince("2005-01-01T00:00:00Z"), [1,3,5,7,19]],
|
||||
'Not modified by author since 2000' => [(new Context)->notModifiedSince("2000-01-01T00:00:00Z"), [1,3,5,7,19]],
|
||||
'Marked or labelled since 2014' => [(new Context)->markedSince("2014-01-01T00:00:00Z"), [8,19]],
|
||||
'Marked or labelled since 2010' => [(new Context)->markedSince("2010-01-01T00:00:00Z"), [2,4,6,8,19,20]],
|
||||
'Not marked or labelled since 2014' => [(new Context)->notMarkedSince("2014-01-01T00:00:00Z"), [1,2,3,4,5,6,7,20]],
|
||||
'Not marked or labelled since 2005' => [(new Context)->notMarkedSince("2005-01-01T00:00:00Z"), [1,3,5,7]],
|
||||
'Marked or labelled between 2000 and 2015' => [(new Context)->markedSince("2000-01-01T00:00:00Z")->notMarkedSince("2015-12-31T23:59:59Z"), [1,2,3,4,5,6,7,8,20]],
|
||||
'Marked or labelled in 2010' => [(new Context)->markedSince("2010-01-01T00:00:00Z")->notMarkedSince("2010-12-31T23:59:59Z"), [2,4,6,20]],
|
||||
'Paged results' => [(new Context)->limit(2)->oldestEdition(4), [4,5]],
|
||||
'Reversed paged results' => [(new Context)->limit(2)->latestEdition(7)->reverse(true), [7,6]],
|
||||
'With label ID 1' => [(new Context)->label(1), [1,19]],
|
||||
'With label ID 2' => [(new Context)->label(2), [1,5,20]],
|
||||
'With label "Interesting"' => [(new Context)->labelName("Interesting"), [1,19]],
|
||||
'With label "Fascinating"' => [(new Context)->labelName("Fascinating"), [1,5,20]],
|
||||
'Article ID 20' => [(new Context)->article(20), [20]],
|
||||
'Edition ID 1001' => [(new Context)->edition(1001), [20]],
|
||||
'Multiple articles' => [(new Context)->articles([1,20,50]), [1,20]],
|
||||
'Multiple starred articles' => [(new Context)->articles([1,2,3])->starred(true), [1]],
|
||||
'Multiple unstarred articles' => [(new Context)->articles([1,2,3])->starred(false), [2,3]],
|
||||
'Multiple articles' => [(new Context)->articles([1,20,50]), [1,20]],
|
||||
'Multiple editions' => [(new Context)->editions([1,1001,50]), [1,20]],
|
||||
'150 articles' => [(new Context)->articles(range(1, Database::LIMIT_SET_SIZE * 3)), [1,2,3,4,5,6,7,8,19,20]],
|
||||
'Search title or content 1' => [(new Context)->searchTerms(["Article"]), [1,2,3]],
|
||||
'Search title or content 2' => [(new Context)->searchTerms(["one", "first"]), [1]],
|
||||
'Search title or content 3' => [(new Context)->searchTerms(["one first"]), []],
|
||||
'Search title 1' => [(new Context)->titleTerms(["two"]), [2]],
|
||||
'Search title 2' => [(new Context)->titleTerms(["title two"]), [2]],
|
||||
'Search title 3' => [(new Context)->titleTerms(["two", "title"]), [2]],
|
||||
'Search title 4' => [(new Context)->titleTerms(["two title"]), []],
|
||||
'Search note 1' => [(new Context)->annotationTerms(["some"]), [2]],
|
||||
'Search note 2' => [(new Context)->annotationTerms(["some Note"]), [2]],
|
||||
'Search note 3' => [(new Context)->annotationTerms(["note", "some"]), [2]],
|
||||
'Search note 4' => [(new Context)->annotationTerms(["some", "sauce"]), []],
|
||||
'Search author 1' => [(new Context)->authorTerms(["doe"]), [4,5,6,7]],
|
||||
'Search author 2' => [(new Context)->authorTerms(["jane doe"]), [6,7]],
|
||||
'Search author 3' => [(new Context)->authorTerms(["doe", "jane"]), [6,7]],
|
||||
'Search author 4' => [(new Context)->authorTerms(["doe jane"]), []],
|
||||
'Folder tree 1 excluding subscription 4' => [(new Context)->not->subscription(4)->folder(1), [5,6]],
|
||||
'Folder tree 1 excluding articles 7 and 8' => [(new Context)->folder(1)->not->articles([7,8]), [5,6]],
|
||||
'Folder tree 1 excluding no articles' => [(new Context)->folder(1)->not->articles([]), [5,6,7,8]],
|
||||
'Marked or labelled between 2000 and 2015 excluding in 2010' => [(new Context)->markedSince("2000-01-01T00:00:00Z")->notMarkedSince("2015-12-31T23:59:59")->not->markedSince("2010-01-01T00:00:00Z")->not->notMarkedSince("2010-12-31T23:59:59Z"), [1,3,5,7,8]],
|
||||
'Search with exclusion' => [(new Context)->searchTerms(["Article"])->not->searchTerms(["one", "two"]), [3]],
|
||||
'Excluded folder tree' => [(new Context)->not->folder(1), [1,2,3,4,19,20]],
|
||||
'Excluding label ID 2' => [(new Context)->not->label(2), [2,3,4,6,7,8,19]],
|
||||
'Excluding label "Fascinating"' => [(new Context)->not->labelName("Fascinating"), [2,3,4,6,7,8,19]],
|
||||
'Search 501 terms' => [(new Context)->searchTerms(array_merge(range(1,500),[str_repeat("a", 1000)])), []],
|
||||
'With tag ID 1' => [(new Context)->tag(1), [5,6,7,8]],
|
||||
'With tag ID 5' => [(new Context)->tag(5), [7,8,19,20]],
|
||||
'With tag "Technology"' => [(new Context)->tagName("Technology"), [5,6,7,8]],
|
||||
'With tag "Politics"' => [(new Context)->tagName("Politics"), [7,8,19,20]],
|
||||
'Excluding tag ID 1' => [(new Context)->not->tag(1), [1,2,3,4,19,20]],
|
||||
'Excluding tag ID 5' => [(new Context)->not->tag(5), [1,2,3,4,5,6]],
|
||||
'Excluding tag "Technology"' => [(new Context)->not->tagName("Technology"), [1,2,3,4,19,20]],
|
||||
'Excluding tag "Politics"' => [(new Context)->not->tagName("Politics"), [1,2,3,4,5,6]],
|
||||
];
|
||||
}
|
||||
|
||||
|
|
|
@ -30,6 +30,8 @@ class TestContext extends \JKingWeb\Arsse\Test\AbstractTest {
|
|||
'offset' => 5,
|
||||
'folder' => 42,
|
||||
'folderShallow' => 42,
|
||||
'tag' => 44,
|
||||
'tagName' => "XLIV",
|
||||
'subscription' => 2112,
|
||||
'article' => 255,
|
||||
'edition' => 65535,
|
||||
|
|
Loading…
Reference in a new issue