diff --git a/lib/Database.php b/lib/Database.php index 30562d97..0310c5a9 100644 --- a/lib/Database.php +++ b/lib/Database.php @@ -1184,18 +1184,18 @@ class Database { if ($context->editions()) { // if multiple specific editions have been requested, filter against the list if (!$context->editions) { - throw new Db\ExceptionInput("tooShort", ['field' => "editions", 'action' => __FUNCTION__, 'min' => 1]); // must have at least one array element + throw new Db\ExceptionInput("tooShort", ['field' => "editions", 'action' => $this->caller(), 'min' => 1]); // must have at least one array element } elseif (sizeof($context->editions) > self::LIMIT_ARTICLES) { - throw new Db\ExceptionInput("tooLong", ['field' => "editions", 'action' => __FUNCTION__, 'max' => self::LIMIT_ARTICLES]); // @codeCoverageIgnore + throw new Db\ExceptionInput("tooLong", ['field' => "editions", 'action' => $this->caller(), 'max' => self::LIMIT_ARTICLES]); // @codeCoverageIgnore } list($inParams, $inTypes) = $this->generateIn($context->editions, "int"); $q->setWhere("latest_editions.edition in ($inParams)", $inTypes, $context->editions); } elseif ($context->articles()) { // if multiple specific articles have been requested, filter against the list if (!$context->articles) { - throw new Db\ExceptionInput("tooShort", ['field' => "articles", 'action' => __FUNCTION__, 'min' => 1]); // must have at least one array element + throw new Db\ExceptionInput("tooShort", ['field' => "articles", 'action' => $this->caller(), 'min' => 1]); // must have at least one array element } elseif (sizeof($context->articles) > self::LIMIT_ARTICLES) { - throw new Db\ExceptionInput("tooLong", ['field' => "articles", 'action' => __FUNCTION__, 'max' => self::LIMIT_ARTICLES]); // @codeCoverageIgnore + throw new Db\ExceptionInput("tooLong", ['field' => "articles", 'action' => $this->caller(), 'max' => self::LIMIT_ARTICLES]); // @codeCoverageIgnore } list($inParams, $inTypes) = $this->generateIn($context->articles, "int"); $q->setWhere("arsse_articles.id in ($inParams)", $inTypes, $context->articles); @@ -1255,12 +1255,21 @@ class Database { // filter based on search terms if ($context->searchTerms()) { if (!$context->searchTerms) { - throw new Db\ExceptionInput("tooShort", ['field' => "searchTerms", 'action' => __FUNCTION__, 'min' => 1]); // must have at least one array element + throw new Db\ExceptionInput("tooShort", ['field' => "searchTerms", 'action' => $this->caller(), 'min' => 1]); // must have at least one array element } elseif (sizeof($context->searchTerms) > self::LIMIT_TERMS) { - throw new Db\ExceptionInput("tooLong", ['field' => "searchTerms", 'action' => __FUNCTION__, 'max' => self::LIMIT_TERMS]); + throw new Db\ExceptionInput("tooLong", ['field' => "searchTerms", 'action' => $this->caller(), 'max' => self::LIMIT_TERMS]); } $q->setWhere(...$this->generateSearch($context->searchTerms, ["arsse_articles.title", "arsse_articles.content"])); } + // filter based on search terms in note + if ($context->annotationTerms()) { + if (!$context->annotationTerms) { + throw new Db\ExceptionInput("tooShort", ['field' => "annotationTerms", 'action' => $this->caller(), 'min' => 1]); // must have at least one array element + } elseif (sizeof($context->annotationTerms) > self::LIMIT_TERMS) { + throw new Db\ExceptionInput("tooLong", ['field' => "annotationTerms", 'action' => $this->caller(), 'max' => self::LIMIT_TERMS]); + } + $q->setWhere(...$this->generateSearch($context->annotationTerms, ["arsse_marks.note"])); + } // return the query return $q; } diff --git a/lib/Misc/Context.php b/lib/Misc/Context.php index 87ada397..1dd1a171 100644 --- a/lib/Misc/Context.php +++ b/lib/Misc/Context.php @@ -34,6 +34,7 @@ class Context { public $labelName; public $labelled = null; public $annotated = null; + public $annotationTerms = null; public $searchTerms = null; protected $props = []; @@ -184,6 +185,13 @@ class Context { return $this->act(__FUNCTION__, func_num_args(), $spec); } + public function annotationTerms(array $spec = null) { + if (isset($spec)) { + $spec = $this->cleanStringArray($spec); + } + return $this->act(__FUNCTION__, func_num_args(), $spec); + } + public function searchTerms(array $spec = null) { if (isset($spec)) { $spec = $this->cleanStringArray($spec); diff --git a/tests/cases/Database/SeriesArticle.php b/tests/cases/Database/SeriesArticle.php index d19f85bc..80114c4d 100644 --- a/tests/cases/Database/SeriesArticle.php +++ b/tests/cases/Database/SeriesArticle.php @@ -497,6 +497,11 @@ trait SeriesArticle { // get items that match search terms $compareIds([1,2,3], (new Context)->searchTerms(["Article"])); $compareIds([1], (new Context)->searchTerms(["one", "first"])); + // get items that match search terms in note + $compareIds([2], (new Context)->annotationTerms(["some"])); + $compareIds([2], (new Context)->annotationTerms(["some", "note"])); + $compareIds([2], (new Context)->annotationTerms(["some note"])); + $compareIds([], (new Context)->annotationTerms(["some", "sauce"])); } public function testListArticlesOfAMissingFolder() { @@ -998,4 +1003,14 @@ trait SeriesArticle { $this->assertException("tooLong", "Db", "ExceptionInput"); Arsse::$db->articleList($this->user, (new Context)->searchTerms(range(1, 105))); } + + public function testSearchTooFewTermsInNote() { + $this->assertException("tooShort", "Db", "ExceptionInput"); + Arsse::$db->articleList($this->user, (new Context)->annotationTerms([])); + } + + public function testSearchTooManyTermsInNote() { + $this->assertException("tooLong", "Db", "ExceptionInput"); + Arsse::$db->articleList($this->user, (new Context)->annotationTerms(range(1, 105))); + } } diff --git a/tests/cases/Db/BaseDriver.php b/tests/cases/Db/BaseDriver.php index 682c6881..4967e84c 100644 --- a/tests/cases/Db/BaseDriver.php +++ b/tests/cases/Db/BaseDriver.php @@ -94,6 +94,7 @@ abstract class BaseDriver extends \JKingWeb\Arsse\Test\AbstractTest { public function testTranslateAToken() { $this->assertRegExp("/^[a-z][a-z0-9]*$/i", $this->drv->sqlToken("greatest")); $this->assertRegExp("/^\"?[a-z][a-z0-9_\-]*\"?$/i", $this->drv->sqlToken("nocase")); + $this->assertRegExp("/^[a-z][a-z0-9]*$/i", $this->drv->sqlToken("like")); $this->assertSame("distinct", $this->drv->sqlToken("distinct")); } diff --git a/tests/cases/Misc/TestContext.php b/tests/cases/Misc/TestContext.php index b767d115..902a6bad 100644 --- a/tests/cases/Misc/TestContext.php +++ b/tests/cases/Misc/TestContext.php @@ -50,6 +50,7 @@ class TestContext extends \JKingWeb\Arsse\Test\AbstractTest { 'labelled' => true, 'annotated' => true, 'searchTerms' => ["foo", "bar"], + 'annotationTerms' => ["foo", "bar"], ]; $times = ['modifiedSince','notModifiedSince','markedSince','notMarkedSince']; $c = new Context; @@ -83,7 +84,7 @@ class TestContext extends \JKingWeb\Arsse\Test\AbstractTest { } public function testCleanStringArrayValues() { - $methods = ["searchTerms"]; + $methods = ["searchTerms", "annotationTerms"]; $now = new \DateTime; $in = [1, 3.0, "ook", 0, true, false, null, $now, ""]; $out = ["1", "3", "ook", "0", valueInfo::normalize($now, ValueInfo::T_STRING)];