aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorArthurHoaro <arthur@hoa.ro>2017-04-01 12:17:37 +0200
committerArthurHoaro <arthur@hoa.ro>2017-05-25 15:51:12 +0200
commit7d86f40bdb2135655b5b4fe8cbcc1ac102114f86 (patch)
treec70ac4ad89a4fc84b8e52114aca7d9755cc92086
parentb64d83cd2b60b6851741787f8ce2ae2c93092841 (diff)
downloadShaarli-7d86f40bdb2135655b5b4fe8cbcc1ac102114f86.tar.gz
Shaarli-7d86f40bdb2135655b5b4fe8cbcc1ac102114f86.tar.zst
Shaarli-7d86f40bdb2135655b5b4fe8cbcc1ac102114f86.zip
Empty tag search will look for not tagged links
Fixes #784 From now, searching for tags with an empty value will return only not tagged links, with the search bar showing `x results [not tagged]`. Note that using the api, the searchtags request parameter must be set to `false` to get the same result. - [ ] Update API doc
-rw-r--r--application/FeedBuilder.php5
-rw-r--r--application/LinkDB.php27
-rw-r--r--application/LinkFilter.php30
-rw-r--r--application/Utils.php4
-rw-r--r--index.php18
-rw-r--r--tests/LinkDBTest.php2
-rw-r--r--tests/LinkFilterTest.php19
-rw-r--r--tests/api/controllers/GetLinksTest.php4
-rw-r--r--tests/api/controllers/InfoTest.php4
-rw-r--r--tests/utils/ReferenceLinkDB.php26
-rw-r--r--tpl/default/linklist.html6
-rw-r--r--tpl/vintage/linklist.html6
12 files changed, 115 insertions, 36 deletions
diff --git a/application/FeedBuilder.php b/application/FeedBuilder.php
index a1f4da48..7377bcec 100644
--- a/application/FeedBuilder.php
+++ b/application/FeedBuilder.php
@@ -97,6 +97,11 @@ class FeedBuilder
97 */ 97 */
98 public function buildData() 98 public function buildData()
99 { 99 {
100 // Search for untagged links
101 if (isset($this->userInput['searchtags']) && empty($this->userInput['searchtags'])) {
102 $this->userInput['searchtags'] = false;
103 }
104
100 // Optionally filter the results: 105 // Optionally filter the results:
101 $linksToDisplay = $this->linkDB->filterSearch($this->userInput); 106 $linksToDisplay = $this->linkDB->filterSearch($this->userInput);
102 107
diff --git a/application/LinkDB.php b/application/LinkDB.php
index 4cee2af9..a03c2c06 100644
--- a/application/LinkDB.php
+++ b/application/LinkDB.php
@@ -450,29 +450,12 @@ You use the community supported version of the original Shaarli project, by Seba
450 public function filterSearch($filterRequest = array(), $casesensitive = false, $visibility = 'all') 450 public function filterSearch($filterRequest = array(), $casesensitive = false, $visibility = 'all')
451 { 451 {
452 // Filter link database according to parameters. 452 // Filter link database according to parameters.
453 $searchtags = !empty($filterRequest['searchtags']) ? escape($filterRequest['searchtags']) : ''; 453 $searchtags = isset($filterRequest['searchtags']) ? escape($filterRequest['searchtags']) : '';
454 $searchterm = !empty($filterRequest['searchterm']) ? escape($filterRequest['searchterm']) : ''; 454 $searchterm = isset($filterRequest['searchterm']) ? escape($filterRequest['searchterm']) : '';
455 455
456 // Search tags + fullsearch. 456 // Search tags + fullsearch - blank string parameter will return all links.
457 if (! empty($searchtags) && ! empty($searchterm)) { 457 $type = LinkFilter::$FILTER_TAG | LinkFilter::$FILTER_TEXT;
458 $type = LinkFilter::$FILTER_TAG | LinkFilter::$FILTER_TEXT; 458 $request = [$searchtags, $searchterm];
459 $request = array($searchtags, $searchterm);
460 }
461 // Search by tags.
462 elseif (! empty($searchtags)) {
463 $type = LinkFilter::$FILTER_TAG;
464 $request = $searchtags;
465 }
466 // Fulltext search.
467 elseif (! empty($searchterm)) {
468 $type = LinkFilter::$FILTER_TEXT;
469 $request = $searchterm;
470 }
471 // Otherwise, display without filtering.
472 else {
473 $type = '';
474 $request = '';
475 }
476 459
477 $linkFilter = new LinkFilter($this); 460 $linkFilter = new LinkFilter($this);
478 return $linkFilter->filter($type, $request, $casesensitive, $visibility); 461 return $linkFilter->filter($type, $request, $casesensitive, $visibility);
diff --git a/application/LinkFilter.php b/application/LinkFilter.php
index 81832a4b..0e887d38 100644
--- a/application/LinkFilter.php
+++ b/application/LinkFilter.php
@@ -253,6 +253,9 @@ class LinkFilter
253 { 253 {
254 // Implode if array for clean up. 254 // Implode if array for clean up.
255 $tags = is_array($tags) ? trim(implode(' ', $tags)) : $tags; 255 $tags = is_array($tags) ? trim(implode(' ', $tags)) : $tags;
256 if ($tags === false) {
257 return $this->filterUntagged($visibility);
258 }
256 if (empty($tags)) { 259 if (empty($tags)) {
257 return $this->noFilter($visibility); 260 return $this->noFilter($visibility);
258 } 261 }
@@ -296,6 +299,33 @@ class LinkFilter
296 } 299 }
297 300
298 /** 301 /**
302 * Return only links without any tag.
303 *
304 * @param string $visibility return only all/private/public links.
305 *
306 * @return array filtered links.
307 */
308 public function filterUntagged($visibility)
309 {
310 $filtered = [];
311 foreach ($this->links as $key => $link) {
312 if ($visibility !== 'all') {
313 if (! $link['private'] && $visibility === 'private') {
314 continue;
315 } else if ($link['private'] && $visibility === 'public') {
316 continue;
317 }
318 }
319
320 if (empty(trim($link['tags']))) {
321 $filtered[$key] = $link;
322 }
323 }
324
325 return $filtered;
326 }
327
328 /**
299 * Returns the list of articles for a given day, chronologically sorted 329 * Returns the list of articles for a given day, chronologically sorted
300 * 330 *
301 * Day must be in the form 'YYYYMMDD' (e.g. '20120125'), e.g. 331 * Day must be in the form 'YYYYMMDD' (e.g. '20120125'), e.g.
diff --git a/application/Utils.php b/application/Utils.php
index 5c077450..87e5cc8f 100644
--- a/application/Utils.php
+++ b/application/Utils.php
@@ -91,6 +91,10 @@ function endsWith($haystack, $needle, $case = true)
91 */ 91 */
92function escape($input) 92function escape($input)
93{ 93{
94 if (is_bool($input)) {
95 return $input;
96 }
97
94 if (is_array($input)) { 98 if (is_array($input)) {
95 $out = array(); 99 $out = array();
96 foreach($input as $key => $value) { 100 foreach($input as $key => $value) {
diff --git a/index.php b/index.php
index 5c21c2f6..c96d0136 100644
--- a/index.php
+++ b/index.php
@@ -1609,7 +1609,15 @@ function renderPage($conf, $pluginManager, $LINKSDB)
1609function buildLinkList($PAGE,$LINKSDB, $conf, $pluginManager) 1609function buildLinkList($PAGE,$LINKSDB, $conf, $pluginManager)
1610{ 1610{
1611 // Used in templates 1611 // Used in templates
1612 $searchtags = !empty($_GET['searchtags']) ? escape(normalize_spaces($_GET['searchtags'])) : ''; 1612 if (isset($_GET['searchtags'])) {
1613 if (! empty($_GET['searchtags'])) {
1614 $searchtags = escape(normalize_spaces($_GET['searchtags']));
1615 } else {
1616 $searchtags = false;
1617 }
1618 } else {
1619 $searchtags = '';
1620 }
1613 $searchterm = !empty($_GET['searchterm']) ? escape(normalize_spaces($_GET['searchterm'])) : ''; 1621 $searchterm = !empty($_GET['searchterm']) ? escape(normalize_spaces($_GET['searchterm'])) : '';
1614 1622
1615 // Smallhash filter 1623 // Smallhash filter
@@ -1624,7 +1632,11 @@ function buildLinkList($PAGE,$LINKSDB, $conf, $pluginManager)
1624 } else { 1632 } else {
1625 // Filter links according search parameters. 1633 // Filter links according search parameters.
1626 $visibility = ! empty($_SESSION['privateonly']) ? 'private' : 'all'; 1634 $visibility = ! empty($_SESSION['privateonly']) ? 'private' : 'all';
1627 $linksToDisplay = $LINKSDB->filterSearch($_GET, false, $visibility); 1635 $request = [
1636 'searchtags' => $searchtags,
1637 'searchterm' => $searchterm,
1638 ];
1639 $linksToDisplay = $LINKSDB->filterSearch($request, false, $visibility);
1628 } 1640 }
1629 1641
1630 // ---- Handle paging. 1642 // ---- Handle paging.
@@ -1671,7 +1683,7 @@ function buildLinkList($PAGE,$LINKSDB, $conf, $pluginManager)
1671 } 1683 }
1672 1684
1673 // Compute paging navigation 1685 // Compute paging navigation
1674 $searchtagsUrl = empty($searchtags) ? '' : '&searchtags=' . urlencode($searchtags); 1686 $searchtagsUrl = $searchtags === '' ? '' : '&searchtags=' . urlencode($searchtags);
1675 $searchtermUrl = empty($searchterm) ? '' : '&searchterm=' . urlencode($searchterm); 1687 $searchtermUrl = empty($searchterm) ? '' : '&searchterm=' . urlencode($searchterm);
1676 $previous_page_url = ''; 1688 $previous_page_url = '';
1677 if ($i != count($keys)) { 1689 if ($i != count($keys)) {
diff --git a/tests/LinkDBTest.php b/tests/LinkDBTest.php
index 1f62a34a..6fbf597a 100644
--- a/tests/LinkDBTest.php
+++ b/tests/LinkDBTest.php
@@ -448,7 +448,7 @@ class LinkDBTest extends PHPUnit_Framework_TestCase
448 public function testReorderLinksDesc() 448 public function testReorderLinksDesc()
449 { 449 {
450 self::$privateLinkDB->reorder('ASC'); 450 self::$privateLinkDB->reorder('ASC');
451 $linkIds = array(42, 4, 1, 0, 7, 6, 8, 41); 451 $linkIds = array(42, 4, 9, 1, 0, 7, 6, 8, 41);
452 $cpt = 0; 452 $cpt = 0;
453 foreach (self::$privateLinkDB as $key => $value) { 453 foreach (self::$privateLinkDB as $key => $value) {
454 $this->assertEquals($linkIds[$cpt++], $key); 454 $this->assertEquals($linkIds[$cpt++], $key);
diff --git a/tests/LinkFilterTest.php b/tests/LinkFilterTest.php
index 37d5ca30..74162358 100644
--- a/tests/LinkFilterTest.php
+++ b/tests/LinkFilterTest.php
@@ -63,6 +63,12 @@ class LinkFilterTest extends PHPUnit_Framework_TestCase
63 count(self::$linkFilter->filter(LinkFilter::$FILTER_TAG, '')) 63 count(self::$linkFilter->filter(LinkFilter::$FILTER_TAG, ''))
64 ); 64 );
65 65
66 // Untagged only
67 $this->assertEquals(
68 self::$refDB->countUntaggedLinks(),
69 count(self::$linkFilter->filter(LinkFilter::$FILTER_TAG, false))
70 );
71
66 $this->assertEquals( 72 $this->assertEquals(
67 ReferenceLinkDB::$NB_LINKS_TOTAL, 73 ReferenceLinkDB::$NB_LINKS_TOTAL,
68 count(self::$linkFilter->filter(LinkFilter::$FILTER_TEXT, '')) 74 count(self::$linkFilter->filter(LinkFilter::$FILTER_TEXT, ''))
@@ -146,7 +152,7 @@ class LinkFilterTest extends PHPUnit_Framework_TestCase
146 public function testFilterDay() 152 public function testFilterDay()
147 { 153 {
148 $this->assertEquals( 154 $this->assertEquals(
149 3, 155 4,
150 count(self::$linkFilter->filter(LinkFilter::$FILTER_DAY, '20121206')) 156 count(self::$linkFilter->filter(LinkFilter::$FILTER_DAY, '20121206'))
151 ); 157 );
152 } 158 }
@@ -339,7 +345,7 @@ class LinkFilterTest extends PHPUnit_Framework_TestCase
339 ); 345 );
340 346
341 $this->assertEquals( 347 $this->assertEquals(
342 7, 348 ReferenceLinkDB::$NB_LINKS_TOTAL - 1,
343 count(self::$linkFilter->filter(LinkFilter::$FILTER_TEXT, '-revolution')) 349 count(self::$linkFilter->filter(LinkFilter::$FILTER_TEXT, '-revolution'))
344 ); 350 );
345 } 351 }
@@ -399,7 +405,7 @@ class LinkFilterTest extends PHPUnit_Framework_TestCase
399 ); 405 );
400 406
401 $this->assertEquals( 407 $this->assertEquals(
402 7, 408 ReferenceLinkDB::$NB_LINKS_TOTAL - 1,
403 count(self::$linkFilter->filter(LinkFilter::$FILTER_TAG, '-free')) 409 count(self::$linkFilter->filter(LinkFilter::$FILTER_TAG, '-free'))
404 ); 410 );
405 } 411 }
@@ -429,6 +435,13 @@ class LinkFilterTest extends PHPUnit_Framework_TestCase
429 1, 435 1,
430 count(self::$linkFilter->filter( 436 count(self::$linkFilter->filter(
431 LinkFilter::$FILTER_TAG | LinkFilter::$FILTER_TEXT, 437 LinkFilter::$FILTER_TAG | LinkFilter::$FILTER_TEXT,
438 array(false, 'PSR-2')
439 ))
440 );
441 $this->assertEquals(
442 1,
443 count(self::$linkFilter->filter(
444 LinkFilter::$FILTER_TAG | LinkFilter::$FILTER_TEXT,
432 array($tags, '') 445 array($tags, '')
433 )) 446 ))
434 ); 447 );
diff --git a/tests/api/controllers/GetLinksTest.php b/tests/api/controllers/GetLinksTest.php
index 10330cd9..f1b262bc 100644
--- a/tests/api/controllers/GetLinksTest.php
+++ b/tests/api/controllers/GetLinksTest.php
@@ -94,7 +94,7 @@ class GetLinksTest extends \PHPUnit_Framework_TestCase
94 $this->assertEquals($this->refDB->countLinks(), count($data)); 94 $this->assertEquals($this->refDB->countLinks(), count($data));
95 95
96 // Check order 96 // Check order
97 $order = [41, 8, 6, 7, 0, 1, 4, 42]; 97 $order = [41, 8, 6, 7, 0, 1, 9, 4, 42];
98 $cpt = 0; 98 $cpt = 0;
99 foreach ($data as $link) { 99 foreach ($data as $link) {
100 $this->assertEquals(self::NB_FIELDS_LINK, count($link)); 100 $this->assertEquals(self::NB_FIELDS_LINK, count($link));
@@ -163,7 +163,7 @@ class GetLinksTest extends \PHPUnit_Framework_TestCase
163 $data = json_decode((string) $response->getBody(), true); 163 $data = json_decode((string) $response->getBody(), true);
164 $this->assertEquals($this->refDB->countLinks(), count($data)); 164 $this->assertEquals($this->refDB->countLinks(), count($data));
165 // Check order 165 // Check order
166 $order = [41, 8, 6, 7, 0, 1, 4, 42]; 166 $order = [41, 8, 6, 7, 0, 1, 9, 4, 42];
167 $cpt = 0; 167 $cpt = 0;
168 foreach ($data as $link) { 168 foreach ($data as $link) {
169 $this->assertEquals(self::NB_FIELDS_LINK, count($link)); 169 $this->assertEquals(self::NB_FIELDS_LINK, count($link));
diff --git a/tests/api/controllers/InfoTest.php b/tests/api/controllers/InfoTest.php
index 4beef3f7..5d6a2329 100644
--- a/tests/api/controllers/InfoTest.php
+++ b/tests/api/controllers/InfoTest.php
@@ -80,7 +80,7 @@ class InfoTest extends \PHPUnit_Framework_TestCase
80 $this->assertEquals(200, $response->getStatusCode()); 80 $this->assertEquals(200, $response->getStatusCode());
81 $data = json_decode((string) $response->getBody(), true); 81 $data = json_decode((string) $response->getBody(), true);
82 82
83 $this->assertEquals(8, $data['global_counter']); 83 $this->assertEquals(\ReferenceLinkDB::$NB_LINKS_TOTAL, $data['global_counter']);
84 $this->assertEquals(2, $data['private_counter']); 84 $this->assertEquals(2, $data['private_counter']);
85 $this->assertEquals('Shaarli', $data['settings']['title']); 85 $this->assertEquals('Shaarli', $data['settings']['title']);
86 $this->assertEquals('?', $data['settings']['header_link']); 86 $this->assertEquals('?', $data['settings']['header_link']);
@@ -103,7 +103,7 @@ class InfoTest extends \PHPUnit_Framework_TestCase
103 $this->assertEquals(200, $response->getStatusCode()); 103 $this->assertEquals(200, $response->getStatusCode());
104 $data = json_decode((string) $response->getBody(), true); 104 $data = json_decode((string) $response->getBody(), true);
105 105
106 $this->assertEquals(8, $data['global_counter']); 106 $this->assertEquals(\ReferenceLinkDB::$NB_LINKS_TOTAL, $data['global_counter']);
107 $this->assertEquals(2, $data['private_counter']); 107 $this->assertEquals(2, $data['private_counter']);
108 $this->assertEquals($title, $data['settings']['title']); 108 $this->assertEquals($title, $data['settings']['title']);
109 $this->assertEquals($headerLink, $data['settings']['header_link']); 109 $this->assertEquals($headerLink, $data['settings']['header_link']);
diff --git a/tests/utils/ReferenceLinkDB.php b/tests/utils/ReferenceLinkDB.php
index 36d58c68..29d63fac 100644
--- a/tests/utils/ReferenceLinkDB.php
+++ b/tests/utils/ReferenceLinkDB.php
@@ -4,7 +4,7 @@
4 */ 4 */
5class ReferenceLinkDB 5class ReferenceLinkDB
6{ 6{
7 public static $NB_LINKS_TOTAL = 8; 7 public static $NB_LINKS_TOTAL = 9;
8 8
9 private $_links = array(); 9 private $_links = array();
10 private $_publicCount = 0; 10 private $_publicCount = 0;
@@ -38,6 +38,16 @@ class ReferenceLinkDB
38 ); 38 );
39 39
40 $this->addLink( 40 $this->addLink(
41 9,
42 'PSR-2: Coding Style Guide',
43 'http://www.php-fig.org/psr/psr-2/',
44 'This guide extends and expands on PSR-1, the basic coding standard.',
45 0,
46 DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, '20121206_152312'),
47 ''
48 );
49
50 $this->addLink(
41 8, 51 8,
42 'Free as in Freedom 2.0 @website', 52 'Free as in Freedom 2.0 @website',
43 'https://static.fsf.org/nosvn/faif-2.0.pdf', 53 'https://static.fsf.org/nosvn/faif-2.0.pdf',
@@ -161,6 +171,20 @@ class ReferenceLinkDB
161 return $this->_privateCount; 171 return $this->_privateCount;
162 } 172 }
163 173
174 /**
175 * Returns the number of links without tag
176 */
177 public function countUntaggedLinks()
178 {
179 $cpt = 0;
180 foreach ($this->_links as $link) {
181 if (empty($link['tags'])) {
182 ++$cpt;
183 }
184 }
185 return $cpt;
186 }
187
164 public function getLinks() 188 public function getLinks()
165 { 189 {
166 return $this->_links; 190 return $this->_links;
diff --git a/tpl/default/linklist.html b/tpl/default/linklist.html
index 57ef4567..3d6be529 100644
--- a/tpl/default/linklist.html
+++ b/tpl/default/linklist.html
@@ -89,7 +89,7 @@
89 <div id="searchcriteria">{'Nothing found.'|t}</div> 89 <div id="searchcriteria">{'Nothing found.'|t}</div>
90 </div> 90 </div>
91 </div> 91 </div>
92 {elseif="!empty($search_term) or !empty($search_tags) or !empty($visibility)"} 92 {elseif="!empty($search_term) or $search_tags !== '' or !empty($visibility)"}
93 <div class="pure-g pure-alert pure-alert-success search-result"> 93 <div class="pure-g pure-alert pure-alert-success search-result">
94 <div class="pure-u-2-24"></div> 94 <div class="pure-u-2-24"></div>
95 <div class="pure-u-20-24"> 95 <div class="pure-u-20-24">
@@ -105,6 +105,10 @@
105 <a href="?removetag={function="urlencode($value)"}">{$value}<span class="remove"><i class="fa fa-times"></i></span></a> 105 <a href="?removetag={function="urlencode($value)"}">{$value}<span class="remove"><i class="fa fa-times"></i></span></a>
106 </span> 106 </span>
107 {/loop} 107 {/loop}
108 {elseif="$search_tags === false"}
109 <span class="label label-tag" title="{'Remove tag'|t}">
110 <a href="?">{'untagged'|t}<span class="remove"><i class="fa fa-times"></i></span></a>
111 </span>
108 {/if} 112 {/if}
109 {if="!empty($visibility)"} 113 {if="!empty($visibility)"}
110 {'with status'|t} 114 {'with status'|t}
diff --git a/tpl/vintage/linklist.html b/tpl/vintage/linklist.html
index fc116667..8458caa1 100644
--- a/tpl/vintage/linklist.html
+++ b/tpl/vintage/linklist.html
@@ -55,7 +55,7 @@
55 55
56 {if="count($links)==0"} 56 {if="count($links)==0"}
57 <div id="searchcriteria">Nothing found.</div> 57 <div id="searchcriteria">Nothing found.</div>
58 {elseif="!empty($search_term) or !empty($search_tags)"} 58 {elseif="!empty($search_term) or $search_tags !== ''"}
59 <div id="searchcriteria"> 59 <div id="searchcriteria">
60 {$result_count} results 60 {$result_count} results
61 {if="!empty($search_term)"} 61 {if="!empty($search_term)"}
@@ -69,6 +69,10 @@
69 <a href="?removetag={function="urlencode($value)"}">{$value} <span class="remove">x</span></a> 69 <a href="?removetag={function="urlencode($value)"}">{$value} <span class="remove">x</span></a>
70 </span> 70 </span>
71 {/loop} 71 {/loop}
72 {elseif="$search_tags === false"}
73 <span class="linktag" title="Remove tag">
74 <a href="?">untagged <span class="remove">x</span></a>
75 </span>
72 {/if} 76 {/if}
73 </div> 77 </div>
74 {/if} 78 {/if}