]> git.immae.eu Git - github/shaarli/Shaarli.git/commitdiff
Merge pull request #393 from ArthurHoaro/tools-js-indent
authorVirtualTam <virtualtam@flibidi.net>
Mon, 7 Dec 2015 20:48:57 +0000 (21:48 +0100)
committerVirtualTam <virtualtam@flibidi.net>
Mon, 7 Dec 2015 20:48:57 +0000 (21:48 +0100)
Minimal indent of tools.html

19 files changed:
.gitignore
Makefile
application/ApplicationUtils.php
application/LinkDB.php
application/Utils.php
index.php [changed mode: 0644->0755]
plugins/playvideos/README.md
plugins/qrcode/qrcode.php
shaarli_version.php
tests/ApplicationUtilsTest.php
tests/CacheTest.php
tests/CachedPageTest.php
tests/LinkDBTest.php
tests/UtilsTest.php
tests/plugins/PlugQrcodeTest.php
tpl/daily.html
tpl/linklist.html
tpl/page.footer.html
tpl/picwall.html

index b98c38b9bfd68374354842bf3a62cb941fc69743..75cd3a6b842a264e9b2423c8391a7ddaa090fc9a 100644 (file)
@@ -19,9 +19,8 @@ composer.lock
 # Ignore development and test resources
 coverage
 doxygen
-tests/datastore.php
-tests/dummycache/
+sandbox
 phpmd.html
 
 # Ignore user plugin configuration
-plugins/*/config.php
\ No newline at end of file
+plugins/*/config.php
index c560d8d16d60f7e023d06c4ec66eaa483b0631f9..a86f9aa8bbe8bdb0b160db7cea331ba605a3eeb0 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -110,6 +110,7 @@ test:
        @echo "-------"
        @echo "PHPUNIT"
        @echo "-------"
+       @mkdir -p sandbox
        @$(BIN)/phpunit tests
 
 ##
@@ -119,6 +120,7 @@ test:
 ### remove all unversioned files
 clean:
        @git clean -df
+       @rm -rf sandbox
 
 ### generate Doxygen documentation
 doxygen: clean
index b0e94e24429cedbbd1645773e8d5e5525b5d6ae7..274331e16f6fe21ac444f330b25c69a0d09e1fe5 100644 (file)
@@ -4,6 +4,110 @@
  */
 class ApplicationUtils
 {
+    private static $GIT_URL = 'https://raw.githubusercontent.com/shaarli/Shaarli';
+    private static $GIT_BRANCHES = array('master', 'stable');
+    private static $VERSION_FILE = 'shaarli_version.php';
+    private static $VERSION_START_TAG = '<?php /* ';
+    private static $VERSION_END_TAG = ' */ ?>';
+
+    /**
+     * Gets the latest version code from the Git repository
+     *
+     * The code is read from the raw content of the version file on the Git server.
+     *
+     * @return mixed the version code from the repository if available, else 'false'
+     */
+    public static function getLatestGitVersionCode($url, $timeout=2)
+    {
+        list($headers, $data) = get_http_url($url, $timeout);
+
+        if (strpos($headers[0], '200 OK') === false) {
+            error_log('Failed to retrieve ' . $url);
+            return false;
+        }
+
+        return str_replace(
+            array(self::$VERSION_START_TAG, self::$VERSION_END_TAG, PHP_EOL),
+            array('', '', ''),
+            $data
+        );
+    }
+
+    /**
+     * Checks if a new Shaarli version has been published on the Git repository
+     *
+     * Updates checks are run periodically, according to the following criteria:
+     * - the update checks are enabled (install, global config);
+     * - the user is logged in (or this is an open instance);
+     * - the last check is older than a given interval;
+     * - the check is non-blocking if the HTTPS connection to Git fails;
+     * - in case of failure, the update file's modification date is updated,
+     *   to avoid intempestive connection attempts.
+     *
+     * @param string $currentVersion the current version code
+     * @param string $updateFile     the file where to store the latest version code
+     * @param int    $checkInterval  the minimum interval between update checks (in seconds
+     * @param bool   $enableCheck    whether to check for new versions
+     * @param bool   $isLoggedIn     whether the user is logged in
+     *
+     * @throws Exception an invalid branch has been set for update checks
+     *
+     * @return mixed the new version code if available and greater, else 'false'
+     */
+    public static function checkUpdate($currentVersion,
+                                       $updateFile,
+                                       $checkInterval,
+                                       $enableCheck,
+                                       $isLoggedIn,
+                                       $branch='stable')
+    {
+        if (! $isLoggedIn) {
+            // Do not check versions for visitors
+            return false;
+        }
+
+        if (empty($enableCheck)) {
+            // Do not check if the user doesn't want to
+            return false;
+        }
+
+        if (is_file($updateFile) && (filemtime($updateFile) > time() - $checkInterval)) {
+            // Shaarli has checked for updates recently - skip HTTP query
+            $latestKnownVersion = file_get_contents($updateFile);
+
+            if (version_compare($latestKnownVersion, $currentVersion) == 1) {
+                return $latestKnownVersion;
+            }
+            return false;
+        }
+
+        if (! in_array($branch, self::$GIT_BRANCHES)) {
+            throw new Exception(
+                'Invalid branch selected for updates: "' . $branch . '"'
+            );
+        }
+
+        // Late Static Binding allows overriding within tests
+        // See http://php.net/manual/en/language.oop5.late-static-bindings.php
+        $latestVersion = static::getLatestGitVersionCode(
+            self::$GIT_URL . '/' . $branch . '/' . self::$VERSION_FILE
+        );
+
+        if (! $latestVersion) {
+            // Only update the file's modification date
+            file_put_contents($updateFile, $currentVersion);
+            return false;
+        }
+
+        // Update the file's content and modification date
+        file_put_contents($updateFile, $latestVersion);
+
+        if (version_compare($latestVersion, $currentVersion) == 1) {
+            return $latestVersion;
+        }
+
+        return false;
+    }
 
     /**
      * Checks the PHP version to ensure Shaarli can run
index 15fadbc3a6baa67e552517b429635aa5f0c79dd1..f771ac8bf7b1677c99c67ac468ea33009c69a6cc 100644 (file)
@@ -57,18 +57,25 @@ class LinkDB implements Iterator, Countable, ArrayAccess
     // Hide public links
     private $_hidePublicLinks;
 
+    // link redirector set in user settings.
+    private $_redirector;
+
     /**
      * Creates a new LinkDB
      *
      * Checks if the datastore exists; else, attempts to create a dummy one.
      *
-     * @param $isLoggedIn is the user logged in?
+     * @param string  $datastore       datastore file path.
+     * @param boolean $isLoggedIn      is the user logged in?
+     * @param boolean $hidePublicLinks if true all links are private.
+     * @param string  $redirector      link redirector set in user settings.
      */
-    function __construct($datastore, $isLoggedIn, $hidePublicLinks)
+    function __construct($datastore, $isLoggedIn, $hidePublicLinks, $redirector = '')
     {
         $this->_datastore = $datastore;
         $this->_loggedIn = $isLoggedIn;
         $this->_hidePublicLinks = $hidePublicLinks;
+        $this->_redirector = $redirector;
         $this->_checkDB();
         $this->_readDB();
     }
@@ -259,7 +266,14 @@ You use the community supported version of the original Shaarli project, by Seba
 
         // Escape links data
         foreach($this->_links as &$link) { 
-            sanitizeLink($link); 
+            sanitizeLink($link);
+            // Do not use the redirector for internal links (Shaarli note URL starting with a '?').
+            if (!empty($this->_redirector) && !startsWith($link['url'], '?')) {
+                $link['real_url'] = $this->_redirector . urlencode($link['url']);
+            }
+            else {
+                $link['real_url'] = $link['url'];
+            }
         }
     }
 
index b8579b4864f174503e9c5dae4c1351999a487a2a..f84f70e44a7f8662f136bd19909b35f338796cbd 100644 (file)
@@ -148,3 +148,56 @@ function is_session_id_valid($sessionId)
 
     return true;
 }
+
+/**
+ * In a string, converts URLs to clickable links.
+ *
+ * @param string $text       input string.
+ * @param string $redirector if a redirector is set, use it to gerenate links.
+ *
+ * @return string returns $text with all links converted to HTML links.
+ *
+ * @see Function inspired from http://www.php.net/manual/en/function.preg-replace.php#85722
+ */
+function text2clickable($text, $redirector)
+{
+    $regex = '!(((?:https?|ftp|file)://|apt:|magnet:)\S+[[:alnum:]]/?)!si';
+
+    if (empty($redirector)) {
+        return preg_replace($regex, '<a href="$1">$1</a>', $text);
+    }
+    // Redirector is set, urlencode the final URL.
+    return preg_replace_callback(
+        $regex,
+        function ($matches) use ($redirector) {
+            return '<a href="' . $redirector . urlencode($matches[1]) .'">'. $matches[1] .'</a>';
+        },
+        $text
+    );
+}
+
+/**
+ * This function inserts &nbsp; where relevant so that multiple spaces are properly displayed in HTML
+ * even in the absence of <pre>  (This is used in description to keep text formatting).
+ *
+ * @param string $text input text.
+ *
+ * @return string formatted text.
+ */
+function space2nbsp($text)
+{
+    return preg_replace('/(^| ) /m', '$1&nbsp;', $text);
+}
+
+/**
+ * Format Shaarli's description
+ * TODO: Move me to ApplicationUtils when it's ready.
+ *
+ * @param string $description shaare's description.
+ * @param string $redirector  if a redirector is set, use it to gerenate links.
+ *
+ * @return string formatted description.
+ */
+function format_description($description, $redirector) {
+    return nl2br(space2nbsp(text2clickable($description, $redirector)));
+}
old mode 100644 (file)
new mode 100755 (executable)
index b4d9395..0dd5829
--- a/index.php
+++ b/index.php
@@ -1,6 +1,6 @@
 <?php
 /**
- * Shaarli v0.6.0 - Shaare your links...
+ * Shaarli v0.6.1 - Shaare your links...
  *
  * The personal, minimalist, super-fast, no-database Delicious clone.
  *
@@ -92,7 +92,8 @@ $GLOBALS['config']['ENABLE_THUMBNAILS'] = true;
 $GLOBALS['config']['ENABLE_LOCALCACHE'] = true;
 
 // Update check frequency for Shaarli. 86400 seconds=24 hours
-$GLOBALS['config']['UPDATECHECK_INTERVAL'] = 86400 ;
+$GLOBALS['config']['UPDATECHECK_BRANCH'] = 'stable';
+$GLOBALS['config']['UPDATECHECK_INTERVAL'] = 86400;
 
 
 /*
@@ -118,7 +119,7 @@ $GLOBALS['config']['PUBSUBHUB_URL'] = '';
 /*
  * PHP configuration
  */
-define('shaarli_version', '0.6.0');
+define('shaarli_version', '0.6.1');
 
 // http://server.com/x/shaarli --> /shaarli/
 define('WEB_PATH', substr($_SERVER["REQUEST_URI"], 0, 1+strrpos($_SERVER["REQUEST_URI"], '/', 0)));
@@ -305,56 +306,15 @@ function setup_login_state() {
 }
 $userIsLoggedIn = setup_login_state();
 
-// Checks if an update is available for Shaarli.
-// (at most once a day, and only for registered user.)
-// Output: '' = no new version.
-//         other= the available version.
-function checkUpdate()
-{
-    if (!isLoggedIn()) return ''; // Do not check versions for visitors.
-    if (empty($GLOBALS['config']['ENABLE_UPDATECHECK'])) return ''; // Do not check if the user doesn't want to.
-
-    // Get latest version number at most once a day.
-    if (!is_file($GLOBALS['config']['UPDATECHECK_FILENAME']) || (filemtime($GLOBALS['config']['UPDATECHECK_FILENAME'])<time()-($GLOBALS['config']['UPDATECHECK_INTERVAL'])))
-    {
-        $version = shaarli_version;
-        list($headers, $data) = get_http_url('https://raw.githubusercontent.com/shaarli/Shaarli/master/shaarli_version.php', 2);
-        if (strpos($headers[0], '200 OK') !== false) {
-            $version = str_replace(' */ ?>', '', str_replace('<?php /* ', '', $data));
-        }
-        // If failed, never mind. We don't want to bother the user with that.
-        file_put_contents($GLOBALS['config']['UPDATECHECK_FILENAME'],$version); // touch file date
-    }
-    // Compare versions:
-    $newestversion=file_get_contents($GLOBALS['config']['UPDATECHECK_FILENAME']);
-    if (version_compare($newestversion,shaarli_version)==1) return $newestversion;
-    return '';
-}
-
 
 // -----------------------------------------------------------------------------------------------
 // Log to text file
 function logm($message)
 {
     $t = strval(date('Y/m/d_H:i:s')).' - '.$_SERVER["REMOTE_ADDR"].' - '.strval($message)."\n";
-    file_put_contents($GLOBAL['config']['LOG_FILE'], $t, FILE_APPEND);
-}
-
-// In a string, converts URLs to clickable links.
-// Function inspired from http://www.php.net/manual/en/function.preg-replace.php#85722
-function text2clickable($url)
-{
-    $redir = empty($GLOBALS['redirector']) ? '' : $GLOBALS['redirector'];
-    return preg_replace('!(((?:https?|ftp|file)://|apt:|magnet:)\S+[[:alnum:]]/?)!si','<a href="'.$redir.'$1" rel="nofollow">$1</a>',$url);
+    file_put_contents($GLOBALS['config']['LOG_FILE'], $t, FILE_APPEND);
 }
 
-// This function inserts &nbsp; where relevant so that multiple spaces are properly displayed in HTML
-// even in the absence of <pre>  (This is used in description to keep text formatting)
-function keepMultipleSpaces($text)
-{
-    return str_replace('  ',' &nbsp;',$text);
-
-}
 // ------------------------------------------------------------------------------------------
 // Sniff browser language to display dates in the right format automatically.
 // (Note that is may not work on your server if the corresponding local is not installed.)
@@ -672,7 +632,25 @@ class pageBuilder
     private function initialize()
     {
         $this->tpl = new RainTPL;
-        $this->tpl->assign('newversion', escape(checkUpdate()));
+
+        try {
+            $version = ApplicationUtils::checkUpdate(
+                shaarli_version,
+                $GLOBALS['config']['UPDATECHECK_FILENAME'],
+                $GLOBALS['config']['UPDATECHECK_INTERVAL'],
+                $GLOBALS['config']['ENABLE_UPDATECHECK'],
+                isLoggedIn(),
+                $GLOBALS['config']['UPDATECHECK_BRANCH']
+            );
+            $this->tpl->assign('newVersion', escape($version));
+            $this->tpl->assign('versionError', '');
+
+        } catch (Exception $exc) {
+            logm($exc->getMessage());
+            $this->tpl->assign('newVersion', '');
+            $this->tpl->assign('versionError', escape($exc->getMessage()));
+        }
+
         $this->tpl->assign('feedurl', escape(index_url($_SERVER)));
         $searchcrits = ''; // Search criteria
         if (!empty($_GET['searchtags'])) {
@@ -746,7 +724,8 @@ function showRSS()
     $LINKSDB = new LinkDB(
         $GLOBALS['config']['DATASTORE'],
         isLoggedIn(),
-        $GLOBALS['config']['HIDE_PUBLIC_LINKS']
+        $GLOBALS['config']['HIDE_PUBLIC_LINKS'],
+        $GLOBALS['redirector']
     );
     // Read links from database (and filter private links if user it not logged in).
 
@@ -797,7 +776,9 @@ function showRSS()
         // If user wants permalinks first, put the final link in description
         if ($usepermalinks===true) $descriptionlink = '(<a href="'.$absurl.'">Link</a>)';
         if (strlen($link['description'])>0) $descriptionlink = '<br>'.$descriptionlink;
-        echo '<description><![CDATA['.nl2br(keepMultipleSpaces(text2clickable($link['description']))).$descriptionlink.']]></description>'."\n</item>\n";
+        echo '<description><![CDATA['.
+            format_description($link['description'], $GLOBALS['redirector']) .
+            $descriptionlink . ']]></description>' . "\n</item>\n";
         $i++;
     }
     echo '</channel></rss><!-- Cached version of '.escape(page_url($_SERVER)).' -->';
@@ -835,7 +816,8 @@ function showATOM()
     $LINKSDB = new LinkDB(
         $GLOBALS['config']['DATASTORE'],
         isLoggedIn(),
-        $GLOBALS['config']['HIDE_PUBLIC_LINKS']
+        $GLOBALS['config']['HIDE_PUBLIC_LINKS'],
+        $GLOBALS['redirector']
     );
 
     // Optionally filter the results:
@@ -876,7 +858,9 @@ function showATOM()
         if ($usepermalinks===true) $descriptionlink = '(<a href="'.$absurl.'">Link</a>)';
         if (strlen($link['description'])>0) $descriptionlink = '<br>'.$descriptionlink;
 
-        $entries.='<content type="html"><![CDATA['.nl2br(keepMultipleSpaces(text2clickable($link['description']))).$descriptionlink."]]></content>\n";
+        $entries .= '<content type="html"><![CDATA['.
+            format_description($link['description'], $GLOBALS['redirector']) .
+            $descriptionlink . "]]></content>\n";
         if ($link['tags']!='') // Adding tags to each ATOM entry (as mentioned in ATOM specification)
         {
             foreach(explode(' ',$link['tags']) as $tag)
@@ -929,7 +913,8 @@ function showDailyRSS() {
     $LINKSDB = new LinkDB(
         $GLOBALS['config']['DATASTORE'],
         isLoggedIn(),
-        $GLOBALS['config']['HIDE_PUBLIC_LINKS']
+        $GLOBALS['config']['HIDE_PUBLIC_LINKS'],
+        $GLOBALS['redirector']
     );
 
     /* Some Shaarlies may have very few links, so we need to look
@@ -983,7 +968,7 @@ function showDailyRSS() {
         // We pre-format some fields for proper output.
         foreach ($linkdates as $linkdate) {
             $l = $LINKSDB[$linkdate];
-            $l['formatedDescription'] = nl2br(keepMultipleSpaces(text2clickable($l['description'])));
+            $l['formatedDescription'] = format_description($l['description'], $GLOBALS['redirector']);
             $l['thumbnail'] = thumbnail($l['url']);
             $l['timestamp'] = linkdate2timestamp($l['linkdate']);
             if (startsWith($l['url'], '?')) {
@@ -1016,7 +1001,8 @@ function showDaily()
     $LINKSDB = new LinkDB(
         $GLOBALS['config']['DATASTORE'],
         isLoggedIn(),
-        $GLOBALS['config']['HIDE_PUBLIC_LINKS']
+        $GLOBALS['config']['HIDE_PUBLIC_LINKS'],
+        $GLOBALS['redirector']
     );
 
     $day=Date('Ymd',strtotime('-1 day')); // Yesterday, in format YYYYMMDD.
@@ -1047,7 +1033,7 @@ function showDaily()
         $taglist = explode(' ',$link['tags']);
         uasort($taglist, 'strcasecmp');
         $linksToDisplay[$key]['taglist']=$taglist;
-        $linksToDisplay[$key]['formatedDescription']=nl2br(keepMultipleSpaces(text2clickable($link['description'])));
+        $linksToDisplay[$key]['formatedDescription'] = format_description($link['description'], $GLOBALS['redirector']);
         $linksToDisplay[$key]['thumbnail'] = thumbnail($link['url']);
         $linksToDisplay[$key]['timestamp'] = linkdate2timestamp($link['linkdate']);
     }
@@ -1107,7 +1093,8 @@ function renderPage()
     $LINKSDB = new LinkDB(
         $GLOBALS['config']['DATASTORE'],
         isLoggedIn(),
-        $GLOBALS['config']['HIDE_PUBLIC_LINKS']
+        $GLOBALS['config']['HIDE_PUBLIC_LINKS'],
+        $GLOBALS['redirector']
     );
 
     $PAGE = new pageBuilder;
@@ -1781,7 +1768,8 @@ function importFile()
     $LINKSDB = new LinkDB(
         $GLOBALS['config']['DATASTORE'],
         isLoggedIn(),
-        $GLOBALS['config']['HIDE_PUBLIC_LINKS']
+        $GLOBALS['config']['HIDE_PUBLIC_LINKS'],
+        $GLOBALS['redirector']
     );
     $filename=$_FILES['filetoupload']['name'];
     $filesize=$_FILES['filetoupload']['size'];
@@ -1932,8 +1920,7 @@ function buildLinkList($PAGE,$LINKSDB)
     while ($i<$end && $i<count($keys))
     {
         $link = $linksToDisplay[$keys[$i]];
-        $link['description']=nl2br(keepMultipleSpaces(text2clickable($link['description'])));
-        $title=$link['title'];
+        $link['description'] = format_description($link['description'], $GLOBALS['redirector']);
         $classLi =  $i%2!=0 ? '' : 'publicLinkHightLight';
         $link['class'] = ($link['private']==0 ? $classLi : 'private');
         $link['timestamp']=linkdate2timestamp($link['linkdate']);
@@ -1974,6 +1961,10 @@ function buildLinkList($PAGE,$LINKSDB)
         'links' => $linkDisp,
         'tags' => $LINKSDB->allTags(),
     );
+    // FIXME! temporary fix - see #399.
+    if (!empty($GLOBALS['pagetitle']) && count($linkDisp) == 1) {
+        $data['pagetitle'] = $GLOBALS['pagetitle'];
+    }
 
     $pluginManager = PluginManager::getInstance();
     $pluginManager->executeHooks('render_linklist', $data, array('loggedin' => isLoggedIn()));
index ec1ead8d4c8f3e43ec4b667e6bca48a255e7f55b..b1698470755d1d7adff2e91528f57518d14afbda 100644 (file)
@@ -1,21 +1,29 @@
 ### â–º Play Videos plugin for Shaarli
-This plugin adds a `â–º Play Videos` button to [Shaarli](https://github.com/shaarli/Shaarli)'s toolbar. Click this button to play all videos on the page in an overlay HTML5 player. Nice for continuous stream of music, documentaries, talks...
 
-This uses code from https://zaius.github.io/youtube_playlist/ and is currently only compatible with Youtube videos.
+Adds a `â–º Play Videos` button to [Shaarli](https://github.com/shaarli/Shaarli)'s toolbar. Click this button to play all videos on the page in an overlay HTML5 player. Nice for continuous stream of music, documentaries, talks...
+
+<!-- TODO screenshot -->
 
-![](https://cdn.mediacru.sh/D_izf0zjAtxy.png)
+This uses code from https://zaius.github.io/youtube_playlist/ and is currently only compatible with Youtube videos.
 
 #### Installation and setup
-Place the files in the `tpl/plugins/playvideos/` directory of your Shaarli.
-This is a default Shaarli plugin, you just have to enable it.
 
-To enable the plugin, add `playvideos` to the `TOOLBAR_PLUGINS` config option in your `index.php` or `data/options.php`. Example:
+This is a default Shaarli plugin, you just have to enable it. See https://github.com/shaarli/Shaarli/wiki/Shaarli-configuration/
 
-    $GLOBALS['config']['TOOLBAR_PLUGINS'] = array('aplugins', 'anotherone', 'playvideos');
 
 #### Troubleshooting
+
 If your server has [Content Security Policy](http://content-security-policy.com/) headers enabled, this may prevent the script from loading fully. You should relax the CSP in your server settings. Example CSP rule for apache2:
-`Header set Content-Security-Policy "script-src 'self' 'unsafe-inline' https://www.youtube.com https://s.ytimg.com 'unsafe-eval'"`
+
+In `/etc/apache2/conf-available/shaarli-csp.conf`:
+
+```apache
+<Directory /path/to/shaarli>
+    Header set Content-Security-Policy "script-src 'self' 'unsafe-inline' https://www.youtube.com https://s.ytimg.com 'unsafe-eval'"
+</Directory>
+```
+
+Then run `a2enconf shaarli-csp; service apache2 reload`
 
 ### License
 ```
@@ -68,4 +76,4 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 THE SOFTWARE.
 
 ----------------------------------------------------
-```
\ No newline at end of file
+```
index 1080c9645d32bfebd76c7914d6d85f3747324f10..5f6e76a2f8c42d035f0c7026158b463935d953b0 100644 (file)
@@ -17,7 +17,7 @@ function hook_qrcode_render_linklist($data)
     $qrcode_html = file_get_contents(PluginManager::$PLUGINS_PATH . '/qrcode/qrcode.html');
 
     foreach ($data['links'] as &$value) {
-        $qrcode = sprintf($qrcode_html, $value['url'], $value['url'], PluginManager::$PLUGINS_PATH);
+        $qrcode = sprintf($qrcode_html, $value['real_url'], $value['real_url'], PluginManager::$PLUGINS_PATH);
         $value['link_plugin'][] = $qrcode;
     }
 
index a5f0a0959f979b77386ddb98597f38d928f626cf..11ad87d7c52814896a0ca255b2e33d9a5b2a3d08 100644 (file)
@@ -1 +1 @@
-<?php /* 0.6.0 */ ?>
+<?php /* 0.6.1 */ ?>
index 01301e689dec6bc47b12dc59aa68b585cd7cd860..6064357dcb50b70da959dc451271621392c449de 100644 (file)
 
 require_once 'application/ApplicationUtils.php';
 
+/**
+ * Fake ApplicationUtils class to avoid HTTP requests
+ */
+class FakeApplicationUtils extends ApplicationUtils
+{
+    public static $VERSION_CODE = '';
+
+    /**
+     * Toggle HTTP requests, allow overriding the version code
+     */
+    public static function getLatestGitVersionCode($url, $timeout=0)
+    {
+        return self::$VERSION_CODE;
+    }
+}
+
 
 /**
  * Unitary tests for Shaarli utilities
  */
 class ApplicationUtilsTest extends PHPUnit_Framework_TestCase
 {
+    protected static $testUpdateFile = 'sandbox/update.txt';
+    protected static $testVersion = '0.5.0';
+    protected static $versionPattern = '/^\d+\.\d+\.\d+$/';
+
+    /**
+     * Reset test data for each test
+     */
+    public function setUp()
+    {
+        FakeApplicationUtils::$VERSION_CODE = '';
+        if (file_exists(self::$testUpdateFile)) {
+            unlink(self::$testUpdateFile);
+        }
+    }
+
+    /**
+     * Retrieve the latest version code available on Git
+     *
+     * Expected format: Semantic Versioning - major.minor.patch
+     */
+    public function testGetLatestGitVersionCode()
+    {
+        $testTimeout = 10;
+
+        $this->assertEquals(
+            '0.5.4',
+            ApplicationUtils::getLatestGitVersionCode(
+                'https://raw.githubusercontent.com/shaarli/Shaarli/'
+               .'v0.5.4/shaarli_version.php',
+                $testTimeout
+            )
+        );
+        $this->assertRegexp(
+            self::$versionPattern,
+            ApplicationUtils::getLatestGitVersionCode(
+                'https://raw.githubusercontent.com/shaarli/Shaarli/'
+               .'master/shaarli_version.php',
+                $testTimeout
+            )
+        );
+    }
+
+    /**
+     * Attempt to retrieve the latest version from an invalid URL
+     */
+    public function testGetLatestGitVersionCodeInvalidUrl()
+    {
+        $this->assertFalse(
+            ApplicationUtils::getLatestGitVersionCode('htttp://null.io', 1)
+        );
+    }
+
+    /**
+     * Test update checks - the user is logged off
+     */
+    public function testCheckUpdateLoggedOff()
+    {
+        $this->assertFalse(
+            ApplicationUtils::checkUpdate(self::$testVersion, 'null', 0, false, false)
+        );
+    }
+
+    /**
+     * Test update checks - the user has disabled updates
+     */
+    public function testCheckUpdateUserDisabled()
+    {
+        $this->assertFalse(
+            ApplicationUtils::checkUpdate(self::$testVersion, 'null', 0, false, true)
+        );
+    }
+
+    /**
+     * A newer version is available
+     */
+    public function testCheckUpdateNewVersionAvailable()
+    {
+        $newVersion = '1.8.3';
+        FakeApplicationUtils::$VERSION_CODE = $newVersion;
+
+        $version = FakeApplicationUtils::checkUpdate(
+            self::$testVersion,
+            self::$testUpdateFile,
+            100,
+            true,
+            true
+        );
+
+        $this->assertEquals($newVersion, $version);
+    }
+
+    /**
+     * No available information about versions
+     */
+    public function testCheckUpdateNewVersionUnavailable()
+    {
+        $version = FakeApplicationUtils::checkUpdate(
+            self::$testVersion,
+            self::$testUpdateFile,
+            100,
+            true,
+            true
+        );
+
+        $this->assertFalse($version);
+    }
+
+    /**
+     * Test update checks - invalid Git branch
+     * @expectedException              Exception
+     * @expectedExceptionMessageRegExp /Invalid branch selected for updates/
+     */
+    public function testCheckUpdateInvalidGitBranch()
+    {
+        ApplicationUtils::checkUpdate('', 'null', 0, true, true, 'unstable');
+    }
+
+    /**
+     * Shaarli is up-to-date
+     */
+    public function testCheckUpdateNewVersionUpToDate()
+    {
+        FakeApplicationUtils::$VERSION_CODE = self::$testVersion;
+
+        $version = FakeApplicationUtils::checkUpdate(
+            self::$testVersion,
+            self::$testUpdateFile,
+            100,
+            true,
+            true
+        );
+
+        $this->assertFalse($version);
+    }
+
+    /**
+     * Time-traveller's Shaarli
+     */
+    public function testCheckUpdateNewVersionMaartiMcFly()
+    {
+        FakeApplicationUtils::$VERSION_CODE = '0.4.1';
+
+        $version = FakeApplicationUtils::checkUpdate(
+            self::$testVersion,
+            self::$testUpdateFile,
+            100,
+            true,
+            true
+        );
+
+        $this->assertFalse($version);
+    }
+
+    /**
+     * The version has been checked recently and Shaarli is up-to-date
+     */
+    public function testCheckUpdateNewVersionTwiceUpToDate()
+    {
+        FakeApplicationUtils::$VERSION_CODE = self::$testVersion;
+
+        // Create the update file
+        $version = FakeApplicationUtils::checkUpdate(
+            self::$testVersion,
+            self::$testUpdateFile,
+            100,
+            true,
+            true
+        );
+
+        $this->assertFalse($version);
+
+        // Reuse the update file
+        $version = FakeApplicationUtils::checkUpdate(
+            self::$testVersion,
+            self::$testUpdateFile,
+            100,
+            true,
+            true
+        );
+
+        $this->assertFalse($version);
+    }
+
+    /**
+     * The version has been checked recently and Shaarli is outdated
+     */
+    public function testCheckUpdateNewVersionTwiceOutdated()
+    {
+        $newVersion = '1.8.3';
+        FakeApplicationUtils::$VERSION_CODE = $newVersion;
+
+        // Create the update file
+        $version = FakeApplicationUtils::checkUpdate(
+            self::$testVersion,
+            self::$testUpdateFile,
+            100,
+            true,
+            true
+        );
+        $this->assertEquals($newVersion, $version);
+
+        // Reuse the update file
+        $version = FakeApplicationUtils::checkUpdate(
+            self::$testVersion,
+            self::$testUpdateFile,
+            100,
+            true,
+            true
+        );
+        $this->assertEquals($newVersion, $version);
+    }
+
     /**
      * Check supported PHP versions
      */
index aa5395b0ab8f16b1906dfa8ece3b1976a43d9d94..26c432254a9d0e966d97f8a949681f035f808d7a 100644 (file)
@@ -11,10 +11,10 @@ require_once 'application/Cache.php';
 /**
  * Unitary tests for cached pages
  */
-class CachedTest extends PHPUnit_Framework_TestCase
+class CacheTest extends PHPUnit_Framework_TestCase
 {
     // test cache directory
-    protected static $testCacheDir = 'tests/dummycache';
+    protected static $testCacheDir = 'sandbox/dummycache';
 
     // dummy cached file names / content
     protected static $pages = array('a', 'toto', 'd7b59c');
@@ -30,13 +30,22 @@ class CachedTest extends PHPUnit_Framework_TestCase
         } else {
             array_map('unlink', glob(self::$testCacheDir.'/*'));
         }
-        
+
         foreach (self::$pages as $page) {
             file_put_contents(self::$testCacheDir.'/'.$page.'.cache', $page);
         }
         file_put_contents(self::$testCacheDir.'/intru.der', 'ShouldNotBeThere');
     }
 
+    /**
+     * Remove dummycache folder after each tests.
+     */
+    public function tearDown()
+    {
+        array_map('unlink', glob(self::$testCacheDir.'/*'));
+        rmdir(self::$testCacheDir);
+    }
+
     /**
      * Purge cached pages
      */
@@ -56,7 +65,7 @@ class CachedTest extends PHPUnit_Framework_TestCase
     public function testPurgeCachedPagesMissingDir()
     {
         $this->assertEquals(
-            'Cannot purge tests/dummycache_missing: no directory',
+            'Cannot purge sandbox/dummycache_missing: no directory',
             purgeCachedPages(self::$testCacheDir.'_missing')
         );
     }
index e97af030af77f4619f41947987caeddbdf30b8b7..51565cd63f591c5e69ff41a1eb29d1e616b52cba 100644 (file)
@@ -11,7 +11,7 @@ require_once 'application/CachedPage.php';
 class CachedPageTest extends PHPUnit_Framework_TestCase
 {
     // test cache directory
-    protected static $testCacheDir = 'tests/pagecache';
+    protected static $testCacheDir = 'sandbox/pagecache';
     protected static $url = 'http://shaar.li/?do=atom';
     protected static $filename;
 
index 8929713d26341941ffce05785d09fe5fb2cced39..7b22b2704f8ba84f3e26995f36c84d071b71161d 100644 (file)
@@ -16,7 +16,7 @@ require_once 'tests/utils/ReferenceLinkDB.php';
 class LinkDBTest extends PHPUnit_Framework_TestCase
 {
     // datastore to test write operations
-    protected static $testDatastore = 'tests/datastore.php';
+    protected static $testDatastore = 'sandbox/datastore.php';
     protected static $refDB = null;
     protected static $publicLinkDB = null;
     protected static $privateLinkDB = null;
@@ -511,4 +511,27 @@ class LinkDBTest extends PHPUnit_Framework_TestCase
             sizeof(self::$publicLinkDB->filterFullText('free software'))
         );
     }
+
+    /**
+     * Test real_url without redirector.
+     */
+    public function testLinkRealUrlWithoutRedirector()
+    {
+        $db = new LinkDB(self::$testDatastore, false, false);
+        foreach($db as $link) {
+            $this->assertEquals($link['url'], $link['real_url']);
+        }
+    }
+
+    /**
+     * Test real_url with redirector.
+     */
+    public function testLinkRealUrlWithRedirector()
+    {
+        $redirector = 'http://redirector.to?';
+        $db = new LinkDB(self::$testDatastore, false, false, $redirector);
+        foreach($db as $link) {
+            $this->assertStringStartsWith($redirector, $link['real_url']);
+        }
+    }
 }
index 4847ea94de299b450c58fa8d13b9cbb92ebe7394..02eecda216f8c03adafe50f57bcb32bdf7ace787 100644 (file)
@@ -187,4 +187,41 @@ class UtilsTest extends PHPUnit_Framework_TestCase
             is_session_id_valid('c0ZqcWF3VFE2NmJBdm1HMVQ0ZHJ3UmZPbTFsNGhkNHI=')
         );
     }
