diff options
-rw-r--r-- | application/FeedBuilder.php | 6 | ||||
-rw-r--r-- | application/LinkDB.php | 184 | ||||
-rw-r--r-- | application/LinkFilter.php | 37 | ||||
-rw-r--r-- | application/LinkUtils.php | 13 | ||||
-rw-r--r-- | application/NetscapeBookmarkUtils.php | 26 | ||||
-rw-r--r-- | application/Updater.php | 45 | ||||
-rw-r--r-- | application/Utils.php | 6 | ||||
-rw-r--r-- | index.php | 104 | ||||
-rw-r--r-- | plugins/isso/isso.php | 4 | ||||
-rw-r--r-- | tests/FeedBuilderTest.php | 31 | ||||
-rw-r--r-- | tests/LinkDBTest.php | 39 | ||||
-rw-r--r-- | tests/LinkFilterTest.php | 6 | ||||
-rw-r--r-- | tests/NetscapeBookmarkUtils/BookmarkExportTest.php | 6 | ||||
-rw-r--r-- | tests/NetscapeBookmarkUtils/BookmarkImportTest.php | 146 | ||||
-rw-r--r-- | tests/Updater/UpdaterTest.php | 98 | ||||
-rw-r--r-- | tests/plugins/PluginIssoTest.php | 25 | ||||
-rw-r--r-- | tests/utils/ReferenceLinkDB.php | 61 | ||||
-rw-r--r-- | tpl/daily.html | 4 | ||||
-rw-r--r-- | tpl/editlink.html | 3 | ||||
-rw-r--r-- | tpl/linklist.html | 6 |
20 files changed, 617 insertions, 233 deletions
diff --git a/application/FeedBuilder.php b/application/FeedBuilder.php index 4036a7cc..fedd90e6 100644 --- a/application/FeedBuilder.php +++ b/application/FeedBuilder.php | |||
@@ -143,7 +143,7 @@ class FeedBuilder | |||
143 | */ | 143 | */ |
144 | protected function buildItem($link, $pageaddr) | 144 | protected function buildItem($link, $pageaddr) |
145 | { | 145 | { |
146 | $link['guid'] = $pageaddr .'?'. smallHash($link['linkdate']); | 146 | $link['guid'] = $pageaddr .'?'. $link['shorturl']; |
147 | // Check for both signs of a note: starting with ? and 7 chars long. | 147 | // Check for both signs of a note: starting with ? and 7 chars long. |
148 | if ($link['url'][0] === '?' && strlen($link['url']) === 7) { | 148 | if ($link['url'][0] === '?' && strlen($link['url']) === 7) { |
149 | $link['url'] = $pageaddr . $link['url']; | 149 | $link['url'] = $pageaddr . $link['url']; |
@@ -156,12 +156,12 @@ class FeedBuilder | |||
156 | $link['description'] = format_description($link['description'], '', $pageaddr); | 156 | $link['description'] = format_description($link['description'], '', $pageaddr); |
157 | $link['description'] .= PHP_EOL .'<br>— '. $permalink; | 157 | $link['description'] .= PHP_EOL .'<br>— '. $permalink; |
158 | 158 | ||
159 | $pubDate = DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, $link['linkdate']); | 159 | $pubDate = $link['created']; |
160 | $link['pub_iso_date'] = $this->getIsoDate($pubDate); | 160 | $link['pub_iso_date'] = $this->getIsoDate($pubDate); |
161 | 161 | ||
162 | // atom:entry elements MUST contain exactly one atom:updated element. | 162 | // atom:entry elements MUST contain exactly one atom:updated element. |
163 | if (!empty($link['updated'])) { | 163 | if (!empty($link['updated'])) { |
164 | $upDate = DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, $link['updated']); | 164 | $upDate = $link['updated']; |
165 | $link['up_iso_date'] = $this->getIsoDate($upDate, DateTime::ATOM); | 165 | $link['up_iso_date'] = $this->getIsoDate($upDate, DateTime::ATOM); |
166 | } else { | 166 | } else { |
167 | $link['up_iso_date'] = $this->getIsoDate($pubDate, DateTime::ATOM);; | 167 | $link['up_iso_date'] = $this->getIsoDate($pubDate, DateTime::ATOM);; |
diff --git a/application/LinkDB.php b/application/LinkDB.php index c8b162b6..1e13286a 100644 --- a/application/LinkDB.php +++ b/application/LinkDB.php | |||
@@ -6,15 +6,15 @@ | |||
6 | * | 6 | * |
7 | * Example: | 7 | * Example: |
8 | * $myLinks = new LinkDB(); | 8 | * $myLinks = new LinkDB(); |
9 | * echo $myLinks['20110826_161819']['title']; | 9 | * echo $myLinks[350]['title']; |
10 | * foreach ($myLinks as $link) | 10 | * foreach ($myLinks as $link) |
11 | * echo $link['title'].' at url '.$link['url'].'; description:'.$link['description']; | 11 | * echo $link['title'].' at url '.$link['url'].'; description:'.$link['description']; |
12 | * | 12 | * |
13 | * Available keys: | 13 | * Available keys: |
14 | * - id: primary key, incremental integer identifier (persistent) | ||
14 | * - description: description of the entry | 15 | * - description: description of the entry |
15 | * - linkdate: creation date of this entry, format: YYYYMMDD_HHMMSS | 16 | * - created: creation date of this entry, DateTime object. |
16 | * (e.g.'20110914_192317') | 17 | * - updated: last modification date of this entry, DateTime object. |
17 | * - updated: last modification date of this entry, format: YYYYMMDD_HHMMSS | ||
18 | * - private: Is this link private? 0=no, other value=yes | 18 | * - private: Is this link private? 0=no, other value=yes |
19 | * - tags: tags attached to this entry (separated by spaces) | 19 | * - tags: tags attached to this entry (separated by spaces) |
20 | * - title Title of the link | 20 | * - title Title of the link |
@@ -22,11 +22,25 @@ | |||
22 | * Can be absolute or relative. | 22 | * Can be absolute or relative. |
23 | * Relative URLs are permalinks (e.g.'?m-ukcw') | 23 | * Relative URLs are permalinks (e.g.'?m-ukcw') |
24 | * - real_url Absolute processed URL. | 24 | * - real_url Absolute processed URL. |
25 | * - shorturl Permalink smallhash | ||
25 | * | 26 | * |
26 | * Implements 3 interfaces: | 27 | * Implements 3 interfaces: |
27 | * - ArrayAccess: behaves like an associative array; | 28 | * - ArrayAccess: behaves like an associative array; |
28 | * - Countable: there is a count() method; | 29 | * - Countable: there is a count() method; |
29 | * - Iterator: usable in foreach () loops. | 30 | * - Iterator: usable in foreach () loops. |
31 | * | ||
32 | * ID mechanism: | ||
33 | * ArrayAccess is implemented in a way that will allow to access a link | ||
34 | * with the unique identifier ID directly with $link[ID]. | ||
35 | * Note that it's not the real key of the link array attribute. | ||
36 | * This mechanism is in place to have persistent link IDs, | ||
37 | * even though the internal array is reordered by date. | ||
38 | * Example: | ||
39 | * - DB: link #1 (2010-01-01) link #2 (2016-01-01) | ||
40 | * - Order: #2 #1 | ||
41 | * - Import links containing: link #3 (2013-01-01) | ||
42 | * - New DB: link #1 (2010-01-01) link #2 (2016-01-01) link #3 (2013-01-01) | ||
43 | * - Real order: #2 #3 #1 | ||
30 | */ | 44 | */ |
31 | class LinkDB implements Iterator, Countable, ArrayAccess | 45 | class LinkDB implements Iterator, Countable, ArrayAccess |
32 | { | 46 | { |
@@ -47,11 +61,17 @@ class LinkDB implements Iterator, Countable, ArrayAccess | |||
47 | // - value: associative array (keys: title, description...) | 61 | // - value: associative array (keys: title, description...) |
48 | private $links; | 62 | private $links; |
49 | 63 | ||
50 | // List of all recorded URLs (key=url, value=linkdate) | 64 | // List of all recorded URLs (key=url, value=link offset) |
51 | // for fast reserve search (url-->linkdate) | 65 | // for fast reserve search (url-->link offset) |
52 | private $urls; | 66 | private $urls; |
53 | 67 | ||
54 | // List of linkdate keys (for the Iterator interface implementation) | 68 | /** |
69 | * @var array List of all links IDS mapped with their array offset. | ||
70 | * Map: id->offset. | ||
71 | */ | ||
72 | protected $ids; | ||
73 | |||
74 | // List of offset keys (for the Iterator interface implementation) | ||
55 | private $keys; | 75 | private $keys; |
56 | 76 | ||
57 | // Position in the $this->keys array (for the Iterator interface) | 77 | // Position in the $this->keys array (for the Iterator interface) |
@@ -121,14 +141,26 @@ class LinkDB implements Iterator, Countable, ArrayAccess | |||
121 | if (!$this->loggedIn) { | 141 | if (!$this->loggedIn) { |
122 | die('You are not authorized to add a link.'); | 142 | die('You are not authorized to add a link.'); |
123 | } | 143 | } |
124 | if (empty($value['linkdate']) || empty($value['url'])) { | 144 | if (!isset($value['id']) || empty($value['url'])) { |
125 | die('Internal Error: A link should always have a linkdate and URL.'); | 145 | die('Internal Error: A link should always have an id and URL.'); |
126 | } | 146 | } |
127 | if (empty($offset)) { | 147 | if ((! empty($offset) && ! is_int($offset)) || ! is_int($value['id'])) { |
128 | die('You must specify a key.'); | 148 | die('You must specify an integer as a key.'); |
149 | } | ||
150 | if (! empty($offset) && $offset !== $value['id']) { | ||
151 | die('Array offset and link ID must be equal.'); | ||
152 | } | ||
153 | |||
154 | // If the link exists, we reuse the real offset, otherwise new entry | ||
155 | $existing = $this->getLinkOffset($offset); | ||
156 | if ($existing !== null) { | ||
157 | $offset = $existing; | ||
158 | } else { | ||
159 | $offset = count($this->links); | ||
129 | } | 160 | } |
130 | $this->links[$offset] = $value; | 161 | $this->links[$offset] = $value; |
131 | $this->urls[$value['url']]=$offset; | 162 | $this->urls[$value['url']] = $offset; |
163 | $this->ids[$value['id']] = $offset; | ||
132 | } | 164 | } |
133 | 165 | ||
134 | /** | 166 | /** |
@@ -136,7 +168,7 @@ class LinkDB implements Iterator, Countable, ArrayAccess | |||
136 | */ | 168 | */ |
137 | public function offsetExists($offset) | 169 | public function offsetExists($offset) |
138 | { | 170 | { |
139 | return array_key_exists($offset, $this->links); | 171 | return array_key_exists($this->getLinkOffset($offset), $this->links); |
140 | } | 172 | } |
141 | 173 | ||
142 | /** | 174 | /** |
@@ -148,9 +180,11 @@ class LinkDB implements Iterator, Countable, ArrayAccess | |||
148 | // TODO: raise an exception | 180 | // TODO: raise an exception |
149 | die('You are not authorized to delete a link.'); | 181 | die('You are not authorized to delete a link.'); |
150 | } | 182 | } |
151 | $url = $this->links[$offset]['url']; | 183 | $realOffset = $this->getLinkOffset($offset); |
184 | $url = $this->links[$realOffset]['url']; | ||
152 | unset($this->urls[$url]); | 185 | unset($this->urls[$url]); |
153 | unset($this->links[$offset]); | 186 | unset($this->ids[$realOffset]); |
187 | unset($this->links[$realOffset]); | ||
154 | } | 188 | } |
155 | 189 | ||
156 | /** | 190 | /** |
@@ -158,7 +192,8 @@ class LinkDB implements Iterator, Countable, ArrayAccess | |||
158 | */ | 192 | */ |
159 | public function offsetGet($offset) | 193 | public function offsetGet($offset) |
160 | { | 194 | { |
161 | return isset($this->links[$offset]) ? $this->links[$offset] : null; | 195 | $realOffset = $this->getLinkOffset($offset); |
196 | return isset($this->links[$realOffset]) ? $this->links[$realOffset] : null; | ||
162 | } | 197 | } |
163 | 198 | ||
164 | /** | 199 | /** |
@@ -166,7 +201,7 @@ class LinkDB implements Iterator, Countable, ArrayAccess | |||
166 | */ | 201 | */ |
167 | public function current() | 202 | public function current() |
168 | { | 203 | { |
169 | return $this->links[$this->keys[$this->position]]; | 204 | return $this[$this->keys[$this->position]]; |
170 | } | 205 | } |
171 | 206 | ||
172 | /** | 207 | /** |
@@ -192,8 +227,7 @@ class LinkDB implements Iterator, Countable, ArrayAccess | |||
192 | */ | 227 | */ |
193 | public function rewind() | 228 | public function rewind() |
194 | { | 229 | { |
195 | $this->keys = array_keys($this->links); | 230 | $this->keys = array_keys($this->ids); |
196 | rsort($this->keys); | ||
197 | $this->position = 0; | 231 | $this->position = 0; |
198 | } | 232 | } |
199 | 233 | ||
@@ -219,6 +253,7 @@ class LinkDB implements Iterator, Countable, ArrayAccess | |||
219 | // Create a dummy database for example | 253 | // Create a dummy database for example |
220 | $this->links = array(); | 254 | $this->links = array(); |
221 | $link = array( | 255 | $link = array( |
256 | 'id' => 1, | ||
222 | 'title'=>' Shaarli: the personal, minimalist, super-fast, no-database delicious clone', | 257 | 'title'=>' Shaarli: the personal, minimalist, super-fast, no-database delicious clone', |
223 | 'url'=>'https://github.com/shaarli/Shaarli/wiki', | 258 | 'url'=>'https://github.com/shaarli/Shaarli/wiki', |
224 | 'description'=>'Welcome to Shaarli! This is your first public bookmark. To edit or delete me, you must first login. | 259 | 'description'=>'Welcome to Shaarli! This is your first public bookmark. To edit or delete me, you must first login. |
@@ -227,20 +262,23 @@ To learn how to use Shaarli, consult the link "Help/documentation" at the bottom | |||
227 | 262 | ||
228 | You use the community supported version of the original Shaarli project, by Sebastien Sauvage.', | 263 | You use the community supported version of the original Shaarli project, by Sebastien Sauvage.', |
229 | 'private'=>0, | 264 | 'private'=>0, |
230 | 'linkdate'=> date('Ymd_His'), | 265 | 'created'=> new DateTime(), |
231 | 'tags'=>'opensource software' | 266 | 'tags'=>'opensource software' |
232 | ); | 267 | ); |
233 | $this->links[$link['linkdate']] = $link; | 268 | $link['shorturl'] = link_small_hash($link['created'], $link['id']); |
269 | $this->links[1] = $link; | ||
234 | 270 | ||
235 | $link = array( | 271 | $link = array( |
272 | 'id' => 0, | ||
236 | 'title'=>'My secret stuff... - Pastebin.com', | 273 | 'title'=>'My secret stuff... - Pastebin.com', |
237 | 'url'=>'http://sebsauvage.net/paste/?8434b27936c09649#bR7XsXhoTiLcqCpQbmOpBi3rq2zzQUC5hBI7ZT1O3x8=', | 274 | 'url'=>'http://sebsauvage.net/paste/?8434b27936c09649#bR7XsXhoTiLcqCpQbmOpBi3rq2zzQUC5hBI7ZT1O3x8=', |
238 | 'description'=>'Shhhh! I\'m a private link only YOU can see. You can delete me too.', | 275 | 'description'=>'Shhhh! I\'m a private link only YOU can see. You can delete me too.', |
239 | 'private'=>1, | 276 | 'private'=>1, |
240 | 'linkdate'=> date('Ymd_His', strtotime('-1 minute')), | 277 | 'created'=> new DateTime('1 minute ago'), |
241 | 'tags'=>'secretstuff' | 278 | 'tags'=>'secretstuff', |
242 | ); | 279 | ); |
243 | $this->links[$link['linkdate']] = $link; | 280 | $link['shorturl'] = link_small_hash($link['created'], $link['id']); |
281 | $this->links[0] = $link; | ||
244 | 282 | ||
245 | // Write database to disk | 283 | // Write database to disk |
246 | $this->write(); | 284 | $this->write(); |
@@ -251,7 +289,6 @@ You use the community supported version of the original Shaarli project, by Seba | |||
251 | */ | 289 | */ |
252 | private function read() | 290 | private function read() |
253 | { | 291 | { |
254 | |||
255 | // Public links are hidden and user not logged in => nothing to show | 292 | // Public links are hidden and user not logged in => nothing to show |
256 | if ($this->hidePublicLinks && !$this->loggedIn) { | 293 | if ($this->hidePublicLinks && !$this->loggedIn) { |
257 | $this->links = array(); | 294 | $this->links = array(); |
@@ -269,23 +306,13 @@ You use the community supported version of the original Shaarli project, by Seba | |||
269 | strlen(self::$phpPrefix), -strlen(self::$phpSuffix))))); | 306 | strlen(self::$phpPrefix), -strlen(self::$phpSuffix))))); |
270 | } | 307 | } |
271 | 308 | ||
272 | // If user is not logged in, filter private links. | 309 | $toremove = array(); |
273 | if (!$this->loggedIn) { | 310 | foreach ($this->links as $key => &$link) { |
274 | $toremove = array(); | 311 | if (! $this->loggedIn && $link['private'] != 0) { |
275 | foreach ($this->links as $link) { | 312 | // Transition for not upgraded databases. |
276 | if ($link['private'] != 0) { | 313 | $toremove[] = $key; |
277 | $toremove[] = $link['linkdate']; | 314 | continue; |
278 | } | ||
279 | } | ||
280 | foreach ($toremove as $linkdate) { | ||
281 | unset($this->links[$linkdate]); | ||
282 | } | 315 | } |
283 | } | ||
284 | |||
285 | $this->urls = array(); | ||
286 | foreach ($this->links as &$link) { | ||
287 | // Keep the list of the mapping URLs-->linkdate up-to-date. | ||
288 | $this->urls[$link['url']] = $link['linkdate']; | ||
289 | 316 | ||
290 | // Sanitize data fields. | 317 | // Sanitize data fields. |
291 | sanitizeLink($link); | 318 | sanitizeLink($link); |
@@ -307,7 +334,24 @@ You use the community supported version of the original Shaarli project, by Seba | |||
307 | else { | 334 | else { |
308 | $link['real_url'] = $link['url']; | 335 | $link['real_url'] = $link['url']; |
309 | } | 336 | } |
337 | |||
338 | // To be able to load links before running the update, and prepare the update | ||
339 | if (! isset($link['created'])) { | ||
340 | $link['id'] = $link['linkdate']; | ||
341 | $link['created'] = DateTime::createFromFormat(self::LINK_DATE_FORMAT, $link['linkdate']); | ||
342 | if (! empty($link['updated'])) { | ||
343 | $link['updated'] = DateTime::createFromFormat(self::LINK_DATE_FORMAT, $link['updated']); | ||
344 | } | ||
345 | $link['shorturl'] = smallHash($link['linkdate']); | ||
346 | } | ||
347 | } | ||
348 | |||
349 | // If user is not logged in, filter private links. | ||
350 | foreach ($toremove as $offset) { | ||
351 | unset($this->links[$offset]); | ||
310 | } | 352 | } |
353 | |||
354 | $this->reorder(); | ||
311 | } | 355 | } |
312 | 356 | ||
313 | /** | 357 | /** |
@@ -430,7 +474,7 @@ You use the community supported version of the original Shaarli project, by Seba | |||
430 | $request = ''; | 474 | $request = ''; |
431 | } | 475 | } |
432 | 476 | ||
433 | $linkFilter = new LinkFilter($this->links); | 477 | $linkFilter = new LinkFilter($this); |
434 | return $linkFilter->filter($type, $request, $casesensitive, $privateonly); | 478 | return $linkFilter->filter($type, $request, $casesensitive, $privateonly); |
435 | } | 479 | } |
436 | 480 | ||
@@ -467,12 +511,64 @@ You use the community supported version of the original Shaarli project, by Seba | |||
467 | public function days() | 511 | public function days() |
468 | { | 512 | { |
469 | $linkDays = array(); | 513 | $linkDays = array(); |
470 | foreach (array_keys($this->links) as $day) { | 514 | foreach ($this->links as $link) { |
471 | $linkDays[substr($day, 0, 8)] = 0; | 515 | $linkDays[$link['created']->format('Ymd')] = 0; |
472 | } | 516 | } |
473 | $linkDays = array_keys($linkDays); | 517 | $linkDays = array_keys($linkDays); |
474 | sort($linkDays); | 518 | sort($linkDays); |
475 | 519 | ||
476 | return $linkDays; | 520 | return $linkDays; |
477 | } | 521 | } |
522 | |||
523 | /** | ||
524 | * Reorder links by creation date (newest first). | ||
525 | * | ||
526 | * Also update the urls and ids mapping arrays. | ||
527 | * | ||
528 | * @param string $order ASC|DESC | ||
529 | */ | ||
530 | public function reorder($order = 'DESC') | ||
531 | { | ||
532 | $order = $order === 'ASC' ? -1 : 1; | ||
533 | // Reorder array by dates. | ||
534 | usort($this->links, function($a, $b) use ($order) { | ||
535 | return $a['created'] < $b['created'] ? 1 * $order : -1 * $order; | ||
536 | }); | ||
537 | |||
538 | $this->urls = array(); | ||
539 | $this->ids = array(); | ||
540 | foreach ($this->links as $key => $link) { | ||
541 | $this->urls[$link['url']] = $key; | ||
542 | $this->ids[$link['id']] = $key; | ||
543 | } | ||
544 | } | ||
545 | |||
546 | /** | ||
547 | * Return the next key for link creation. | ||
548 | * E.g. If the last ID is 597, the next will be 598. | ||
549 | * | ||
550 | * @return int next ID. | ||
551 | */ | ||
552 | public function getNextId() | ||
553 | { | ||
554 | if (!empty($this->ids)) { | ||
555 | return max(array_keys($this->ids)) + 1; | ||
556 | } | ||
557 | return 0; | ||
558 | } | ||
559 | |||
560 | /** | ||
561 | * Returns a link offset in links array from its unique ID. | ||
562 | * | ||
563 | * @param int $id Persistent ID of a link. | ||
564 | * | ||
565 | * @return int Real offset in local array, or null if doesn't exist. | ||
566 | */ | ||
567 | protected function getLinkOffset($id) | ||
568 | { | ||
569 | if (isset($this->ids[$id])) { | ||
570 | return $this->ids[$id]; | ||
571 | } | ||
572 | return null; | ||
573 | } | ||
478 | } | 574 | } |
diff --git a/application/LinkFilter.php b/application/LinkFilter.php index d4fe28df..daa6d9cc 100644 --- a/application/LinkFilter.php +++ b/application/LinkFilter.php | |||
@@ -33,12 +33,12 @@ class LinkFilter | |||
33 | public static $HASHTAG_CHARS = '\p{Pc}\p{N}\p{L}\p{Mn}'; | 33 | public static $HASHTAG_CHARS = '\p{Pc}\p{N}\p{L}\p{Mn}'; |
34 | 34 | ||
35 | /** | 35 | /** |
36 | * @var array all available links. | 36 | * @var LinkDB all available links. |
37 | */ | 37 | */ |
38 | private $links; | 38 | private $links; |
39 | 39 | ||
40 | /** | 40 | /** |
41 | * @param array $links initialization. | 41 | * @param LinkDB $links initialization. |
42 | */ | 42 | */ |
43 | public function __construct($links) | 43 | public function __construct($links) |
44 | { | 44 | { |
@@ -94,18 +94,16 @@ class LinkFilter | |||
94 | private function noFilter($privateonly = false) | 94 | private function noFilter($privateonly = false) |
95 | { | 95 | { |
96 | if (! $privateonly) { | 96 | if (! $privateonly) { |
97 | krsort($this->links); | ||
98 | return $this->links; | 97 | return $this->links; |
99 | } | 98 | } |
100 | 99 | ||
101 | $out = array(); | 100 | $out = array(); |
102 | foreach ($this->links as $value) { | 101 | foreach ($this->links as $key => $value) { |
103 | if ($value['private']) { | 102 | if ($value['private']) { |
104 | $out[$value['linkdate']] = $value; | 103 | $out[$key] = $value; |
105 | } | 104 | } |
106 | } | 105 | } |
107 | 106 | ||
108 | krsort($out); | ||
109 | return $out; | 107 | return $out; |
110 | } | 108 | } |
111 | 109 | ||
@@ -121,10 +119,10 @@ class LinkFilter | |||
121 | private function filterSmallHash($smallHash) | 119 | private function filterSmallHash($smallHash) |
122 | { | 120 | { |
123 | $filtered = array(); | 121 | $filtered = array(); |
124 | foreach ($this->links as $l) { | 122 | foreach ($this->links as $key => $l) { |
125 | if ($smallHash == smallHash($l['linkdate'])) { | 123 | if ($smallHash == $l['shorturl']) { |
126 | // Yes, this is ugly and slow | 124 | // Yes, this is ugly and slow |
127 | $filtered[$l['linkdate']] = $l; | 125 | $filtered[$key] = $l; |
128 | return $filtered; | 126 | return $filtered; |
129 | } | 127 | } |
130 | } | 128 | } |
@@ -188,7 +186,7 @@ class LinkFilter | |||
188 | $keys = array('title', 'description', 'url', 'tags'); | 186 | $keys = array('title', 'description', 'url', 'tags'); |
189 | 187 | ||
190 | // Iterate over every stored link. | 188 | // Iterate over every stored link. |
191 | foreach ($this->links as $link) { | 189 | foreach ($this->links as $id => $link) { |
192 | 190 | ||
193 | // ignore non private links when 'privatonly' is on. | 191 | // ignore non private links when 'privatonly' is on. |
194 | if (! $link['private'] && $privateonly === true) { | 192 | if (! $link['private'] && $privateonly === true) { |
@@ -222,11 +220,10 @@ class LinkFilter | |||
222 | } | 220 | } |
223 | 221 | ||
224 | if ($found) { | 222 | if ($found) { |
225 | $filtered[$link['linkdate']] = $link; | 223 | $filtered[$id] = $link; |
226 | } | 224 | } |
227 | } | 225 | } |
228 | 226 | ||
229 | krsort($filtered); | ||
230 | return $filtered; | 227 | return $filtered; |
231 | } | 228 | } |
232 | 229 | ||
@@ -256,7 +253,7 @@ class LinkFilter | |||
256 | return $filtered; | 253 | return $filtered; |
257 | } | 254 | } |
258 | 255 | ||
259 | foreach ($this->links as $link) { | 256 | foreach ($this->links as $key => $link) { |
260 | // ignore non private links when 'privatonly' is on. | 257 | // ignore non private links when 'privatonly' is on. |
261 | if (! $link['private'] && $privateonly === true) { | 258 | if (! $link['private'] && $privateonly === true) { |
262 | continue; | 259 | continue; |
@@ -278,10 +275,9 @@ class LinkFilter | |||
278 | } | 275 | } |
279 | 276 | ||
280 | if ($found) { | 277 | if ($found) { |
281 | $filtered[$link['linkdate']] = $link; | 278 | $filtered[$key] = $link; |
282 | } | 279 | } |
283 | } | 280 | } |
284 | krsort($filtered); | ||
285 | return $filtered; | 281 | return $filtered; |
286 | } | 282 | } |
287 | 283 | ||
@@ -304,13 +300,14 @@ class LinkFilter | |||
304 | } | 300 | } |
305 | 301 | ||
306 | $filtered = array(); | 302 | $filtered = array(); |
307 | foreach ($this->links as $l) { | 303 | foreach ($this->links as $key => $l) { |
308 | if (startsWith($l['linkdate'], $day)) { | 304 | if ($l['created']->format('Ymd') == $day) { |
309 | $filtered[$l['linkdate']] = $l; | 305 | $filtered[$key] = $l; |
310 | } | 306 | } |
311 | } | 307 | } |
312 | ksort($filtered); | 308 | |
313 | return $filtered; | 309 | // sort by date ASC |
310 | return array_reverse($filtered, true); | ||
314 | } | 311 | } |
315 | 312 | ||
316 | /** | 313 | /** |
diff --git a/application/LinkUtils.php b/application/LinkUtils.php index 9d9ae3cb..cf58f808 100644 --- a/application/LinkUtils.php +++ b/application/LinkUtils.php | |||
@@ -169,3 +169,16 @@ function space2nbsp($text) | |||
169 | function format_description($description, $redirector = '', $indexUrl = '') { | 169 | function format_description($description, $redirector = '', $indexUrl = '') { |
170 | return nl2br(space2nbsp(hashtag_autolink(text2clickable($description, $redirector), $indexUrl))); | 170 | return nl2br(space2nbsp(hashtag_autolink(text2clickable($description, $redirector), $indexUrl))); |
171 | } | 171 | } |
172 | |||
173 | /** | ||
174 | * Generate a small hash for a link. | ||
175 | * | ||
176 | * @param DateTime $date Link creation date. | ||
177 | * @param int $id Link ID. | ||
178 | * | ||
179 | * @return string the small hash generated from link data. | ||
180 | */ | ||
181 | function link_small_hash($date, $id) | ||
182 | { | ||
183 | return smallHash($date->format(LinkDB::LINK_DATE_FORMAT) . $id); | ||
184 | } | ||
diff --git a/application/NetscapeBookmarkUtils.php b/application/NetscapeBookmarkUtils.php index dd21f05b..e7148d00 100644 --- a/application/NetscapeBookmarkUtils.php +++ b/application/NetscapeBookmarkUtils.php | |||
@@ -38,7 +38,7 @@ class NetscapeBookmarkUtils | |||
38 | if ($link['private'] == 0 && $selection == 'private') { | 38 | if ($link['private'] == 0 && $selection == 'private') { |
39 | continue; | 39 | continue; |
40 | } | 40 | } |
41 | $date = DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, $link['linkdate']); | 41 | $date = $link['created']; |
42 | $link['timestamp'] = $date->getTimestamp(); | 42 | $link['timestamp'] = $date->getTimestamp(); |
43 | $link['taglist'] = str_replace(' ', ',', $link['tags']); | 43 | $link['taglist'] = str_replace(' ', ',', $link['tags']); |
44 | 44 | ||
@@ -147,7 +147,6 @@ class NetscapeBookmarkUtils | |||
147 | 'url' => $bkm['uri'], | 147 | 'url' => $bkm['uri'], |
148 | 'description' => $bkm['note'], | 148 | 'description' => $bkm['note'], |
149 | 'private' => $private, | 149 | 'private' => $private, |
150 | 'linkdate'=> '', | ||
151 | 'tags' => $bkm['tags'] | 150 | 'tags' => $bkm['tags'] |
152 | ); | 151 | ); |
153 | 152 | ||
@@ -161,25 +160,22 @@ class NetscapeBookmarkUtils | |||
161 | } | 160 | } |
162 | 161 | ||
163 | // Overwrite an existing link, keep its date | 162 | // Overwrite an existing link, keep its date |
164 | $newLink['linkdate'] = $existingLink['linkdate']; | 163 | $newLink['id'] = $existingLink['id']; |
165 | $linkDb[$existingLink['linkdate']] = $newLink; | 164 | $newLink['created'] = $existingLink['created']; |
165 | $newLink['updated'] = new DateTime(); | ||
166 | $linkDb[$existingLink['id']] = $newLink; | ||
166 | $importCount++; | 167 | $importCount++; |
167 | $overwriteCount++; | 168 | $overwriteCount++; |
168 | continue; | 169 | continue; |
169 | } | 170 | } |
170 | 171 | ||
171 | // Add a new link | 172 | // Add a new link - @ used for UNIX timestamps |
172 | $newLinkDate = new DateTime('@'.strval($bkm['time'])); | 173 | $newLinkDate = new DateTime('@'.strval($bkm['time'])); |
173 | while (!empty($linkDb[$newLinkDate->format(LinkDB::LINK_DATE_FORMAT)])) { | 174 | $newLinkDate->setTimezone(new DateTimeZone(date_default_timezone_get())); |
174 | // Ensure the date/time is not already used | 175 | $newLink['created'] = $newLinkDate; |
175 | // - this hack is necessary as the date/time acts as a primary key | 176 | $newLink['id'] = $linkDb->getNextId(); |
176 | // - apply 1 second increments until an unused index is found | 177 | $newLink['shorturl'] = link_small_hash($newLink['created'], $newLink['id']); |
177 | // See https://github.com/shaarli/Shaarli/issues/351 | 178 | $linkDb[$newLink['id']] = $newLink; |
178 | $newLinkDate->add(new DateInterval('PT1S')); | ||
179 | } | ||
180 | $linkDbDate = $newLinkDate->format(LinkDB::LINK_DATE_FORMAT); | ||
181 | $newLink['linkdate'] = $linkDbDate; | ||
182 | $linkDb[$linkDbDate] = $newLink; | ||
183 | $importCount++; | 179 | $importCount++; |
184 | } | 180 | } |
185 | 181 | ||
diff --git a/application/Updater.php b/application/Updater.php index 36eddd4f..f0d02814 100644 --- a/application/Updater.php +++ b/application/Updater.php | |||
@@ -138,10 +138,10 @@ class Updater | |||
138 | public function updateMethodRenameDashTags() | 138 | public function updateMethodRenameDashTags() |
139 | { | 139 | { |
140 | $linklist = $this->linkDB->filterSearch(); | 140 | $linklist = $this->linkDB->filterSearch(); |
141 | foreach ($linklist as $link) { | 141 | foreach ($linklist as $key => $link) { |
142 | $link['tags'] = preg_replace('/(^| )\-/', '$1', $link['tags']); | 142 | $link['tags'] = preg_replace('/(^| )\-/', '$1', $link['tags']); |
143 | $link['tags'] = implode(' ', array_unique(LinkFilter::tagsStrToArray($link['tags'], true))); | 143 | $link['tags'] = implode(' ', array_unique(LinkFilter::tagsStrToArray($link['tags'], true))); |
144 | $this->linkDB[$link['linkdate']] = $link; | 144 | $this->linkDB[$key] = $link; |
145 | } | 145 | } |
146 | $this->linkDB->save($this->conf->get('resource.page_cache')); | 146 | $this->linkDB->save($this->conf->get('resource.page_cache')); |
147 | return true; | 147 | return true; |
@@ -215,6 +215,47 @@ class Updater | |||
215 | } | 215 | } |
216 | return true; | 216 | return true; |
217 | } | 217 | } |
218 | |||
219 | /** | ||
220 | * Update the database to use the new ID system, which replaces linkdate primary keys. | ||
221 | * Also, creation and update dates are now DateTime objects (done by LinkDB). | ||
222 | * | ||
223 | * Since this update is very sensitve (changing the whole database), the datastore will be | ||
224 | * automatically backed up into the file datastore.<datetime>.php. | ||
225 | * | ||
226 | * LinkDB also adds the field 'shorturl' with the precedent format (linkdate smallhash), | ||
227 | * which will be saved by this method. | ||
228 | * | ||
229 | * @return bool true if the update is successful, false otherwise. | ||
230 | */ | ||
231 | public function updateMethodDatastoreIds() | ||
232 | { | ||
233 | // up to date database | ||
234 | if (isset($this->linkDB[0])) { | ||
235 | return true; | ||
236 | } | ||
237 | |||
238 | $save = $this->conf->get('resource.data_dir') .'/datastore.'. date('YmdHis') .'.php'; | ||
239 | copy($this->conf->get('resource.datastore'), $save); | ||
240 | |||
241 | $links = array(); | ||
242 | foreach ($this->linkDB as $offset => $value) { | ||
243 | $links[] = $value; | ||
244 | unset($this->linkDB[$offset]); | ||
245 | } | ||
246 | $links = array_reverse($links); | ||
247 | $cpt = 0; | ||
248 | foreach ($links as $l) { | ||
249 | unset($l['linkdate']); | ||
250 | $l['id'] = $cpt; | ||
251 | $this->linkDB[$cpt++] = $l; | ||
252 | } | ||
253 | |||
254 | $this->linkDB->save($this->conf->get('resource.page_cache')); | ||
255 | $this->linkDB->reorder(); | ||
256 | |||
257 | return true; | ||
258 | } | ||
218 | } | 259 | } |
219 | 260 | ||
220 | /** | 261 | /** |
diff --git a/application/Utils.php b/application/Utils.php index 0166ee2a..0a5b476e 100644 --- a/application/Utils.php +++ b/application/Utils.php | |||
@@ -31,7 +31,11 @@ function logm($logFile, $clientIp, $message) | |||
31 | * - are NOT cryptographically secure (they CAN be forged) | 31 | * - are NOT cryptographically secure (they CAN be forged) |
32 | * | 32 | * |
33 | * In Shaarli, they are used as a tinyurl-like link to individual entries, | 33 | * In Shaarli, they are used as a tinyurl-like link to individual entries, |
34 | * e.g. smallHash('20111006_131924') --> yZH23w | 34 | * built once with the combination of the date and item ID. |
35 | * e.g. smallHash('20111006_131924' . 142) --> eaWxtQ | ||
36 | * | ||
37 | * @warning before v0.8.1, smallhashes were built only with the date, | ||
38 | * and their value has been preserved. | ||
35 | * | 39 | * |
36 | * @param string $text Create a hash from this text. | 40 | * @param string $text Create a hash from this text. |
37 | * | 41 | * |
@@ -564,24 +564,19 @@ function showDailyRSS($conf) { | |||
564 | ); | 564 | ); |
565 | 565 | ||
566 | /* Some Shaarlies may have very few links, so we need to look | 566 | /* Some Shaarlies may have very few links, so we need to look |
567 | back in time (rsort()) until we have enough days ($nb_of_days). | 567 | back in time until we have enough days ($nb_of_days). |
568 | */ | 568 | */ |
569 | $linkdates = array(); | ||
570 | foreach ($LINKSDB as $linkdate => $value) { | ||
571 | $linkdates[] = $linkdate; | ||
572 | } | ||
573 | rsort($linkdates); | ||
574 | $nb_of_days = 7; // We take 7 days. | 569 | $nb_of_days = 7; // We take 7 days. |
575 | $today = date('Ymd'); | 570 | $today = date('Ymd'); |
576 | $days = array(); | 571 | $days = array(); |
577 | 572 | ||
578 | foreach ($linkdates as $linkdate) { | 573 | foreach ($LINKSDB as $link) { |
579 | $day = substr($linkdate, 0, 8); // Extract day (without time) | 574 | $day = $link['created']->format('Ymd'); // Extract day (without time) |
580 | if (strcmp($day,$today) < 0) { | 575 | if (strcmp($day, $today) < 0) { |
581 | if (empty($days[$day])) { | 576 | if (empty($days[$day])) { |
582 | $days[$day] = array(); | 577 | $days[$day] = array(); |
583 | } | 578 | } |
584 | $days[$day][] = $linkdate; | 579 | $days[$day][] = $link; |
585 | } | 580 | } |
586 | 581 | ||
587 | if (count($days) > $nb_of_days) { | 582 | if (count($days) > $nb_of_days) { |
@@ -601,24 +596,18 @@ function showDailyRSS($conf) { | |||
601 | echo '<copyright>'. $pageaddr .'</copyright>'. PHP_EOL; | 596 | echo '<copyright>'. $pageaddr .'</copyright>'. PHP_EOL; |
602 | 597 | ||
603 | // For each day. | 598 | // For each day. |
604 | foreach ($days as $day => $linkdates) { | 599 | foreach ($days as $day => $links) { |
605 | $dayDate = DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, $day.'_000000'); | 600 | $dayDate = DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, $day.'_000000'); |
606 | $absurl = escape(index_url($_SERVER).'?do=daily&day='.$day); // Absolute URL of the corresponding "Daily" page. | 601 | $absurl = escape(index_url($_SERVER).'?do=daily&day='.$day); // Absolute URL of the corresponding "Daily" page. |
607 | 602 | ||
608 | // Build the HTML body of this RSS entry. | ||
609 | $links = array(); | ||
610 | |||
611 | // We pre-format some fields for proper output. | 603 | // We pre-format some fields for proper output. |
612 | foreach ($linkdates as $linkdate) { | 604 | foreach ($links as &$link) { |
613 | $l = $LINKSDB[$linkdate]; | 605 | $link['formatedDescription'] = format_description($link['description'], $conf->get('redirector.url')); |
614 | $l['formatedDescription'] = format_description($l['description'], $conf->get('redirector.url')); | 606 | $link['thumbnail'] = thumbnail($conf, $link['url']); |
615 | $l['thumbnail'] = thumbnail($conf, $l['url']); | 607 | $link['timestamp'] = $link['created']->getTimestamp(); |
616 | $l_date = DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, $l['linkdate']); | 608 | if (startsWith($link['url'], '?')) { |
617 | $l['timestamp'] = $l_date->getTimestamp(); | 609 | $link['url'] = index_url($_SERVER) . $link['url']; // make permalink URL absolute |
618 | if (startsWith($l['url'], '?')) { | ||
619 | $l['url'] = index_url($_SERVER) . $l['url']; // make permalink URL absolute | ||
620 | } | 610 | } |
621 | $links[$linkdate] = $l; | ||
622 | } | 611 | } |
623 | 612 | ||
624 | // Then build the HTML for this day: | 613 | // Then build the HTML for this day: |
@@ -680,8 +669,7 @@ function showDaily($pageBuilder, $LINKSDB, $conf, $pluginManager) | |||
680 | $linksToDisplay[$key]['taglist']=$taglist; | 669 | $linksToDisplay[$key]['taglist']=$taglist; |
681 | $linksToDisplay[$key]['formatedDescription'] = format_description($link['description'], $conf->get('redirector.url')); | 670 | $linksToDisplay[$key]['formatedDescription'] = format_description($link['description'], $conf->get('redirector.url')); |
682 | $linksToDisplay[$key]['thumbnail'] = thumbnail($conf, $link['url']); | 671 | $linksToDisplay[$key]['thumbnail'] = thumbnail($conf, $link['url']); |
683 | $date = DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, $link['linkdate']); | 672 | $linksToDisplay[$key]['timestamp'] = $link['created']->getTimestamp(); |
684 | $linksToDisplay[$key]['timestamp'] = $date->getTimestamp(); | ||
685 | } | 673 | } |
686 | 674 | ||
687 | /* We need to spread the articles on 3 columns. | 675 | /* We need to spread the articles on 3 columns. |
@@ -831,7 +819,7 @@ function renderPage($conf, $pluginManager) | |||
831 | // Get only links which have a thumbnail. | 819 | // Get only links which have a thumbnail. |
832 | foreach($links as $link) | 820 | foreach($links as $link) |
833 | { | 821 | { |
834 | $permalink='?'.escape(smallHash($link['linkdate'])); | 822 | $permalink='?'.$link['shorturl']; |
835 | $thumb=lazyThumbnail($conf, $link['url'],$permalink); | 823 | $thumb=lazyThumbnail($conf, $link['url'],$permalink); |
836 | if ($thumb!='') // Only output links which have a thumbnail. | 824 | if ($thumb!='') // Only output links which have a thumbnail. |
837 | { | 825 | { |
@@ -1245,13 +1233,28 @@ function renderPage($conf, $pluginManager) | |||
1245 | // -------- User clicked the "Save" button when editing a link: Save link to database. | 1233 | // -------- User clicked the "Save" button when editing a link: Save link to database. |
1246 | if (isset($_POST['save_edit'])) | 1234 | if (isset($_POST['save_edit'])) |
1247 | { | 1235 | { |
1248 | $linkdate = $_POST['lf_linkdate']; | ||
1249 | $updated = isset($LINKSDB[$linkdate]) ? strval(date('Ymd_His')) : false; | ||
1250 | |||
1251 | // Go away! | 1236 | // Go away! |
1252 | if (! tokenOk($_POST['token'])) { | 1237 | if (! tokenOk($_POST['token'])) { |
1253 | die('Wrong token.'); | 1238 | die('Wrong token.'); |
1254 | } | 1239 | } |
1240 | |||
1241 | // lf_id should only be present if the link exists. | ||
1242 | $id = !empty($_POST['lf_id']) ? intval(escape($_POST['lf_id'])) : $LINKSDB->getNextId(); | ||
1243 | // Linkdate is kept here to: | ||
1244 | // - use the same permalink for notes as they're displayed when creating them | ||
1245 | // - let users hack creation date of their posts | ||
1246 | // See: https://github.com/shaarli/Shaarli/wiki/Datastore-hacks#changing-the-timestamp-for-a-link | ||
1247 | $linkdate = escape($_POST['lf_linkdate']); | ||
1248 | if (isset($LINKSDB[$id])) { | ||
1249 | // Edit | ||
1250 | $created = DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, $linkdate); | ||
1251 | $updated = new DateTime(); | ||
1252 | } else { | ||
1253 | // New link | ||
1254 | $created = DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, $linkdate); | ||
1255 | $updated = null; | ||
1256 | } | ||
1257 | |||
1255 | // Remove multiple spaces. | 1258 | // Remove multiple spaces. |
1256 | $tags = trim(preg_replace('/\s\s+/', ' ', $_POST['lf_tags'])); | 1259 | $tags = trim(preg_replace('/\s\s+/', ' ', $_POST['lf_tags'])); |
1257 | // Remove first '-' char in tags. | 1260 | // Remove first '-' char in tags. |
@@ -1268,14 +1271,17 @@ function renderPage($conf, $pluginManager) | |||
1268 | } | 1271 | } |
1269 | 1272 | ||
1270 | $link = array( | 1273 | $link = array( |
1274 | 'id' => $id, | ||
1271 | 'title' => trim($_POST['lf_title']), | 1275 | 'title' => trim($_POST['lf_title']), |
1272 | 'url' => $url, | 1276 | 'url' => $url, |
1273 | 'description' => $_POST['lf_description'], | 1277 | 'description' => $_POST['lf_description'], |
1274 | 'private' => (isset($_POST['lf_private']) ? 1 : 0), | 1278 | 'private' => (isset($_POST['lf_private']) ? 1 : 0), |
1275 | 'linkdate' => $linkdate, | 1279 | 'created' => $created, |
1276 | 'updated' => $updated, | 1280 | 'updated' => $updated, |
1277 | 'tags' => str_replace(',', ' ', $tags) | 1281 | 'tags' => str_replace(',', ' ', $tags), |
1282 | 'shorturl' => link_small_hash($created, $id), | ||
1278 | ); | 1283 | ); |
1284 | |||
1279 | // If title is empty, use the URL as title. | 1285 | // If title is empty, use the URL as title. |
1280 | if ($link['title'] == '') { | 1286 | if ($link['title'] == '') { |
1281 | $link['title'] = $link['url']; | 1287 | $link['title'] = $link['url']; |
@@ -1283,7 +1289,7 @@ function renderPage($conf, $pluginManager) | |||
1283 | 1289 | ||
1284 | $pluginManager->executeHooks('save_link', $link); | 1290 | $pluginManager->executeHooks('save_link', $link); |
1285 | 1291 | ||
1286 | $LINKSDB[$linkdate] = $link; | 1292 | $LINKSDB[$id] = $link; |
1287 | $LINKSDB->save($conf->get('resource.page_cache')); | 1293 | $LINKSDB->save($conf->get('resource.page_cache')); |
1288 | pubsubhub($conf); | 1294 | pubsubhub($conf); |
1289 | 1295 | ||
@@ -1296,7 +1302,7 @@ function renderPage($conf, $pluginManager) | |||
1296 | $returnurl = !empty($_POST['returnurl']) ? $_POST['returnurl'] : '?'; | 1302 | $returnurl = !empty($_POST['returnurl']) ? $_POST['returnurl'] : '?'; |
1297 | $location = generateLocation($returnurl, $_SERVER['HTTP_HOST'], array('addlink', 'post', 'edit_link')); | 1303 | $location = generateLocation($returnurl, $_SERVER['HTTP_HOST'], array('addlink', 'post', 'edit_link')); |
1298 | // Scroll to the link which has been edited. | 1304 | // Scroll to the link which has been edited. |
1299 | $location .= '#' . smallHash($_POST['lf_linkdate']); | 1305 | $location .= '#' . $link['shorturl']; |
1300 | // After saving the link, redirect to the page the user was on. | 1306 | // After saving the link, redirect to the page the user was on. |
1301 | header('Location: '. $location); | 1307 | header('Location: '. $location); |
1302 | exit; | 1308 | exit; |
@@ -1307,8 +1313,10 @@ function renderPage($conf, $pluginManager) | |||
1307 | { | 1313 | { |
1308 | // If we are called from the bookmarklet, we must close the popup: | 1314 | // If we are called from the bookmarklet, we must close the popup: |
1309 | if (isset($_GET['source']) && ($_GET['source']=='bookmarklet' || $_GET['source']=='firefoxsocialapi')) { echo '<script>self.close();</script>'; exit; } | 1315 | if (isset($_GET['source']) && ($_GET['source']=='bookmarklet' || $_GET['source']=='firefoxsocialapi')) { echo '<script>self.close();</script>'; exit; } |
1316 | $link = $LINKSDB[(int) escape($_POST['lf_id'])]; | ||
1310 | $returnurl = ( isset($_POST['returnurl']) ? $_POST['returnurl'] : '?' ); | 1317 | $returnurl = ( isset($_POST['returnurl']) ? $_POST['returnurl'] : '?' ); |
1311 | $returnurl .= '#'.smallHash($_POST['lf_linkdate']); // Scroll to the link which has been edited. | 1318 | // Scroll to the link which has been edited. |
1319 | $returnurl .= '#'. $link['shorturl']; | ||
1312 | $returnurl = generateLocation($returnurl, $_SERVER['HTTP_HOST'], array('addlink', 'post', 'edit_link')); | 1320 | $returnurl = generateLocation($returnurl, $_SERVER['HTTP_HOST'], array('addlink', 'post', 'edit_link')); |
1313 | header('Location: '.$returnurl); // After canceling, redirect to the page the user was on. | 1321 | header('Location: '.$returnurl); // After canceling, redirect to the page the user was on. |
1314 | exit; | 1322 | exit; |
@@ -1318,14 +1326,17 @@ function renderPage($conf, $pluginManager) | |||
1318 | if (isset($_POST['delete_link'])) | 1326 | if (isset($_POST['delete_link'])) |
1319 | { | 1327 | { |
1320 | if (!tokenOk($_POST['token'])) die('Wrong token.'); | 1328 | if (!tokenOk($_POST['token'])) die('Wrong token.'); |
1329 | |||
1321 | // We do not need to ask for confirmation: | 1330 | // We do not need to ask for confirmation: |
1322 | // - confirmation is handled by JavaScript | 1331 | // - confirmation is handled by JavaScript |
1323 | // - we are protected from XSRF by the token. | 1332 | // - we are protected from XSRF by the token. |
1324 | $linkdate=$_POST['lf_linkdate']; | ||
1325 | 1333 | ||
1326 | $pluginManager->executeHooks('delete_link', $LINKSDB[$linkdate]); | 1334 | // FIXME! We keep `lf_linkdate` for consistency before a proper API. To be removed. |
1335 | $id = isset($_POST['lf_id']) ? intval(escape($_POST['lf_id'])) : intval(escape($_POST['lf_linkdate'])); | ||
1336 | |||
1337 | $pluginManager->executeHooks('delete_link', $LINKSDB[$id]); | ||
1327 | 1338 | ||
1328 | unset($LINKSDB[$linkdate]); | 1339 | unset($LINKSDB[$id]); |
1329 | $LINKSDB->save('resource.page_cache'); // save to disk | 1340 | $LINKSDB->save('resource.page_cache'); // save to disk |
1330 | 1341 | ||
1331 | // If we are called from the bookmarklet, we must close the popup: | 1342 | // If we are called from the bookmarklet, we must close the popup: |
@@ -1364,8 +1375,10 @@ function renderPage($conf, $pluginManager) | |||
1364 | // -------- User clicked the "EDIT" button on a link: Display link edit form. | 1375 | // -------- User clicked the "EDIT" button on a link: Display link edit form. |
1365 | if (isset($_GET['edit_link'])) | 1376 | if (isset($_GET['edit_link'])) |
1366 | { | 1377 | { |
1367 | $link = $LINKSDB[$_GET['edit_link']]; // Read database | 1378 | $id = (int) escape($_GET['edit_link']); |
1379 | $link = $LINKSDB[$id]; // Read database | ||
1368 | if (!$link) { header('Location: ?'); exit; } // Link not found in database. | 1380 | if (!$link) { header('Location: ?'); exit; } // Link not found in database. |
1381 | $link['linkdate'] = $link['created']->format(LinkDB::LINK_DATE_FORMAT); | ||
1369 | $data = array( | 1382 | $data = array( |
1370 | 'link' => $link, | 1383 | 'link' => $link, |
1371 | 'link_is_new' => false, | 1384 | 'link_is_new' => false, |
@@ -1389,10 +1402,10 @@ function renderPage($conf, $pluginManager) | |||
1389 | $link_is_new = false; | 1402 | $link_is_new = false; |
1390 | // Check if URL is not already in database (in this case, we will edit the existing link) | 1403 | // Check if URL is not already in database (in this case, we will edit the existing link) |
1391 | $link = $LINKSDB->getLinkFromUrl($url); | 1404 | $link = $LINKSDB->getLinkFromUrl($url); |
1392 | if (!$link) | 1405 | if (! $link) |
1393 | { | 1406 | { |
1394 | $link_is_new = true; | 1407 | $link_is_new = true; |
1395 | $linkdate = strval(date('Ymd_His')); | 1408 | $linkdate = strval(date(LinkDB::LINK_DATE_FORMAT)); |
1396 | // Get title if it was provided in URL (by the bookmarklet). | 1409 | // Get title if it was provided in URL (by the bookmarklet). |
1397 | $title = empty($_GET['title']) ? '' : escape($_GET['title']); | 1410 | $title = empty($_GET['title']) ? '' : escape($_GET['title']); |
1398 | // Get description if it was provided in URL (by the bookmarklet). [Bronco added that] | 1411 | // Get description if it was provided in URL (by the bookmarklet). [Bronco added that] |
@@ -1416,7 +1429,7 @@ function renderPage($conf, $pluginManager) | |||
1416 | } | 1429 | } |
1417 | 1430 | ||
1418 | if ($url == '') { | 1431 | if ($url == '') { |
1419 | $url = '?' . smallHash($linkdate); | 1432 | $url = '?' . smallHash($linkdate . $LINKSDB->getNextId()); |
1420 | $title = 'Note: '; | 1433 | $title = 'Note: '; |
1421 | } | 1434 | } |
1422 | $url = escape($url); | 1435 | $url = escape($url); |
@@ -1430,6 +1443,8 @@ function renderPage($conf, $pluginManager) | |||
1430 | 'tags' => $tags, | 1443 | 'tags' => $tags, |
1431 | 'private' => $private | 1444 | 'private' => $private |
1432 | ); | 1445 | ); |
1446 | } else { | ||
1447 | $link['linkdate'] = $link['created']->format(LinkDB::LINK_DATE_FORMAT); | ||
1433 | } | 1448 | } |
1434 | 1449 | ||
1435 | $data = array( | 1450 | $data = array( |
@@ -1635,18 +1650,15 @@ function buildLinkList($PAGE,$LINKSDB, $conf, $pluginManager) | |||
1635 | $link['description'] = format_description($link['description'], $conf->get('redirector.url')); | 1650 | $link['description'] = format_description($link['description'], $conf->get('redirector.url')); |
1636 | $classLi = ($i % 2) != 0 ? '' : 'publicLinkHightLight'; | 1651 | $classLi = ($i % 2) != 0 ? '' : 'publicLinkHightLight'; |
1637 | $link['class'] = $link['private'] == 0 ? $classLi : 'private'; | 1652 | $link['class'] = $link['private'] == 0 ? $classLi : 'private'; |
1638 | $date = DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, $link['linkdate']); | 1653 | $link['timestamp'] = $link['created']->getTimestamp(); |
1639 | $link['timestamp'] = $date->getTimestamp(); | ||
1640 | if (! empty($link['updated'])) { | 1654 | if (! empty($link['updated'])) { |
1641 | $date = DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, $link['updated']); | 1655 | $link['updated_timestamp'] = $link['updated']->getTimestamp(); |
1642 | $link['updated_timestamp'] = $date->getTimestamp(); | ||
1643 | } else { | 1656 | } else { |
1644 | $link['updated_timestamp'] = ''; | 1657 | $link['updated_timestamp'] = ''; |
1645 | } | 1658 | } |
1646 | $taglist = explode(' ', $link['tags']); | 1659 | $taglist = explode(' ', $link['tags']); |
1647 | uasort($taglist, 'strcasecmp'); | 1660 | uasort($taglist, 'strcasecmp'); |
1648 | $link['taglist'] = $taglist; | 1661 | $link['taglist'] = $taglist; |
1649 | $link['shorturl'] = smallHash($link['linkdate']); | ||
1650 | // Check for both signs of a note: starting with ? and 7 chars long. | 1662 | // Check for both signs of a note: starting with ? and 7 chars long. |
1651 | if ($link['url'][0] === '?' && | 1663 | if ($link['url'][0] === '?' && |
1652 | strlen($link['url']) === 7) { | 1664 | strlen($link['url']) === 7) { |
diff --git a/plugins/isso/isso.php b/plugins/isso/isso.php index ffb7cfac..ce16645f 100644 --- a/plugins/isso/isso.php +++ b/plugins/isso/isso.php | |||
@@ -41,9 +41,9 @@ function hook_isso_render_linklist($data, $conf) | |||
41 | // Only display comments for permalinks. | 41 | // Only display comments for permalinks. |
42 | if (count($data['links']) == 1 && empty($data['search_tags']) && empty($data['search_term'])) { | 42 | if (count($data['links']) == 1 && empty($data['search_tags']) && empty($data['search_term'])) { |
43 | $link = reset($data['links']); | 43 | $link = reset($data['links']); |
44 | $isso_html = file_get_contents(PluginManager::$PLUGINS_PATH . '/isso/isso.html'); | 44 | $issoHtml = file_get_contents(PluginManager::$PLUGINS_PATH . '/isso/isso.html'); |
45 | 45 | ||
46 | $isso = sprintf($isso_html, $issoUrl, $issoUrl, $link['linkdate'], $link['linkdate']); | 46 | $isso = sprintf($issoHtml, $issoUrl, $issoUrl, $link['id'], $link['id']); |
47 | $data['plugin_end_zone'][] = $isso; | 47 | $data['plugin_end_zone'][] = $isso; |
48 | 48 | ||
49 | // Hackish way to include this CSS file only when necessary. | 49 | // Hackish way to include this CSS file only when necessary. |
diff --git a/tests/FeedBuilderTest.php b/tests/FeedBuilderTest.php index d7839402..06a44506 100644 --- a/tests/FeedBuilderTest.php +++ b/tests/FeedBuilderTest.php | |||
@@ -84,8 +84,9 @@ class FeedBuilderTest extends PHPUnit_Framework_TestCase | |||
84 | $this->assertEquals(ReferenceLinkDB::$NB_LINKS_TOTAL, count($data['links'])); | 84 | $this->assertEquals(ReferenceLinkDB::$NB_LINKS_TOTAL, count($data['links'])); |
85 | 85 | ||
86 | // Test first link (note link) | 86 | // Test first link (note link) |
87 | $link = array_shift($data['links']); | 87 | $link = reset($data['links']); |
88 | $this->assertEquals('20150310_114651', $link['linkdate']); | 88 | $this->assertEquals(41, $link['id']); |
89 | $this->assertEquals(DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, '20150310_114651'), $link['created']); | ||
89 | $this->assertEquals('http://host.tld/?WDWyig', $link['guid']); | 90 | $this->assertEquals('http://host.tld/?WDWyig', $link['guid']); |
90 | $this->assertEquals('http://host.tld/?WDWyig', $link['url']); | 91 | $this->assertEquals('http://host.tld/?WDWyig', $link['url']); |
91 | $this->assertRegExp('/Tue, 10 Mar 2015 11:46:51 \+\d{4}/', $link['pub_iso_date']); | 92 | $this->assertRegExp('/Tue, 10 Mar 2015 11:46:51 \+\d{4}/', $link['pub_iso_date']); |
@@ -99,14 +100,14 @@ class FeedBuilderTest extends PHPUnit_Framework_TestCase | |||
99 | $this->assertEquals('sTuff', $link['taglist'][0]); | 100 | $this->assertEquals('sTuff', $link['taglist'][0]); |
100 | 101 | ||
101 | // Test URL with external link. | 102 | // Test URL with external link. |
102 | $this->assertEquals('https://static.fsf.org/nosvn/faif-2.0.pdf', $data['links']['20150310_114633']['url']); | 103 | $this->assertEquals('https://static.fsf.org/nosvn/faif-2.0.pdf', $data['links'][8]['url']); |
103 | 104 | ||
104 | // Test multitags. | 105 | // Test multitags. |
105 | $this->assertEquals(5, count($data['links']['20141125_084734']['taglist'])); | 106 | $this->assertEquals(5, count($data['links'][6]['taglist'])); |
106 | $this->assertEquals('css', $data['links']['20141125_084734']['taglist'][0]); | 107 | $this->assertEquals('css', $data['links'][6]['taglist'][0]); |
107 | 108 | ||
108 | // Test update date | 109 | // Test update date |
109 | $this->assertRegExp('/2016-08-03T09:30:33\+\d{2}:\d{2}/', $data['links']['20150310_114633']['up_iso_date']); | 110 | $this->assertRegExp('/2016-08-03T09:30:33\+\d{2}:\d{2}/', $data['links'][8]['up_iso_date']); |
110 | } | 111 | } |
111 | 112 | ||
112 | /** | 113 | /** |
@@ -119,9 +120,9 @@ class FeedBuilderTest extends PHPUnit_Framework_TestCase | |||
119 | $data = $feedBuilder->buildData(); | 120 | $data = $feedBuilder->buildData(); |
120 | $this->assertEquals(ReferenceLinkDB::$NB_LINKS_TOTAL, count($data['links'])); | 121 | $this->assertEquals(ReferenceLinkDB::$NB_LINKS_TOTAL, count($data['links'])); |
121 | $this->assertRegExp('/2016-08-03T09:30:33\+\d{2}:\d{2}/', $data['last_update']); | 122 | $this->assertRegExp('/2016-08-03T09:30:33\+\d{2}:\d{2}/', $data['last_update']); |
122 | $link = array_shift($data['links']); | 123 | $link = reset($data['links']); |
123 | $this->assertRegExp('/2015-03-10T11:46:51\+\d{2}:\d{2}/', $link['pub_iso_date']); | 124 | $this->assertRegExp('/2015-03-10T11:46:51\+\d{2}:\d{2}/', $link['pub_iso_date']); |
124 | $this->assertRegExp('/2016-08-03T09:30:33\+\d{2}:\d{2}/', $data['links']['20150310_114633']['up_iso_date']); | 125 | $this->assertRegExp('/2016-08-03T09:30:33\+\d{2}:\d{2}/', $data['links'][8]['up_iso_date']); |
125 | } | 126 | } |
126 | 127 | ||
127 | /** | 128 | /** |
@@ -138,7 +139,8 @@ class FeedBuilderTest extends PHPUnit_Framework_TestCase | |||
138 | $data = $feedBuilder->buildData(); | 139 | $data = $feedBuilder->buildData(); |
139 | $this->assertEquals(1, count($data['links'])); | 140 | $this->assertEquals(1, count($data['links'])); |
140 | $link = array_shift($data['links']); | 141 | $link = array_shift($data['links']); |
141 | $this->assertEquals('20150310_114651', $link['linkdate']); | 142 | $this->assertEquals(41, $link['id']); |
143 | $this->assertEquals(DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, '20150310_114651'), $link['created']); | ||
142 | } | 144 | } |
143 | 145 | ||
144 | /** | 146 | /** |
@@ -154,7 +156,8 @@ class FeedBuilderTest extends PHPUnit_Framework_TestCase | |||
154 | $data = $feedBuilder->buildData(); | 156 | $data = $feedBuilder->buildData(); |
155 | $this->assertEquals(1, count($data['links'])); | 157 | $this->assertEquals(1, count($data['links'])); |
156 | $link = array_shift($data['links']); | 158 | $link = array_shift($data['links']); |
157 | $this->assertEquals('20150310_114651', $link['linkdate']); | 159 | $this->assertEquals(41, $link['id']); |
160 | $this->assertEquals(DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, '20150310_114651'), $link['created']); | ||
158 | } | 161 | } |
159 | 162 | ||
160 | /** | 163 | /** |
@@ -170,15 +173,17 @@ class FeedBuilderTest extends PHPUnit_Framework_TestCase | |||
170 | $this->assertTrue($data['usepermalinks']); | 173 | $this->assertTrue($data['usepermalinks']); |
171 | // First link is a permalink | 174 | // First link is a permalink |
172 | $link = array_shift($data['links']); | 175 | $link = array_shift($data['links']); |
173 | $this->assertEquals('20150310_114651', $link['linkdate']); | 176 | $this->assertEquals(41, $link['id']); |
177 | $this->assertEquals(DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, '20150310_114651'), $link['created']); | ||
174 | $this->assertEquals('http://host.tld/?WDWyig', $link['guid']); | 178 | $this->assertEquals('http://host.tld/?WDWyig', $link['guid']); |
175 | $this->assertEquals('http://host.tld/?WDWyig', $link['url']); | 179 | $this->assertEquals('http://host.tld/?WDWyig', $link['url']); |
176 | $this->assertContains('Direct link', $link['description']); | 180 | $this->assertContains('Direct link', $link['description']); |
177 | $this->assertContains('http://host.tld/?WDWyig', $link['description']); | 181 | $this->assertContains('http://host.tld/?WDWyig', $link['description']); |
178 | // Second link is a direct link | 182 | // Second link is a direct link |
179 | $link = array_shift($data['links']); | 183 | $link = array_shift($data['links']); |
180 | $this->assertEquals('20150310_114633', $link['linkdate']); | 184 | $this->assertEquals(8, $link['id']); |
181 | $this->assertEquals('http://host.tld/?kLHmZg', $link['guid']); | 185 | $this->assertEquals(DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, '20150310_114633'), $link['created']); |
186 | $this->assertEquals('http://host.tld/?RttfEw', $link['guid']); | ||
182 | $this->assertEquals('https://static.fsf.org/nosvn/faif-2.0.pdf', $link['url']); | 187 | $this->assertEquals('https://static.fsf.org/nosvn/faif-2.0.pdf', $link['url']); |
183 | $this->assertContains('Direct link', $link['description']); | 188 | $this->assertContains('Direct link', $link['description']); |
184 | $this->assertContains('https://static.fsf.org/nosvn/faif-2.0.pdf', $link['description']); | 189 | $this->assertContains('https://static.fsf.org/nosvn/faif-2.0.pdf', $link['description']); |
diff --git a/tests/LinkDBTest.php b/tests/LinkDBTest.php index 9d79386c..1f62a34a 100644 --- a/tests/LinkDBTest.php +++ b/tests/LinkDBTest.php | |||
@@ -186,14 +186,15 @@ class LinkDBTest extends PHPUnit_Framework_TestCase | |||
186 | $dbSize = sizeof($testDB); | 186 | $dbSize = sizeof($testDB); |
187 | 187 | ||
188 | $link = array( | 188 | $link = array( |
189 | 'id' => 42, | ||
189 | 'title'=>'an additional link', | 190 | 'title'=>'an additional link', |
190 | 'url'=>'http://dum.my', | 191 | 'url'=>'http://dum.my', |
191 | 'description'=>'One more', | 192 | 'description'=>'One more', |
192 | 'private'=>0, | 193 | 'private'=>0, |
193 | 'linkdate'=>'20150518_190000', | 194 | 'created'=> DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, '20150518_190000'), |
194 | 'tags'=>'unit test' | 195 | 'tags'=>'unit test' |
195 | ); | 196 | ); |
196 | $testDB[$link['linkdate']] = $link; | 197 | $testDB[$link['id']] = $link; |
197 | $testDB->save('tests'); | 198 | $testDB->save('tests'); |
198 | 199 | ||
199 | $testDB = new LinkDB(self::$testDatastore, true, false); | 200 | $testDB = new LinkDB(self::$testDatastore, true, false); |
@@ -238,12 +239,12 @@ class LinkDBTest extends PHPUnit_Framework_TestCase | |||
238 | public function testDays() | 239 | public function testDays() |
239 | { | 240 | { |
240 | $this->assertEquals( | 241 | $this->assertEquals( |
241 | array('20121206', '20130614', '20150310'), | 242 | array('20100310', '20121206', '20130614', '20150310'), |
242 | self::$publicLinkDB->days() | 243 | self::$publicLinkDB->days() |
243 | ); | 244 | ); |
244 | 245 | ||
245 | $this->assertEquals( | 246 | $this->assertEquals( |
246 | array('20121206', '20130614', '20141125', '20150310'), | 247 | array('20100310', '20121206', '20130614', '20141125', '20150310'), |
247 | self::$privateLinkDB->days() | 248 | self::$privateLinkDB->days() |
248 | ); | 249 | ); |
249 | } | 250 | } |
@@ -290,10 +291,11 @@ class LinkDBTest extends PHPUnit_Framework_TestCase | |||
290 | 'stallman' => 1, | 291 | 'stallman' => 1, |
291 | 'free' => 1, | 292 | 'free' => 1, |
292 | '-exclude' => 1, | 293 | '-exclude' => 1, |
294 | 'hashtag' => 2, | ||
293 | // The DB contains a link with `sTuff` and another one with `stuff` tag. | 295 | // The DB contains a link with `sTuff` and another one with `stuff` tag. |
294 | // They need to be grouped with the first case found (`sTuff`). | 296 | // They need to be grouped with the first case found - order by date DESC: `sTuff`. |
295 | 'sTuff' => 2, | 297 | 'sTuff' => 2, |
296 | 'hashtag' => 2, | 298 | 'ut' => 1, |
297 | ), | 299 | ), |
298 | self::$publicLinkDB->allTags() | 300 | self::$publicLinkDB->allTags() |
299 | ); | 301 | ); |
@@ -321,6 +323,7 @@ class LinkDBTest extends PHPUnit_Framework_TestCase | |||
321 | 'tag2' => 1, | 323 | 'tag2' => 1, |
322 | 'tag3' => 1, | 324 | 'tag3' => 1, |
323 | 'tag4' => 1, | 325 | 'tag4' => 1, |
326 | 'ut' => 1, | ||
324 | ), | 327 | ), |
325 | self::$privateLinkDB->allTags() | 328 | self::$privateLinkDB->allTags() |
326 | ); | 329 | ); |
@@ -411,6 +414,11 @@ class LinkDBTest extends PHPUnit_Framework_TestCase | |||
411 | 1, | 414 | 1, |
412 | count(self::$publicLinkDB->filterHash($request)) | 415 | count(self::$publicLinkDB->filterHash($request)) |
413 | ); | 416 | ); |
417 | $request = smallHash('20150310_114633' . 8); | ||
418 | $this->assertEquals( | ||
419 | 1, | ||
420 | count(self::$publicLinkDB->filterHash($request)) | ||
421 | ); | ||
414 | } | 422 | } |
415 | 423 | ||
416 | /** | 424 | /** |
@@ -433,4 +441,23 @@ class LinkDBTest extends PHPUnit_Framework_TestCase | |||
433 | { | 441 | { |
434 | self::$publicLinkDB->filterHash(''); | 442 | self::$publicLinkDB->filterHash(''); |
435 | } | 443 | } |
444 | |||
445 | /** | ||
446 | * Test reorder with asc/desc parameter. | ||
447 | */ | ||
448 | public function testReorderLinksDesc() | ||
449 | { | ||
450 | self::$privateLinkDB->reorder('ASC'); | ||
451 | $linkIds = array(42, 4, 1, 0, 7, 6, 8, 41); | ||
452 | $cpt = 0; | ||
453 | foreach (self::$privateLinkDB as $key => $value) { | ||
454 | $this->assertEquals($linkIds[$cpt++], $key); | ||
455 | } | ||
456 | self::$privateLinkDB->reorder('DESC'); | ||
457 | $linkIds = array_reverse($linkIds); | ||
458 | $cpt = 0; | ||
459 | foreach (self::$privateLinkDB as $key => $value) { | ||
460 | $this->assertEquals($linkIds[$cpt++], $key); | ||
461 | } | ||
462 | } | ||
436 | } | 463 | } |
diff --git a/tests/LinkFilterTest.php b/tests/LinkFilterTest.php index 7d45fc59..21d680a5 100644 --- a/tests/LinkFilterTest.php +++ b/tests/LinkFilterTest.php | |||
@@ -159,7 +159,7 @@ class LinkFilterTest extends PHPUnit_Framework_TestCase | |||
159 | 159 | ||
160 | $this->assertEquals( | 160 | $this->assertEquals( |
161 | 'MediaGoblin', | 161 | 'MediaGoblin', |
162 | $links['20130614_184135']['title'] | 162 | $links[7]['title'] |
163 | ); | 163 | ); |
164 | } | 164 | } |
165 | 165 | ||
@@ -286,7 +286,7 @@ class LinkFilterTest extends PHPUnit_Framework_TestCase | |||
286 | ); | 286 | ); |
287 | 287 | ||
288 | $this->assertEquals( | 288 | $this->assertEquals( |
289 | 6, | 289 | 7, |
290 | count(self::$linkFilter->filter(LinkFilter::$FILTER_TEXT, '-revolution')) | 290 | count(self::$linkFilter->filter(LinkFilter::$FILTER_TEXT, '-revolution')) |
291 | ); | 291 | ); |
292 | } | 292 | } |
@@ -346,7 +346,7 @@ class LinkFilterTest extends PHPUnit_Framework_TestCase | |||
346 | ); | 346 | ); |
347 | 347 | ||
348 | $this->assertEquals( | 348 | $this->assertEquals( |
349 | 6, | 349 | 7, |
350 | count(self::$linkFilter->filter(LinkFilter::$FILTER_TAG, '-free')) | 350 | count(self::$linkFilter->filter(LinkFilter::$FILTER_TAG, '-free')) |
351 | ); | 351 | ); |
352 | } | 352 | } |
diff --git a/tests/NetscapeBookmarkUtils/BookmarkExportTest.php b/tests/NetscapeBookmarkUtils/BookmarkExportTest.php index cc54ab9f..6a47bbb9 100644 --- a/tests/NetscapeBookmarkUtils/BookmarkExportTest.php +++ b/tests/NetscapeBookmarkUtils/BookmarkExportTest.php | |||
@@ -50,7 +50,7 @@ class BookmarkExportTest extends PHPUnit_Framework_TestCase | |||
50 | $links = NetscapeBookmarkUtils::filterAndFormat(self::$linkDb, 'all', false, ''); | 50 | $links = NetscapeBookmarkUtils::filterAndFormat(self::$linkDb, 'all', false, ''); |
51 | $this->assertEquals(self::$refDb->countLinks(), sizeof($links)); | 51 | $this->assertEquals(self::$refDb->countLinks(), sizeof($links)); |
52 | foreach ($links as $link) { | 52 | foreach ($links as $link) { |
53 | $date = DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, $link['linkdate']); | 53 | $date = $link['created']; |
54 | $this->assertEquals( | 54 | $this->assertEquals( |
55 | $date->getTimestamp(), | 55 | $date->getTimestamp(), |
56 | $link['timestamp'] | 56 | $link['timestamp'] |
@@ -70,7 +70,7 @@ class BookmarkExportTest extends PHPUnit_Framework_TestCase | |||
70 | $links = NetscapeBookmarkUtils::filterAndFormat(self::$linkDb, 'private', false, ''); | 70 | $links = NetscapeBookmarkUtils::filterAndFormat(self::$linkDb, 'private', false, ''); |
71 | $this->assertEquals(self::$refDb->countPrivateLinks(), sizeof($links)); | 71 | $this->assertEquals(self::$refDb->countPrivateLinks(), sizeof($links)); |
72 | foreach ($links as $link) { | 72 | foreach ($links as $link) { |
73 | $date = DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, $link['linkdate']); | 73 | $date = $link['created']; |
74 | $this->assertEquals( | 74 | $this->assertEquals( |
75 | $date->getTimestamp(), | 75 | $date->getTimestamp(), |
76 | $link['timestamp'] | 76 | $link['timestamp'] |
@@ -90,7 +90,7 @@ class BookmarkExportTest extends PHPUnit_Framework_TestCase | |||
90 | $links = NetscapeBookmarkUtils::filterAndFormat(self::$linkDb, 'public', false, ''); | 90 | $links = NetscapeBookmarkUtils::filterAndFormat(self::$linkDb, 'public', false, ''); |
91 | $this->assertEquals(self::$refDb->countPublicLinks(), sizeof($links)); | 91 | $this->assertEquals(self::$refDb->countPublicLinks(), sizeof($links)); |
92 | foreach ($links as $link) { | 92 | foreach ($links as $link) { |
93 | $date = DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, $link['linkdate']); | 93 | $date = $link['created']; |
94 | $this->assertEquals( | 94 | $this->assertEquals( |
95 | $date->getTimestamp(), | 95 | $date->getTimestamp(), |
96 | $link['timestamp'] | 96 | $link['timestamp'] |
diff --git a/tests/NetscapeBookmarkUtils/BookmarkImportTest.php b/tests/NetscapeBookmarkUtils/BookmarkImportTest.php index f0ad500f..0ca07eac 100644 --- a/tests/NetscapeBookmarkUtils/BookmarkImportTest.php +++ b/tests/NetscapeBookmarkUtils/BookmarkImportTest.php | |||
@@ -43,6 +43,18 @@ class BookmarkImportTest extends PHPUnit_Framework_TestCase | |||
43 | protected $pagecache = 'tests'; | 43 | protected $pagecache = 'tests'; |
44 | 44 | ||
45 | /** | 45 | /** |
46 | * @var string Save the current timezone. | ||
47 | */ | ||
48 | protected static $defaultTimeZone; | ||
49 | |||
50 | public static function setUpBeforeClass() | ||
51 | { | ||
52 | self::$defaultTimeZone = date_default_timezone_get(); | ||
53 | // Timezone without DST for test consistency | ||
54 | date_default_timezone_set('Africa/Nairobi'); | ||
55 | } | ||
56 | |||
57 | /** | ||
46 | * Resets test data before each test | 58 | * Resets test data before each test |
47 | */ | 59 | */ |
48 | protected function setUp() | 60 | protected function setUp() |
@@ -55,6 +67,11 @@ class BookmarkImportTest extends PHPUnit_Framework_TestCase | |||
55 | $this->linkDb = new LinkDB(self::$testDatastore, true, false); | 67 | $this->linkDb = new LinkDB(self::$testDatastore, true, false); |
56 | } | 68 | } |
57 | 69 | ||
70 | public static function tearDownAfterClass() | ||
71 | { | ||
72 | date_default_timezone_set(self::$defaultTimeZone); | ||
73 | } | ||
74 | |||
58 | /** | 75 | /** |
59 | * Attempt to import bookmarks from an empty file | 76 | * Attempt to import bookmarks from an empty file |
60 | */ | 77 | */ |
@@ -98,18 +115,19 @@ class BookmarkImportTest extends PHPUnit_Framework_TestCase | |||
98 | 115 | ||
99 | $this->assertEquals( | 116 | $this->assertEquals( |
100 | array( | 117 | array( |
101 | 'linkdate' => '20160618_173944', | 118 | 'id' => 0, |
119 | 'created' => DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, '20160618_203944'), | ||
102 | 'title' => 'Hg Init a Mercurial tutorial by Joel Spolsky', | 120 | 'title' => 'Hg Init a Mercurial tutorial by Joel Spolsky', |
103 | 'url' => 'http://hginit.com/', | 121 | 'url' => 'http://hginit.com/', |
104 | 'description' => '', | 122 | 'description' => '', |
105 | 'private' => 0, | 123 | 'private' => 0, |
106 | 'tags' => '' | 124 | 'tags' => '', |
125 | 'shorturl' => 'La37cg', | ||
107 | ), | 126 | ), |
108 | $this->linkDb->getLinkFromUrl('http://hginit.com/') | 127 | $this->linkDb->getLinkFromUrl('http://hginit.com/') |
109 | ); | 128 | ); |
110 | } | 129 | } |
111 | 130 | ||
112 | |||
113 | /** | 131 | /** |
114 | * Import bookmarks nested in a folder hierarchy | 132 | * Import bookmarks nested in a folder hierarchy |
115 | */ | 133 | */ |
@@ -126,89 +144,105 @@ class BookmarkImportTest extends PHPUnit_Framework_TestCase | |||
126 | 144 | ||
127 | $this->assertEquals( | 145 | $this->assertEquals( |
128 | array( | 146 | array( |
129 | 'linkdate' => '20160225_205541', | 147 | 'id' => 0, |
148 | 'created' => DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, '20160225_235541'), | ||
130 | 'title' => 'Nested 1', | 149 | 'title' => 'Nested 1', |
131 | 'url' => 'http://nest.ed/1', | 150 | 'url' => 'http://nest.ed/1', |
132 | 'description' => '', | 151 | 'description' => '', |
133 | 'private' => 0, | 152 | 'private' => 0, |
134 | 'tags' => 'tag1 tag2' | 153 | 'tags' => 'tag1 tag2', |
154 | 'shorturl' => 'KyDNKA', | ||
135 | ), | 155 | ), |
136 | $this->linkDb->getLinkFromUrl('http://nest.ed/1') | 156 | $this->linkDb->getLinkFromUrl('http://nest.ed/1') |
137 | ); | 157 | ); |
138 | $this->assertEquals( | 158 | $this->assertEquals( |
139 | array( | 159 | array( |
140 | 'linkdate' => '20160225_205542', | 160 | 'id' => 1, |
161 | 'created' => DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, '20160225_235542'), | ||
141 | 'title' => 'Nested 1-1', | 162 | 'title' => 'Nested 1-1', |
142 | 'url' => 'http://nest.ed/1-1', | 163 | 'url' => 'http://nest.ed/1-1', |
143 | 'description' => '', | 164 | 'description' => '', |
144 | 'private' => 0, | 165 | 'private' => 0, |
145 | 'tags' => 'folder1 tag1 tag2' | 166 | 'tags' => 'folder1 tag1 tag2', |
167 | 'shorturl' => 'T2LnXg', | ||
146 | ), | 168 | ), |
147 | $this->linkDb->getLinkFromUrl('http://nest.ed/1-1') | 169 | $this->linkDb->getLinkFromUrl('http://nest.ed/1-1') |
148 | ); | 170 | ); |
149 | $this->assertEquals( | 171 | $this->assertEquals( |
150 | array( | 172 | array( |
151 | 'linkdate' => '20160225_205547', | 173 | 'id' => 2, |
174 | 'created' => DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, '20160225_235547'), | ||
152 | 'title' => 'Nested 1-2', | 175 | 'title' => 'Nested 1-2', |
153 | 'url' => 'http://nest.ed/1-2', | 176 | 'url' => 'http://nest.ed/1-2', |
154 | 'description' => '', | 177 | 'description' => '', |
155 | 'private' => 0, | 178 | 'private' => 0, |
156 | 'tags' => 'folder1 tag3 tag4' | 179 | 'tags' => 'folder1 tag3 tag4', |
180 | 'shorturl' => '46SZxA', | ||
157 | ), | 181 | ), |
158 | $this->linkDb->getLinkFromUrl('http://nest.ed/1-2') | 182 | $this->linkDb->getLinkFromUrl('http://nest.ed/1-2') |
159 | ); | 183 | ); |
160 | $this->assertEquals( | 184 | $this->assertEquals( |
161 | array( | 185 | array( |
162 | 'linkdate' => '20160202_172222', | 186 | 'id' => 3, |
187 | 'created' => DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, '20160202_202222'), | ||
163 | 'title' => 'Nested 2-1', | 188 | 'title' => 'Nested 2-1', |
164 | 'url' => 'http://nest.ed/2-1', | 189 | 'url' => 'http://nest.ed/2-1', |
165 | 'description' => 'First link of the second section', | 190 | 'description' => 'First link of the second section', |
166 | 'private' => 1, | 191 | 'private' => 1, |
167 | 'tags' => 'folder2' | 192 | 'tags' => 'folder2', |
193 | 'shorturl' => '4UHOSw', | ||
168 | ), | 194 | ), |
169 | $this->linkDb->getLinkFromUrl('http://nest.ed/2-1') | 195 | $this->linkDb->getLinkFromUrl('http://nest.ed/2-1') |
170 | ); | 196 | ); |
171 | $this->assertEquals( | 197 | $this->assertEquals( |
172 | array( | 198 | array( |
173 | 'linkdate' => '20160119_200227', | 199 | 'id' => 4, |
200 | 'created' => DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, '20160119_230227'), | ||
174 | 'title' => 'Nested 2-2', | 201 | 'title' => 'Nested 2-2', |
175 | 'url' => 'http://nest.ed/2-2', | 202 | 'url' => 'http://nest.ed/2-2', |
176 | 'description' => 'Second link of the second section', | 203 | 'description' => 'Second link of the second section', |
177 | 'private' => 1, | 204 | 'private' => 1, |
178 | 'tags' => 'folder2' | 205 | 'tags' => 'folder2', |
206 | 'shorturl' => 'yfzwbw', | ||
179 | ), | 207 | ), |
180 | $this->linkDb->getLinkFromUrl('http://nest.ed/2-2') | 208 | $this->linkDb->getLinkFromUrl('http://nest.ed/2-2') |
181 | ); | 209 | ); |
182 | $this->assertEquals( | 210 | $this->assertEquals( |
183 | array( | 211 | array( |
184 | 'linkdate' => '20160202_172223', | 212 | 'id' => 5, |
213 | 'created' => DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, '20160202_202222'), | ||
185 | 'title' => 'Nested 3-1', | 214 | 'title' => 'Nested 3-1', |
186 | 'url' => 'http://nest.ed/3-1', | 215 | 'url' => 'http://nest.ed/3-1', |
187 | 'description' => '', | 216 | 'description' => '', |
188 | 'private' => 0, | 217 | 'private' => 0, |
189 | 'tags' => 'folder3 folder3-1 tag3' | 218 | 'tags' => 'folder3 folder3-1 tag3', |
219 | 'shorturl' => 'UwxIUQ', | ||
190 | ), | 220 | ), |
191 | $this->linkDb->getLinkFromUrl('http://nest.ed/3-1') | 221 | $this->linkDb->getLinkFromUrl('http://nest.ed/3-1') |
192 | ); | 222 | ); |
193 | $this->assertEquals( | 223 | $this->assertEquals( |
194 | array( | 224 | array( |
195 | 'linkdate' => '20160119_200228', | 225 | 'id' => 6, |
226 | 'created' => DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, '20160119_230227'), | ||
196 | 'title' => 'Nested 3-2', | 227 | 'title' => 'Nested 3-2', |
197 | 'url' => 'http://nest.ed/3-2', | 228 | 'url' => 'http://nest.ed/3-2', |
198 | 'description' => '', | 229 | 'description' => '', |
199 | 'private' => 0, | 230 | 'private' => 0, |
200 | 'tags' => 'folder3 folder3-1' | 231 | 'tags' => 'folder3 folder3-1', |
232 | 'shorturl' => 'p8dyZg', | ||
201 | ), | 233 | ), |
202 | $this->linkDb->getLinkFromUrl('http://nest.ed/3-2') | 234 | $this->linkDb->getLinkFromUrl('http://nest.ed/3-2') |
203 | ); | 235 | ); |
204 | $this->assertEquals( | 236 | $this->assertEquals( |
205 | array( | 237 | array( |
206 | 'linkdate' => '20160229_081541', | 238 | 'id' => 7, |
239 | 'created' => DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, '20160229_111541'), | ||
207 | 'title' => 'Nested 2', | 240 | 'title' => 'Nested 2', |
208 | 'url' => 'http://nest.ed/2', | 241 | 'url' => 'http://nest.ed/2', |
209 | 'description' => '', | 242 | 'description' => '', |
210 | 'private' => 0, | 243 | 'private' => 0, |
211 | 'tags' => 'tag4' | 244 | 'tags' => 'tag4', |
245 | 'shorturl' => 'Gt3Uug', | ||
212 | ), | 246 | ), |
213 | $this->linkDb->getLinkFromUrl('http://nest.ed/2') | 247 | $this->linkDb->getLinkFromUrl('http://nest.ed/2') |
214 | ); | 248 | ); |
@@ -227,28 +261,34 @@ class BookmarkImportTest extends PHPUnit_Framework_TestCase | |||
227 | .' 2 links imported, 0 links overwritten, 0 links skipped.', | 261 | .' 2 links imported, 0 links overwritten, 0 links skipped.', |
228 | NetscapeBookmarkUtils::import(array(), $files, $this->linkDb, $this->pagecache) | 262 | NetscapeBookmarkUtils::import(array(), $files, $this->linkDb, $this->pagecache) |
229 | ); | 263 | ); |
264 | |||
230 | $this->assertEquals(2, count($this->linkDb)); | 265 | $this->assertEquals(2, count($this->linkDb)); |
231 | $this->assertEquals(1, count_private($this->linkDb)); | 266 | $this->assertEquals(1, count_private($this->linkDb)); |
232 | 267 | ||
233 | $this->assertEquals( | 268 | $this->assertEquals( |
234 | array( | 269 | array( |
235 | 'linkdate' => '20001010_105536', | 270 | 'id' => 0, |
271 | // Old link - UTC+4 (note that TZ in the import file is ignored). | ||
272 | 'created' => DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, '20001010_135536'), | ||
236 | 'title' => 'Secret stuff', | 273 | 'title' => 'Secret stuff', |
237 | 'url' => 'https://private.tld', | 274 | 'url' => 'https://private.tld', |
238 | 'description' => "Super-secret stuff you're not supposed to know about", | 275 | 'description' => "Super-secret stuff you're not supposed to know about", |
239 | 'private' => 1, | 276 | 'private' => 1, |
240 | 'tags' => 'private secret' | 277 | 'tags' => 'private secret', |
278 | 'shorturl' => 'EokDtA', | ||
241 | ), | 279 | ), |
242 | $this->linkDb->getLinkFromUrl('https://private.tld') | 280 | $this->linkDb->getLinkFromUrl('https://private.tld') |
243 | ); | 281 | ); |
244 | $this->assertEquals( | 282 | $this->assertEquals( |
245 | array( | 283 | array( |
246 | 'linkdate' => '20160225_205548', | 284 | 'id' => 1, |
285 | 'created' => DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, '20160225_235548'), | ||
247 | 'title' => 'Public stuff', | 286 | 'title' => 'Public stuff', |
248 | 'url' => 'http://public.tld', | 287 | 'url' => 'http://public.tld', |
249 | 'description' => '', | 288 | 'description' => '', |
250 | 'private' => 0, | 289 | 'private' => 0, |
251 | 'tags' => 'public hello world' | 290 | 'tags' => 'public hello world', |
291 | 'shorturl' => 'Er9ddA', | ||
252 | ), | 292 | ), |
253 | $this->linkDb->getLinkFromUrl('http://public.tld') | 293 | $this->linkDb->getLinkFromUrl('http://public.tld') |
254 | ); | 294 | ); |
@@ -271,23 +311,28 @@ class BookmarkImportTest extends PHPUnit_Framework_TestCase | |||
271 | 311 | ||
272 | $this->assertEquals( | 312 | $this->assertEquals( |
273 | array( | 313 | array( |
274 | 'linkdate' => '20001010_105536', | 314 | 'id' => 0, |
315 | // Note that TZ in the import file is ignored. | ||
316 | 'created' => DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, '20001010_135536'), | ||
275 | 'title' => 'Secret stuff', | 317 | 'title' => 'Secret stuff', |
276 | 'url' => 'https://private.tld', | 318 | 'url' => 'https://private.tld', |
277 | 'description' => "Super-secret stuff you're not supposed to know about", | 319 | 'description' => "Super-secret stuff you're not supposed to know about", |
278 | 'private' => 1, | 320 | 'private' => 1, |
279 | 'tags' => 'private secret' | 321 | 'tags' => 'private secret', |
322 | 'shorturl' => 'EokDtA', | ||
280 | ), | 323 | ), |
281 | $this->linkDb->getLinkFromUrl('https://private.tld') | 324 | $this->linkDb->getLinkFromUrl('https://private.tld') |
282 | ); | 325 | ); |
283 | $this->assertEquals( | 326 | $this->assertEquals( |
284 | array( | 327 | array( |
285 | 'linkdate' => '20160225_205548', | 328 | 'id' => 1, |
329 | 'created' => DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, '20160225_235548'), | ||
286 | 'title' => 'Public stuff', | 330 | 'title' => 'Public stuff', |
287 | 'url' => 'http://public.tld', | 331 | 'url' => 'http://public.tld', |
288 | 'description' => '', | 332 | 'description' => '', |
289 | 'private' => 0, | 333 | 'private' => 0, |
290 | 'tags' => 'public hello world' | 334 | 'tags' => 'public hello world', |
335 | 'shorturl' => 'Er9ddA', | ||
291 | ), | 336 | ), |
292 | $this->linkDb->getLinkFromUrl('http://public.tld') | 337 | $this->linkDb->getLinkFromUrl('http://public.tld') |
293 | ); | 338 | ); |
@@ -309,11 +354,11 @@ class BookmarkImportTest extends PHPUnit_Framework_TestCase | |||
309 | $this->assertEquals(0, count_private($this->linkDb)); | 354 | $this->assertEquals(0, count_private($this->linkDb)); |
310 | $this->assertEquals( | 355 | $this->assertEquals( |
311 | 0, | 356 | 0, |
312 | $this->linkDb['20001010_105536']['private'] | 357 | $this->linkDb[0]['private'] |
313 | ); | 358 | ); |
314 | $this->assertEquals( | 359 | $this->assertEquals( |
315 | 0, | 360 | 0, |
316 | $this->linkDb['20160225_205548']['private'] | 361 | $this->linkDb[1]['private'] |
317 | ); | 362 | ); |
318 | } | 363 | } |
319 | 364 | ||
@@ -333,11 +378,11 @@ class BookmarkImportTest extends PHPUnit_Framework_TestCase | |||
333 | $this->assertEquals(2, count_private($this->linkDb)); | 378 | $this->assertEquals(2, count_private($this->linkDb)); |
334 | $this->assertEquals( | 379 | $this->assertEquals( |
335 | 1, | 380 | 1, |
336 | $this->linkDb['20001010_105536']['private'] | 381 | $this->linkDb['0']['private'] |
337 | ); | 382 | ); |
338 | $this->assertEquals( | 383 | $this->assertEquals( |
339 | 1, | 384 | 1, |
340 | $this->linkDb['20160225_205548']['private'] | 385 | $this->linkDb['1']['private'] |
341 | ); | 386 | ); |
342 | } | 387 | } |
343 | 388 | ||
@@ -359,13 +404,12 @@ class BookmarkImportTest extends PHPUnit_Framework_TestCase | |||
359 | $this->assertEquals(2, count_private($this->linkDb)); | 404 | $this->assertEquals(2, count_private($this->linkDb)); |
360 | $this->assertEquals( | 405 | $this->assertEquals( |
361 | 1, | 406 | 1, |
362 | $this->linkDb['20001010_105536']['private'] | 407 | $this->linkDb[0]['private'] |
363 | ); | 408 | ); |
364 | $this->assertEquals( | 409 | $this->assertEquals( |
365 | 1, | 410 | 1, |
366 | $this->linkDb['20160225_205548']['private'] | 411 | $this->linkDb[1]['private'] |
367 | ); | 412 | ); |
368 | |||
369 | // re-import as public, enable overwriting | 413 | // re-import as public, enable overwriting |
370 | $post = array( | 414 | $post = array( |
371 | 'privacy' => 'public', | 415 | 'privacy' => 'public', |
@@ -380,11 +424,11 @@ class BookmarkImportTest extends PHPUnit_Framework_TestCase | |||
380 | $this->assertEquals(0, count_private($this->linkDb)); | 424 | $this->assertEquals(0, count_private($this->linkDb)); |
381 | $this->assertEquals( | 425 | $this->assertEquals( |
382 | 0, | 426 | 0, |
383 | $this->linkDb['20001010_105536']['private'] | 427 | $this->linkDb[0]['private'] |
384 | ); | 428 | ); |
385 | $this->assertEquals( | 429 | $this->assertEquals( |
386 | 0, | 430 | 0, |
387 | $this->linkDb['20160225_205548']['private'] | 431 | $this->linkDb[1]['private'] |
388 | ); | 432 | ); |
389 | } | 433 | } |
390 | 434 | ||
@@ -406,11 +450,11 @@ class BookmarkImportTest extends PHPUnit_Framework_TestCase | |||
406 | $this->assertEquals(0, count_private($this->linkDb)); | 450 | $this->assertEquals(0, count_private($this->linkDb)); |
407 | $this->assertEquals( | 451 | $this->assertEquals( |
408 | 0, | 452 | 0, |
409 | $this->linkDb['20001010_105536']['private'] | 453 | $this->linkDb['0']['private'] |
410 | ); | 454 | ); |
411 | $this->assertEquals( | 455 | $this->assertEquals( |
412 | 0, | 456 | 0, |
413 | $this->linkDb['20160225_205548']['private'] | 457 | $this->linkDb['1']['private'] |
414 | ); | 458 | ); |
415 | 459 | ||
416 | // re-import as private, enable overwriting | 460 | // re-import as private, enable overwriting |
@@ -427,11 +471,11 @@ class BookmarkImportTest extends PHPUnit_Framework_TestCase | |||
427 | $this->assertEquals(2, count_private($this->linkDb)); | 471 | $this->assertEquals(2, count_private($this->linkDb)); |
428 | $this->assertEquals( | 472 | $this->assertEquals( |
429 | 1, | 473 | 1, |
430 | $this->linkDb['20001010_105536']['private'] | 474 | $this->linkDb['0']['private'] |
431 | ); | 475 | ); |
432 | $this->assertEquals( | 476 | $this->assertEquals( |
433 | 1, | 477 | 1, |
434 | $this->linkDb['20160225_205548']['private'] | 478 | $this->linkDb['1']['private'] |
435 | ); | 479 | ); |
436 | } | 480 | } |
437 | 481 | ||
@@ -480,11 +524,11 @@ class BookmarkImportTest extends PHPUnit_Framework_TestCase | |||
480 | $this->assertEquals(0, count_private($this->linkDb)); | 524 | $this->assertEquals(0, count_private($this->linkDb)); |
481 | $this->assertEquals( | 525 | $this->assertEquals( |
482 | 'tag1 tag2 tag3 private secret', | 526 | 'tag1 tag2 tag3 private secret', |
483 | $this->linkDb['20001010_105536']['tags'] | 527 | $this->linkDb['0']['tags'] |
484 | ); | 528 | ); |
485 | $this->assertEquals( | 529 | $this->assertEquals( |
486 | 'tag1 tag2 tag3 public hello world', | 530 | 'tag1 tag2 tag3 public hello world', |
487 | $this->linkDb['20160225_205548']['tags'] | 531 | $this->linkDb['1']['tags'] |
488 | ); | 532 | ); |
489 | } | 533 | } |
490 | 534 | ||
@@ -507,16 +551,16 @@ class BookmarkImportTest extends PHPUnit_Framework_TestCase | |||
507 | $this->assertEquals(0, count_private($this->linkDb)); | 551 | $this->assertEquals(0, count_private($this->linkDb)); |
508 | $this->assertEquals( | 552 | $this->assertEquals( |
509 | 'tag1& tag2 "tag3" private secret', | 553 | 'tag1& tag2 "tag3" private secret', |
510 | $this->linkDb['20001010_105536']['tags'] | 554 | $this->linkDb['0']['tags'] |
511 | ); | 555 | ); |
512 | $this->assertEquals( | 556 | $this->assertEquals( |
513 | 'tag1& tag2 "tag3" public hello world', | 557 | 'tag1& tag2 "tag3" public hello world', |
514 | $this->linkDb['20160225_205548']['tags'] | 558 | $this->linkDb['1']['tags'] |
515 | ); | 559 | ); |
516 | } | 560 | } |
517 | 561 | ||
518 | /** | 562 | /** |
519 | * Ensure each imported bookmark has a unique linkdate | 563 | * Ensure each imported bookmark has a unique id |
520 | * | 564 | * |
521 | * See https://github.com/shaarli/Shaarli/issues/351 | 565 | * See https://github.com/shaarli/Shaarli/issues/351 |
522 | */ | 566 | */ |
@@ -531,16 +575,16 @@ class BookmarkImportTest extends PHPUnit_Framework_TestCase | |||
531 | $this->assertEquals(3, count($this->linkDb)); | 575 | $this->assertEquals(3, count($this->linkDb)); |
532 | $this->assertEquals(0, count_private($this->linkDb)); | 576 | $this->assertEquals(0, count_private($this->linkDb)); |
533 | $this->assertEquals( | 577 | $this->assertEquals( |
534 | '20160225_205548', | 578 | 0, |
535 | $this->linkDb['20160225_205548']['linkdate'] | 579 | $this->linkDb[0]['id'] |
536 | ); | 580 | ); |
537 | $this->assertEquals( | 581 | $this->assertEquals( |
538 | '20160225_205549', | 582 | 1, |
539 | $this->linkDb['20160225_205549']['linkdate'] | 583 | $this->linkDb[1]['id'] |
540 | ); | 584 | ); |
541 | $this->assertEquals( | 585 | $this->assertEquals( |
542 | '20160225_205550', | 586 | 2, |
543 | $this->linkDb['20160225_205550']['linkdate'] | 587 | $this->linkDb[2]['id'] |
544 | ); | 588 | ); |
545 | } | 589 | } |
546 | } | 590 | } |
diff --git a/tests/Updater/UpdaterTest.php b/tests/Updater/UpdaterTest.php index 0d0ad922..4948fe52 100644 --- a/tests/Updater/UpdaterTest.php +++ b/tests/Updater/UpdaterTest.php | |||
@@ -214,6 +214,7 @@ $GLOBALS[\'privateLinkByDefault\'] = true;'; | |||
214 | $refDB = new ReferenceLinkDB(); | 214 | $refDB = new ReferenceLinkDB(); |
215 | $refDB->write(self::$testDatastore); | 215 | $refDB->write(self::$testDatastore); |
216 | $linkDB = new LinkDB(self::$testDatastore, true, false); | 216 | $linkDB = new LinkDB(self::$testDatastore, true, false); |
217 | |||
217 | $this->assertEmpty($linkDB->filterSearch(array('searchtags' => 'exclude'))); | 218 | $this->assertEmpty($linkDB->filterSearch(array('searchtags' => 'exclude'))); |
218 | $updater = new Updater(array(), $linkDB, $this->conf, true); | 219 | $updater = new Updater(array(), $linkDB, $this->conf, true); |
219 | $updater->updateMethodRenameDashTags(); | 220 | $updater->updateMethodRenameDashTags(); |
@@ -287,4 +288,101 @@ $GLOBALS[\'privateLinkByDefault\'] = true;'; | |||
287 | $this->assertEquals(escape($redirectorUrl), $this->conf->get('redirector.url')); | 288 | $this->assertEquals(escape($redirectorUrl), $this->conf->get('redirector.url')); |
288 | unlink($sandbox .'.json.php'); | 289 | unlink($sandbox .'.json.php'); |
289 | } | 290 | } |
291 | |||
292 | /** | ||
293 | * Test updateMethodDatastoreIds(). | ||
294 | */ | ||
295 | public function testDatastoreIds() | ||
296 | { | ||
297 | $links = array( | ||
298 | '20121206_182539' => array( | ||
299 | 'linkdate' => '20121206_182539', | ||
300 | 'title' => 'Geek and Poke', | ||
301 | 'url' => 'http://geek-and-poke.com/', | ||
302 | 'description' => 'desc', | ||
303 | 'tags' => 'dev cartoon tag1 tag2 tag3 tag4 ', | ||
304 | 'updated' => '20121206_190301', | ||
305 | 'private' => false, | ||
306 | ), | ||
307 | '20121206_172539' => array( | ||
308 | 'linkdate' => '20121206_172539', | ||
309 | 'title' => 'UserFriendly - Samba', | ||
310 | 'url' => 'http://ars.userfriendly.org/cartoons/?id=20010306', | ||
311 | 'description' => '', | ||
312 | 'tags' => 'samba cartoon web', | ||
313 | 'private' => false, | ||
314 | ), | ||
315 | '20121206_142300' => array( | ||
316 | 'linkdate' => '20121206_142300', | ||
317 | 'title' => 'UserFriendly - Web Designer', | ||
318 | 'url' => 'http://ars.userfriendly.org/cartoons/?id=20121206', | ||
319 | 'description' => 'Naming conventions... #private', | ||
320 | 'tags' => 'samba cartoon web', | ||
321 | 'private' => true, | ||
322 | ), | ||
323 | ); | ||
324 | $refDB = new ReferenceLinkDB(); | ||
325 | $refDB->setLinks($links); | ||
326 | $refDB->write(self::$testDatastore); | ||
327 | $linkDB = new LinkDB(self::$testDatastore, true, false); | ||
328 | |||
329 | $checksum = hash_file('sha1', self::$testDatastore); | ||
330 | |||
331 | $this->conf->set('resource.data_dir', 'sandbox'); | ||
332 | $this->conf->set('resource.datastore', self::$testDatastore); | ||
333 | |||
334 | $updater = new Updater(array(), $linkDB, $this->conf, true); | ||
335 | $this->assertTrue($updater->updateMethodDatastoreIds()); | ||
336 | |||
337 | $linkDB = new LinkDB(self::$testDatastore, true, false); | ||
338 | |||
339 | $backup = glob($this->conf->get('resource.data_dir') . '/datastore.'. date('YmdH') .'*.php'); | ||
340 | $backup = $backup[0]; | ||
341 | |||
342 | $this->assertFileExists($backup); | ||
343 | $this->assertEquals($checksum, hash_file('sha1', $backup)); | ||
344 | unlink($backup); | ||
345 | |||
346 | $this->assertEquals(3, count($linkDB)); | ||
347 | $this->assertTrue(isset($linkDB[0])); | ||
348 | $this->assertFalse(isset($linkDB[0]['linkdate'])); | ||
349 | $this->assertEquals(0, $linkDB[0]['id']); | ||
350 | $this->assertEquals('UserFriendly - Web Designer', $linkDB[0]['title']); | ||
351 | $this->assertEquals('http://ars.userfriendly.org/cartoons/?id=20121206', $linkDB[0]['url']); | ||
352 | $this->assertEquals('Naming conventions... #private', $linkDB[0]['description']); | ||
353 | $this->assertEquals('samba cartoon web', $linkDB[0]['tags']); | ||
354 | $this->assertTrue($linkDB[0]['private']); | ||
355 | $this->assertEquals(DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, '20121206_142300'), $linkDB[0]['created']); | ||
356 | |||
357 | $this->assertTrue(isset($linkDB[1])); | ||
358 | $this->assertFalse(isset($linkDB[1]['linkdate'])); | ||
359 | $this->assertEquals(1, $linkDB[1]['id']); | ||
360 | $this->assertEquals('UserFriendly - Samba', $linkDB[1]['title']); | ||
361 | $this->assertEquals(DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, '20121206_172539'), $linkDB[1]['created']); | ||
362 | |||
363 | $this->assertTrue(isset($linkDB[2])); | ||
364 | $this->assertFalse(isset($linkDB[2]['linkdate'])); | ||
365 | $this->assertEquals(2, $linkDB[2]['id']); | ||
366 | $this->assertEquals('Geek and Poke', $linkDB[2]['title']); | ||
367 | $this->assertEquals(DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, '20121206_182539'), $linkDB[2]['created']); | ||
368 | $this->assertEquals(DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, '20121206_190301'), $linkDB[2]['updated']); | ||
369 | } | ||
370 | |||
371 | /** | ||
372 | * Test updateMethodDatastoreIds() with the update already applied: nothing to do. | ||
373 | */ | ||
374 | public function testDatastoreIdsNothingToDo() | ||
375 | { | ||
376 | $refDB = new ReferenceLinkDB(); | ||
377 | $refDB->write(self::$testDatastore); | ||
378 | $linkDB = new LinkDB(self::$testDatastore, true, false); | ||
379 | |||
380 | $this->conf->set('resource.data_dir', 'sandbox'); | ||
381 | $this->conf->set('resource.datastore', self::$testDatastore); | ||
382 | |||
383 | $checksum = hash_file('sha1', self::$testDatastore); | ||
384 | $updater = new Updater(array(), $linkDB, $this->conf, true); | ||
385 | $this->assertTrue($updater->updateMethodDatastoreIds()); | ||
386 | $this->assertEquals($checksum, hash_file('sha1', self::$testDatastore)); | ||
387 | } | ||
290 | } | 388 | } |
diff --git a/tests/plugins/PluginIssoTest.php b/tests/plugins/PluginIssoTest.php index 1f545c7d..6b7904dd 100644 --- a/tests/plugins/PluginIssoTest.php +++ b/tests/plugins/PluginIssoTest.php | |||
@@ -47,12 +47,14 @@ class PluginIssoTest extends PHPUnit_Framework_TestCase | |||
47 | $conf->set('plugins.ISSO_SERVER', 'value'); | 47 | $conf->set('plugins.ISSO_SERVER', 'value'); |
48 | 48 | ||
49 | $str = 'http://randomstr.com/test'; | 49 | $str = 'http://randomstr.com/test'; |
50 | $date = '20161118_100001'; | ||
50 | $data = array( | 51 | $data = array( |
51 | 'title' => $str, | 52 | 'title' => $str, |
52 | 'links' => array( | 53 | 'links' => array( |
53 | array( | 54 | array( |
55 | 'id' => 12, | ||
54 | 'url' => $str, | 56 | 'url' => $str, |
55 | 'linkdate' => 'abc', | 57 | 'created' => DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, $date), |
56 | ) | 58 | ) |
57 | ) | 59 | ) |
58 | ); | 60 | ); |
@@ -65,7 +67,14 @@ class PluginIssoTest extends PHPUnit_Framework_TestCase | |||
65 | 67 | ||
66 | // plugin data | 68 | // plugin data |
67 | $this->assertEquals(1, count($data['plugin_end_zone'])); | 69 | $this->assertEquals(1, count($data['plugin_end_zone'])); |
68 | $this->assertNotFalse(strpos($data['plugin_end_zone'][0], 'abc')); | 70 | $this->assertNotFalse(strpos( |
71 | $data['plugin_end_zone'][0], | ||
72 | 'data-isso-id="'. $data['links'][0]['id'] .'"' | ||
73 | )); | ||
74 | $this->assertNotFalse(strpos( | ||
75 | $data['plugin_end_zone'][0], | ||
76 | 'data-title="'. $data['links'][0]['id'] .'"' | ||
77 | )); | ||
69 | $this->assertNotFalse(strpos($data['plugin_end_zone'][0], 'embed.min.js')); | 78 | $this->assertNotFalse(strpos($data['plugin_end_zone'][0], 'embed.min.js')); |
70 | } | 79 | } |
71 | 80 | ||
@@ -78,16 +87,20 @@ class PluginIssoTest extends PHPUnit_Framework_TestCase | |||
78 | $conf->set('plugins.ISSO_SERVER', 'value'); | 87 | $conf->set('plugins.ISSO_SERVER', 'value'); |
79 | 88 | ||
80 | $str = 'http://randomstr.com/test'; | 89 | $str = 'http://randomstr.com/test'; |
90 | $date1 = '20161118_100001'; | ||
91 | $date2 = '20161118_100002'; | ||
81 | $data = array( | 92 | $data = array( |
82 | 'title' => $str, | 93 | 'title' => $str, |
83 | 'links' => array( | 94 | 'links' => array( |
84 | array( | 95 | array( |
96 | 'id' => 12, | ||
85 | 'url' => $str, | 97 | 'url' => $str, |
86 | 'linkdate' => 'abc', | 98 | 'created' => DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, $date1), |
87 | ), | 99 | ), |
88 | array( | 100 | array( |
101 | 'id' => 13, | ||
89 | 'url' => $str . '2', | 102 | 'url' => $str . '2', |
90 | 'linkdate' => 'abc2', | 103 | 'created' => DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, $date2), |
91 | ), | 104 | ), |
92 | ) | 105 | ) |
93 | ); | 106 | ); |
@@ -106,12 +119,14 @@ class PluginIssoTest extends PHPUnit_Framework_TestCase | |||
106 | $conf->set('plugins.ISSO_SERVER', 'value'); | 119 | $conf->set('plugins.ISSO_SERVER', 'value'); |
107 | 120 | ||
108 | $str = 'http://randomstr.com/test'; | 121 | $str = 'http://randomstr.com/test'; |
122 | $date = '20161118_100001'; | ||
109 | $data = array( | 123 | $data = array( |
110 | 'title' => $str, | 124 | 'title' => $str, |
111 | 'links' => array( | 125 | 'links' => array( |
112 | array( | 126 | array( |
127 | 'id' => 12, | ||
113 | 'url' => $str, | 128 | 'url' => $str, |
114 | 'linkdate' => 'abc', | 129 | 'created' => DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, $date), |
115 | ) | 130 | ) |
116 | ), | 131 | ), |
117 | 'search_term' => $str | 132 | 'search_term' => $str |
diff --git a/tests/utils/ReferenceLinkDB.php b/tests/utils/ReferenceLinkDB.php index abca4656..36d58c68 100644 --- a/tests/utils/ReferenceLinkDB.php +++ b/tests/utils/ReferenceLinkDB.php | |||
@@ -4,7 +4,7 @@ | |||
4 | */ | 4 | */ |
5 | class ReferenceLinkDB | 5 | class ReferenceLinkDB |
6 | { | 6 | { |
7 | public static $NB_LINKS_TOTAL = 7; | 7 | public static $NB_LINKS_TOTAL = 8; |
8 | 8 | ||
9 | private $_links = array(); | 9 | private $_links = array(); |
10 | private $_publicCount = 0; | 10 | private $_publicCount = 0; |
@@ -16,66 +16,87 @@ class ReferenceLinkDB | |||
16 | public function __construct() | 16 | public function __construct() |
17 | { | 17 | { |
18 | $this->addLink( | 18 | $this->addLink( |
19 | 41, | ||
19 | 'Link title: @website', | 20 | 'Link title: @website', |
20 | '?WDWyig', | 21 | '?WDWyig', |
21 | 'Stallman has a beard and is part of the Free Software Foundation (or not). Seriously, read this. #hashtag', | 22 | 'Stallman has a beard and is part of the Free Software Foundation (or not). Seriously, read this. #hashtag', |
22 | 0, | 23 | 0, |
23 | '20150310_114651', | 24 | DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, '20150310_114651'), |
24 | 'sTuff' | 25 | 'sTuff', |
26 | null, | ||
27 | 'WDWyig' | ||
25 | ); | 28 | ); |
26 | 29 | ||
27 | $this->addLink( | 30 | $this->addLink( |
31 | 42, | ||
32 | 'Note: I have a big ID but an old date', | ||
33 | '?WDWyig', | ||
34 | 'Used to test links reordering.', | ||
35 | 0, | ||
36 | DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, '20100310_101010'), | ||
37 | 'ut' | ||
38 | ); | ||
39 | |||
40 | $this->addLink( | ||
41 | 8, | ||
28 | 'Free as in Freedom 2.0 @website', | 42 | 'Free as in Freedom 2.0 @website', |
29 | 'https://static.fsf.org/nosvn/faif-2.0.pdf', | 43 | 'https://static.fsf.org/nosvn/faif-2.0.pdf', |
30 | 'Richard Stallman and the Free Software Revolution. Read this. #hashtag', | 44 | 'Richard Stallman and the Free Software Revolution. Read this. #hashtag', |
31 | 0, | 45 | 0, |
32 | '20150310_114633', | 46 | DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, '20150310_114633'), |
33 | 'free gnu software stallman -exclude stuff hashtag', | 47 | 'free gnu software stallman -exclude stuff hashtag', |
34 | '20160803_093033' | 48 | DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, '20160803_093033') |
35 | ); | 49 | ); |
36 | 50 | ||
37 | $this->addLink( | 51 | $this->addLink( |
52 | 7, | ||
38 | 'MediaGoblin', | 53 | 'MediaGoblin', |
39 | 'http://mediagoblin.org/', | 54 | 'http://mediagoblin.org/', |
40 | 'A free software media publishing platform #hashtagOther', | 55 | 'A free software media publishing platform #hashtagOther', |
41 | 0, | 56 | 0, |
42 | '20130614_184135', | 57 | DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, '20130614_184135'), |
43 | 'gnu media web .hidden hashtag' | 58 | 'gnu media web .hidden hashtag', |
59 | null, | ||
60 | 'IuWvgA' | ||
44 | ); | 61 | ); |
45 | 62 | ||
46 | $this->addLink( | 63 | $this->addLink( |
64 | 6, | ||
47 | 'w3c-markup-validator', | 65 | 'w3c-markup-validator', |
48 | 'https://dvcs.w3.org/hg/markup-validator/summary', | 66 | 'https://dvcs.w3.org/hg/markup-validator/summary', |
49 | 'Mercurial repository for the W3C Validator #private', | 67 | 'Mercurial repository for the W3C Validator #private', |
50 | 1, | 68 | 1, |
51 | '20141125_084734', | 69 | DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, '20141125_084734'), |
52 | 'css html w3c web Mercurial' | 70 | 'css html w3c web Mercurial' |
53 | ); | 71 | ); |
54 | 72 | ||
55 | $this->addLink( | 73 | $this->addLink( |
74 | 4, | ||
56 | 'UserFriendly - Web Designer', | 75 | 'UserFriendly - Web Designer', |
57 | 'http://ars.userfriendly.org/cartoons/?id=20121206', | 76 | 'http://ars.userfriendly.org/cartoons/?id=20121206', |
58 | 'Naming conventions... #private', | 77 | 'Naming conventions... #private', |
59 | 0, | 78 | 0, |
60 | '20121206_142300', | 79 | DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, '20121206_142300'), |
61 | 'dev cartoon web' | 80 | 'dev cartoon web' |
62 | ); | 81 | ); |
63 | 82 | ||
64 | $this->addLink( | 83 | $this->addLink( |
84 | 1, | ||
65 | 'UserFriendly - Samba', | 85 | 'UserFriendly - Samba', |
66 | 'http://ars.userfriendly.org/cartoons/?id=20010306', | 86 | 'http://ars.userfriendly.org/cartoons/?id=20010306', |
67 | 'Tropical printing', | 87 | 'Tropical printing', |
68 | 0, | 88 | 0, |
69 | '20121206_172539', | 89 | DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, '20121206_172539'), |
70 | 'samba cartoon web' | 90 | 'samba cartoon web' |
71 | ); | 91 | ); |
72 | 92 | ||
73 | $this->addLink( | 93 | $this->addLink( |
94 | 0, | ||
74 | 'Geek and Poke', | 95 | 'Geek and Poke', |
75 | 'http://geek-and-poke.com/', | 96 | 'http://geek-and-poke.com/', |
76 | '', | 97 | '', |
77 | 1, | 98 | 1, |
78 | '20121206_182539', | 99 | DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, '20121206_182539'), |
79 | 'dev cartoon tag1 tag2 tag3 tag4 ' | 100 | 'dev cartoon tag1 tag2 tag3 tag4 ' |
80 | ); | 101 | ); |
81 | } | 102 | } |
@@ -83,18 +104,20 @@ class ReferenceLinkDB | |||
83 | /** | 104 | /** |
84 | * Adds a new link | 105 | * Adds a new link |
85 | */ | 106 | */ |
86 | protected function addLink($title, $url, $description, $private, $date, $tags, $updated = '') | 107 | protected function addLink($id, $title, $url, $description, $private, $date, $tags, $updated = '', $shorturl = '') |
87 | { | 108 | { |
88 | $link = array( | 109 | $link = array( |
110 | 'id' => $id, | ||
89 | 'title' => $title, | 111 | 'title' => $title, |
90 | 'url' => $url, | 112 | 'url' => $url, |
91 | 'description' => $description, | 113 | 'description' => $description, |
92 | 'private' => $private, | 114 | 'private' => $private, |
93 | 'linkdate' => $date, | ||
94 | 'tags' => $tags, | 115 | 'tags' => $tags, |
116 | 'created' => $date, | ||
95 | 'updated' => $updated, | 117 | 'updated' => $updated, |
118 | 'shorturl' => $shorturl ? $shorturl : smallHash($date->format(LinkDB::LINK_DATE_FORMAT) . $id), | ||
96 | ); | 119 | ); |
97 | $this->_links[$date] = $link; | 120 | $this->_links[$id] = $link; |
98 | 121 | ||
99 | if ($private) { | 122 | if ($private) { |
100 | $this->_privateCount++; | 123 | $this->_privateCount++; |
@@ -142,4 +165,14 @@ class ReferenceLinkDB | |||
142 | { | 165 | { |
143 | return $this->_links; | 166 | return $this->_links; |
144 | } | 167 | } |
168 | |||
169 | /** | ||
170 | * Setter to override link creation. | ||
171 | * | ||
172 | * @param array $links List of links. | ||
173 | */ | ||
174 | public function setLinks($links) | ||
175 | { | ||
176 | $this->_links = $links; | ||
177 | } | ||
145 | } | 178 | } |
diff --git a/tpl/daily.html b/tpl/daily.html index b82ad483..eba0af3b 100644 --- a/tpl/daily.html +++ b/tpl/daily.html | |||
@@ -49,13 +49,13 @@ | |||
49 | {$link=$value} | 49 | {$link=$value} |
50 | <div class="dailyEntry"> | 50 | <div class="dailyEntry"> |
51 | <div class="dailyEntryPermalink"> | 51 | <div class="dailyEntryPermalink"> |
52 | <a href="?{$link.linkdate|smallHash}"> | 52 | <a href="?{$value.shorturl}"> |
53 | <img src="../images/squiggle2.png" width="25" height="26" title="permalink" alt="permalink"> | 53 | <img src="../images/squiggle2.png" width="25" height="26" title="permalink" alt="permalink"> |
54 | </a> | 54 | </a> |
55 | </div> | 55 | </div> |
56 | {if="!$hide_timestamps || isLoggedIn()"} | 56 | {if="!$hide_timestamps || isLoggedIn()"} |
57 | <div class="dailyEntryLinkdate"> | 57 | <div class="dailyEntryLinkdate"> |
58 | <a href="?{$link.linkdate|smallHash}">{function="strftime('%c', $link.timestamp)"}</a> | 58 | <a href="?{$value.shorturl}">{function="strftime('%c', $link.timestamp)"}</a> |
59 | </div> | 59 | </div> |
60 | {/if} | 60 | {/if} |
61 | {if="$link.tags"} | 61 | {if="$link.tags"} |
diff --git a/tpl/editlink.html b/tpl/editlink.html index 9e7621db..870cc168 100644 --- a/tpl/editlink.html +++ b/tpl/editlink.html | |||
@@ -16,6 +16,9 @@ | |||
16 | <div id="editlinkform"> | 16 | <div id="editlinkform"> |
17 | <form method="post" name="linkform"> | 17 | <form method="post" name="linkform"> |
18 | <input type="hidden" name="lf_linkdate" value="{$link.linkdate}"> | 18 | <input type="hidden" name="lf_linkdate" value="{$link.linkdate}"> |
19 | {if="isset($link.id)"} | ||
20 | <input type="hidden" name="lf_id" value="{$link.id}"> | ||
21 | {/if} | ||
19 | <label for="lf_url"><i>URL</i></label><br><input type="text" name="lf_url" id="lf_url" value="{$link.url}" class="lf_input"><br> | 22 | <label for="lf_url"><i>URL</i></label><br><input type="text" name="lf_url" id="lf_url" value="{$link.url}" class="lf_input"><br> |
20 | <label for="lf_title"><i>Title</i></label><br><input type="text" name="lf_title" id="lf_title" value="{$link.title}" class="lf_input"><br> | 23 | <label for="lf_title"><i>Title</i></label><br><input type="text" name="lf_title" id="lf_title" value="{$link.title}" class="lf_input"><br> |
21 | <label for="lf_description"><i>Description</i></label><br><textarea name="lf_description" id="lf_description" rows="4" cols="25">{$link.description}</textarea><br> | 24 | <label for="lf_description"><i>Description</i></label><br><textarea name="lf_description" id="lf_description" rows="4" cols="25">{$link.description}</textarea><br> |
diff --git a/tpl/linklist.html b/tpl/linklist.html index 3fe86deb..0f1a5e8c 100644 --- a/tpl/linklist.html +++ b/tpl/linklist.html | |||
@@ -81,11 +81,11 @@ | |||
81 | {if="isLoggedIn()"} | 81 | {if="isLoggedIn()"} |
82 | <div class="linkeditbuttons"> | 82 | <div class="linkeditbuttons"> |
83 | <form method="GET" class="buttoneditform"> | 83 | <form method="GET" class="buttoneditform"> |
84 | <input type="hidden" name="edit_link" value="{$value.linkdate}"> | 84 | <input type="hidden" name="edit_link" value="{$value.id}"> |
85 | <input type="image" alt="Edit" src="images/edit_icon.png#" title="Edit" class="button_edit"> | 85 | <input type="image" alt="Edit" src="images/edit_icon.png#" title="Edit" class="button_edit"> |
86 | </form><br> | 86 | </form><br> |
87 | <form method="POST" class="buttoneditform"> | 87 | <form method="POST" class="buttoneditform"> |
88 | <input type="hidden" name="lf_linkdate" value="{$value.linkdate}"> | 88 | <input type="hidden" name="lf_linkdate" value="{$value.id}"> |
89 | <input type="hidden" name="token" value="{$token}"> | 89 | <input type="hidden" name="token" value="{$token}"> |
90 | <input type="hidden" name="delete_link"> | 90 | <input type="hidden" name="delete_link"> |
91 | <input type="image" alt="Delete" src="images/delete_icon.png#" title="Delete" | 91 | <input type="image" alt="Delete" src="images/delete_icon.png#" title="Delete" |
@@ -101,7 +101,7 @@ | |||
101 | {if="!$hide_timestamps || isLoggedIn()"} | 101 | {if="!$hide_timestamps || isLoggedIn()"} |
102 | {$updated=$value.updated_timestamp ? 'Edited: '. strftime('%c', $value.updated_timestamp) : 'Permalink'} | 102 | {$updated=$value.updated_timestamp ? 'Edited: '. strftime('%c', $value.updated_timestamp) : 'Permalink'} |
103 | <span class="linkdate" title="Permalink"> | 103 | <span class="linkdate" title="Permalink"> |
104 | <a href="?{$value.linkdate|smallHash}"> | 104 | <a href="?{$value.shorturl}"> |
105 | <span title="{$updated}"> | 105 | <span title="{$updated}"> |
106 | {function="strftime('%c', $value.timestamp)"} | 106 | {function="strftime('%c', $value.timestamp)"} |
107 | {if="$value.updated_timestamp"}*{/if} | 107 | {if="$value.updated_timestamp"}*{/if} |