From 29d108820f05615d5c36608fde86f64f0750531a Mon Sep 17 00:00:00 2001 From: ArthurHoaro Date: Mon, 28 Nov 2016 15:30:17 +0100 Subject: Link ID refactoring Links now use an incremental unique numeric identifier. This ID is persistent and must never change. ArrayAccess is used to match the link ID with the array keys (see the comment in LinkDB for more details) Key 'created' added, with creation date as a DateTime object. 'updated' is now also a DateTime. --- application/LinkDB.php | 178 +++++++++++++++++++++++++++++++++++++------------ 1 file changed, 135 insertions(+), 43 deletions(-) diff --git a/application/LinkDB.php b/application/LinkDB.php index c8b162b6..e429ab4f 100644 --- a/application/LinkDB.php +++ b/application/LinkDB.php @@ -6,15 +6,15 @@ * * Example: * $myLinks = new LinkDB(); - * echo $myLinks['20110826_161819']['title']; + * echo $myLinks[350]['title']; * foreach ($myLinks as $link) * echo $link['title'].' at url '.$link['url'].'; description:'.$link['description']; * * Available keys: + * - id: primary key, incremental integer identifier (persistent) * - description: description of the entry - * - linkdate: creation date of this entry, format: YYYYMMDD_HHMMSS - * (e.g.'20110914_192317') - * - updated: last modification date of this entry, format: YYYYMMDD_HHMMSS + * - created: creation date of this entry, DateTime object. + * - updated: last modification date of this entry, DateTime object. * - private: Is this link private? 0=no, other value=yes * - tags: tags attached to this entry (separated by spaces) * - title Title of the link @@ -27,6 +27,19 @@ * - ArrayAccess: behaves like an associative array; * - Countable: there is a count() method; * - Iterator: usable in foreach () loops. + * + * ID mechanism: + * ArrayAccess is implemented in a way that will allow to access a link + * with the unique identifier ID directly with $link[ID]. + * Note that it's not the real key of the link array attribute. + * This mechanism is in place to have persistent link IDs, + * even though the internal array is reordered by date. + * Example: + * - DB: link #1 (2010-01-01) link #2 (2016-01-01) + * - Order: #2 #1 + * - Import links containing: link #3 (2013-01-01) + * - New DB: link #1 (2010-01-01) link #2 (2016-01-01) link #3 (2013-01-01) + * - Real order: #2 #3 #1 */ class LinkDB implements Iterator, Countable, ArrayAccess { @@ -47,11 +60,17 @@ class LinkDB implements Iterator, Countable, ArrayAccess // - value: associative array (keys: title, description...) private $links; - // List of all recorded URLs (key=url, value=linkdate) - // for fast reserve search (url-->linkdate) + // List of all recorded URLs (key=url, value=link offset) + // for fast reserve search (url-->link offset) private $urls; - // List of linkdate keys (for the Iterator interface implementation) + /** + * @var array List of all links IDS mapped with their array offset. + * Map: id->offset. + */ + protected $ids; + + // List of offset keys (for the Iterator interface implementation) private $keys; // Position in the $this->keys array (for the Iterator interface) @@ -121,14 +140,26 @@ class LinkDB implements Iterator, Countable, ArrayAccess if (!$this->loggedIn) { die('You are not authorized to add a link.'); } - if (empty($value['linkdate']) || empty($value['url'])) { - die('Internal Error: A link should always have a linkdate and URL.'); + if (!isset($value['id']) || empty($value['url'])) { + die('Internal Error: A link should always have an id and URL.'); } - if (empty($offset)) { - die('You must specify a key.'); + if ((! empty($offset) && ! is_int($offset)) || ! is_int($value['id'])) { + die('You must specify an integer as a key.'); + } + if (! empty($offset) && $offset !== $value['id']) { + die('Array offset and link ID must be equal.'); + } + + // If the link exists, we reuse the real offset, otherwise new entry + $existing = $this->getLinkOffset($offset); + if ($existing !== null) { + $offset = $existing; + } else { + $offset = count($this->links); } $this->links[$offset] = $value; - $this->urls[$value['url']]=$offset; + $this->urls[$value['url']] = $offset; + $this->ids[$value['id']] = $offset; } /** @@ -136,7 +167,7 @@ class LinkDB implements Iterator, Countable, ArrayAccess */ public function offsetExists($offset) { - return array_key_exists($offset, $this->links); + return array_key_exists($this->getLinkOffset($offset), $this->links); } /** @@ -148,9 +179,11 @@ class LinkDB implements Iterator, Countable, ArrayAccess // TODO: raise an exception die('You are not authorized to delete a link.'); } - $url = $this->links[$offset]['url']; + $realOffset = $this->getLinkOffset($offset); + $url = $this->links[$realOffset]['url']; unset($this->urls[$url]); - unset($this->links[$offset]); + unset($this->ids[$realOffset]); + unset($this->links[$realOffset]); } /** @@ -158,7 +191,8 @@ class LinkDB implements Iterator, Countable, ArrayAccess */ public function offsetGet($offset) { - return isset($this->links[$offset]) ? $this->links[$offset] : null; + $realOffset = $this->getLinkOffset($offset); + return isset($this->links[$realOffset]) ? $this->links[$realOffset] : null; } /** @@ -166,7 +200,7 @@ class LinkDB implements Iterator, Countable, ArrayAccess */ public function current() { - return $this->links[$this->keys[$this->position]]; + return $this[$this->keys[$this->position]]; } /** @@ -192,8 +226,7 @@ class LinkDB implements Iterator, Countable, ArrayAccess */ public function rewind() { - $this->keys = array_keys($this->links); - rsort($this->keys); + $this->keys = array_keys($this->ids); $this->position = 0; } @@ -219,6 +252,7 @@ class LinkDB implements Iterator, Countable, ArrayAccess // Create a dummy database for example $this->links = array(); $link = array( + 'id' => 1, 'title'=>' Shaarli: the personal, minimalist, super-fast, no-database delicious clone', 'url'=>'https://github.com/shaarli/Shaarli/wiki', 'description'=>'Welcome to Shaarli! This is your first public bookmark. To edit or delete me, you must first login. @@ -227,20 +261,21 @@ To learn how to use Shaarli, consult the link "Help/documentation" at the bottom You use the community supported version of the original Shaarli project, by Sebastien Sauvage.', 'private'=>0, - 'linkdate'=> date('Ymd_His'), + 'created'=> new DateTime(), 'tags'=>'opensource software' ); - $this->links[$link['linkdate']] = $link; + $this->links[1] = $link; $link = array( + 'id' => 0, 'title'=>'My secret stuff... - Pastebin.com', 'url'=>'http://sebsauvage.net/paste/?8434b27936c09649#bR7XsXhoTiLcqCpQbmOpBi3rq2zzQUC5hBI7ZT1O3x8=', 'description'=>'Shhhh! I\'m a private link only YOU can see. You can delete me too.', 'private'=>1, - 'linkdate'=> date('Ymd_His', strtotime('-1 minute')), + 'created'=> new DateTime('1 minute ago'), 'tags'=>'secretstuff' ); - $this->links[$link['linkdate']] = $link; + $this->links[0] = $link; // Write database to disk $this->write(); @@ -251,7 +286,6 @@ You use the community supported version of the original Shaarli project, by Seba */ private function read() { - // Public links are hidden and user not logged in => nothing to show if ($this->hidePublicLinks && !$this->loggedIn) { $this->links = array(); @@ -269,23 +303,13 @@ You use the community supported version of the original Shaarli project, by Seba strlen(self::$phpPrefix), -strlen(self::$phpSuffix))))); } - // If user is not logged in, filter private links. - if (!$this->loggedIn) { - $toremove = array(); - foreach ($this->links as $link) { - if ($link['private'] != 0) { - $toremove[] = $link['linkdate']; - } - } - foreach ($toremove as $linkdate) { - unset($this->links[$linkdate]); + $toremove = array(); + foreach ($this->links as $key => &$link) { + if (! $this->loggedIn && $link['private'] != 0) { + // Transition for not upgraded databases. + $toremove[] = $key; + continue; } - } - - $this->urls = array(); - foreach ($this->links as &$link) { - // Keep the list of the mapping URLs-->linkdate up-to-date. - $this->urls[$link['url']] = $link['linkdate']; // Sanitize data fields. sanitizeLink($link); @@ -307,7 +331,23 @@ You use the community supported version of the original Shaarli project, by Seba else { $link['real_url'] = $link['url']; } + + // To be able to load links before running the update, and prepare the update + if (! isset($link['created'])) { + $link['id'] = $link['linkdate']; + $link['created'] = DateTime::createFromFormat('Ymd_His', $link['linkdate']); + if (! empty($link['updated'])) { + $link['updated'] = DateTime::createFromFormat('Ymd_His', $link['updated']); + } + } + } + + // If user is not logged in, filter private links. + foreach ($toremove as $offset) { + unset($this->links[$offset]); } + + $this->reorder(); } /** @@ -430,7 +470,7 @@ You use the community supported version of the original Shaarli project, by Seba $request = ''; } - $linkFilter = new LinkFilter($this->links); + $linkFilter = new LinkFilter($this); return $linkFilter->filter($type, $request, $casesensitive, $privateonly); } @@ -467,12 +507,64 @@ You use the community supported version of the original Shaarli project, by Seba public function days() { $linkDays = array(); - foreach (array_keys($this->links) as $day) { - $linkDays[substr($day, 0, 8)] = 0; + foreach ($this->links as $link) { + $linkDays[$link['created']->format('Ymd')] = 0; } $linkDays = array_keys($linkDays); sort($linkDays); return $linkDays; } + + /** + * Reorder links by creation date (newest first). + * + * Also update the urls and ids mapping arrays. + * + * @param string $order ASC|DESC + */ + public function reorder($order = 'DESC') + { + $order = $order === 'ASC' ? -1 : 1; + // Reorder array by dates. + usort($this->links, function($a, $b) use ($order) { + return $a['created'] < $b['created'] ? 1 * $order : -1 * $order; + }); + + $this->urls = array(); + $this->ids = array(); + foreach ($this->links as $key => $link) { + $this->urls[$link['url']] = $key; + $this->ids[$link['id']] = $key; + } + } + + /** + * Return the next key for link creation. + * E.g. If the last ID is 597, the next will be 598. + * + * @return int next ID. + */ + public function getNextId() + { + if (!empty($this->ids)) { + return max(array_keys($this->ids)) + 1; + } + return 0; + } + + /** + * Returns a link offset in links array from its unique ID. + * + * @param int $id Persistent ID of a link. + * + * @return int Real offset in local array, or null if doesn't exists. + */ + protected function getLinkOffset($id) + { + if (isset($this->ids[$id])) { + return $this->ids[$id]; + } + return null; + } } -- cgit v1.2.3 From 1dc37f9cf8397e6050c4d5d981da263e6333a849 Mon Sep 17 00:00:00 2001 From: ArthurHoaro Date: Mon, 28 Nov 2016 16:14:33 +0100 Subject: Update method to use the new ID system, which replaces linkdate primary keys. creation and update dates are now DateTime objects. Since this update is very sensitve (changing the whole database), the datastore will be automatically backed up into the file datastore..php. --- application/Updater.php | 46 ++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 44 insertions(+), 2 deletions(-) diff --git a/application/Updater.php b/application/Updater.php index 36eddd4f..94b63990 100644 --- a/application/Updater.php +++ b/application/Updater.php @@ -138,10 +138,10 @@ class Updater public function updateMethodRenameDashTags() { $linklist = $this->linkDB->filterSearch(); - foreach ($linklist as $link) { + foreach ($linklist as $key => $link) { $link['tags'] = preg_replace('/(^| )\-/', '$1', $link['tags']); $link['tags'] = implode(' ', array_unique(LinkFilter::tagsStrToArray($link['tags'], true))); - $this->linkDB[$link['linkdate']] = $link; + $this->linkDB[$key] = $link; } $this->linkDB->save($this->conf->get('resource.page_cache')); return true; @@ -215,6 +215,48 @@ class Updater } return true; } + + /** + * Update the database to use the new ID system, which replaces linkdate primary keys. + * Also, creation and update dates are now DateTime objects. + * + * Since this update is very sensitve (changing the whole database), the datastore will be + * automatically backed up into the file datastore..php. + * + * @return bool true if the update is successful, false otherwise. + */ + public function updateMethodDatastoreIds() + { + // up to date database + if (isset($this->linkDB[0])) { + return true; + } + + $save = $this->conf->get('resource.data_dir') .'/datastore.'. date('YmdHis') .'.php'; + copy($this->conf->get('resource.datastore'), $save); + + $links = array(); + foreach ($this->linkDB as $offset => $value) { + $links[] = $value; + unset($this->linkDB[$offset]); + } + $links = array_reverse($links); + $cpt = 0; + foreach ($links as $l) { + $l['created'] = DateTime::createFromFormat('Ymd_His', $l['linkdate']); + if (! empty($l['updated'])) { + $l['updated'] = DateTime::createFromFormat('Ymd_His', $l['updated']); + } + unset($l['linkdate']); + $l['id'] = $cpt; + $this->linkDB[$cpt++] = $l; + } + + $this->linkDB->save($this->conf->get('resource.page_cache')); + $this->linkDB->reorder(); + + return true; + } } /** -- cgit v1.2.3 From 01878a75b93b9966f7366ea2937c118bbc3e459e Mon Sep 17 00:00:00 2001 From: ArthurHoaro Date: Mon, 28 Nov 2016 16:16:44 +0100 Subject: Apply the new ID system accros the whole codebase --- application/FeedBuilder.php | 6 +-- application/LinkFilter.php | 37 +++++++------- application/NetscapeBookmarkUtils.php | 25 ++++------ application/Updater.php | 6 +-- index.php | 92 ++++++++++++++++++++++------------- plugins/isso/isso.php | 6 ++- tpl/daily.html | 4 +- tpl/editlink.html | 3 ++ tpl/linklist.html | 6 +-- 9 files changed, 100 insertions(+), 85 deletions(-) diff --git a/application/FeedBuilder.php b/application/FeedBuilder.php index 4036a7cc..bfdf2fd3 100644 --- a/application/FeedBuilder.php +++ b/application/FeedBuilder.php @@ -143,7 +143,7 @@ class FeedBuilder */ protected function buildItem($link, $pageaddr) { - $link['guid'] = $pageaddr .'?'. smallHash($link['linkdate']); + $link['guid'] = $pageaddr .'?'. smallHash($link['created']->format('Ymd_His')); // Check for both signs of a note: starting with ? and 7 chars long. if ($link['url'][0] === '?' && strlen($link['url']) === 7) { $link['url'] = $pageaddr . $link['url']; @@ -156,12 +156,12 @@ class FeedBuilder $link['description'] = format_description($link['description'], '', $pageaddr); $link['description'] .= PHP_EOL .'
— '. $permalink; - $pubDate = DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, $link['linkdate']); + $pubDate = $link['created']; $link['pub_iso_date'] = $this->getIsoDate($pubDate); // atom:entry elements MUST contain exactly one atom:updated element. if (!empty($link['updated'])) { - $upDate = DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, $link['updated']); + $upDate = $link['updated']; $link['up_iso_date'] = $this->getIsoDate($upDate, DateTime::ATOM); } else { $link['up_iso_date'] = $this->getIsoDate($pubDate, DateTime::ATOM);; diff --git a/application/LinkFilter.php b/application/LinkFilter.php index d4fe28df..7bab46ba 100644 --- a/application/LinkFilter.php +++ b/application/LinkFilter.php @@ -33,12 +33,12 @@ class LinkFilter public static $HASHTAG_CHARS = '\p{Pc}\p{N}\p{L}\p{Mn}'; /** - * @var array all available links. + * @var LinkDB all available links. */ private $links; /** - * @param array $links initialization. + * @param LinkDB $links initialization. */ public function __construct($links) { @@ -94,18 +94,16 @@ class LinkFilter private function noFilter($privateonly = false) { if (! $privateonly) { - krsort($this->links); return $this->links; } $out = array(); - foreach ($this->links as $value) { + foreach ($this->links as $key => $value) { if ($value['private']) { - $out[$value['linkdate']] = $value; + $out[$key] = $value; } } - krsort($out); return $out; } @@ -121,10 +119,10 @@ class LinkFilter private function filterSmallHash($smallHash) { $filtered = array(); - foreach ($this->links as $l) { - if ($smallHash == smallHash($l['linkdate'])) { + foreach ($this->links as $key => $l) { + if ($smallHash == smallHash($l['created']->format('Ymd_His'))) { // Yes, this is ugly and slow - $filtered[$l['linkdate']] = $l; + $filtered[$key] = $l; return $filtered; } } @@ -188,7 +186,7 @@ class LinkFilter $keys = array('title', 'description', 'url', 'tags'); // Iterate over every stored link. - foreach ($this->links as $link) { + foreach ($this->links as $id => $link) { // ignore non private links when 'privatonly' is on. if (! $link['private'] && $privateonly === true) { @@ -222,11 +220,10 @@ class LinkFilter } if ($found) { - $filtered[$link['linkdate']] = $link; + $filtered[$id] = $link; } } - krsort($filtered); return $filtered; } @@ -256,7 +253,7 @@ class LinkFilter return $filtered; } - foreach ($this->links as $link) { + foreach ($this->links as $key => $link) { // ignore non private links when 'privatonly' is on. if (! $link['private'] && $privateonly === true) { continue; @@ -278,10 +275,9 @@ class LinkFilter } if ($found) { - $filtered[$link['linkdate']] = $link; + $filtered[$key] = $link; } } - krsort($filtered); return $filtered; } @@ -304,13 +300,14 @@ class LinkFilter } $filtered = array(); - foreach ($this->links as $l) { - if (startsWith($l['linkdate'], $day)) { - $filtered[$l['linkdate']] = $l; + foreach ($this->links as $key => $l) { + if ($l['created']->format('Ymd') == $day) { + $filtered[$key] = $l; } } - ksort($filtered); - return $filtered; + + // sort by date ASC + return array_reverse($filtered, true); } /** diff --git a/application/NetscapeBookmarkUtils.php b/application/NetscapeBookmarkUtils.php index dd21f05b..8a939adb 100644 --- a/application/NetscapeBookmarkUtils.php +++ b/application/NetscapeBookmarkUtils.php @@ -38,7 +38,7 @@ class NetscapeBookmarkUtils if ($link['private'] == 0 && $selection == 'private') { continue; } - $date = DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, $link['linkdate']); + $date = $link['created']; $link['timestamp'] = $date->getTimestamp(); $link['taglist'] = str_replace(' ', ',', $link['tags']); @@ -147,7 +147,6 @@ class NetscapeBookmarkUtils 'url' => $bkm['uri'], 'description' => $bkm['note'], 'private' => $private, - 'linkdate'=> '', 'tags' => $bkm['tags'] ); @@ -161,25 +160,21 @@ class NetscapeBookmarkUtils } // Overwrite an existing link, keep its date - $newLink['linkdate'] = $existingLink['linkdate']; - $linkDb[$existingLink['linkdate']] = $newLink; + $newLink['id'] = $existingLink['id']; + $newLink['created'] = $existingLink['created']; + $newLink['updated'] = new DateTime(); + $linkDb[$existingLink['id']] = $newLink; $importCount++; $overwriteCount++; continue; } - // Add a new link + // Add a new link - @ used for UNIX timestamps $newLinkDate = new DateTime('@'.strval($bkm['time'])); - while (!empty($linkDb[$newLinkDate->format(LinkDB::LINK_DATE_FORMAT)])) { - // Ensure the date/time is not already used - // - this hack is necessary as the date/time acts as a primary key - // - apply 1 second increments until an unused index is found - // See https://github.com/shaarli/Shaarli/issues/351 - $newLinkDate->add(new DateInterval('PT1S')); - } - $linkDbDate = $newLinkDate->format(LinkDB::LINK_DATE_FORMAT); - $newLink['linkdate'] = $linkDbDate; - $linkDb[$linkDbDate] = $newLink; + $newLinkDate->setTimezone(new DateTimeZone(date_default_timezone_get())); + $newLink['created'] = $newLinkDate; + $newLink['id'] = $linkDb->getNextId(); + $linkDb[$newLink['id']] = $newLink; $importCount++; } diff --git a/application/Updater.php b/application/Updater.php index 94b63990..16c8c376 100644 --- a/application/Updater.php +++ b/application/Updater.php @@ -218,7 +218,7 @@ class Updater /** * Update the database to use the new ID system, which replaces linkdate primary keys. - * Also, creation and update dates are now DateTime objects. + * Also, creation and update dates are now DateTime objects (done by LinkDB). * * Since this update is very sensitve (changing the whole database), the datastore will be * automatically backed up into the file datastore..php. @@ -243,10 +243,6 @@ class Updater $links = array_reverse($links); $cpt = 0; foreach ($links as $l) { - $l['created'] = DateTime::createFromFormat('Ymd_His', $l['linkdate']); - if (! empty($l['updated'])) { - $l['updated'] = DateTime::createFromFormat('Ymd_His', $l['updated']); - } unset($l['linkdate']); $l['id'] = $cpt; $this->linkDB[$cpt++] = $l; diff --git a/index.php b/index.php index 5366cb0e..05f06452 100644 --- a/index.php +++ b/index.php @@ -564,24 +564,23 @@ function showDailyRSS($conf) { ); /* Some Shaarlies may have very few links, so we need to look - back in time (rsort()) until we have enough days ($nb_of_days). + back in time until we have enough days ($nb_of_days). */ - $linkdates = array(); - foreach ($LINKSDB as $linkdate => $value) { - $linkdates[] = $linkdate; + $ids = array(); + foreach ($LINKSDB as $id => $value) { + $ids[] = $id; } - rsort($linkdates); $nb_of_days = 7; // We take 7 days. $today = date('Ymd'); $days = array(); - foreach ($linkdates as $linkdate) { - $day = substr($linkdate, 0, 8); // Extract day (without time) - if (strcmp($day,$today) < 0) { + foreach ($ids as $id) { + $day = $LINKSDB[$id]['created']->format('Ymd'); // Extract day (without time) + if (strcmp($day, $today) < 0) { if (empty($days[$day])) { $days[$day] = array(); } - $days[$day][] = $linkdate; + $days[$day][] = $id; } if (count($days) > $nb_of_days) { @@ -601,7 +600,7 @@ function showDailyRSS($conf) { echo ''. $pageaddr .''. PHP_EOL; // For each day. - foreach ($days as $day => $linkdates) { + foreach ($days as $day => $ids) { $dayDate = DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, $day.'_000000'); $absurl = escape(index_url($_SERVER).'?do=daily&day='.$day); // Absolute URL of the corresponding "Daily" page. @@ -609,16 +608,15 @@ function showDailyRSS($conf) { $links = array(); // We pre-format some fields for proper output. - foreach ($linkdates as $linkdate) { - $l = $LINKSDB[$linkdate]; + foreach ($ids as $id) { + $l = $LINKSDB[$id]; $l['formatedDescription'] = format_description($l['description'], $conf->get('redirector.url')); $l['thumbnail'] = thumbnail($conf, $l['url']); - $l_date = DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, $l['linkdate']); - $l['timestamp'] = $l_date->getTimestamp(); + $l['timestamp'] = $l['created']->getTimestamp(); if (startsWith($l['url'], '?')) { $l['url'] = index_url($_SERVER) . $l['url']; // make permalink URL absolute } - $links[$linkdate] = $l; + $links[$id] = $l; } // Then build the HTML for this day: @@ -677,11 +675,11 @@ function showDaily($pageBuilder, $LINKSDB, $conf, $pluginManager) $taglist = explode(' ',$link['tags']); uasort($taglist, 'strcasecmp'); + $linksToDisplay[$key]['shorturl'] = smallHash($link['created']->format('Ymd_His')); $linksToDisplay[$key]['taglist']=$taglist; $linksToDisplay[$key]['formatedDescription'] = format_description($link['description'], $conf->get('redirector.url')); $linksToDisplay[$key]['thumbnail'] = thumbnail($conf, $link['url']); - $date = DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, $link['linkdate']); - $linksToDisplay[$key]['timestamp'] = $date->getTimestamp(); + $linksToDisplay[$key]['timestamp'] = $link['created']->getTimestamp(); } /* We need to spread the articles on 3 columns. @@ -831,7 +829,7 @@ function renderPage($conf, $pluginManager) // Get only links which have a thumbnail. foreach($links as $link) { - $permalink='?'.escape(smallHash($link['linkdate'])); + $permalink='?'.escape(smallHash($link['created']->format('Ymd_His'))); $thumb=lazyThumbnail($conf, $link['url'],$permalink); if ($thumb!='') // Only output links which have a thumbnail. { @@ -1245,13 +1243,28 @@ function renderPage($conf, $pluginManager) // -------- User clicked the "Save" button when editing a link: Save link to database. if (isset($_POST['save_edit'])) { - $linkdate = $_POST['lf_linkdate']; - $updated = isset($LINKSDB[$linkdate]) ? strval(date('Ymd_His')) : false; - // Go away! if (! tokenOk($_POST['token'])) { die('Wrong token.'); } + + // lf_id should only be present if the link exists. + $id = !empty($_POST['lf_id']) ? (int) escape($_POST['lf_id']) : $LINKSDB->getNextId(); + // Linkdate is kept here to: + // - use the same permalink for notes as they're displayed when creating them + // - let users hack creation date of their posts + // See: https://github.com/shaarli/Shaarli/wiki/Datastore-hacks#changing-the-timestamp-for-a-link + $linkdate = escape($_POST['lf_linkdate']); + if (isset($LINKSDB[$id])) { + // Edit + $created = DateTime::createFromFormat('Ymd_His', $linkdate); + $updated = new DateTime(); + } else { + // New link + $created = DateTime::createFromFormat('Ymd_His', $linkdate); + $updated = null; + } + // Remove multiple spaces. $tags = trim(preg_replace('/\s\s+/', ' ', $_POST['lf_tags'])); // Remove first '-' char in tags. @@ -1268,14 +1281,16 @@ function renderPage($conf, $pluginManager) } $link = array( + 'id' => $id, 'title' => trim($_POST['lf_title']), 'url' => $url, 'description' => $_POST['lf_description'], 'private' => (isset($_POST['lf_private']) ? 1 : 0), - 'linkdate' => $linkdate, + 'created' => $created, 'updated' => $updated, 'tags' => str_replace(',', ' ', $tags) ); + // If title is empty, use the URL as title. if ($link['title'] == '') { $link['title'] = $link['url']; @@ -1283,7 +1298,7 @@ function renderPage($conf, $pluginManager) $pluginManager->executeHooks('save_link', $link); - $LINKSDB[$linkdate] = $link; + $LINKSDB[$id] = $link; $LINKSDB->save($conf->get('resource.page_cache')); pubsubhub($conf); @@ -1296,7 +1311,7 @@ function renderPage($conf, $pluginManager) $returnurl = !empty($_POST['returnurl']) ? $_POST['returnurl'] : '?'; $location = generateLocation($returnurl, $_SERVER['HTTP_HOST'], array('addlink', 'post', 'edit_link')); // Scroll to the link which has been edited. - $location .= '#' . smallHash($_POST['lf_linkdate']); + $location .= '#' . smallHash($created->format('Ymd_His')); // After saving the link, redirect to the page the user was on. header('Location: '. $location); exit; @@ -1307,8 +1322,10 @@ function renderPage($conf, $pluginManager) { // If we are called from the bookmarklet, we must close the popup: if (isset($_GET['source']) && ($_GET['source']=='bookmarklet' || $_GET['source']=='firefoxsocialapi')) { echo ''; exit; } + $link = $LINKSDB[(int) escape($_POST['lf_id'])]; $returnurl = ( isset($_POST['returnurl']) ? $_POST['returnurl'] : '?' ); - $returnurl .= '#'.smallHash($_POST['lf_linkdate']); // Scroll to the link which has been edited. + // Scroll to the link which has been edited. + $returnurl .= '#'.smallHash($link['created']->format('Ymd_His')); $returnurl = generateLocation($returnurl, $_SERVER['HTTP_HOST'], array('addlink', 'post', 'edit_link')); header('Location: '.$returnurl); // After canceling, redirect to the page the user was on. exit; @@ -1318,14 +1335,17 @@ function renderPage($conf, $pluginManager) if (isset($_POST['delete_link'])) { if (!tokenOk($_POST['token'])) die('Wrong token.'); + // We do not need to ask for confirmation: // - confirmation is handled by JavaScript // - we are protected from XSRF by the token. - $linkdate=$_POST['lf_linkdate']; - $pluginManager->executeHooks('delete_link', $LINKSDB[$linkdate]); + // FIXME! We keep `lf_linkdate` for consistency before a proper API. To be removed. + $id = isset($_POST['lf_id']) ? (int) escape($_POST['lf_id']) : (int) escape($_POST['lf_linkdate']); - unset($LINKSDB[$linkdate]); + $pluginManager->executeHooks('delete_link', $LINKSDB[$id]); + + unset($LINKSDB[$id]); $LINKSDB->save('resource.page_cache'); // save to disk // If we are called from the bookmarklet, we must close the popup: @@ -1364,8 +1384,10 @@ function renderPage($conf, $pluginManager) // -------- User clicked the "EDIT" button on a link: Display link edit form. if (isset($_GET['edit_link'])) { - $link = $LINKSDB[$_GET['edit_link']]; // Read database + $id = (int) escape($_GET['edit_link']); + $link = $LINKSDB[$id]; // Read database if (!$link) { header('Location: ?'); exit; } // Link not found in database. + $link['linkdate'] = $link['created']->format('Ymd_His'); $data = array( 'link' => $link, 'link_is_new' => false, @@ -1389,7 +1411,7 @@ function renderPage($conf, $pluginManager) $link_is_new = false; // Check if URL is not already in database (in this case, we will edit the existing link) $link = $LINKSDB->getLinkFromUrl($url); - if (!$link) + if (! $link) { $link_is_new = true; $linkdate = strval(date('Ymd_His')); @@ -1430,6 +1452,8 @@ function renderPage($conf, $pluginManager) 'tags' => $tags, 'private' => $private ); + } else { + $link['linkdate'] = $link['created']->format('Ymd_His'); } $data = array( @@ -1635,18 +1659,16 @@ function buildLinkList($PAGE,$LINKSDB, $conf, $pluginManager) $link['description'] = format_description($link['description'], $conf->get('redirector.url')); $classLi = ($i % 2) != 0 ? '' : 'publicLinkHightLight'; $link['class'] = $link['private'] == 0 ? $classLi : 'private'; - $date = DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, $link['linkdate']); - $link['timestamp'] = $date->getTimestamp(); + $link['timestamp'] = $link['created']->getTimestamp(); if (! empty($link['updated'])) { - $date = DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, $link['updated']); - $link['updated_timestamp'] = $date->getTimestamp(); + $link['updated_timestamp'] = $link['updated']->getTimestamp(); } else { $link['updated_timestamp'] = ''; } $taglist = explode(' ', $link['tags']); uasort($taglist, 'strcasecmp'); $link['taglist'] = $taglist; - $link['shorturl'] = smallHash($link['linkdate']); + $link['shorturl'] = smallHash($link['created']->format('Ymd_His')); // Check for both signs of a note: starting with ? and 7 chars long. if ($link['url'][0] === '?' && strlen($link['url']) === 7) { diff --git a/plugins/isso/isso.php b/plugins/isso/isso.php index ffb7cfac..c44f3c09 100644 --- a/plugins/isso/isso.php +++ b/plugins/isso/isso.php @@ -41,9 +41,11 @@ function hook_isso_render_linklist($data, $conf) // Only display comments for permalinks. if (count($data['links']) == 1 && empty($data['search_tags']) && empty($data['search_term'])) { $link = reset($data['links']); - $isso_html = file_get_contents(PluginManager::$PLUGINS_PATH . '/isso/isso.html'); + $issoHtml = file_get_contents(PluginManager::$PLUGINS_PATH . '/isso/isso.html'); - $isso = sprintf($isso_html, $issoUrl, $issoUrl, $link['linkdate'], $link['linkdate']); + // FIXME! KO thread unique si même date + $linkDate = $link['created']->format('Ymd_His'); + $isso = sprintf($issoHtml, $issoUrl, $issoUrl, $linkDate, $linkDate); $data['plugin_end_zone'][] = $isso; // Hackish way to include this CSS file only when necessary. 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 @@ {$link=$value}
{if="!$hide_timestamps || isLoggedIn()"} {/if} {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 @@
+ {if="isset($link.id)"} + + {/if}





diff --git a/tpl/linklist.html b/tpl/linklist.html index ddfd729a..de9586c6 100644 --- a/tpl/linklist.html +++ b/tpl/linklist.html @@ -71,11 +71,11 @@ {if="isLoggedIn()"}
- +
- + - + {function="strftime('%c', $value.timestamp)"} {if="$value.updated_timestamp"}*{/if} -- cgit v1.2.3 From c3dfd8995921083ff7250c25d0b6ab1184b91aff Mon Sep 17 00:00:00 2001 From: ArthurHoaro Date: Mon, 28 Nov 2016 16:17:25 +0100 Subject: Unit Test for the new ID system --- tests/FeedBuilderTest.php | 31 +++-- tests/LinkDBTest.php | 39 +++++- tests/LinkFilterTest.php | 6 +- tests/NetscapeBookmarkUtils/BookmarkExportTest.php | 6 +- tests/NetscapeBookmarkUtils/BookmarkImportTest.php | 146 ++++++++++++++------- tests/Updater/UpdaterTest.php | 98 ++++++++++++++ tests/plugins/PluginIssoTest.php | 14 +- tests/utils/ReferenceLinkDB.php | 61 +++++++-- 8 files changed, 306 insertions(+), 95 deletions(-) diff --git a/tests/FeedBuilderTest.php b/tests/FeedBuilderTest.php index d7839402..ea1dde25 100644 --- a/tests/FeedBuilderTest.php +++ b/tests/FeedBuilderTest.php @@ -84,8 +84,9 @@ class FeedBuilderTest extends PHPUnit_Framework_TestCase $this->assertEquals(ReferenceLinkDB::$NB_LINKS_TOTAL, count($data['links'])); // Test first link (note link) - $link = array_shift($data['links']); - $this->assertEquals('20150310_114651', $link['linkdate']); + $link = reset($data['links']); + $this->assertEquals(41, $link['id']); + $this->assertEquals(DateTime::createFromFormat('Ymd_His', '20150310_114651'), $link['created']); $this->assertEquals('http://host.tld/?WDWyig', $link['guid']); $this->assertEquals('http://host.tld/?WDWyig', $link['url']); $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 $this->assertEquals('sTuff', $link['taglist'][0]); // Test URL with external link. - $this->assertEquals('https://static.fsf.org/nosvn/faif-2.0.pdf', $data['links']['20150310_114633']['url']); + $this->assertEquals('https://static.fsf.org/nosvn/faif-2.0.pdf', $data['links'][8]['url']); // Test multitags. - $this->assertEquals(5, count($data['links']['20141125_084734']['taglist'])); - $this->assertEquals('css', $data['links']['20141125_084734']['taglist'][0]); + $this->assertEquals(5, count($data['links'][6]['taglist'])); + $this->assertEquals('css', $data['links'][6]['taglist'][0]); // Test update date - $this->assertRegExp('/2016-08-03T09:30:33\+\d{2}:\d{2}/', $data['links']['20150310_114633']['up_iso_date']); + $this->assertRegExp('/2016-08-03T09:30:33\+\d{2}:\d{2}/', $data['links'][8]['up_iso_date']); } /** @@ -119,9 +120,9 @@ class FeedBuilderTest extends PHPUnit_Framework_TestCase $data = $feedBuilder->buildData(); $this->assertEquals(ReferenceLinkDB::$NB_LINKS_TOTAL, count($data['links'])); $this->assertRegExp('/2016-08-03T09:30:33\+\d{2}:\d{2}/', $data['last_update']); - $link = array_shift($data['links']); + $link = reset($data['links']); $this->assertRegExp('/2015-03-10T11:46:51\+\d{2}:\d{2}/', $link['pub_iso_date']); - $this->assertRegExp('/2016-08-03T09:30:33\+\d{2}:\d{2}/', $data['links']['20150310_114633']['up_iso_date']); + $this->assertRegExp('/2016-08-03T09:30:33\+\d{2}:\d{2}/', $data['links'][8]['up_iso_date']); } /** @@ -138,7 +139,8 @@ class FeedBuilderTest extends PHPUnit_Framework_TestCase $data = $feedBuilder->buildData(); $this->assertEquals(1, count($data['links'])); $link = array_shift($data['links']); - $this->assertEquals('20150310_114651', $link['linkdate']); + $this->assertEquals(41, $link['id']); + $this->assertEquals(DateTime::createFromFormat('Ymd_His', '20150310_114651'), $link['created']); } /** @@ -154,7 +156,8 @@ class FeedBuilderTest extends PHPUnit_Framework_TestCase $data = $feedBuilder->buildData(); $this->assertEquals(1, count($data['links'])); $link = array_shift($data['links']); - $this->assertEquals('20150310_114651', $link['linkdate']); + $this->assertEquals(41, $link['id']); + $this->assertEquals(DateTime::createFromFormat('Ymd_His', '20150310_114651'), $link['created']); } /** @@ -170,15 +173,17 @@ class FeedBuilderTest extends PHPUnit_Framework_TestCase $this->assertTrue($data['usepermalinks']); // First link is a permalink $link = array_shift($data['links']); - $this->assertEquals('20150310_114651', $link['linkdate']); + $this->assertEquals(41, $link['id']); + $this->assertEquals(DateTime::createFromFormat('Ymd_His', '20150310_114651'), $link['created']); $this->assertEquals('http://host.tld/?WDWyig', $link['guid']); $this->assertEquals('http://host.tld/?WDWyig', $link['url']); $this->assertContains('Direct link', $link['description']); $this->assertContains('http://host.tld/?WDWyig', $link['description']); // Second link is a direct link $link = array_shift($data['links']); - $this->assertEquals('20150310_114633', $link['linkdate']); - $this->assertEquals('http://host.tld/?kLHmZg', $link['guid']); + $this->assertEquals(8, $link['id']); + $this->assertEquals(DateTime::createFromFormat('Ymd_His', '20150310_114633'), $link['created']); + $this->assertEquals('http://host.tld/?RttfEw', $link['guid']); $this->assertEquals('https://static.fsf.org/nosvn/faif-2.0.pdf', $link['url']); $this->assertContains('Direct link', $link['description']); $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..bedc680e 100644 --- a/tests/LinkDBTest.php +++ b/tests/LinkDBTest.php @@ -186,14 +186,15 @@ class LinkDBTest extends PHPUnit_Framework_TestCase $dbSize = sizeof($testDB); $link = array( + 'id' => 42, 'title'=>'an additional link', 'url'=>'http://dum.my', 'description'=>'One more', 'private'=>0, - 'linkdate'=>'20150518_190000', + 'created'=> DateTime::createFromFormat('Ymd_His', '20150518_190000'), 'tags'=>'unit test' ); - $testDB[$link['linkdate']] = $link; + $testDB[$link['id']] = $link; $testDB->save('tests'); $testDB = new LinkDB(self::$testDatastore, true, false); @@ -238,12 +239,12 @@ class LinkDBTest extends PHPUnit_Framework_TestCase public function testDays() { $this->assertEquals( - array('20121206', '20130614', '20150310'), + array('20100310', '20121206', '20130614', '20150310'), self::$publicLinkDB->days() ); $this->assertEquals( - array('20121206', '20130614', '20141125', '20150310'), + array('20100310', '20121206', '20130614', '20141125', '20150310'), self::$privateLinkDB->days() ); } @@ -290,10 +291,11 @@ class LinkDBTest extends PHPUnit_Framework_TestCase 'stallman' => 1, 'free' => 1, '-exclude' => 1, + 'hashtag' => 2, // The DB contains a link with `sTuff` and another one with `stuff` tag. - // They need to be grouped with the first case found (`sTuff`). + // They need to be grouped with the first case found - order by date DESC: `sTuff`. 'sTuff' => 2, - 'hashtag' => 2, + 'ut' => 1, ), self::$publicLinkDB->allTags() ); @@ -321,6 +323,7 @@ class LinkDBTest extends PHPUnit_Framework_TestCase 'tag2' => 1, 'tag3' => 1, 'tag4' => 1, + 'ut' => 1, ), self::$privateLinkDB->allTags() ); @@ -411,6 +414,11 @@ class LinkDBTest extends PHPUnit_Framework_TestCase 1, count(self::$publicLinkDB->filterHash($request)) ); + $request = smallHash('20150310_114633' . 8); + $this->assertEquals( + 1, + count(self::$publicLinkDB->filterHash($request)) + ); } /** @@ -433,4 +441,23 @@ class LinkDBTest extends PHPUnit_Framework_TestCase { self::$publicLinkDB->filterHash(''); } + + /** + * Test reorder with asc/desc parameter. + */ + public function testReorderLinksDesc() + { + self::$publicLinkDB->reorder('ASC'); + $linkIdToTest = 42; + foreach (self::$publicLinkDB as $key => $value) { + $this->assertEquals($linkIdToTest, $key); + break; + } + self::$publicLinkDB->reorder('DESC'); + $linkIdToTest = 41; + foreach (self::$publicLinkDB as $key => $value) { + $this->assertEquals($linkIdToTest, $key); + break; + } + } } 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 $this->assertEquals( 'MediaGoblin', - $links['20130614_184135']['title'] + $links[7]['title'] ); } @@ -286,7 +286,7 @@ class LinkFilterTest extends PHPUnit_Framework_TestCase ); $this->assertEquals( - 6, + 7, count(self::$linkFilter->filter(LinkFilter::$FILTER_TEXT, '-revolution')) ); } @@ -346,7 +346,7 @@ class LinkFilterTest extends PHPUnit_Framework_TestCase ); $this->assertEquals( - 6, + 7, count(self::$linkFilter->filter(LinkFilter::$FILTER_TAG, '-free')) ); } 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 $links = NetscapeBookmarkUtils::filterAndFormat(self::$linkDb, 'all', false, ''); $this->assertEquals(self::$refDb->countLinks(), sizeof($links)); foreach ($links as $link) { - $date = DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, $link['linkdate']); + $date = $link['created']; $this->assertEquals( $date->getTimestamp(), $link['timestamp'] @@ -70,7 +70,7 @@ class BookmarkExportTest extends PHPUnit_Framework_TestCase $links = NetscapeBookmarkUtils::filterAndFormat(self::$linkDb, 'private', false, ''); $this->assertEquals(self::$refDb->countPrivateLinks(), sizeof($links)); foreach ($links as $link) { - $date = DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, $link['linkdate']); + $date = $link['created']; $this->assertEquals( $date->getTimestamp(), $link['timestamp'] @@ -90,7 +90,7 @@ class BookmarkExportTest extends PHPUnit_Framework_TestCase $links = NetscapeBookmarkUtils::filterAndFormat(self::$linkDb, 'public', false, ''); $this->assertEquals(self::$refDb->countPublicLinks(), sizeof($links)); foreach ($links as $link) { - $date = DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, $link['linkdate']); + $date = $link['created']; $this->assertEquals( $date->getTimestamp(), $link['timestamp'] diff --git a/tests/NetscapeBookmarkUtils/BookmarkImportTest.php b/tests/NetscapeBookmarkUtils/BookmarkImportTest.php index f0ad500f..96895b00 100644 --- a/tests/NetscapeBookmarkUtils/BookmarkImportTest.php +++ b/tests/NetscapeBookmarkUtils/BookmarkImportTest.php @@ -42,6 +42,18 @@ class BookmarkImportTest extends PHPUnit_Framework_TestCase */ protected $pagecache = 'tests'; + /** + * @var string Save the current timezone. + */ + protected static $defaultTimeZone; + + public static function setUpBeforeClass() + { + self::$defaultTimeZone = date_default_timezone_get(); + // Timezone without DST for test consistency + date_default_timezone_set('Africa/Nairobi'); + } + /** * Resets test data before each test */ @@ -55,6 +67,11 @@ class BookmarkImportTest extends PHPUnit_Framework_TestCase $this->linkDb = new LinkDB(self::$testDatastore, true, false); } + public static function tearDownAfterClass() + { + date_default_timezone_set(self::$defaultTimeZone); + } + /** * Attempt to import bookmarks from an empty file */ @@ -98,18 +115,19 @@ class BookmarkImportTest extends PHPUnit_Framework_TestCase $this->assertEquals( array( - 'linkdate' => '20160618_173944', + 'id' => 0, + 'created' => DateTime::createFromFormat('Ymd_His', '20160618_203944'), 'title' => 'Hg Init a Mercurial tutorial by Joel Spolsky', 'url' => 'http://hginit.com/', 'description' => '', 'private' => 0, - 'tags' => '' + 'tags' => '', + 'shorturl' => 'La37cg', ), $this->linkDb->getLinkFromUrl('http://hginit.com/') ); } - /** * Import bookmarks nested in a folder hierarchy */ @@ -126,89 +144,105 @@ class BookmarkImportTest extends PHPUnit_Framework_TestCase $this->assertEquals( array( - 'linkdate' => '20160225_205541', + 'id' => 0, + 'created' => DateTime::createFromFormat('Ymd_His', '20160225_235541'), 'title' => 'Nested 1', 'url' => 'http://nest.ed/1', 'description' => '', 'private' => 0, - 'tags' => 'tag1 tag2' + 'tags' => 'tag1 tag2', + 'shorturl' => 'KyDNKA', ), $this->linkDb->getLinkFromUrl('http://nest.ed/1') ); $this->assertEquals( array( - 'linkdate' => '20160225_205542', + 'id' => 1, + 'created' => DateTime::createFromFormat('Ymd_His', '20160225_235542'), 'title' => 'Nested 1-1', 'url' => 'http://nest.ed/1-1', 'description' => '', 'private' => 0, - 'tags' => 'folder1 tag1 tag2' + 'tags' => 'folder1 tag1 tag2', + 'shorturl' => 'T2LnXg', ), $this->linkDb->getLinkFromUrl('http://nest.ed/1-1') ); $this->assertEquals( array( - 'linkdate' => '20160225_205547', + 'id' => 2, + 'created' => DateTime::createFromFormat('Ymd_His', '20160225_235547'), 'title' => 'Nested 1-2', 'url' => 'http://nest.ed/1-2', 'description' => '', 'private' => 0, - 'tags' => 'folder1 tag3 tag4' + 'tags' => 'folder1 tag3 tag4', + 'shorturl' => '46SZxA', ), $this->linkDb->getLinkFromUrl('http://nest.ed/1-2') ); $this->assertEquals( array( - 'linkdate' => '20160202_172222', + 'id' => 3, + 'created' => DateTime::createFromFormat('Ymd_His', '20160202_202222'), 'title' => 'Nested 2-1', 'url' => 'http://nest.ed/2-1', 'description' => 'First link of the second section', 'private' => 1, - 'tags' => 'folder2' + 'tags' => 'folder2', + 'shorturl' => '4UHOSw', ), $this->linkDb->getLinkFromUrl('http://nest.ed/2-1') ); $this->assertEquals( array( - 'linkdate' => '20160119_200227', + 'id' => 4, + 'created' => DateTime::createFromFormat('Ymd_His', '20160119_230227'), 'title' => 'Nested 2-2', 'url' => 'http://nest.ed/2-2', 'description' => 'Second link of the second section', 'private' => 1, - 'tags' => 'folder2' + 'tags' => 'folder2', + 'shorturl' => 'yfzwbw', ), $this->linkDb->getLinkFromUrl('http://nest.ed/2-2') ); $this->assertEquals( array( - 'linkdate' => '20160202_172223', + 'id' => 5, + 'created' => DateTime::createFromFormat('Ymd_His', '20160202_202222'), 'title' => 'Nested 3-1', 'url' => 'http://nest.ed/3-1', 'description' => '', 'private' => 0, - 'tags' => 'folder3 folder3-1 tag3' + 'tags' => 'folder3 folder3-1 tag3', + 'shorturl' => 'UwxIUQ', ), $this->linkDb->getLinkFromUrl('http://nest.ed/3-1') ); $this->assertEquals( array( - 'linkdate' => '20160119_200228', + 'id' => 6, + 'created' => DateTime::createFromFormat('Ymd_His', '20160119_230227'), 'title' => 'Nested 3-2', 'url' => 'http://nest.ed/3-2', 'description' => '', 'private' => 0, - 'tags' => 'folder3 folder3-1' + 'tags' => 'folder3 folder3-1', + 'shorturl' => 'p8dyZg', ), $this->linkDb->getLinkFromUrl('http://nest.ed/3-2') ); $this->assertEquals( array( - 'linkdate' => '20160229_081541', + 'id' => 7, + 'created' => DateTime::createFromFormat('Ymd_His', '20160229_111541'), 'title' => 'Nested 2', 'url' => 'http://nest.ed/2', 'description' => '', 'private' => 0, - 'tags' => 'tag4' + 'tags' => 'tag4', + 'shorturl' => 'Gt3Uug', ), $this->linkDb->getLinkFromUrl('http://nest.ed/2') ); @@ -227,28 +261,34 @@ class BookmarkImportTest extends PHPUnit_Framework_TestCase .' 2 links imported, 0 links overwritten, 0 links skipped.', NetscapeBookmarkUtils::import(array(), $files, $this->linkDb, $this->pagecache) ); + $this->assertEquals(2, count($this->linkDb)); $this->assertEquals(1, count_private($this->linkDb)); $this->assertEquals( array( - 'linkdate' => '20001010_105536', + 'id' => 0, + // Old link - UTC+4 (note that TZ in the import file is ignored). + 'created' => DateTime::createFromFormat('Ymd_His', '20001010_135536'), 'title' => 'Secret stuff', 'url' => 'https://private.tld', 'description' => "Super-secret stuff you're not supposed to know about", 'private' => 1, - 'tags' => 'private secret' + 'tags' => 'private secret', + 'shorturl' => 'EokDtA', ), $this->linkDb->getLinkFromUrl('https://private.tld') ); $this->assertEquals( array( - 'linkdate' => '20160225_205548', + 'id' => 1, + 'created' => DateTime::createFromFormat('Ymd_His', '20160225_235548'), 'title' => 'Public stuff', 'url' => 'http://public.tld', 'description' => '', 'private' => 0, - 'tags' => 'public hello world' + 'tags' => 'public hello world', + 'shorturl' => 'Er9ddA', ), $this->linkDb->getLinkFromUrl('http://public.tld') ); @@ -271,23 +311,28 @@ class BookmarkImportTest extends PHPUnit_Framework_TestCase $this->assertEquals( array( - 'linkdate' => '20001010_105536', + 'id' => 0, + // Note that TZ in the import file is ignored. + 'created' => DateTime::createFromFormat('Ymd_His', '20001010_135536'), 'title' => 'Secret stuff', 'url' => 'https://private.tld', 'description' => "Super-secret stuff you're not supposed to know about", 'private' => 1, - 'tags' => 'private secret' + 'tags' => 'private secret', + 'shorturl' => 'EokDtA', ), $this->linkDb->getLinkFromUrl('https://private.tld') ); $this->assertEquals( array( - 'linkdate' => '20160225_205548', + 'id' => 1, + 'created' => DateTime::createFromFormat('Ymd_His', '20160225_235548'), 'title' => 'Public stuff', 'url' => 'http://public.tld', 'description' => '', 'private' => 0, - 'tags' => 'public hello world' + 'tags' => 'public hello world', + 'shorturl' => 'Er9ddA', ), $this->linkDb->getLinkFromUrl('http://public.tld') ); @@ -309,11 +354,11 @@ class BookmarkImportTest extends PHPUnit_Framework_TestCase $this->assertEquals(0, count_private($this->linkDb)); $this->assertEquals( 0, - $this->linkDb['20001010_105536']['private'] + $this->linkDb[0]['private'] ); $this->assertEquals( 0, - $this->linkDb['20160225_205548']['private'] + $this->linkDb[1]['private'] ); } @@ -333,11 +378,11 @@ class BookmarkImportTest extends PHPUnit_Framework_TestCase $this->assertEquals(2, count_private($this->linkDb)); $this->assertEquals( 1, - $this->linkDb['20001010_105536']['private'] + $this->linkDb['0']['private'] ); $this->assertEquals( 1, - $this->linkDb['20160225_205548']['private'] + $this->linkDb['1']['private'] ); } @@ -359,13 +404,12 @@ class BookmarkImportTest extends PHPUnit_Framework_TestCase $this->assertEquals(2, count_private($this->linkDb)); $this->assertEquals( 1, - $this->linkDb['20001010_105536']['private'] + $this->linkDb[0]['private'] ); $this->assertEquals( 1, - $this->linkDb['20160225_205548']['private'] + $this->linkDb[1]['private'] ); - // re-import as public, enable overwriting $post = array( 'privacy' => 'public', @@ -380,11 +424,11 @@ class BookmarkImportTest extends PHPUnit_Framework_TestCase $this->assertEquals(0, count_private($this->linkDb)); $this->assertEquals( 0, - $this->linkDb['20001010_105536']['private'] + $this->linkDb[0]['private'] ); $this->assertEquals( 0, - $this->linkDb['20160225_205548']['private'] + $this->linkDb[1]['private'] ); } @@ -406,11 +450,11 @@ class BookmarkImportTest extends PHPUnit_Framework_TestCase $this->assertEquals(0, count_private($this->linkDb)); $this->assertEquals( 0, - $this->linkDb['20001010_105536']['private'] + $this->linkDb['0']['private'] ); $this->assertEquals( 0, - $this->linkDb['20160225_205548']['private'] + $this->linkDb['1']['private'] ); // re-import as private, enable overwriting @@ -427,11 +471,11 @@ class BookmarkImportTest extends PHPUnit_Framework_TestCase $this->assertEquals(2, count_private($this->linkDb)); $this->assertEquals( 1, - $this->linkDb['20001010_105536']['private'] + $this->linkDb['0']['private'] ); $this->assertEquals( 1, - $this->linkDb['20160225_205548']['private'] + $this->linkDb['1']['private'] ); } @@ -480,11 +524,11 @@ class BookmarkImportTest extends PHPUnit_Framework_TestCase $this->assertEquals(0, count_private($this->linkDb)); $this->assertEquals( 'tag1 tag2 tag3 private secret', - $this->linkDb['20001010_105536']['tags'] + $this->linkDb['0']['tags'] ); $this->assertEquals( 'tag1 tag2 tag3 public hello world', - $this->linkDb['20160225_205548']['tags'] + $this->linkDb['1']['tags'] ); } @@ -507,16 +551,16 @@ class BookmarkImportTest extends PHPUnit_Framework_TestCase $this->assertEquals(0, count_private($this->linkDb)); $this->assertEquals( 'tag1& tag2 "tag3" private secret', - $this->linkDb['20001010_105536']['tags'] + $this->linkDb['0']['tags'] ); $this->assertEquals( 'tag1& tag2 "tag3" public hello world', - $this->linkDb['20160225_205548']['tags'] + $this->linkDb['1']['tags'] ); } /** - * Ensure each imported bookmark has a unique linkdate + * Ensure each imported bookmark has a unique id * * See https://github.com/shaarli/Shaarli/issues/351 */ @@ -531,16 +575,16 @@ class BookmarkImportTest extends PHPUnit_Framework_TestCase $this->assertEquals(3, count($this->linkDb)); $this->assertEquals(0, count_private($this->linkDb)); $this->assertEquals( - '20160225_205548', - $this->linkDb['20160225_205548']['linkdate'] + 0, + $this->linkDb[0]['id'] ); $this->assertEquals( - '20160225_205549', - $this->linkDb['20160225_205549']['linkdate'] + 1, + $this->linkDb[1]['id'] ); $this->assertEquals( - '20160225_205550', - $this->linkDb['20160225_205550']['linkdate'] + 2, + $this->linkDb[2]['id'] ); } } diff --git a/tests/Updater/UpdaterTest.php b/tests/Updater/UpdaterTest.php index 0d0ad922..b8a050b0 100644 --- a/tests/Updater/UpdaterTest.php +++ b/tests/Updater/UpdaterTest.php @@ -214,6 +214,7 @@ $GLOBALS[\'privateLinkByDefault\'] = true;'; $refDB = new ReferenceLinkDB(); $refDB->write(self::$testDatastore); $linkDB = new LinkDB(self::$testDatastore, true, false); + $this->assertEmpty($linkDB->filterSearch(array('searchtags' => 'exclude'))); $updater = new Updater(array(), $linkDB, $this->conf, true); $updater->updateMethodRenameDashTags(); @@ -287,4 +288,101 @@ $GLOBALS[\'privateLinkByDefault\'] = true;'; $this->assertEquals(escape($redirectorUrl), $this->conf->get('redirector.url')); unlink($sandbox .'.json.php'); } + + /** + * Test updateMethodDatastoreIds(). + */ + public function testDatastoreIds() + { + $links = array( + '20121206_182539' => array( + 'linkdate' => '20121206_182539', + 'title' => 'Geek and Poke', + 'url' => 'http://geek-and-poke.com/', + 'description' => 'desc', + 'tags' => 'dev cartoon tag1 tag2 tag3 tag4 ', + 'updated' => '20121206_190301', + 'private' => false, + ), + '20121206_172539' => array( + 'linkdate' => '20121206_172539', + 'title' => 'UserFriendly - Samba', + 'url' => 'http://ars.userfriendly.org/cartoons/?id=20010306', + 'description' => '', + 'tags' => 'samba cartoon web', + 'private' => false, + ), + '20121206_142300' => array( + 'linkdate' => '20121206_142300', + 'title' => 'UserFriendly - Web Designer', + 'url' => 'http://ars.userfriendly.org/cartoons/?id=20121206', + 'description' => 'Naming conventions... #private', + 'tags' => 'samba cartoon web', + 'private' => true, + ), + ); + $refDB = new ReferenceLinkDB(); + $refDB->setLinks($links); + $refDB->write(self::$testDatastore); + $linkDB = new LinkDB(self::$testDatastore, true, false); + + $checksum = hash_file('sha1', self::$testDatastore); + + $this->conf->set('resource.data_dir', 'sandbox'); + $this->conf->set('resource.datastore', self::$testDatastore); + + $updater = new Updater(array(), $linkDB, $this->conf, true); + $this->assertTrue($updater->updateMethodDatastoreIds()); + + $linkDB = new LinkDB(self::$testDatastore, true, false); + + $backup = glob($this->conf->get('resource.data_dir') . '/datastore.'. date('YmdH') .'*.php'); + $backup = $backup[0]; + + $this->assertFileExists($backup); + $this->assertEquals($checksum, hash_file('sha1', $backup)); + unlink($backup); + + $this->assertEquals(3, count($linkDB)); + $this->assertTrue(isset($linkDB[0])); + $this->assertFalse(isset($linkDB[0]['linkdate'])); + $this->assertEquals(0, $linkDB[0]['id']); + $this->assertEquals('UserFriendly - Web Designer', $linkDB[0]['title']); + $this->assertEquals('http://ars.userfriendly.org/cartoons/?id=20121206', $linkDB[0]['url']); + $this->assertEquals('Naming conventions... #private', $linkDB[0]['description']); + $this->assertEquals('samba cartoon web', $linkDB[0]['tags']); + $this->assertTrue($linkDB[0]['private']); + $this->assertEquals(DateTime::createFromFormat('Ymd_His', '20121206_142300'), $linkDB[0]['created']); + + $this->assertTrue(isset($linkDB[1])); + $this->assertFalse(isset($linkDB[1]['linkdate'])); + $this->assertEquals(1, $linkDB[1]['id']); + $this->assertEquals('UserFriendly - Samba', $linkDB[1]['title']); + $this->assertEquals(DateTime::createFromFormat('Ymd_His', '20121206_172539'), $linkDB[1]['created']); + + $this->assertTrue(isset($linkDB[2])); + $this->assertFalse(isset($linkDB[2]['linkdate'])); + $this->assertEquals(2, $linkDB[2]['id']); + $this->assertEquals('Geek and Poke', $linkDB[2]['title']); + $this->assertEquals(DateTime::createFromFormat('Ymd_His', '20121206_182539'), $linkDB[2]['created']); + $this->assertEquals(DateTime::createFromFormat('Ymd_His', '20121206_190301'), $linkDB[2]['updated']); + } + + /** + * Test updateMethodDatastoreIds() with the update already applied: nothing to do. + */ + public function testDatastoreIdsNothingToDo() + { + $refDB = new ReferenceLinkDB(); + $refDB->write(self::$testDatastore); + $linkDB = new LinkDB(self::$testDatastore, true, false); + + $this->conf->set('resource.data_dir', 'sandbox'); + $this->conf->set('resource.datastore', self::$testDatastore); + + $checksum = hash_file('sha1', self::$testDatastore); + $updater = new Updater(array(), $linkDB, $this->conf, true); + $this->assertTrue($updater->updateMethodDatastoreIds()); + $this->assertEquals($checksum, hash_file('sha1', self::$testDatastore)); + } } diff --git a/tests/plugins/PluginIssoTest.php b/tests/plugins/PluginIssoTest.php index 1f545c7d..ea86a05c 100644 --- a/tests/plugins/PluginIssoTest.php +++ b/tests/plugins/PluginIssoTest.php @@ -47,12 +47,13 @@ class PluginIssoTest extends PHPUnit_Framework_TestCase $conf->set('plugins.ISSO_SERVER', 'value'); $str = 'http://randomstr.com/test'; + $date = '20161118_100001'; $data = array( 'title' => $str, 'links' => array( array( 'url' => $str, - 'linkdate' => 'abc', + 'created' => DateTime::createFromFormat('Ymd_His', $date), ) ) ); @@ -65,7 +66,7 @@ class PluginIssoTest extends PHPUnit_Framework_TestCase // plugin data $this->assertEquals(1, count($data['plugin_end_zone'])); - $this->assertNotFalse(strpos($data['plugin_end_zone'][0], 'abc')); + $this->assertNotFalse(strpos($data['plugin_end_zone'][0], $date)); $this->assertNotFalse(strpos($data['plugin_end_zone'][0], 'embed.min.js')); } @@ -78,16 +79,18 @@ class PluginIssoTest extends PHPUnit_Framework_TestCase $conf->set('plugins.ISSO_SERVER', 'value'); $str = 'http://randomstr.com/test'; + $date1 = '20161118_100001'; + $date2 = '20161118_100002'; $data = array( 'title' => $str, 'links' => array( array( 'url' => $str, - 'linkdate' => 'abc', + 'created' => DateTime::createFromFormat('Ymd_His', $date1), ), array( 'url' => $str . '2', - 'linkdate' => 'abc2', + 'created' => DateTime::createFromFormat('Ymd_His', $date2), ), ) ); @@ -106,12 +109,13 @@ class PluginIssoTest extends PHPUnit_Framework_TestCase $conf->set('plugins.ISSO_SERVER', 'value'); $str = 'http://randomstr.com/test'; + $date = '20161118_100001'; $data = array( 'title' => $str, 'links' => array( array( 'url' => $str, - 'linkdate' => 'abc', + 'created' => DateTime::createFromFormat('Ymd_His', $date), ) ), 'search_term' => $str diff --git a/tests/utils/ReferenceLinkDB.php b/tests/utils/ReferenceLinkDB.php index abca4656..6b16c9e8 100644 --- a/tests/utils/ReferenceLinkDB.php +++ b/tests/utils/ReferenceLinkDB.php @@ -4,7 +4,7 @@ */ class ReferenceLinkDB { - public static $NB_LINKS_TOTAL = 7; + public static $NB_LINKS_TOTAL = 8; private $_links = array(); private $_publicCount = 0; @@ -16,66 +16,87 @@ class ReferenceLinkDB public function __construct() { $this->addLink( + 41, 'Link title: @website', '?WDWyig', 'Stallman has a beard and is part of the Free Software Foundation (or not). Seriously, read this. #hashtag', 0, - '20150310_114651', - 'sTuff' + DateTime::createFromFormat('Ymd_His', '20150310_114651'), + 'sTuff', + null, + 'WDWyig' ); $this->addLink( + 42, + 'Note: I have a big ID but an old date', + '?WDWyig', + 'Used to test links reordering.', + 0, + DateTime::createFromFormat('Ymd_His', '20100310_101010'), + 'ut' + ); + + $this->addLink( + 8, 'Free as in Freedom 2.0 @website', 'https://static.fsf.org/nosvn/faif-2.0.pdf', 'Richard Stallman and the Free Software Revolution. Read this. #hashtag', 0, - '20150310_114633', + DateTime::createFromFormat('Ymd_His', '20150310_114633'), 'free gnu software stallman -exclude stuff hashtag', - '20160803_093033' + DateTime::createFromFormat('Ymd_His', '20160803_093033') ); $this->addLink( + 7, 'MediaGoblin', 'http://mediagoblin.org/', 'A free software media publishing platform #hashtagOther', 0, - '20130614_184135', - 'gnu media web .hidden hashtag' + DateTime::createFromFormat('Ymd_His', '20130614_184135'), + 'gnu media web .hidden hashtag', + null, + 'IuWvgA' ); $this->addLink( + 6, 'w3c-markup-validator', 'https://dvcs.w3.org/hg/markup-validator/summary', 'Mercurial repository for the W3C Validator #private', 1, - '20141125_084734', + DateTime::createFromFormat('Ymd_His', '20141125_084734'), 'css html w3c web Mercurial' ); $this->addLink( + 4, 'UserFriendly - Web Designer', 'http://ars.userfriendly.org/cartoons/?id=20121206', 'Naming conventions... #private', 0, - '20121206_142300', + DateTime::createFromFormat('Ymd_His', '20121206_142300'), 'dev cartoon web' ); $this->addLink( + 1, 'UserFriendly - Samba', 'http://ars.userfriendly.org/cartoons/?id=20010306', 'Tropical printing', 0, - '20121206_172539', + DateTime::createFromFormat('Ymd_His', '20121206_172539'), 'samba cartoon web' ); $this->addLink( + 0, 'Geek and Poke', 'http://geek-and-poke.com/', '', 1, - '20121206_182539', + DateTime::createFromFormat('Ymd_His', '20121206_182539'), 'dev cartoon tag1 tag2 tag3 tag4 ' ); } @@ -83,18 +104,20 @@ class ReferenceLinkDB /** * Adds a new link */ - protected function addLink($title, $url, $description, $private, $date, $tags, $updated = '') + protected function addLink($id, $title, $url, $description, $private, $date, $tags, $updated = '', $shorturl = '') { $link = array( + 'id' => $id, 'title' => $title, 'url' => $url, 'description' => $description, 'private' => $private, - 'linkdate' => $date, 'tags' => $tags, + 'created' => $date, 'updated' => $updated, + 'shorturl' => $shorturl ? $shorturl : smallHash($date->format('Ymd_His') . $id), ); - $this->_links[$date] = $link; + $this->_links[$id] = $link; if ($private) { $this->_privateCount++; @@ -142,4 +165,14 @@ class ReferenceLinkDB { return $this->_links; } + + /** + * Setter to override link creation. + * + * @param array $links List of links. + */ + public function setLinks($links) + { + $this->_links = $links; + } } -- cgit v1.2.3 From d592daea8343bb4dfecff5d97e93699581ccc58c Mon Sep 17 00:00:00 2001 From: ArthurHoaro Date: Mon, 28 Nov 2016 18:24:15 +0100 Subject: Add a persistent 'shorturl' key to all links All existing link will keep their permalinks. New links will have smallhash generated with date+id. The purpose of this is to avoid collision between links due to their creation date. --- application/FeedBuilder.php | 2 +- application/LinkDB.php | 12 +++-- application/LinkFilter.php | 2 +- application/LinkUtils.php | 13 +++++ application/NetscapeBookmarkUtils.php | 1 + application/Updater.php | 3 ++ application/Utils.php | 6 ++- index.php | 56 +++++++++------------- plugins/isso/isso.php | 4 +- tests/FeedBuilderTest.php | 10 ++-- tests/LinkDBTest.php | 22 ++++----- tests/NetscapeBookmarkUtils/BookmarkImportTest.php | 26 +++++----- tests/Updater/UpdaterTest.php | 8 ++-- tests/plugins/PluginIssoTest.php | 21 ++++++-- tests/utils/ReferenceLinkDB.php | 20 ++++---- 15 files changed, 115 insertions(+), 91 deletions(-) diff --git a/application/FeedBuilder.php b/application/FeedBuilder.php index bfdf2fd3..fedd90e6 100644 --- a/application/FeedBuilder.php +++ b/application/FeedBuilder.php @@ -143,7 +143,7 @@ class FeedBuilder */ protected function buildItem($link, $pageaddr) { - $link['guid'] = $pageaddr .'?'. smallHash($link['created']->format('Ymd_His')); + $link['guid'] = $pageaddr .'?'. $link['shorturl']; // Check for both signs of a note: starting with ? and 7 chars long. if ($link['url'][0] === '?' && strlen($link['url']) === 7) { $link['url'] = $pageaddr . $link['url']; diff --git a/application/LinkDB.php b/application/LinkDB.php index e429ab4f..1e13286a 100644 --- a/application/LinkDB.php +++ b/application/LinkDB.php @@ -22,6 +22,7 @@ * Can be absolute or relative. * Relative URLs are permalinks (e.g.'?m-ukcw') * - real_url Absolute processed URL. + * - shorturl Permalink smallhash * * Implements 3 interfaces: * - ArrayAccess: behaves like an associative array; @@ -264,6 +265,7 @@ You use the community supported version of the original Shaarli project, by Seba 'created'=> new DateTime(), 'tags'=>'opensource software' ); + $link['shorturl'] = link_small_hash($link['created'], $link['id']); $this->links[1] = $link; $link = array( @@ -273,8 +275,9 @@ You use the community supported version of the original Shaarli project, by Seba 'description'=>'Shhhh! I\'m a private link only YOU can see. You can delete me too.', 'private'=>1, 'created'=> new DateTime('1 minute ago'), - 'tags'=>'secretstuff' + 'tags'=>'secretstuff', ); + $link['shorturl'] = link_small_hash($link['created'], $link['id']); $this->links[0] = $link; // Write database to disk @@ -335,10 +338,11 @@ You use the community supported version of the original Shaarli project, by Seba // To be able to load links before running the update, and prepare the update if (! isset($link['created'])) { $link['id'] = $link['linkdate']; - $link['created'] = DateTime::createFromFormat('Ymd_His', $link['linkdate']); + $link['created'] = DateTime::createFromFormat(self::LINK_DATE_FORMAT, $link['linkdate']); if (! empty($link['updated'])) { - $link['updated'] = DateTime::createFromFormat('Ymd_His', $link['updated']); + $link['updated'] = DateTime::createFromFormat(self::LINK_DATE_FORMAT, $link['updated']); } + $link['shorturl'] = smallHash($link['linkdate']); } } @@ -558,7 +562,7 @@ You use the community supported version of the original Shaarli project, by Seba * * @param int $id Persistent ID of a link. * - * @return int Real offset in local array, or null if doesn't exists. + * @return int Real offset in local array, or null if doesn't exist. */ protected function getLinkOffset($id) { diff --git a/application/LinkFilter.php b/application/LinkFilter.php index 7bab46ba..daa6d9cc 100644 --- a/application/LinkFilter.php +++ b/application/LinkFilter.php @@ -120,7 +120,7 @@ class LinkFilter { $filtered = array(); foreach ($this->links as $key => $l) { - if ($smallHash == smallHash($l['created']->format('Ymd_His'))) { + if ($smallHash == $l['shorturl']) { // Yes, this is ugly and slow $filtered[$key] = $l; return $filtered; 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) function format_description($description, $redirector = '', $indexUrl = '') { return nl2br(space2nbsp(hashtag_autolink(text2clickable($description, $redirector), $indexUrl))); } + +/** + * Generate a small hash for a link. + * + * @param DateTime $date Link creation date. + * @param int $id Link ID. + * + * @return string the small hash generated from link data. + */ +function link_small_hash($date, $id) +{ + return smallHash($date->format(LinkDB::LINK_DATE_FORMAT) . $id); +} diff --git a/application/NetscapeBookmarkUtils.php b/application/NetscapeBookmarkUtils.php index 8a939adb..e7148d00 100644 --- a/application/NetscapeBookmarkUtils.php +++ b/application/NetscapeBookmarkUtils.php @@ -174,6 +174,7 @@ class NetscapeBookmarkUtils $newLinkDate->setTimezone(new DateTimeZone(date_default_timezone_get())); $newLink['created'] = $newLinkDate; $newLink['id'] = $linkDb->getNextId(); + $newLink['shorturl'] = link_small_hash($newLink['created'], $newLink['id']); $linkDb[$newLink['id']] = $newLink; $importCount++; } diff --git a/application/Updater.php b/application/Updater.php index 16c8c376..f0d02814 100644 --- a/application/Updater.php +++ b/application/Updater.php @@ -223,6 +223,9 @@ class Updater * Since this update is very sensitve (changing the whole database), the datastore will be * automatically backed up into the file datastore..php. * + * LinkDB also adds the field 'shorturl' with the precedent format (linkdate smallhash), + * which will be saved by this method. + * * @return bool true if the update is successful, false otherwise. */ public function updateMethodDatastoreIds() 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) * - are NOT cryptographically secure (they CAN be forged) * * In Shaarli, they are used as a tinyurl-like link to individual entries, - * e.g. smallHash('20111006_131924') --> yZH23w + * built once with the combination of the date and item ID. + * e.g. smallHash('20111006_131924' . 142) --> eaWxtQ + * + * @warning before v0.8.1, smallhashes were built only with the date, + * and their value has been preserved. * * @param string $text Create a hash from this text. * diff --git a/index.php b/index.php index 05f06452..fdbdfaa2 100644 --- a/index.php +++ b/index.php @@ -566,21 +566,17 @@ function showDailyRSS($conf) { /* Some Shaarlies may have very few links, so we need to look back in time until we have enough days ($nb_of_days). */ - $ids = array(); - foreach ($LINKSDB as $id => $value) { - $ids[] = $id; - } $nb_of_days = 7; // We take 7 days. $today = date('Ymd'); $days = array(); - foreach ($ids as $id) { - $day = $LINKSDB[$id]['created']->format('Ymd'); // Extract day (without time) + foreach ($LINKSDB as $link) { + $day = $link['created']->format('Ymd'); // Extract day (without time) if (strcmp($day, $today) < 0) { if (empty($days[$day])) { $days[$day] = array(); } - $days[$day][] = $id; + $days[$day][] = $link; } if (count($days) > $nb_of_days) { @@ -600,23 +596,18 @@ function showDailyRSS($conf) { echo ''. $pageaddr .''. PHP_EOL; // For each day. - foreach ($days as $day => $ids) { + foreach ($days as $day => $links) { $dayDate = DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, $day.'_000000'); $absurl = escape(index_url($_SERVER).'?do=daily&day='.$day); // Absolute URL of the corresponding "Daily" page. - // Build the HTML body of this RSS entry. - $links = array(); - // We pre-format some fields for proper output. - foreach ($ids as $id) { - $l = $LINKSDB[$id]; - $l['formatedDescription'] = format_description($l['description'], $conf->get('redirector.url')); - $l['thumbnail'] = thumbnail($conf, $l['url']); - $l['timestamp'] = $l['created']->getTimestamp(); - if (startsWith($l['url'], '?')) { - $l['url'] = index_url($_SERVER) . $l['url']; // make permalink URL absolute + foreach ($links as &$link) { + $link['formatedDescription'] = format_description($link['description'], $conf->get('redirector.url')); + $link['thumbnail'] = thumbnail($conf, $link['url']); + $link['timestamp'] = $link['created']->getTimestamp(); + if (startsWith($link['url'], '?')) { + $link['url'] = index_url($_SERVER) . $link['url']; // make permalink URL absolute } - $links[$id] = $l; } // Then build the HTML for this day: @@ -675,7 +666,6 @@ function showDaily($pageBuilder, $LINKSDB, $conf, $pluginManager) $taglist = explode(' ',$link['tags']); uasort($taglist, 'strcasecmp'); - $linksToDisplay[$key]['shorturl'] = smallHash($link['created']->format('Ymd_His')); $linksToDisplay[$key]['taglist']=$taglist; $linksToDisplay[$key]['formatedDescription'] = format_description($link['description'], $conf->get('redirector.url')); $linksToDisplay[$key]['thumbnail'] = thumbnail($conf, $link['url']); @@ -829,7 +819,7 @@ function renderPage($conf, $pluginManager) // Get only links which have a thumbnail. foreach($links as $link) { - $permalink='?'.escape(smallHash($link['created']->format('Ymd_His'))); + $permalink='?'.$link['shorturl']; $thumb=lazyThumbnail($conf, $link['url'],$permalink); if ($thumb!='') // Only output links which have a thumbnail. { @@ -1249,7 +1239,7 @@ function renderPage($conf, $pluginManager) } // lf_id should only be present if the link exists. - $id = !empty($_POST['lf_id']) ? (int) escape($_POST['lf_id']) : $LINKSDB->getNextId(); + $id = !empty($_POST['lf_id']) ? intval(escape($_POST['lf_id'])) : $LINKSDB->getNextId(); // Linkdate is kept here to: // - use the same permalink for notes as they're displayed when creating them // - let users hack creation date of their posts @@ -1257,11 +1247,11 @@ function renderPage($conf, $pluginManager) $linkdate = escape($_POST['lf_linkdate']); if (isset($LINKSDB[$id])) { // Edit - $created = DateTime::createFromFormat('Ymd_His', $linkdate); + $created = DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, $linkdate); $updated = new DateTime(); } else { // New link - $created = DateTime::createFromFormat('Ymd_His', $linkdate); + $created = DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, $linkdate); $updated = null; } @@ -1288,7 +1278,8 @@ function renderPage($conf, $pluginManager) 'private' => (isset($_POST['lf_private']) ? 1 : 0), 'created' => $created, 'updated' => $updated, - 'tags' => str_replace(',', ' ', $tags) + 'tags' => str_replace(',', ' ', $tags), + 'shorturl' => link_small_hash($created, $id), ); // If title is empty, use the URL as title. @@ -1311,7 +1302,7 @@ function renderPage($conf, $pluginManager) $returnurl = !empty($_POST['returnurl']) ? $_POST['returnurl'] : '?'; $location = generateLocation($returnurl, $_SERVER['HTTP_HOST'], array('addlink', 'post', 'edit_link')); // Scroll to the link which has been edited. - $location .= '#' . smallHash($created->format('Ymd_His')); + $location .= '#' . $link['shorturl']; // After saving the link, redirect to the page the user was on. header('Location: '. $location); exit; @@ -1325,7 +1316,7 @@ function renderPage($conf, $pluginManager) $link = $LINKSDB[(int) escape($_POST['lf_id'])]; $returnurl = ( isset($_POST['returnurl']) ? $_POST['returnurl'] : '?' ); // Scroll to the link which has been edited. - $returnurl .= '#'.smallHash($link['created']->format('Ymd_His')); + $returnurl .= '#'. $link['shorturl']; $returnurl = generateLocation($returnurl, $_SERVER['HTTP_HOST'], array('addlink', 'post', 'edit_link')); header('Location: '.$returnurl); // After canceling, redirect to the page the user was on. exit; @@ -1341,7 +1332,7 @@ function renderPage($conf, $pluginManager) // - we are protected from XSRF by the token. // FIXME! We keep `lf_linkdate` for consistency before a proper API. To be removed. - $id = isset($_POST['lf_id']) ? (int) escape($_POST['lf_id']) : (int) escape($_POST['lf_linkdate']); + $id = isset($_POST['lf_id']) ? intval(escape($_POST['lf_id'])) : intval(escape($_POST['lf_linkdate'])); $pluginManager->executeHooks('delete_link', $LINKSDB[$id]); @@ -1387,7 +1378,7 @@ function renderPage($conf, $pluginManager) $id = (int) escape($_GET['edit_link']); $link = $LINKSDB[$id]; // Read database if (!$link) { header('Location: ?'); exit; } // Link not found in database. - $link['linkdate'] = $link['created']->format('Ymd_His'); + $link['linkdate'] = $link['created']->format(LinkDB::LINK_DATE_FORMAT); $data = array( 'link' => $link, 'link_is_new' => false, @@ -1414,7 +1405,7 @@ function renderPage($conf, $pluginManager) if (! $link) { $link_is_new = true; - $linkdate = strval(date('Ymd_His')); + $linkdate = strval(date(LinkDB::LINK_DATE_FORMAT)); // Get title if it was provided in URL (by the bookmarklet). $title = empty($_GET['title']) ? '' : escape($_GET['title']); // Get description if it was provided in URL (by the bookmarklet). [Bronco added that] @@ -1438,7 +1429,7 @@ function renderPage($conf, $pluginManager) } if ($url == '') { - $url = '?' . smallHash($linkdate); + $url = '?' . smallHash($linkdate . $LINKSDB->getNextId()); $title = 'Note: '; } $url = escape($url); @@ -1453,7 +1444,7 @@ function renderPage($conf, $pluginManager) 'private' => $private ); } else { - $link['linkdate'] = $link['created']->format('Ymd_His'); + $link['linkdate'] = $link['created']->format(LinkDB::LINK_DATE_FORMAT); } $data = array( @@ -1668,7 +1659,6 @@ function buildLinkList($PAGE,$LINKSDB, $conf, $pluginManager) $taglist = explode(' ', $link['tags']); uasort($taglist, 'strcasecmp'); $link['taglist'] = $taglist; - $link['shorturl'] = smallHash($link['created']->format('Ymd_His')); // Check for both signs of a note: starting with ? and 7 chars long. if ($link['url'][0] === '?' && strlen($link['url']) === 7) { diff --git a/plugins/isso/isso.php b/plugins/isso/isso.php index c44f3c09..ce16645f 100644 --- a/plugins/isso/isso.php +++ b/plugins/isso/isso.php @@ -43,9 +43,7 @@ function hook_isso_render_linklist($data, $conf) $link = reset($data['links']); $issoHtml = file_get_contents(PluginManager::$PLUGINS_PATH . '/isso/isso.html'); - // FIXME! KO thread unique si même date - $linkDate = $link['created']->format('Ymd_His'); - $isso = sprintf($issoHtml, $issoUrl, $issoUrl, $linkDate, $linkDate); + $isso = sprintf($issoHtml, $issoUrl, $issoUrl, $link['id'], $link['id']); $data['plugin_end_zone'][] = $isso; // Hackish way to include this CSS file only when necessary. diff --git a/tests/FeedBuilderTest.php b/tests/FeedBuilderTest.php index ea1dde25..06a44506 100644 --- a/tests/FeedBuilderTest.php +++ b/tests/FeedBuilderTest.php @@ -86,7 +86,7 @@ class FeedBuilderTest extends PHPUnit_Framework_TestCase // Test first link (note link) $link = reset($data['links']); $this->assertEquals(41, $link['id']); - $this->assertEquals(DateTime::createFromFormat('Ymd_His', '20150310_114651'), $link['created']); + $this->assertEquals(DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, '20150310_114651'), $link['created']); $this->assertEquals('http://host.tld/?WDWyig', $link['guid']); $this->assertEquals('http://host.tld/?WDWyig', $link['url']); $this->assertRegExp('/Tue, 10 Mar 2015 11:46:51 \+\d{4}/', $link['pub_iso_date']); @@ -140,7 +140,7 @@ class FeedBuilderTest extends PHPUnit_Framework_TestCase $this->assertEquals(1, count($data['links'])); $link = array_shift($data['links']); $this->assertEquals(41, $link['id']); - $this->assertEquals(DateTime::createFromFormat('Ymd_His', '20150310_114651'), $link['created']); + $this->assertEquals(DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, '20150310_114651'), $link['created']); } /** @@ -157,7 +157,7 @@ class FeedBuilderTest extends PHPUnit_Framework_TestCase $this->assertEquals(1, count($data['links'])); $link = array_shift($data['links']); $this->assertEquals(41, $link['id']); - $this->assertEquals(DateTime::createFromFormat('Ymd_His', '20150310_114651'), $link['created']); + $this->assertEquals(DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, '20150310_114651'), $link['created']); } /** @@ -174,7 +174,7 @@ class FeedBuilderTest extends PHPUnit_Framework_TestCase // First link is a permalink $link = array_shift($data['links']); $this->assertEquals(41, $link['id']); - $this->assertEquals(DateTime::createFromFormat('Ymd_His', '20150310_114651'), $link['created']); + $this->assertEquals(DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, '20150310_114651'), $link['created']); $this->assertEquals('http://host.tld/?WDWyig', $link['guid']); $this->assertEquals('http://host.tld/?WDWyig', $link['url']); $this->assertContains('Direct link', $link['description']); @@ -182,7 +182,7 @@ class FeedBuilderTest extends PHPUnit_Framework_TestCase // Second link is a direct link $link = array_shift($data['links']); $this->assertEquals(8, $link['id']); - $this->assertEquals(DateTime::createFromFormat('Ymd_His', '20150310_114633'), $link['created']); + $this->assertEquals(DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, '20150310_114633'), $link['created']); $this->assertEquals('http://host.tld/?RttfEw', $link['guid']); $this->assertEquals('https://static.fsf.org/nosvn/faif-2.0.pdf', $link['url']); $this->assertContains('Direct link', $link['description']); diff --git a/tests/LinkDBTest.php b/tests/LinkDBTest.php index bedc680e..1f62a34a 100644 --- a/tests/LinkDBTest.php +++ b/tests/LinkDBTest.php @@ -191,7 +191,7 @@ class LinkDBTest extends PHPUnit_Framework_TestCase 'url'=>'http://dum.my', 'description'=>'One more', 'private'=>0, - 'created'=> DateTime::createFromFormat('Ymd_His', '20150518_190000'), + 'created'=> DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, '20150518_190000'), 'tags'=>'unit test' ); $testDB[$link['id']] = $link; @@ -447,17 +447,17 @@ class LinkDBTest extends PHPUnit_Framework_TestCase */ public function testReorderLinksDesc() { - self::$publicLinkDB->reorder('ASC'); - $linkIdToTest = 42; - foreach (self::$publicLinkDB as $key => $value) { - $this->assertEquals($linkIdToTest, $key); - break; + self::$privateLinkDB->reorder('ASC'); + $linkIds = array(42, 4, 1, 0, 7, 6, 8, 41); + $cpt = 0; + foreach (self::$privateLinkDB as $key => $value) { + $this->assertEquals($linkIds[$cpt++], $key); } - self::$publicLinkDB->reorder('DESC'); - $linkIdToTest = 41; - foreach (self::$publicLinkDB as $key => $value) { - $this->assertEquals($linkIdToTest, $key); - break; + self::$privateLinkDB->reorder('DESC'); + $linkIds = array_reverse($linkIds); + $cpt = 0; + foreach (self::$privateLinkDB as $key => $value) { + $this->assertEquals($linkIds[$cpt++], $key); } } } diff --git a/tests/NetscapeBookmarkUtils/BookmarkImportTest.php b/tests/NetscapeBookmarkUtils/BookmarkImportTest.php index 96895b00..0ca07eac 100644 --- a/tests/NetscapeBookmarkUtils/BookmarkImportTest.php +++ b/tests/NetscapeBookmarkUtils/BookmarkImportTest.php @@ -116,7 +116,7 @@ class BookmarkImportTest extends PHPUnit_Framework_TestCase $this->assertEquals( array( 'id' => 0, - 'created' => DateTime::createFromFormat('Ymd_His', '20160618_203944'), + 'created' => DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, '20160618_203944'), 'title' => 'Hg Init a Mercurial tutorial by Joel Spolsky', 'url' => 'http://hginit.com/', 'description' => '', @@ -145,7 +145,7 @@ class BookmarkImportTest extends PHPUnit_Framework_TestCase $this->assertEquals( array( 'id' => 0, - 'created' => DateTime::createFromFormat('Ymd_His', '20160225_235541'), + 'created' => DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, '20160225_235541'), 'title' => 'Nested 1', 'url' => 'http://nest.ed/1', 'description' => '', @@ -158,7 +158,7 @@ class BookmarkImportTest extends PHPUnit_Framework_TestCase $this->assertEquals( array( 'id' => 1, - 'created' => DateTime::createFromFormat('Ymd_His', '20160225_235542'), + 'created' => DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, '20160225_235542'), 'title' => 'Nested 1-1', 'url' => 'http://nest.ed/1-1', 'description' => '', @@ -171,7 +171,7 @@ class BookmarkImportTest extends PHPUnit_Framework_TestCase $this->assertEquals( array( 'id' => 2, - 'created' => DateTime::createFromFormat('Ymd_His', '20160225_235547'), + 'created' => DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, '20160225_235547'), 'title' => 'Nested 1-2', 'url' => 'http://nest.ed/1-2', 'description' => '', @@ -184,7 +184,7 @@ class BookmarkImportTest extends PHPUnit_Framework_TestCase $this->assertEquals( array( 'id' => 3, - 'created' => DateTime::createFromFormat('Ymd_His', '20160202_202222'), + 'created' => DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, '20160202_202222'), 'title' => 'Nested 2-1', 'url' => 'http://nest.ed/2-1', 'description' => 'First link of the second section', @@ -197,7 +197,7 @@ class BookmarkImportTest extends PHPUnit_Framework_TestCase $this->assertEquals( array( 'id' => 4, - 'created' => DateTime::createFromFormat('Ymd_His', '20160119_230227'), + 'created' => DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, '20160119_230227'), 'title' => 'Nested 2-2', 'url' => 'http://nest.ed/2-2', 'description' => 'Second link of the second section', @@ -210,7 +210,7 @@ class BookmarkImportTest extends PHPUnit_Framework_TestCase $this->assertEquals( array( 'id' => 5, - 'created' => DateTime::createFromFormat('Ymd_His', '20160202_202222'), + 'created' => DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, '20160202_202222'), 'title' => 'Nested 3-1', 'url' => 'http://nest.ed/3-1', 'description' => '', @@ -223,7 +223,7 @@ class BookmarkImportTest extends PHPUnit_Framework_TestCase $this->assertEquals( array( 'id' => 6, - 'created' => DateTime::createFromFormat('Ymd_His', '20160119_230227'), + 'created' => DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, '20160119_230227'), 'title' => 'Nested 3-2', 'url' => 'http://nest.ed/3-2', 'description' => '', @@ -236,7 +236,7 @@ class BookmarkImportTest extends PHPUnit_Framework_TestCase $this->assertEquals( array( 'id' => 7, - 'created' => DateTime::createFromFormat('Ymd_His', '20160229_111541'), + 'created' => DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, '20160229_111541'), 'title' => 'Nested 2', 'url' => 'http://nest.ed/2', 'description' => '', @@ -269,7 +269,7 @@ class BookmarkImportTest extends PHPUnit_Framework_TestCase array( 'id' => 0, // Old link - UTC+4 (note that TZ in the import file is ignored). - 'created' => DateTime::createFromFormat('Ymd_His', '20001010_135536'), + 'created' => DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, '20001010_135536'), 'title' => 'Secret stuff', 'url' => 'https://private.tld', 'description' => "Super-secret stuff you're not supposed to know about", @@ -282,7 +282,7 @@ class BookmarkImportTest extends PHPUnit_Framework_TestCase $this->assertEquals( array( 'id' => 1, - 'created' => DateTime::createFromFormat('Ymd_His', '20160225_235548'), + 'created' => DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, '20160225_235548'), 'title' => 'Public stuff', 'url' => 'http://public.tld', 'description' => '', @@ -313,7 +313,7 @@ class BookmarkImportTest extends PHPUnit_Framework_TestCase array( 'id' => 0, // Note that TZ in the import file is ignored. - 'created' => DateTime::createFromFormat('Ymd_His', '20001010_135536'), + 'created' => DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, '20001010_135536'), 'title' => 'Secret stuff', 'url' => 'https://private.tld', 'description' => "Super-secret stuff you're not supposed to know about", @@ -326,7 +326,7 @@ class BookmarkImportTest extends PHPUnit_Framework_TestCase $this->assertEquals( array( 'id' => 1, - 'created' => DateTime::createFromFormat('Ymd_His', '20160225_235548'), + 'created' => DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, '20160225_235548'), 'title' => 'Public stuff', 'url' => 'http://public.tld', 'description' => '', diff --git a/tests/Updater/UpdaterTest.php b/tests/Updater/UpdaterTest.php index b8a050b0..4948fe52 100644 --- a/tests/Updater/UpdaterTest.php +++ b/tests/Updater/UpdaterTest.php @@ -352,20 +352,20 @@ $GLOBALS[\'privateLinkByDefault\'] = true;'; $this->assertEquals('Naming conventions... #private', $linkDB[0]['description']); $this->assertEquals('samba cartoon web', $linkDB[0]['tags']); $this->assertTrue($linkDB[0]['private']); - $this->assertEquals(DateTime::createFromFormat('Ymd_His', '20121206_142300'), $linkDB[0]['created']); + $this->assertEquals(DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, '20121206_142300'), $linkDB[0]['created']); $this->assertTrue(isset($linkDB[1])); $this->assertFalse(isset($linkDB[1]['linkdate'])); $this->assertEquals(1, $linkDB[1]['id']); $this->assertEquals('UserFriendly - Samba', $linkDB[1]['title']); - $this->assertEquals(DateTime::createFromFormat('Ymd_His', '20121206_172539'), $linkDB[1]['created']); + $this->assertEquals(DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, '20121206_172539'), $linkDB[1]['created']); $this->assertTrue(isset($linkDB[2])); $this->assertFalse(isset($linkDB[2]['linkdate'])); $this->assertEquals(2, $linkDB[2]['id']); $this->assertEquals('Geek and Poke', $linkDB[2]['title']); - $this->assertEquals(DateTime::createFromFormat('Ymd_His', '20121206_182539'), $linkDB[2]['created']); - $this->assertEquals(DateTime::createFromFormat('Ymd_His', '20121206_190301'), $linkDB[2]['updated']); + $this->assertEquals(DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, '20121206_182539'), $linkDB[2]['created']); + $this->assertEquals(DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, '20121206_190301'), $linkDB[2]['updated']); } /** diff --git a/tests/plugins/PluginIssoTest.php b/tests/plugins/PluginIssoTest.php index ea86a05c..6b7904dd 100644 --- a/tests/plugins/PluginIssoTest.php +++ b/tests/plugins/PluginIssoTest.php @@ -52,8 +52,9 @@ class PluginIssoTest extends PHPUnit_Framework_TestCase 'title' => $str, 'links' => array( array( + 'id' => 12, 'url' => $str, - 'created' => DateTime::createFromFormat('Ymd_His', $date), + 'created' => DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, $date), ) ) ); @@ -66,7 +67,14 @@ class PluginIssoTest extends PHPUnit_Framework_TestCase // plugin data $this->assertEquals(1, count($data['plugin_end_zone'])); - $this->assertNotFalse(strpos($data['plugin_end_zone'][0], $date)); + $this->assertNotFalse(strpos( + $data['plugin_end_zone'][0], + 'data-isso-id="'. $data['links'][0]['id'] .'"' + )); + $this->assertNotFalse(strpos( + $data['plugin_end_zone'][0], + 'data-title="'. $data['links'][0]['id'] .'"' + )); $this->assertNotFalse(strpos($data['plugin_end_zone'][0], 'embed.min.js')); } @@ -85,12 +93,14 @@ class PluginIssoTest extends PHPUnit_Framework_TestCase 'title' => $str, 'links' => array( array( + 'id' => 12, 'url' => $str, - 'created' => DateTime::createFromFormat('Ymd_His', $date1), + 'created' => DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, $date1), ), array( + 'id' => 13, 'url' => $str . '2', - 'created' => DateTime::createFromFormat('Ymd_His', $date2), + 'created' => DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, $date2), ), ) ); @@ -114,8 +124,9 @@ class PluginIssoTest extends PHPUnit_Framework_TestCase 'title' => $str, 'links' => array( array( + 'id' => 12, 'url' => $str, - 'created' => DateTime::createFromFormat('Ymd_His', $date), + 'created' => DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, $date), ) ), 'search_term' => $str diff --git a/tests/utils/ReferenceLinkDB.php b/tests/utils/ReferenceLinkDB.php index 6b16c9e8..36d58c68 100644 --- a/tests/utils/ReferenceLinkDB.php +++ b/tests/utils/ReferenceLinkDB.php @@ -21,7 +21,7 @@ class ReferenceLinkDB '?WDWyig', 'Stallman has a beard and is part of the Free Software Foundation (or not). Seriously, read this. #hashtag', 0, - DateTime::createFromFormat('Ymd_His', '20150310_114651'), + DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, '20150310_114651'), 'sTuff', null, 'WDWyig' @@ -33,7 +33,7 @@ class ReferenceLinkDB '?WDWyig', 'Used to test links reordering.', 0, - DateTime::createFromFormat('Ymd_His', '20100310_101010'), + DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, '20100310_101010'), 'ut' ); @@ -43,9 +43,9 @@ class ReferenceLinkDB 'https://static.fsf.org/nosvn/faif-2.0.pdf', 'Richard Stallman and the Free Software Revolution. Read this. #hashtag', 0, - DateTime::createFromFormat('Ymd_His', '20150310_114633'), + DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, '20150310_114633'), 'free gnu software stallman -exclude stuff hashtag', - DateTime::createFromFormat('Ymd_His', '20160803_093033') + DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, '20160803_093033') ); $this->addLink( @@ -54,7 +54,7 @@ class ReferenceLinkDB 'http://mediagoblin.org/', 'A free software media publishing platform #hashtagOther', 0, - DateTime::createFromFormat('Ymd_His', '20130614_184135'), + DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, '20130614_184135'), 'gnu media web .hidden hashtag', null, 'IuWvgA' @@ -66,7 +66,7 @@ class ReferenceLinkDB 'https://dvcs.w3.org/hg/markup-validator/summary', 'Mercurial repository for the W3C Validator #private', 1, - DateTime::createFromFormat('Ymd_His', '20141125_084734'), + DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, '20141125_084734'), 'css html w3c web Mercurial' ); @@ -76,7 +76,7 @@ class ReferenceLinkDB 'http://ars.userfriendly.org/cartoons/?id=20121206', 'Naming conventions... #private', 0, - DateTime::createFromFormat('Ymd_His', '20121206_142300'), + DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, '20121206_142300'), 'dev cartoon web' ); @@ -86,7 +86,7 @@ class ReferenceLinkDB 'http://ars.userfriendly.org/cartoons/?id=20010306', 'Tropical printing', 0, - DateTime::createFromFormat('Ymd_His', '20121206_172539'), + DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, '20121206_172539'), 'samba cartoon web' ); @@ -96,7 +96,7 @@ class ReferenceLinkDB 'http://geek-and-poke.com/', '', 1, - DateTime::createFromFormat('Ymd_His', '20121206_182539'), + DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, '20121206_182539'), 'dev cartoon tag1 tag2 tag3 tag4 ' ); } @@ -115,7 +115,7 @@ class ReferenceLinkDB 'tags' => $tags, 'created' => $date, 'updated' => $updated, - 'shorturl' => $shorturl ? $shorturl : smallHash($date->format('Ymd_His') . $id), + 'shorturl' => $shorturl ? $shorturl : smallHash($date->format(LinkDB::LINK_DATE_FORMAT) . $id), ); $this->_links[$id] = $link; -- cgit v1.2.3