+
+    /**
+     * Test text2clickable without a redirector being set.
+     */
+    public function testText2clickableWithoutRedirector()
+    {
+        $text = 'stuff http://hello.there/is=someone#here otherstuff';
+        $expectedText = 'stuff <a href="http://hello.there/is=someone#here">http://hello.there/is=someone#here</a> otherstuff';
+        $processedText = text2clickable($text, '');
+        $this->assertEquals($expectedText, $processedText);
+    }
+
+    /**
+     * Test text2clickable a redirector set.
+     */
+    public function testText2clickableWithRedirector()
+    {
+        $text = 'stuff http://hello.there/is=someone#here otherstuff';
+        $redirector = 'http://redirector.to';
+        $expectedText = 'stuff <a href="'.
+            $redirector .
+            urlencode('http://hello.there/is=someone#here') .
+            '">http://hello.there/is=someone#here</a> otherstuff';
+        $processedText = text2clickable($text, $redirector);
+        $this->assertEquals($expectedText, $processedText);
+    }
+
+    /**
+     * Test testSpace2nbsp.
+     */
+    public function testSpace2nbsp()
+    {
+        $text = '  Are you   thrilled  by flags   ?'. PHP_EOL .' Really?';
+        $expectedText = '&nbsp; Are you &nbsp; thrilled &nbsp;by flags &nbsp; ?'. PHP_EOL .'&nbsp;Really?';
+        $processedText = space2nbsp($text);
+        $this->assertEquals($expectedText, $processedText);
+    }
 }
