mirror of
https://code.mensbeam.com/MensBeam/Arsse.git
synced 2024-12-22 13:12:41 +00:00
Retrofits dates to use ranges
Article and edition ranges still need work
This commit is contained in:
parent
73497688fc
commit
2c2bb4a856
15 changed files with 161 additions and 188 deletions
|
@ -164,39 +164,39 @@ trait ExclusionMethods {
|
|||
return $this->act(__FUNCTION__, func_num_args(), $spec);
|
||||
}
|
||||
|
||||
public function latestArticle(int $spec = null) {
|
||||
public function articleRange(?int $start = null, ?int $end = null) {
|
||||
if ($start === null && $end === null) {
|
||||
$spec = null;
|
||||
} else {
|
||||
$spec = [$start, $end];
|
||||
}
|
||||
return $this->act(__FUNCTION__, func_num_args(), $spec);
|
||||
}
|
||||
|
||||
public function oldestArticle(int $spec = null) {
|
||||
public function editionRange(?int $start = null, ?int $end = null) {
|
||||
if ($start === null && $end === null) {
|
||||
$spec = null;
|
||||
} else {
|
||||
$spec = [$start, $end];
|
||||
}
|
||||
return $this->act(__FUNCTION__, func_num_args(), $spec);
|
||||
}
|
||||
|
||||
public function latestEdition(int $spec = null) {
|
||||
public function modifiedRange($start = null, $end = null) {
|
||||
if ($start === null && $end === null) {
|
||||
$spec = null;
|
||||
} else {
|
||||
$spec = [Date::normalize($start), Date::normalize($end)];
|
||||
}
|
||||
return $this->act(__FUNCTION__, func_num_args(), $spec);
|
||||
}
|
||||
|
||||
public function oldestEdition(int $spec = null) {
|
||||
return $this->act(__FUNCTION__, func_num_args(), $spec);
|
||||
}
|
||||
|
||||
public function modifiedSince($spec = null) {
|
||||
$spec = Date::normalize($spec);
|
||||
return $this->act(__FUNCTION__, func_num_args(), $spec);
|
||||
}
|
||||
|
||||
public function notModifiedSince($spec = null) {
|
||||
$spec = Date::normalize($spec);
|
||||
return $this->act(__FUNCTION__, func_num_args(), $spec);
|
||||
}
|
||||
|
||||
public function markedSince($spec = null) {
|
||||
$spec = Date::normalize($spec);
|
||||
return $this->act(__FUNCTION__, func_num_args(), $spec);
|
||||
}
|
||||
|
||||
public function notMarkedSince($spec = null) {
|
||||
$spec = Date::normalize($spec);
|
||||
public function markedRange($start = null, $end = null) {
|
||||
if ($start === null && $end === null) {
|
||||
$spec = null;
|
||||
} else {
|
||||
$spec = [Date::normalize($start), Date::normalize($end)];
|
||||
}
|
||||
return $this->act(__FUNCTION__, func_num_args(), $spec);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,12 +29,8 @@ trait ExclusionProperties {
|
|||
public $searchTerms = null;
|
||||
public $titleTerms = null;
|
||||
public $authorTerms = null;
|
||||
public $oldestArticle = null;
|
||||
public $latestArticle = null;
|
||||
public $oldestEdition = null;
|
||||
public $latestEdition = null;
|
||||
public $modifiedSince = null;
|
||||
public $notModifiedSince = null;
|
||||
public $markedSince = null;
|
||||
public $notMarkedSince = null;
|
||||
public $articleRange = [null, null];
|
||||
public $editionRange = [null, null];
|
||||
public $modifiedRange = [null, null];
|
||||
public $markedRange = [null, null];
|
||||
}
|
||||
|
|
|
@ -1556,31 +1556,30 @@ class Database {
|
|||
$q->setLimit($context->limit, $context->offset);
|
||||
// handle the simple context options
|
||||
$options = [
|
||||
// each context array consists of a column identifier (see $colDefs above), a comparison operator, a data type, and an option to pair with for BETWEEN evaluation
|
||||
"edition" => ["edition", "=", "int", ""],
|
||||
"editions" => ["edition", "in", "int", ""],
|
||||
"article" => ["id", "=", "int", ""],
|
||||
"articles" => ["id", "in", "int", ""],
|
||||
"oldestArticle" => ["id", ">=", "int", "latestArticle"],
|
||||
"latestArticle" => ["id", "<=", "int", "oldestArticle"],
|
||||
"oldestEdition" => ["edition", ">=", "int", "latestEdition"],
|
||||
"latestEdition" => ["edition", "<=", "int", "oldestEdition"],
|
||||
"modifiedSince" => ["modified_date", ">=", "datetime", "notModifiedSince"],
|
||||
"notModifiedSince" => ["modified_date", "<=", "datetime", "modifiedSince"],
|
||||
"markedSince" => ["marked_date", ">=", "datetime", "notMarkedSince"],
|
||||
"notMarkedSince" => ["marked_date", "<=", "datetime", "markedSince"],
|
||||
"folderShallow" => ["folder", "=", "int", ""],
|
||||
"foldersShallow" => ["folder", "in", "int", ""],
|
||||
"subscription" => ["subscription", "=", "int", ""],
|
||||
"subscriptions" => ["subscription", "in", "int", ""],
|
||||
"unread" => ["unread", "=", "bool", ""],
|
||||
"starred" => ["starred", "=", "bool", ""],
|
||||
"hidden" => ["hidden", "=", "bool", ""],
|
||||
// each context array consists of a column identifier (see $colDefs above), a comparison operator, and a data type; the "between" operator has special handling
|
||||
"edition" => ["edition", "=", "int"],
|
||||
"editions" => ["edition", "in", "int"],
|
||||
"article" => ["id", "=", "int"],
|
||||
"articles" => ["id", "in", "int"],
|
||||
"articleRange" => ["id", "between", "int"],
|
||||
"editionRange" => ["edition", "between", "int"],
|
||||
"modifiedRange" => ["modified_date", "between", "datetime"],
|
||||
"markedRange" => ["marked_date", "between", "datetime"],
|
||||
"folderShallow" => ["folder", "=", "int"],
|
||||
"foldersShallow" => ["folder", "in", "int"],
|
||||
"subscription" => ["subscription", "=", "int"],
|
||||
"subscriptions" => ["subscription", "in", "int"],
|
||||
"unread" => ["unread", "=", "bool"],
|
||||
"starred" => ["starred", "=", "bool"],
|
||||
"hidden" => ["hidden", "=", "bool"],
|
||||
];
|
||||
foreach ($options as $m => [$col, $op, $type, $pair]) {
|
||||
foreach ($options as $m => [$col, $op, $type]) {
|
||||
if (!$context->$m()) {
|
||||
// context is not being used
|
||||
continue;
|
||||
} elseif ($op === "between") {
|
||||
// option is a range
|
||||
$q->setWhereNot("{$colDefs[$col]} BETWEEN ? AND ?", [$type, $type], $context->$m);
|
||||
} elseif (is_array($context->$m)) {
|
||||
// context option is an array of values
|
||||
if (!$context->$m) {
|
||||
|
@ -1588,23 +1587,18 @@ class Database {
|
|||
}
|
||||
[$clause, $types, $values] = $this->generateIn($context->$m, $type);
|
||||
$q->setWhere("{$colDefs[$col]} $op ($clause)", $types, $values);
|
||||
} elseif ($pair && $context->$pair()) {
|
||||
// option is paired with another which is also being used
|
||||
if ($op === ">=") {
|
||||
$q->setWhere("{$colDefs[$col]} BETWEEN ? AND ?", [$type, $type], [$context->$m, $context->$pair]);
|
||||
} else {
|
||||
// option has already been paired
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
$q->setWhere("{$colDefs[$col]} $op ?", $type, $context->$m);
|
||||
}
|
||||
}
|
||||
// further handle exclusionary options if specified
|
||||
foreach ($options as $m => [$col, $op, $type, $pair]) {
|
||||
foreach ($options as $m => [$col, $op, $type]) {
|
||||
if (!method_exists($context->not, $m) || !$context->not->$m()) {
|
||||
// context option is not being used
|
||||
continue;
|
||||
} elseif ($op === "between") {
|
||||
// option is a range
|
||||
$q->setWhereNot("{$colDefs[$col]} BETWEEN ? AND ?", [$type, $type], $context->not->$m);
|
||||
} elseif (is_array($context->not->$m)) {
|
||||
if (!$context->not->$m) {
|
||||
// for exclusions we don't care if the array is empty
|
||||
|
@ -1612,14 +1606,6 @@ class Database {
|
|||
}
|
||||
[$clause, $types, $values] = $this->generateIn($context->not->$m, $type);
|
||||
$q->setWhereNot("{$colDefs[$col]} $op ($clause)", $types, $values);
|
||||
} elseif ($pair && $context->not->$pair()) {
|
||||
// option is paired with another which is also being used
|
||||
if ($op === ">=") {
|
||||
$q->setWhereNot("{$colDefs[$col]} BETWEEN ? AND ?", [$type, $type], [$context->not->$m, $context->not->$pair]);
|
||||
} else {
|
||||
// option has already been paired
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
$q->setWhereNot("{$colDefs[$col]} $op ?", $type, $context->not->$m);
|
||||
}
|
||||
|
|
|
@ -244,7 +244,7 @@ class API extends \JKingWeb\Arsse\REST\AbstractHandler {
|
|||
$c = new Context;
|
||||
$id = $P['id'];
|
||||
if ($P['before']) {
|
||||
$c->notMarkedSince($P['before']);
|
||||
$c->markedRange(null, $P['before']);
|
||||
}
|
||||
switch ($P['mark']) {
|
||||
case "item":
|
||||
|
@ -310,7 +310,7 @@ class API extends \JKingWeb\Arsse\REST\AbstractHandler {
|
|||
$c = (new Context)->hidden(false);
|
||||
$lastUnread = Date::normalize($lastUnread, "sql");
|
||||
$since = Date::sub("PT15S", $lastUnread);
|
||||
$c->unread(false)->markedSince($since);
|
||||
$c->unread(false)->markedRange($since, null);
|
||||
Arsse::$db->articleMark(Arsse::$user->id, ['read' => false], $c);
|
||||
}
|
||||
|
||||
|
|
|
@ -893,8 +893,7 @@ class V1 extends \JKingWeb\Arsse\REST\AbstractHandler {
|
|||
->limit($query['limit'] ?? self::DEFAULT_ENTRY_LIMIT) // NOTE: This does not honour user preferences
|
||||
->offset($query['offset'])
|
||||
->starred($query['starred'])
|
||||
->modifiedSince($query['after']) // FIXME: This may not be the correct date field
|
||||
->notModifiedSince($query['before'])
|
||||
->modifiedRange($query['after'], $query['before']) // FIXME: This may not be the correct date field
|
||||
->oldestArticle($query['after_entry_id'] ? $query['after_entry_id'] + 1 : null) // FIXME: This might be edition
|
||||
->latestArticle($query['before_entry_id'] ? $query['before_entry_id'] - 1 : null)
|
||||
->searchTerms(strlen($query['search'] ?? "") ? preg_split("/\s+/", $query['search']) : null); // NOTE: Miniflux matches only whole words; we match simple substrings
|
||||
|
|
|
@ -556,7 +556,7 @@ class V1_2 extends \JKingWeb\Arsse\REST\AbstractHandler {
|
|||
}
|
||||
// whether to return only updated items
|
||||
if ($data['lastModified']) {
|
||||
$c->markedSince($data['lastModified']);
|
||||
$c->markedRange($data['lastModified'], null);
|
||||
}
|
||||
// perform the fetch
|
||||
try {
|
||||
|
|
|
@ -256,7 +256,7 @@ class API extends \JKingWeb\Arsse\REST\AbstractHandler {
|
|||
public function opGetCounters(array $data): array {
|
||||
$user = Arsse::$user->id;
|
||||
$starred = Arsse::$db->articleStarred($user);
|
||||
$fresh = Arsse::$db->articleCount($user, (new Context)->unread(true)->modifiedSince(Date::sub("PT24H", $this->now()))->hidden(false));
|
||||
$fresh = Arsse::$db->articleCount($user, (new Context)->unread(true)->modifiedRange(Date::sub("PT24H", $this->now()), null)->hidden(false));
|
||||
$countAll = 0;
|
||||
$countSubs = 0;
|
||||
$feeds = [];
|
||||
|
@ -361,7 +361,7 @@ class API extends \JKingWeb\Arsse\REST\AbstractHandler {
|
|||
'id' => "FEED:".self::FEED_FRESH,
|
||||
'bare_id' => self::FEED_FRESH,
|
||||
'icon' => "images/fresh.png",
|
||||
'unread' => Arsse::$db->articleCount($user, (new Context)->unread(true)->modifiedSince(Date::sub("PT24H", $this->now()))->hidden(false)),
|
||||
'unread' => Arsse::$db->articleCount($user, (new Context)->unread(true)->modifiedRange(Date::sub("PT24H", $this->now()), null)->hidden(false)),
|
||||
], $tSpecial),
|
||||
array_merge([ // Starred articles
|
||||
'name' => Arsse::$lang->msg("API.TTRSS.Feed.Starred"),
|
||||
|
@ -545,7 +545,7 @@ class API extends \JKingWeb\Arsse\REST\AbstractHandler {
|
|||
// FIXME: this is pretty inefficient
|
||||
$f = $map[self::CAT_SPECIAL];
|
||||
$cats[$f]['unread'] += Arsse::$db->articleStarred($user)['unread']; // starred
|
||||
$cats[$f]['unread'] += Arsse::$db->articleCount($user, (new Context)->unread(true)->modifiedSince(Date::sub("PT24H", $this->now()))->hidden(false)); // fresh
|
||||
$cats[$f]['unread'] += Arsse::$db->articleCount($user, (new Context)->unread(true)->modifiedRange(Date::sub("PT24H", $this->now()), null)->hidden(false)); // fresh
|
||||
if (!$read) {
|
||||
// if we're only including unread entries, remove any categories with zero unread items (this will by definition also exclude empties)
|
||||
$count = sizeof($cats);
|
||||
|
@ -697,7 +697,7 @@ class API extends \JKingWeb\Arsse\REST\AbstractHandler {
|
|||
if ($cat == self::CAT_ALL || $cat == self::CAT_SPECIAL) {
|
||||
// gather some statistics
|
||||
$starred = Arsse::$db->articleStarred($user)['unread'];
|
||||
$fresh = Arsse::$db->articleCount($user, (new Context)->unread(true)->modifiedSince(Date::sub("PT24H", $this->now()))->hidden(false));
|
||||
$fresh = Arsse::$db->articleCount($user, (new Context)->unread(true)->modifiedRange(Date::sub("PT24H", $this->now()), null)->hidden(false));
|
||||
$global = Arsse::$db->articleCount($user, (new Context)->unread(true)->hidden(false));
|
||||
$published = 0; // TODO: if the Published feed is implemented, the getFeeds method needs to be adjusted accordingly
|
||||
$archived = 0; // the archived feed is non-functional in the TT-RSS protocol itself
|
||||
|
@ -1096,7 +1096,7 @@ class API extends \JKingWeb\Arsse\REST\AbstractHandler {
|
|||
// TODO: if the Published feed is implemented, the catchup function needs to be modified accordingly
|
||||
return $out;
|
||||
case self::FEED_FRESH:
|
||||
$c->modifiedSince(Date::sub("PT24H", $this->now()));
|
||||
$c->modifiedRange(Date::sub("PT24H", $this->now()), null);
|
||||
break;
|
||||
case self::FEED_ALL:
|
||||
// no context needed here
|
||||
|
@ -1112,13 +1112,13 @@ class API extends \JKingWeb\Arsse\REST\AbstractHandler {
|
|||
}
|
||||
switch ($mode) {
|
||||
case "2week":
|
||||
$c->notModifiedSince(Date::sub("P2W", $this->now()));
|
||||
$c->modifiedRange($c->modifiedRange[0], Date::sub("P2W", $this->now()));
|
||||
break;
|
||||
case "1week":
|
||||
$c->notModifiedSince(Date::sub("P1W", $this->now()));
|
||||
$c->modifiedRange($c->modifiedRange[0], Date::sub("P1W", $this->now()));
|
||||
break;
|
||||
case "1day":
|
||||
$c->notModifiedSince(Date::sub("PT24H", $this->now()));
|
||||
$c->modifiedRange($c->modifiedRange[0], Date::sub("PT24H", $this->now()));
|
||||
}
|
||||
// perform the marking
|
||||
try {
|
||||
|
@ -1473,13 +1473,13 @@ class API extends \JKingWeb\Arsse\REST\AbstractHandler {
|
|||
// TODO: if the Published feed is implemented, the headline function needs to be modified accordingly
|
||||
return new ResultEmpty;
|
||||
case self::FEED_FRESH:
|
||||
$c->modifiedSince(Date::sub("PT24H", $this->now()))->unread(true);
|
||||
$c->modifiedRange(Date::sub("PT24H", $this->now()), null)->unread(true);
|
||||
break;
|
||||
case self::FEED_ALL:
|
||||
// no context needed here
|
||||
break;
|
||||
case self::FEED_READ:
|
||||
$c->markedSince(Date::sub("PT24H", $this->now()))->unread(false); // FIXME: this selects any recently touched (read, starred, annotated) article which is read, not necessarily a recently read one
|
||||
$c->markedRange(Date::sub("PT24H", $this->now()), null)->unread(false); // FIXME: this selects any recently touched (read, starred, annotated) article which is read, not necessarily a recently read one
|
||||
break;
|
||||
default:
|
||||
// any actual feed
|
||||
|
|
|
@ -320,16 +320,15 @@ class Search {
|
|||
$end = $day."T23:59:59+00:00";
|
||||
// if a date is already set, the same date is a no-op; anything else is a contradiction
|
||||
$cc = $neg ? $c->not : $c;
|
||||
if ($cc->modifiedSince() || $cc->notModifiedSince()) {
|
||||
if (!$cc->modifiedSince() || !$cc->notModifiedSince() || $cc->modifiedSince->format("c") !== $start || $cc->notModifiedSince->format("c") !== $end) {
|
||||
if ($cc->modifiedRange()) {
|
||||
if (!$cc->modifiedRange[0] || !$cc->modifiedRange[1] || $cc->modifiedRange[0]->format("c") !== $start || $cc->modifiedRange[1]->format("c") !== $end) {
|
||||
// FIXME: multiple negative dates should be allowed, but the design of the Context class does not support this
|
||||
throw new Exception;
|
||||
} else {
|
||||
return $c;
|
||||
}
|
||||
}
|
||||
$cc->modifiedSince($start);
|
||||
$cc->notModifiedSince($end);
|
||||
$cc->modifiedRange($start, $end);
|
||||
return $c;
|
||||
}
|
||||
|
||||
|
|
|
@ -462,16 +462,16 @@ trait SeriesArticle {
|
|||
'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]],
|
||||
'Modified by author since 2005' => [(new Context)->modifiedRange("2005-01-01T00:00:00Z", null), [2,4,6,8,20]],
|
||||
'Modified by author since 2010' => [(new Context)->modifiedRange("2010-01-01T00:00:00Z", null), [2,4,6,8,20]],
|
||||
'Not modified by author since 2005' => [(new Context)->modifiedRange(null, "2005-01-01T00:00:00Z"), [1,3,5,7,19]],
|
||||
'Not modified by author since 2000' => [(new Context)->modifiedRange(null, "2000-01-01T00:00:00Z"), [1,3,5,7,19]],
|
||||
'Marked or labelled since 2014' => [(new Context)->markedRange("2014-01-01T00:00:00Z", null), [8,19]],
|
||||
'Marked or labelled since 2010' => [(new Context)->markedRange("2010-01-01T00:00:00Z", null), [2,4,6,8,19,20]],
|
||||
'Not marked or labelled since 2014' => [(new Context)->markedRange(null, "2014-01-01T00:00:00Z"), [1,2,3,4,5,6,7,20]],
|
||||
'Not marked or labelled since 2005' => [(new Context)->markedRange(null, "2005-01-01T00:00:00Z"), [1,3,5,7]],
|
||||
'Marked or labelled between 2000 and 2015' => [(new Context)->markedRange("2000-01-01T00:00:00Z", "2015-12-31T23:59:59Z"), [1,2,3,4,5,6,7,8,20]],
|
||||
'Marked or labelled in 2010' => [(new Context)->markedRange("2010-01-01T00:00:00Z", "2010-12-31T23:59:59Z"), [2,4,6,20]],
|
||||
'Paged results' => [(new Context)->limit(2)->oldestEdition(4), [4,5]],
|
||||
'With label ID 1' => [(new Context)->label(1), [1,19]],
|
||||
'With label ID 2' => [(new Context)->label(2), [1,5,20]],
|
||||
|
@ -505,7 +505,7 @@ trait SeriesArticle {
|
|||
'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]],
|
||||
'Marked or labelled between 2000 and 2015 excluding in 2010' => [(new Context)->markedRange("2000-01-01T00:00:00Z", "2015-12-31T23:59:59")->not->markedRange("2010-01-01T00:00:00Z", "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]],
|
||||
|
@ -953,7 +953,7 @@ trait SeriesArticle {
|
|||
}
|
||||
|
||||
public function testMarkByLastMarked(): void {
|
||||
Arsse::$db->articleMark($this->user, ['starred' => true], (new Context)->markedSince('2017-01-01T00:00:00Z'));
|
||||
Arsse::$db->articleMark($this->user, ['starred' => true], (new Context)->markedRange('2017-01-01T00:00:00Z', null));
|
||||
$now = Date::transform(time(), "sql");
|
||||
$state = $this->primeExpectations($this->data, $this->checkTables);
|
||||
$state['arsse_marks']['rows'][8][3] = 1;
|
||||
|
@ -964,7 +964,7 @@ trait SeriesArticle {
|
|||
}
|
||||
|
||||
public function testMarkByNotLastMarked(): void {
|
||||
Arsse::$db->articleMark($this->user, ['starred' => true], (new Context)->notMarkedSince('2000-01-01T00:00:00Z'));
|
||||
Arsse::$db->articleMark($this->user, ['starred' => true], (new Context)->markedRange(null, '2000-01-01T00:00:00Z'));
|
||||
$now = Date::transform(time(), "sql");
|
||||
$state = $this->primeExpectations($this->data, $this->checkTables);
|
||||
$state['arsse_marks']['rows'][] = [13,5,0,1,$now,'',0];
|
||||
|
|
|
@ -47,10 +47,6 @@ class TestContext extends \JKingWeb\Arsse\Test\AbstractTest {
|
|||
'unread' => true,
|
||||
'starred' => true,
|
||||
'hidden' => true,
|
||||
'modifiedSince' => new \DateTime(),
|
||||
'notModifiedSince' => new \DateTime(),
|
||||
'markedSince' => new \DateTime(),
|
||||
'notMarkedSince' => new \DateTime(),
|
||||
'editions' => [1,2],
|
||||
'articles' => [1,2],
|
||||
'label' => 2112,
|
||||
|
@ -65,21 +61,17 @@ class TestContext extends \JKingWeb\Arsse\Test\AbstractTest {
|
|||
'authorTerms' => ["foo", "bar"],
|
||||
'not' => (new Context)->subscription(5),
|
||||
];
|
||||
$times = ['modifiedSince','notModifiedSince','markedSince','notMarkedSince'];
|
||||
$ranges = ['modifiedRange', 'markedRange', 'articleRange', 'editionRange'];
|
||||
$c = new Context;
|
||||
foreach ((new \ReflectionObject($c))->getMethods(\ReflectionMethod::IS_PUBLIC) as $m) {
|
||||
if ($m->isStatic() || strpos($m->name, "__") === 0) {
|
||||
if ($m->isStatic() || strpos($m->name, "__") === 0 || in_array($m->name, $ranges)) {
|
||||
continue;
|
||||
}
|
||||
$method = $m->name;
|
||||
$this->assertArrayHasKey($method, $v, "Context method $method not included in test");
|
||||
$this->assertInstanceOf(Context::class, $c->$method($v[$method]));
|
||||
$this->assertTrue($c->$method());
|
||||
if (in_array($method, $times)) {
|
||||
$this->assertTime($c->$method, $v[$method], "Context method $method did not return the expected results");
|
||||
} else {
|
||||
$this->assertSame($c->$method, $v[$method], "Context method $method did not return the expected results");
|
||||
}
|
||||
$this->assertSame($c->$method, $v[$method], "Context method $method did not return the expected results");
|
||||
// clear the context option
|
||||
$c->$method(null);
|
||||
$this->assertFalse($c->$method());
|
||||
|
|
|
@ -407,7 +407,7 @@ class TestAPI extends \JKingWeb\Arsse\Test\AbstractTest {
|
|||
["mark=group&as=unread&id=-1", (new Context)->not->folder(0), $markUnread, $listUnread],
|
||||
["mark=group&as=saved&id=-1", (new Context)->not->folder(0), $markSaved, $listSaved],
|
||||
["mark=group&as=unsaved&id=-1", (new Context)->not->folder(0), $markUnsaved, $listSaved],
|
||||
["mark=group&as=read&id=-1&before=946684800", (new Context)->not->folder(0)->notMarkedSince("2000-01-01T00:00:00Z"), $markRead, $listUnread],
|
||||
["mark=group&as=read&id=-1&before=946684800", (new Context)->not->folder(0)->markedRange(null, "2000-01-01T00:00:00Z"), $markRead, $listUnread],
|
||||
["mark=item&as=unread", new Context, [], []],
|
||||
["mark=item&id=6", new Context, [], []],
|
||||
["as=unread&id=6", new Context, [], []],
|
||||
|
@ -462,7 +462,7 @@ class TestAPI extends \JKingWeb\Arsse\Test\AbstractTest {
|
|||
$this->dbMock->articleMark->returns(0);
|
||||
$exp = new JsonResponse($out);
|
||||
$this->assertMessage($exp, $this->req("api", ['unread_recently_read' => 1]));
|
||||
$this->dbMock->articleMark->calledWith($this->userId, ['read' => false], $this->equalTo((new Context)->unread(false)->markedSince("1999-12-31T23:59:45Z")->hidden(false)));
|
||||
$this->dbMock->articleMark->calledWith($this->userId, ['read' => false], $this->equalTo((new Context)->unread(false)->markedRange("1999-12-31T23:59:45Z", null)->hidden(false)));
|
||||
$this->dbMock->articleList->with($this->userId, (new Context)->limit(1)->hidden(false), ["marked_date"], ["marked_date desc"])->returns(new Result([]));
|
||||
$this->assertMessage($exp, $this->req("api", ['unread_recently_read' => 1]));
|
||||
$this->dbMock->articleMark->once()->called(); // only called one time, above
|
||||
|
|
|
@ -768,9 +768,10 @@ class TestV1 extends \JKingWeb\Arsse\Test\AbstractTest {
|
|||
["/entries?starred=", (clone $c)->starred(true), $o, self::ENTRIES, false, new Response(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])],
|
||||
["/entries?starred=true", (clone $c)->starred(true), $o, self::ENTRIES, false, new Response(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])],
|
||||
["/entries?starred=false", (clone $c)->starred(true), $o, self::ENTRIES, false, new Response(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])],
|
||||
["/entries?after=0", (clone $c)->modifiedSince(0), $o, self::ENTRIES, false, new Response(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])],
|
||||
["/entries?after=0", (clone $c)->modifiedRange(0, null), $o, self::ENTRIES, false, new Response(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])],
|
||||
["/entries?before=0", $c, $o, self::ENTRIES, false, new Response(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])],
|
||||
["/entries?before=1", (clone $c)->notModifiedSince(1), $o, self::ENTRIES, false, new Response(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])],
|
||||
["/entries?before=1", (clone $c)->modifiedRange(null, 1), $o, self::ENTRIES, false, new Response(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])],
|
||||
["/entries?before=1&after=0", (clone $c)->modifiedRange(0, 1), $o, self::ENTRIES, false, new Response(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])],
|
||||
["/entries?after_entry_id=42", (clone $c)->oldestArticle(43), $o, self::ENTRIES, false, new Response(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])],
|
||||
["/entries?before_entry_id=47", (clone $c)->latestArticle(46), $o, self::ENTRIES, false, new Response(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])],
|
||||
["/entries?search=alpha%20beta", (clone $c)->searchTerms(["alpha", "beta"]), $o, self::ENTRIES, false, new Response(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])],
|
||||
|
|
|
@ -695,7 +695,7 @@ class TestV1_2 extends \JKingWeb\Arsse\Test\AbstractTest {
|
|||
["/items", ['type' => 3, 'id' => 0], clone $c, $out, $r200],
|
||||
["/items", ['getRead' => true], clone $c, $out, $r200],
|
||||
["/items", ['getRead' => false], (clone $c)->unread(true), $out, $r200],
|
||||
["/items", ['lastModified' => $t->getTimestamp()], (clone $c)->markedSince($t), $out, $r200],
|
||||
["/items", ['lastModified' => $t->getTimestamp()], (clone $c)->markedRange($t, null), $out, $r200],
|
||||
["/items", ['oldestFirst' => true, 'batchSize' => 10, 'offset' => 5], (clone $c)->oldestEdition(6)->limit(10), $out, $r200],
|
||||
["/items", ['oldestFirst' => false, 'batchSize' => 5, 'offset' => 5], (clone $c)->latestEdition(4)->limit(5), $out, $r200],
|
||||
["/items", ['oldestFirst' => false, 'batchSize' => 5, 'offset' => 0], (clone $c)->limit(5), $out, $r200],
|
||||
|
@ -708,7 +708,7 @@ class TestV1_2 extends \JKingWeb\Arsse\Test\AbstractTest {
|
|||
["/items/updated", ['type' => 3, 'id' => 0], clone $c, $out, $r200],
|
||||
["/items/updated", ['getRead' => true], clone $c, $out, $r200],
|
||||
["/items/updated", ['getRead' => false], (clone $c)->unread(true), $out, $r200],
|
||||
["/items/updated", ['lastModified' => $t->getTimestamp()], (clone $c)->markedSince($t), $out, $r200],
|
||||
["/items/updated", ['lastModified' => $t->getTimestamp()], (clone $c)->markedRange($t, null), $out, $r200],
|
||||
["/items/updated", ['oldestFirst' => true, 'batchSize' => 10, 'offset' => 5], (clone $c)->oldestEdition(6)->limit(10), $out, $r200],
|
||||
["/items/updated", ['oldestFirst' => false, 'batchSize' => 5, 'offset' => 5], (clone $c)->latestEdition(4)->limit(5), $out, $r200],
|
||||
["/items/updated", ['oldestFirst' => false, 'batchSize' => 5, 'offset' => 0], (clone $c)->limit(5), $out, $r200],
|
||||
|
|
|
@ -959,7 +959,7 @@ LONG_STRING;
|
|||
$this->dbMock->folderList->with("~", null, false)->returns(new Result($this->v($this->topFolders)));
|
||||
$this->dbMock->subscriptionList->returns(new Result($this->v($this->subscriptions)));
|
||||
$this->dbMock->labelList->returns(new Result($this->v($this->labels)));
|
||||
$this->dbMock->articleCount->with("~", $this->equalTo((new Context)->hidden(false)->unread(true)->modifiedSince(Date::sub("PT24H", self::NOW))))->returns(7);
|
||||
$this->dbMock->articleCount->with("~", $this->equalTo((new Context)->hidden(false)->unread(true)->modifiedRange(Date::sub("PT24H", self::NOW), null)))->returns(7);
|
||||
$this->dbMock->articleStarred->returns($this->v($this->starred));
|
||||
$this->assertMessage($exp, $this->req($in));
|
||||
}
|
||||
|
@ -1060,7 +1060,7 @@ LONG_STRING;
|
|||
['id' => -2, 'kind' => "cat", 'counter' => 6],
|
||||
];
|
||||
$this->assertMessage($this->respGood($exp), $this->req($in));
|
||||
$this->dbMock->articleCount->calledWith($this->userId, $this->equalTo((new Context)->hidden(false)->unread(true)->modifiedSince(Date::sub("PT24H", self::NOW))));
|
||||
$this->dbMock->articleCount->calledWith($this->userId, $this->equalTo((new Context)->hidden(false)->unread(true)->modifiedRange(Date::sub("PT24H", self::NOW), null)));
|
||||
}
|
||||
|
||||
/** @dataProvider provideLabelListings */
|
||||
|
@ -1152,7 +1152,7 @@ LONG_STRING;
|
|||
$this->assertMessage($this->respGood($exp), $this->req($in[0]));
|
||||
$exp = ['categories' => ['identifier' => 'id','label' => 'name','items' => [['name' => 'Special','id' => 'CAT:-1','bare_id' => -1,'type' => 'category','unread' => 0,'items' => [['name' => 'All articles','id' => 'FEED:-4','bare_id' => -4,'icon' => 'images/folder.png','unread' => 35,'type' => 'feed','auxcounter' => 0,'error' => '','updated' => ''],['name' => 'Fresh articles','id' => 'FEED:-3','bare_id' => -3,'icon' => 'images/fresh.png','unread' => 7,'type' => 'feed','auxcounter' => 0,'error' => '','updated' => ''],['name' => 'Starred articles','id' => 'FEED:-1','bare_id' => -1,'icon' => 'images/star.png','unread' => 4,'type' => 'feed','auxcounter' => 0,'error' => '','updated' => ''],['name' => 'Published articles','id' => 'FEED:-2','bare_id' => -2,'icon' => 'images/feed.png','unread' => 0,'type' => 'feed','auxcounter' => 0,'error' => '','updated' => ''],['name' => 'Archived articles','id' => 'FEED:0','bare_id' => 0,'icon' => 'images/archive.png','unread' => 0,'type' => 'feed','auxcounter' => 0,'error' => '','updated' => ''],['name' => 'Recently read','id' => 'FEED:-6','bare_id' => -6,'icon' => 'images/time.png','unread' => 0,'type' => 'feed','auxcounter' => 0,'error' => '','updated' => '']]],['name' => 'Labels','id' => 'CAT:-2','bare_id' => -2,'type' => 'category','unread' => 6,'items' => [['name' => 'Fascinating','id' => 'FEED:-1027','bare_id' => -1027,'unread' => 0,'icon' => 'images/label.png','type' => 'feed','auxcounter' => 0,'error' => '','updated' => '','fg_color' => '','bg_color' => ''],['name' => 'Interesting','id' => 'FEED:-1029','bare_id' => -1029,'unread' => 0,'icon' => 'images/label.png','type' => 'feed','auxcounter' => 0,'error' => '','updated' => '','fg_color' => '','bg_color' => ''],['name' => 'Logical','id' => 'FEED:-1025','bare_id' => -1025,'unread' => 0,'icon' => 'images/label.png','type' => 'feed','auxcounter' => 0,'error' => '','updated' => '','fg_color' => '','bg_color' => '']]],['name' => 'Politics','id' => 'CAT:3','bare_id' => 3,'parent_id' => null,'type' => 'category','auxcounter' => 0,'unread' => 0,'child_unread' => 0,'checkbox' => false,'param' => '(3 feeds)','items' => [['name' => 'Local','id' => 'CAT:5','bare_id' => 5,'parent_id' => 3,'type' => 'category','auxcounter' => 0,'unread' => 0,'child_unread' => 0,'checkbox' => false,'param' => '(1 feed)','items' => [['name' => 'Toronto Star','id' => 'FEED:2','bare_id' => 2,'icon' => 'feed-icons/2.ico','error' => 'oops','param' => '2011-11-11T11:11:11Z','unread' => 0,'auxcounter' => 0,'checkbox' => false]]],['name' => 'National','id' => 'CAT:6','bare_id' => 6,'parent_id' => 3,'type' => 'category','auxcounter' => 0,'unread' => 0,'child_unread' => 0,'checkbox' => false,'param' => '(2 feeds)','items' => [['name' => 'CBC News','id' => 'FEED:4','bare_id' => 4,'icon' => 'feed-icons/4.ico','error' => '','param' => '2017-10-09T15:58:34Z','unread' => 0,'auxcounter' => 0,'checkbox' => false],['name' => 'Ottawa Citizen','id' => 'FEED:5','bare_id' => 5,'icon' => false,'error' => '','param' => '2017-07-07T17:07:17Z','unread' => 0,'auxcounter' => 0,'checkbox' => false]]]]],['name' => 'Science','id' => 'CAT:1','bare_id' => 1,'parent_id' => null,'type' => 'category','auxcounter' => 0,'unread' => 0,'child_unread' => 0,'checkbox' => false,'param' => '(2 feeds)','items' => [['name' => 'Rocketry','id' => 'CAT:2','bare_id' => 2,'parent_id' => 1,'type' => 'category','auxcounter' => 0,'unread' => 0,'child_unread' => 0,'checkbox' => false,'param' => '(1 feed)','items' => [['name' => 'NASA JPL','id' => 'FEED:1','bare_id' => 1,'icon' => false,'error' => '','param' => '2017-09-15T22:54:16Z','unread' => 0,'auxcounter' => 0,'checkbox' => false]]],['name' => 'Ars Technica','id' => 'FEED:3','bare_id' => 3,'icon' => 'feed-icons/3.ico','error' => 'argh','param' => '2016-05-23T06:40:02Z','unread' => 0,'auxcounter' => 0,'checkbox' => false]]],['name' => 'Uncategorized','id' => 'CAT:0','bare_id' => 0,'type' => 'category','auxcounter' => 0,'unread' => 0,'child_unread' => 0,'checkbox' => false,'parent_id' => null,'param' => '(1 feed)','items' => [['name' => 'Eurogamer','id' => 'FEED:6','bare_id' => 6,'icon' => 'feed-icons/6.ico','error' => '','param' => '2010-02-12T20:08:47Z','unread' => 0,'auxcounter' => 0,'checkbox' => false]]]]]];
|
||||
$this->assertMessage($this->respGood($exp), $this->req($in[1]));
|
||||
$this->dbMock->articleCount->twice()->calledWith($this->userId, $this->equalTo((new Context)->hidden(false)->unread(true)->modifiedSince(Date::sub("PT24H", self::NOW))));
|
||||
$this->dbMock->articleCount->twice()->calledWith($this->userId, $this->equalTo((new Context)->hidden(false)->unread(true)->modifiedRange(Date::sub("PT24H", self::NOW), null)));
|
||||
}
|
||||
|
||||
/** @dataProvider provideMassMarkings */
|
||||
|
@ -1180,8 +1180,8 @@ LONG_STRING;
|
|||
[['feed_id' => 0, 'is_cat' => true, 'mode' => "bogus"], (clone $c)->folderShallow(0)],
|
||||
[['feed_id' => -1], (clone $c)->starred(true)],
|
||||
[['feed_id' => -1, 'is_cat' => "t"], null],
|
||||
[['feed_id' => -3], (clone $c)->modifiedSince(Date::sub("PT24H", self::NOW))],
|
||||
[['feed_id' => -3, 'mode' => "1day"], (clone $c)->modifiedSince(Date::sub("PT24H", self::NOW))->notModifiedSince(Date::sub("PT24H", self::NOW))], // this is a nonsense query, but it's what TT-RSS appearsto do
|
||||
[['feed_id' => -3], (clone $c)->modifiedRange(Date::sub("PT24H", self::NOW), null)],
|
||||
[['feed_id' => -3, 'mode' => "1day"], (clone $c)->modifiedRange(Date::sub("PT24H", self::NOW), Date::sub("PT24H", self::NOW))], // this is a nonsense query, but it's what TT-RSS appearsto do
|
||||
[['feed_id' => -3, 'is_cat' => true], null],
|
||||
[['feed_id' => -2], null],
|
||||
[['feed_id' => -2, 'is_cat' => true], (clone $c)->labelled(true)],
|
||||
|
@ -1191,9 +1191,9 @@ LONG_STRING;
|
|||
[['feed_id' => -6, 'is_cat' => "f"], null],
|
||||
[['feed_id' => -2112], (clone $c)->label(1088)],
|
||||
[['feed_id' => 42, 'is_cat' => true], (clone $c)->folder(42)],
|
||||
[['feed_id' => 42, 'is_cat' => true, 'mode' => "1week"], (clone $c)->folder(42)->notModifiedSince(Date::sub("P1W", self::NOW))],
|
||||
[['feed_id' => 42, 'is_cat' => true, 'mode' => "1week"], (clone $c)->folder(42)->modifiedRange(null, Date::sub("P1W", self::NOW))],
|
||||
[['feed_id' => 2112], (clone $c)->subscription(2112)],
|
||||
[['feed_id' => 2112, 'mode' => "2week"], (clone $c)->subscription(2112)->notModifiedSince(Date::sub("P2W", self::NOW))],
|
||||
[['feed_id' => 2112, 'mode' => "2week"], (clone $c)->subscription(2112)->modifiedRange(null, Date::sub("P2W", self::NOW))],
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -1202,7 +1202,7 @@ LONG_STRING;
|
|||
$in = array_merge(['op' => "getFeeds", 'sid' => "PriestsOfSyrinx"], $in);
|
||||
// statistical mocks
|
||||
$this->dbMock->articleStarred->returns($this->v($this->starred));
|
||||
$this->dbMock->articleCount->with("~", $this->equalTo((new Context)->unread(true)->hidden(false)->modifiedSince(Date::sub("PT24H", self::NOW))))->returns(7);
|
||||
$this->dbMock->articleCount->with("~", $this->equalTo((new Context)->unread(true)->hidden(false)->modifiedRange(Date::sub("PT24H", self::NOW), null)))->returns(7);
|
||||
$this->dbMock->articleCount->with("~", $this->equalTo((new Context)->unread(true)->hidden(false)))->returns(35);
|
||||
// label mocks
|
||||
$this->dbMock->labelList->returns(new Result($this->v($this->labels)));
|
||||
|
@ -1521,61 +1521,61 @@ LONG_STRING;
|
|||
$fields = ["id", "guid", "title", "author", "url", "unread", "starred", "edited_date", "published_date", "subscription", "subscription_title", "note"];
|
||||
$sort = ["edited_date desc"];
|
||||
return [
|
||||
[true, [], null, $c, [], [], $this->respErr("INCORRECT_USAGE")],
|
||||
[true, ['feed_id' => 0], null, $c, [], [], $this->respGood([])],
|
||||
[true, ['feed_id' => -1], $out, (clone $c)->starred(true), $fields, ["marked_date desc"], $expFull],
|
||||
[true, ['feed_id' => -2], null, $c, [], [], $this->respGood([])],
|
||||
[true, ['feed_id' => -4], $out, $c, $fields, $sort, $expFull],
|
||||
[true, ['feed_id' => 2112], $gone, (clone $c)->subscription(2112), $fields, $sort, $this->respGood([])],
|
||||
[true, ['feed_id' => -2112], $out, (clone $c)->label(1088), $fields, $sort, $expFull],
|
||||
[true, ['feed_id' => -4, 'view_mode' => "adaptive"], $out, (clone $c)->unread(true), $fields, $sort, $expFull],
|
||||
[true, ['feed_id' => -4, 'view_mode' => "published"], null, $c, [], [], $this->respGood([])],
|
||||
[true, ['feed_id' => -2112, 'view_mode' => "adaptive"], $out, (clone $c)->label(1088)->unread(true), $fields, $sort, $expFull],
|
||||
[true, ['feed_id' => -2112, 'view_mode' => "unread"], $out, (clone $c)->label(1088)->unread(true), $fields, $sort, $expFull],
|
||||
[true, ['feed_id' => 42, 'view_mode' => "marked"], $out, (clone $c)->subscription(42)->starred(true), $fields, $sort, $expFull],
|
||||
[true, ['feed_id' => 42, 'view_mode' => "has_note"], $out, (clone $c)->subscription(42)->annotated(true), $fields, $sort, $expFull],
|
||||
[true, ['feed_id' => 42, 'view_mode' => "unread", 'search' => "unread:false"], null, $c, [], [], $this->respGood([])],
|
||||
[true, ['feed_id' => 42, 'search' => "pub:true"], null, $c, [], [], $this->respGood([])],
|
||||
[true, ['feed_id' => -4, 'limit' => 5], $out, (clone $c)->limit(5), $fields, $sort, $expFull],
|
||||
[true, ['feed_id' => -4, 'skip' => 2], $out, (clone $c)->offset(2), $fields, $sort, $expFull],
|
||||
[true, ['feed_id' => -4, 'limit' => 5, 'skip' => 2], $out, (clone $c)->limit(5)->offset(2), $fields, $sort, $expFull],
|
||||
[true, ['feed_id' => -4, 'since_id' => 47], $out, (clone $c)->oldestArticle(48), $fields, $sort, $expFull],
|
||||
[true, ['feed_id' => -3, 'is_cat' => true], $out, $c, $fields, $sort, $expFull],
|
||||
[true, ['feed_id' => -4, 'is_cat' => true], $out, $c, $fields, $sort, $expFull],
|
||||
[true, ['feed_id' => -2, 'is_cat' => true], $out, (clone $c)->labelled(true), $fields, $sort, $expFull],
|
||||
[true, ['feed_id' => -1, 'is_cat' => true], null, $c, [], [], $this->respGood([])],
|
||||
[true, ['feed_id' => 0, 'is_cat' => true], $out, (clone $c)->folderShallow(0), $fields, $sort, $expFull],
|
||||
[true, ['feed_id' => 0, 'is_cat' => true, 'include_nested' => true], $out, (clone $c)->folderShallow(0), $fields, $sort, $expFull],
|
||||
[true, ['feed_id' => 42, 'is_cat' => true], $out, (clone $c)->folderShallow(42), $fields, $sort, $expFull],
|
||||
[true, ['feed_id' => 42, 'is_cat' => true, 'include_nested' => true], $out, (clone $c)->folder(42), $fields, $sort, $expFull],
|
||||
[true, ['feed_id' => -4, 'order_by' => "feed_dates"], $out, $c, $fields, $sort, $expFull],
|
||||
[true, ['feed_id' => -4, 'order_by' => "date_reverse"], $out, $c, $fields, ["edited_date"], $expFull],
|
||||
[true, ['feed_id' => 42, 'search' => "interesting"], $out, (clone $c)->subscription(42)->searchTerms(["interesting"]), $fields, $sort, $expFull],
|
||||
[true, ['feed_id' => -6], $out, (clone $c)->unread(false)->markedSince(Date::sub("PT24H", $t)), $fields, ["marked_date desc"], $expFull],
|
||||
[true, ['feed_id' => -6, 'view_mode' => "unread"], null, $c, $fields, $sort, $this->respGood([])],
|
||||
[true, ['feed_id' => -3], $out, (clone $c)->unread(true)->modifiedSince(Date::sub("PT24H", $t)), $fields, $sort, $expFull],
|
||||
[true, ['feed_id' => -3, 'view_mode' => "marked"], $out, (clone $c)->unread(true)->starred(true)->modifiedSince(Date::sub("PT24H", $t)), $fields, $sort, $expFull],
|
||||
[false, [], null, (clone $c)->limit(null), [], [], $this->respErr("INCORRECT_USAGE")],
|
||||
[false, ['feed_id' => 0], null, (clone $c)->limit(null), [], [], $this->respGood([])],
|
||||
[false, ['feed_id' => -1], $comp, (clone $c)->limit(null)->starred(true), ["id"], ["marked_date desc"], $expComp],
|
||||
[false, ['feed_id' => -2], null, (clone $c)->limit(null), [], [], $this->respGood([])],
|
||||
[false, ['feed_id' => -4], $comp, (clone $c)->limit(null), ["id"], $sort, $expComp],
|
||||
[false, ['feed_id' => 2112], $gone, (clone $c)->limit(null)->subscription(2112), ["id"], $sort, $this->respGood([])],
|
||||
[false, ['feed_id' => -2112], $comp, (clone $c)->limit(null)->label(1088), ["id"], $sort, $expComp],
|
||||
[false, ['feed_id' => -4, 'view_mode' => "adaptive"], $comp, (clone $c)->limit(null)->unread(true), ["id"], $sort, $expComp],
|
||||
[false, ['feed_id' => -4, 'view_mode' => "published"], null, (clone $c)->limit(null), [], [], $this->respGood([])],
|
||||
[false, ['feed_id' => -2112, 'view_mode' => "adaptive"], $comp, (clone $c)->limit(null)->label(1088)->unread(true), ["id"], $sort, $expComp],
|
||||
[false, ['feed_id' => -2112, 'view_mode' => "unread"], $comp, (clone $c)->limit(null)->label(1088)->unread(true), ["id"], $sort, $expComp],
|
||||
[false, ['feed_id' => 42, 'view_mode' => "marked"], $comp, (clone $c)->limit(null)->subscription(42)->starred(true), ["id"], $sort, $expComp],
|
||||
[false, ['feed_id' => 42, 'view_mode' => "has_note"], $comp, (clone $c)->limit(null)->subscription(42)->annotated(true), ["id"], $sort, $expComp],
|
||||
[false, ['feed_id' => -4, 'limit' => 5], $comp, (clone $c)->limit(5), ["id"], $sort, $expComp],
|
||||
[false, ['feed_id' => -4, 'skip' => 2], $comp, (clone $c)->limit(null)->offset(2), ["id"], $sort, $expComp],
|
||||
[false, ['feed_id' => -4, 'limit' => 5, 'skip' => 2], $comp, (clone $c)->limit(5)->offset(2), ["id"], $sort, $expComp],
|
||||
[false, ['feed_id' => -4, 'since_id' => 47], $comp, (clone $c)->limit(null)->oldestArticle(48), ["id"], $sort, $expComp],
|
||||
[false, ['feed_id' => -6], $comp, (clone $c)->limit(null)->unread(false)->markedSince(Date::sub("PT24H", $t)), ["id"], ["marked_date desc"], $expComp],
|
||||
[false, ['feed_id' => -6, 'view_mode' => "unread"], null, (clone $c)->limit(null), ["id"], $sort, $this->respGood([])],
|
||||
[false, ['feed_id' => -3], $comp, (clone $c)->limit(null)->unread(true)->modifiedSince(Date::sub("PT24H", $t)), ["id"], $sort, $expComp],
|
||||
[false, ['feed_id' => -3, 'view_mode' => "marked"], $comp, (clone $c)->limit(null)->unread(true)->starred(true)->modifiedSince(Date::sub("PT24H", $t)), ["id"], $sort, $expComp],
|
||||
[true, [], null, $c, [], [], $this->respErr("INCORRECT_USAGE")],
|
||||
[true, ['feed_id' => 0], null, $c, [], [], $this->respGood([])],
|
||||
[true, ['feed_id' => -1], $out, (clone $c)->starred(true), $fields, ["marked_date desc"], $expFull],
|
||||
[true, ['feed_id' => -2], null, $c, [], [], $this->respGood([])],
|
||||
[true, ['feed_id' => -4], $out, $c, $fields, $sort, $expFull],
|
||||
[true, ['feed_id' => 2112], $gone, (clone $c)->subscription(2112), $fields, $sort, $this->respGood([])],
|
||||
[true, ['feed_id' => -2112], $out, (clone $c)->label(1088), $fields, $sort, $expFull],
|
||||
[true, ['feed_id' => -4, 'view_mode' => "adaptive"], $out, (clone $c)->unread(true), $fields, $sort, $expFull],
|
||||
[true, ['feed_id' => -4, 'view_mode' => "published"], null, $c, [], [], $this->respGood([])],
|
||||
[true, ['feed_id' => -2112, 'view_mode' => "adaptive"], $out, (clone $c)->label(1088)->unread(true), $fields, $sort, $expFull],
|
||||
[true, ['feed_id' => -2112, 'view_mode' => "unread"], $out, (clone $c)->label(1088)->unread(true), $fields, $sort, $expFull],
|
||||
[true, ['feed_id' => 42, 'view_mode' => "marked"], $out, (clone $c)->subscription(42)->starred(true), $fields, $sort, $expFull],
|
||||
[true, ['feed_id' => 42, 'view_mode' => "has_note"], $out, (clone $c)->subscription(42)->annotated(true), $fields, $sort, $expFull],
|
||||
[true, ['feed_id' => 42, 'view_mode' => "unread", 'search' => "unread:false"], null, $c, [], [], $this->respGood([])],
|
||||
[true, ['feed_id' => 42, 'search' => "pub:true"], null, $c, [], [], $this->respGood([])],
|
||||
[true, ['feed_id' => -4, 'limit' => 5], $out, (clone $c)->limit(5), $fields, $sort, $expFull],
|
||||
[true, ['feed_id' => -4, 'skip' => 2], $out, (clone $c)->offset(2), $fields, $sort, $expFull],
|
||||
[true, ['feed_id' => -4, 'limit' => 5, 'skip' => 2], $out, (clone $c)->limit(5)->offset(2), $fields, $sort, $expFull],
|
||||
[true, ['feed_id' => -4, 'since_id' => 47], $out, (clone $c)->oldestArticle(48), $fields, $sort, $expFull],
|
||||
[true, ['feed_id' => -3, 'is_cat' => true], $out, $c, $fields, $sort, $expFull],
|
||||
[true, ['feed_id' => -4, 'is_cat' => true], $out, $c, $fields, $sort, $expFull],
|
||||
[true, ['feed_id' => -2, 'is_cat' => true], $out, (clone $c)->labelled(true), $fields, $sort, $expFull],
|
||||
[true, ['feed_id' => -1, 'is_cat' => true], null, $c, [], [], $this->respGood([])],
|
||||
[true, ['feed_id' => 0, 'is_cat' => true], $out, (clone $c)->folderShallow(0), $fields, $sort, $expFull],
|
||||
[true, ['feed_id' => 0, 'is_cat' => true, 'include_nested' => true], $out, (clone $c)->folderShallow(0), $fields, $sort, $expFull],
|
||||
[true, ['feed_id' => 42, 'is_cat' => true], $out, (clone $c)->folderShallow(42), $fields, $sort, $expFull],
|
||||
[true, ['feed_id' => 42, 'is_cat' => true, 'include_nested' => true], $out, (clone $c)->folder(42), $fields, $sort, $expFull],
|
||||
[true, ['feed_id' => -4, 'order_by' => "feed_dates"], $out, $c, $fields, $sort, $expFull],
|
||||
[true, ['feed_id' => -4, 'order_by' => "date_reverse"], $out, $c, $fields, ["edited_date"], $expFull],
|
||||
[true, ['feed_id' => 42, 'search' => "interesting"], $out, (clone $c)->subscription(42)->searchTerms(["interesting"]), $fields, $sort, $expFull],
|
||||
[true, ['feed_id' => -6], $out, (clone $c)->unread(false)->markedRange(Date::sub("PT24H", $t), null), $fields, ["marked_date desc"], $expFull],
|
||||
[true, ['feed_id' => -6, 'view_mode' => "unread"], null, $c, $fields, $sort, $this->respGood([])],
|
||||
[true, ['feed_id' => -3], $out, (clone $c)->unread(true)->modifiedRange(Date::sub("PT24H", $t), null), $fields, $sort, $expFull],
|
||||
[true, ['feed_id' => -3, 'view_mode' => "marked"], $out, (clone $c)->unread(true)->starred(true)->modifiedRange(Date::sub("PT24H", $t), null), $fields, $sort, $expFull],
|
||||
[false, [], null, (clone $c)->limit(null), [], [], $this->respErr("INCORRECT_USAGE")],
|
||||
[false, ['feed_id' => 0], null, (clone $c)->limit(null), [], [], $this->respGood([])],
|
||||
[false, ['feed_id' => -1], $comp, (clone $c)->limit(null)->starred(true), ["id"], ["marked_date desc"], $expComp],
|
||||
[false, ['feed_id' => -2], null, (clone $c)->limit(null), [], [], $this->respGood([])],
|
||||
[false, ['feed_id' => -4], $comp, (clone $c)->limit(null), ["id"], $sort, $expComp],
|
||||
[false, ['feed_id' => 2112], $gone, (clone $c)->limit(null)->subscription(2112), ["id"], $sort, $this->respGood([])],
|
||||
[false, ['feed_id' => -2112], $comp, (clone $c)->limit(null)->label(1088), ["id"], $sort, $expComp],
|
||||
[false, ['feed_id' => -4, 'view_mode' => "adaptive"], $comp, (clone $c)->limit(null)->unread(true), ["id"], $sort, $expComp],
|
||||
[false, ['feed_id' => -4, 'view_mode' => "published"], null, (clone $c)->limit(null), [], [], $this->respGood([])],
|
||||
[false, ['feed_id' => -2112, 'view_mode' => "adaptive"], $comp, (clone $c)->limit(null)->label(1088)->unread(true), ["id"], $sort, $expComp],
|
||||
[false, ['feed_id' => -2112, 'view_mode' => "unread"], $comp, (clone $c)->limit(null)->label(1088)->unread(true), ["id"], $sort, $expComp],
|
||||
[false, ['feed_id' => 42, 'view_mode' => "marked"], $comp, (clone $c)->limit(null)->subscription(42)->starred(true), ["id"], $sort, $expComp],
|
||||
[false, ['feed_id' => 42, 'view_mode' => "has_note"], $comp, (clone $c)->limit(null)->subscription(42)->annotated(true), ["id"], $sort, $expComp],
|
||||
[false, ['feed_id' => -4, 'limit' => 5], $comp, (clone $c)->limit(5), ["id"], $sort, $expComp],
|
||||
[false, ['feed_id' => -4, 'skip' => 2], $comp, (clone $c)->limit(null)->offset(2), ["id"], $sort, $expComp],
|
||||
[false, ['feed_id' => -4, 'limit' => 5, 'skip' => 2], $comp, (clone $c)->limit(5)->offset(2), ["id"], $sort, $expComp],
|
||||
[false, ['feed_id' => -4, 'since_id' => 47], $comp, (clone $c)->limit(null)->oldestArticle(48), ["id"], $sort, $expComp],
|
||||
[false, ['feed_id' => -6], $comp, (clone $c)->limit(null)->unread(false)->markedRange(Date::sub("PT24H", $t), null), ["id"], ["marked_date desc"], $expComp],
|
||||
[false, ['feed_id' => -6, 'view_mode' => "unread"], null, (clone $c)->limit(null), ["id"], $sort, $this->respGood([])],
|
||||
[false, ['feed_id' => -3], $comp, (clone $c)->limit(null)->unread(true)->modifiedRange(Date::sub("PT24H", $t), null), ["id"], $sort, $expComp],
|
||||
[false, ['feed_id' => -3, 'view_mode' => "marked"], $comp, (clone $c)->limit(null)->unread(true)->starred(true)->modifiedRange(Date::sub("PT24H", $t), null), ["id"], $sort, $expComp],
|
||||
];
|
||||
}
|
||||
|
||||
|
|
|
@ -101,10 +101,10 @@ class TestSearch extends \JKingWeb\Arsse\Test\AbstractTest {
|
|||
'Doubled boolean' => ['unread:true unread:true', (new Context)->unread(true)],
|
||||
'Bare blank date' => ['@', new Context],
|
||||
'Quoted blank date' => ['"@"', new Context],
|
||||
'Bare ISO date' => ['@2019-03-01', (new Context)->modifiedSince("2019-03-01T00:00:00Z")->notModifiedSince("2019-03-01T23:59:59Z")],
|
||||
'Quoted ISO date' => ['"@March 1st, 2019"', (new Context)->modifiedSince("2019-03-01T00:00:00Z")->notModifiedSince("2019-03-01T23:59:59Z")],
|
||||
'Bare negative ISO date' => ['-@2019-03-01', (new Context)->not->modifiedSince("2019-03-01T00:00:00Z")->not->notModifiedSince("2019-03-01T23:59:59Z")],
|
||||
'Quoted negative English date' => ['"-@March 1st, 2019"', (new Context)->not->modifiedSince("2019-03-01T00:00:00Z")->not->notModifiedSince("2019-03-01T23:59:59Z")],
|
||||
'Bare ISO date' => ['@2019-03-01', (new Context)->modifiedRange("2019-03-01T00:00:00Z", "2019-03-01T23:59:59Z")],
|
||||
'Quoted ISO date' => ['"@March 1st, 2019"', (new Context)->modifiedRange("2019-03-01T00:00:00Z", "2019-03-01T23:59:59Z")],
|
||||
'Bare negative ISO date' => ['-@2019-03-01', (new Context)->not->modifiedRange("2019-03-01T00:00:00Z", "2019-03-01T23:59:59Z")],
|
||||
'Quoted negative English date' => ['"-@March 1st, 2019"', (new Context)->not->modifiedRange("2019-03-01T00:00:00Z", "2019-03-01T23:59:59Z")],
|
||||
'Invalid date' => ['@Bugaboo', new Context],
|
||||
'Escaped quoted date 1' => ['"@""Yesterday" and today', (new Context)->searchTerms(["and", "today"])],
|
||||
'Escaped quoted date 2' => ['"@\\"Yesterday" and today', (new Context)->searchTerms(["and", "today"])],
|
||||
|
@ -112,8 +112,8 @@ class TestSearch extends \JKingWeb\Arsse\Test\AbstractTest {
|
|||
'Escaped quoted date 4' => ['"@Yesterday\\and today', new Context],
|
||||
'Escaped quoted date 5' => ['"@Yesterday"and today', (new Context)->searchTerms(["today"])],
|
||||
'Contradictory dates' => ['@Yesterday @Today', null],
|
||||
'Doubled date' => ['"@March 1st, 2019" @2019-03-01', (new Context)->modifiedSince("2019-03-01T00:00:00Z")->notModifiedSince("2019-03-01T23:59:59Z")],
|
||||
'Doubled negative date' => ['"-@March 1st, 2019" -@2019-03-01', (new Context)->not->modifiedSince("2019-03-01T00:00:00Z")->not->notModifiedSince("2019-03-01T23:59:59Z")],
|
||||
'Doubled date' => ['"@March 1st, 2019" @2019-03-01', (new Context)->modifiedRange("2019-03-01T00:00:00Z", "2019-03-01T23:59:59Z")],
|
||||
'Doubled negative date' => ['"-@March 1st, 2019" -@2019-03-01', (new Context)->not->modifiedRange("2019-03-01T00:00:00Z", "2019-03-01T23:59:59Z")],
|
||||
];
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue