diff options
-rw-r--r-- | application/LinkDB.php | 2 | ||||
-rw-r--r-- | application/LinkFilter.php | 30 | ||||
-rw-r--r-- | application/Updater.php | 15 | ||||
-rw-r--r-- | index.php | 2 | ||||
-rw-r--r-- | tests/LinkDBTest.php | 6 | ||||
-rw-r--r-- | tests/LinkFilterTest.php | 16 | ||||
-rw-r--r-- | tests/Updater/UpdaterTest.php | 18 | ||||
-rw-r--r-- | tests/utils/ReferenceLinkDB.php | 2 |
8 files changed, 79 insertions, 12 deletions
diff --git a/application/LinkDB.php b/application/LinkDB.php index a95b3f36..416aa0d3 100644 --- a/application/LinkDB.php +++ b/application/LinkDB.php | |||
@@ -340,7 +340,7 @@ You use the community supported version of the original Shaarli project, by Seba | |||
340 | * | 340 | * |
341 | * @return array filtered links | 341 | * @return array filtered links |
342 | */ | 342 | */ |
343 | public function filter($type, $request, $casesensitive = false, $privateonly = false) | 343 | public function filter($type = '', $request = '', $casesensitive = false, $privateonly = false) |
344 | { | 344 | { |
345 | $linkFilter = new LinkFilter($this->_links); | 345 | $linkFilter = new LinkFilter($this->_links); |
346 | $requestFilter = is_array($request) ? implode(' ', $request) : $request; | 346 | $requestFilter = is_array($request) ? implode(' ', $request) : $request; |
diff --git a/application/LinkFilter.php b/application/LinkFilter.php index 096d3b04..ceb47d16 100644 --- a/application/LinkFilter.php +++ b/application/LinkFilter.php | |||
@@ -209,19 +209,33 @@ class LinkFilter | |||
209 | */ | 209 | */ |
210 | public function filterTags($tags, $casesensitive = false, $privateonly = false) | 210 | public function filterTags($tags, $casesensitive = false, $privateonly = false) |
211 | { | 211 | { |
212 | $searchtags = $this->tagsStrToArray($tags, $casesensitive); | 212 | $searchtags = self::tagsStrToArray($tags, $casesensitive); |
213 | $filtered = array(); | 213 | $filtered = array(); |
214 | if (empty($searchtags)) { | ||
215 | return $filtered; | ||
216 | } | ||
214 | 217 | ||
215 | foreach ($this->links as $l) { | 218 | foreach ($this->links as $link) { |
216 | // ignore non private links when 'privatonly' is on. | 219 | // ignore non private links when 'privatonly' is on. |
217 | if (! $l['private'] && $privateonly === true) { | 220 | if (! $link['private'] && $privateonly === true) { |
218 | continue; | 221 | continue; |
219 | } | 222 | } |
220 | 223 | ||
221 | $linktags = $this->tagsStrToArray($l['tags'], $casesensitive); | 224 | $linktags = self::tagsStrToArray($link['tags'], $casesensitive); |
222 | 225 | ||
223 | if (count(array_intersect($linktags, $searchtags)) == count($searchtags)) { | 226 | $found = true; |
224 | $filtered[$l['linkdate']] = $l; | 227 | for ($i = 0 ; $i < count($searchtags) && $found; $i++) { |
228 | // Exclusive search, quit if tag found. | ||
229 | // Or, tag not found in the link, quit. | ||
230 | if (($searchtags[$i][0] == '-' && in_array(substr($searchtags[$i], 1), $linktags)) | ||
231 | || ($searchtags[$i][0] != '-') && ! in_array($searchtags[$i], $linktags) | ||
232 | ) { | ||
233 | $found = false; | ||
234 | } | ||
235 | } | ||
236 | |||
237 | if ($found) { | ||
238 | $filtered[$link['linkdate']] = $link; | ||
225 | } | 239 | } |
226 | } | 240 | } |
227 | krsort($filtered); | 241 | krsort($filtered); |
@@ -266,12 +280,12 @@ class LinkFilter | |||
266 | * | 280 | * |
267 | * @return array filtered tags string. | 281 | * @return array filtered tags string. |
268 | */ | 282 | */ |
269 | public function tagsStrToArray($tags, $casesensitive) | 283 | public static function tagsStrToArray($tags, $casesensitive) |
270 | { | 284 | { |
271 | // We use UTF-8 conversion to handle various graphemes (i.e. cyrillic, or greek) | 285 | // We use UTF-8 conversion to handle various graphemes (i.e. cyrillic, or greek) |
272 | $tagsOut = $casesensitive ? $tags : mb_convert_case($tags, MB_CASE_LOWER, 'UTF-8'); | 286 | $tagsOut = $casesensitive ? $tags : mb_convert_case($tags, MB_CASE_LOWER, 'UTF-8'); |
273 | $tagsOut = str_replace(',', ' ', $tagsOut); | 287 | $tagsOut = str_replace(',', ' ', $tagsOut); |
274 | 288 | ||
275 | return explode(' ', trim($tagsOut)); | 289 | return array_filter(explode(' ', trim($tagsOut)), 'strlen'); |
276 | } | 290 | } |
277 | } | 291 | } |
diff --git a/application/Updater.php b/application/Updater.php index 20ae0c4d..773a1ffa 100644 --- a/application/Updater.php +++ b/application/Updater.php | |||
@@ -131,6 +131,21 @@ class Updater | |||
131 | 131 | ||
132 | return true; | 132 | return true; |
133 | } | 133 | } |
134 | |||
135 | /** | ||
136 | * Rename tags starting with a '-' to work with tag exclusion search. | ||
137 | */ | ||
138 | public function updateMethodRenameDashTags() | ||
139 | { | ||
140 | $linklist = $this->linkDB->filter(); | ||
141 | foreach ($linklist as $link) { | ||
142 | $link['tags'] = preg_replace('/(^| )\-/', '$1', $link['tags']); | ||
143 | $link['tags'] = implode(' ', array_unique(LinkFilter::tagsStrToArray($link['tags'], true))); | ||
144 | $this->linkDB[$link['linkdate']] = $link; | ||
145 | } | ||
146 | $this->linkDB->savedb($this->config['config']['PAGECACHE']); | ||
147 | return true; | ||
148 | } | ||
134 | } | 149 | } |
135 | 150 | ||
136 | /** | 151 | /** |
@@ -1558,6 +1558,8 @@ function renderPage() | |||
1558 | } | 1558 | } |
1559 | // Remove multiple spaces. | 1559 | // Remove multiple spaces. |
1560 | $tags = trim(preg_replace('/\s\s+/', ' ', $_POST['lf_tags'])); | 1560 | $tags = trim(preg_replace('/\s\s+/', ' ', $_POST['lf_tags'])); |
1561 | // Remove first '-' char in tags. | ||
1562 | $tags = preg_replace('/(^| )\-/', '$1', $tags); | ||
1561 | // Remove duplicates. | 1563 | // Remove duplicates. |
1562 | $tags = implode(' ', array_unique(explode(' ', $tags))); | 1564 | $tags = implode(' ', array_unique(explode(' ', $tags))); |
1563 | $linkdate = $_POST['lf_linkdate']; | 1565 | $linkdate = $_POST['lf_linkdate']; |
diff --git a/tests/LinkDBTest.php b/tests/LinkDBTest.php index 3b1a2057..06edea79 100644 --- a/tests/LinkDBTest.php +++ b/tests/LinkDBTest.php | |||
@@ -276,7 +276,8 @@ class LinkDBTest extends PHPUnit_Framework_TestCase | |||
276 | 'media' => 1, | 276 | 'media' => 1, |
277 | 'software' => 1, | 277 | 'software' => 1, |
278 | 'stallman' => 1, | 278 | 'stallman' => 1, |
279 | 'free' => 1 | 279 | 'free' => 1, |
280 | '-exclude' => 1, | ||
280 | ), | 281 | ), |
281 | self::$publicLinkDB->allTags() | 282 | self::$publicLinkDB->allTags() |
282 | ); | 283 | ); |
@@ -295,7 +296,8 @@ class LinkDBTest extends PHPUnit_Framework_TestCase | |||
295 | 'html' => 1, | 296 | 'html' => 1, |
296 | 'w3c' => 1, | 297 | 'w3c' => 1, |
297 | 'css' => 1, | 298 | 'css' => 1, |
298 | 'Mercurial' => 1 | 299 | 'Mercurial' => 1, |
300 | '-exclude' => 1, | ||
299 | ), | 301 | ), |
300 | self::$privateLinkDB->allTags() | 302 | self::$privateLinkDB->allTags() |
301 | ); | 303 | ); |
diff --git a/tests/LinkFilterTest.php b/tests/LinkFilterTest.php index 5fb2423f..164af0d4 100644 --- a/tests/LinkFilterTest.php +++ b/tests/LinkFilterTest.php | |||
@@ -254,4 +254,20 @@ class LinkFilterTest extends PHPUnit_Framework_TestCase | |||
254 | count(self::$linkFilter->filter(LinkFilter::$FILTER_TEXT, 'free software')) | 254 | count(self::$linkFilter->filter(LinkFilter::$FILTER_TEXT, 'free software')) |
255 | ); | 255 | ); |
256 | } | 256 | } |
257 | |||
258 | /** | ||
259 | * Tag search with exclusion. | ||
260 | */ | ||
261 | public function testTagFilterWithExclusion() | ||
262 | { | ||
263 | $this->assertEquals( | ||
264 | 1, | ||
265 | count(self::$linkFilter->filter(LinkFilter::$FILTER_TAG, 'gnu -free')) | ||
266 | ); | ||
267 | |||
268 | $this->assertEquals( | ||
269 | 5, | ||
270 | count(self::$linkFilter->filter(LinkFilter::$FILTER_TAG, '-free')) | ||
271 | ); | ||
272 | } | ||
257 | } | 273 | } |
diff --git a/tests/Updater/UpdaterTest.php b/tests/Updater/UpdaterTest.php index 63ed5e03..84b82350 100644 --- a/tests/Updater/UpdaterTest.php +++ b/tests/Updater/UpdaterTest.php | |||
@@ -14,6 +14,11 @@ class UpdaterTest extends PHPUnit_Framework_TestCase | |||
14 | private static $configFields; | 14 | private static $configFields; |
15 | 15 | ||
16 | /** | 16 | /** |
17 | * @var string Path to test datastore. | ||
18 | */ | ||
19 | protected static $testDatastore = 'sandbox/datastore.php'; | ||
20 | |||
21 | /** | ||
17 | * Executed before each test. | 22 | * Executed before each test. |
18 | */ | 23 | */ |
19 | public function setUp() | 24 | public function setUp() |
@@ -31,6 +36,7 @@ class UpdaterTest extends PHPUnit_Framework_TestCase | |||
31 | 'config' => array( | 36 | 'config' => array( |
32 | 'CONFIG_FILE' => 'tests/Updater/config.php', | 37 | 'CONFIG_FILE' => 'tests/Updater/config.php', |
33 | 'DATADIR' => 'tests/Updater', | 38 | 'DATADIR' => 'tests/Updater', |
39 | 'PAGECACHE' => 'sandbox/pagecache', | ||
34 | 'config1' => 'config1data', | 40 | 'config1' => 'config1data', |
35 | 'config2' => 'config2data', | 41 | 'config2' => 'config2data', |
36 | ) | 42 | ) |
@@ -224,4 +230,16 @@ class UpdaterTest extends PHPUnit_Framework_TestCase | |||
224 | include self::$configFields['config']['CONFIG_FILE']; | 230 | include self::$configFields['config']['CONFIG_FILE']; |
225 | $this->assertEquals(self::$configFields['login'], $GLOBALS['login']); | 231 | $this->assertEquals(self::$configFields['login'], $GLOBALS['login']); |
226 | } | 232 | } |
233 | |||
234 | public function testRenameDashTags() | ||
235 | { | ||
236 | $refDB = new ReferenceLinkDB(); | ||
237 | $refDB->write(self::$testDatastore); | ||
238 | $linkDB = new LinkDB(self::$testDatastore, true, false); | ||
239 | $this->assertEmpty($linkDB->filter(LinkFilter::$FILTER_TAG, 'exclude')); | ||
240 | $updater = new Updater(array(), self::$configFields, $linkDB, true); | ||
241 | $updater->updateMethodRenameDashTags(); | ||
242 | var_dump($linkDB->filter(LinkFilter::$FILTER_TAG, 'exclude')); | ||
243 | $this->assertNotEmpty($linkDB->filter(LinkFilter::$FILTER_TAG, 'exclude')); | ||
244 | } | ||
227 | } | 245 | } |
diff --git a/tests/utils/ReferenceLinkDB.php b/tests/utils/ReferenceLinkDB.php index 011317ef..2f188d29 100644 --- a/tests/utils/ReferenceLinkDB.php +++ b/tests/utils/ReferenceLinkDB.php | |||
@@ -19,7 +19,7 @@ class ReferenceLinkDB | |||
19 | 'Richard Stallman and the Free Software Revolution', | 19 | 'Richard Stallman and the Free Software Revolution', |
20 | 0, | 20 | 0, |
21 | '20150310_114633', | 21 | '20150310_114633', |
22 | 'free gnu software stallman' | 22 | 'free gnu software stallman -exclude' |
23 | ); | 23 | ); |
24 | 24 | ||
25 | $this->addLink( | 25 | $this->addLink( |