index 86dc7f293059a94830f0cbec3f0f7cc74229becc..c749fa86f6a49aa167bb4c8c7761a2ce32b38f8c 100644 (file)
@@ -30,7 +30,7 @@ class PlugQrcodeTest extends PHPUnit_Framework_TestCase
             'title' => $str,
             'links' => array(
                 array(
-                    'url' => $str,
+                    'real_url' => $str,
                 )
             )
         );
@@ -39,7 +39,7 @@ class PlugQrcodeTest extends PHPUnit_Framework_TestCase
         $link = $data['links'][0];
         // data shouldn't be altered
         $this->assertEquals($str, $data['title']);
-        $this->assertEquals($str, $link['url']);
+        $this->assertEquals($str, $link['real_url']);
 
         // plugin data
         $this->assertEquals(1, count($link['link_plugin']));
index 93a3ab4521cbf82c7ea1e0b70e82cfb688c10d6c..063dc89a76cff9a963f2f83d8763b87a7de116ad 100644 (file)
@@ -66,7 +66,7 @@
                             </div>
                         {/if}
                         <div class="dailyEntryTitle">
-                            <a href="{$link.url}">{$link.title}</a>
+                            <a href="{$link.real_url}">{$link.title}</a>
                         </div>
                         {if="$link.thumbnail"}
                             <div class="dailyEntryThumbnail">{$link.thumbnail}</div>
index f6e9e82b6a42eaf39690129dd99717abbb505524..666748a7b3f2d4bf660ee116ed016af9b2dc32a3 100644 (file)
@@ -70,7 +70,9 @@
                         </form>
                     </div>
                 {/if}
-                <span class="linktitle"><a href="{$redirector}{$value.url}">{$value.title}</a></span>
+                <span class="linktitle">
+                    <a href="{$value.real_url}">{$value.title}</a>
+                </span>
                 <br>
                 {if="$value.description"}<div class="linkdescription">{$value.description}</div>{/if}
                 {if="!$GLOBALS['config']['HIDE_TIMESTAMPS'] || isLoggedIn()"}
@@ -83,7 +85,7 @@
                     <span>{$value}</span> -
                 {/loop}
 
-                <a href="{$value.url}"><span class="linkurl" title="Short link">{$value.url}</span></a><br>
+                <a href="{$value.real_url}"><span class="linkurl" title="Short link">{$value.url}</span></a><br>
                 {if="$value.tags"}
                     <div class="linktaglist">
                     {loop="value.taglist"}<span class="linktag" title="Add tag"><a href="?addtag={$value|urlencode}">{$value}</a></span> {/loop}
index 6c29850ffe2ba3af06a031c13b4527223950880a..b20aae540adab9b9c6d7ca277ac342dc06ef3524 100644 (file)
@@ -4,8 +4,16 @@
         {$value}
     {/loop}
 </div>
-{if="$newversion"}
-    <div id="newversion"><span id="version_id">&#x25CF;</span> Shaarli {$newversion} is <a href="https://github.com/shaarli/Shaarli/releases">available</a>.</div>
+{if="$newVersion"}
+<div id="newversion">
+  <span id="version_id">&#x25CF;</span> Shaarli {$newVersion} is
+  <a href="https://github.com/shaarli/Shaarli/releases">available</a>.
+</div>
+{/if}
+{if="$versionError"}
+<div id="newversion">
+  Error: {$versionError}
+</div>
 {/if}
 {if="isLoggedIn()"}
 <script>function confirmDeleteLink() { var agree=confirm("Are you sure you want to delete this link ?"); if (agree) return true ; else return false ; }</script>
index 97d5efdf7c43d2d6c710482d9a5da8cbf77dc84d..230c948b783d9f1fc550bb594e4709b89b9ddf44 100644 (file)
@@ -16,7 +16,7 @@
         <div id="picwall_container">
             {loop="linksToDisplay"}
             <div class="picwall_pictureframe">
-                   {$value.thumbnail}<a href="{$value.url}"><span class="info">{$value.title}</span></a>
+                   {$value.thumbnail}<a href="{$value.real_url}"><span class="info">{$value.title}</span></a>
                 {loop="$value.picwall_plugin"}
                     {$value}
                 {/loop}