diff options
-rw-r--r-- | .gitignore | 5 | ||||
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | application/ApplicationUtils.php | 104 | ||||
-rw-r--r-- | application/LinkDB.php | 20 | ||||
-rw-r--r-- | application/Utils.php | 53 | ||||
-rwxr-xr-x[-rw-r--r--] | index.php | 107 | ||||
-rw-r--r-- | plugins/playvideos/README.md | 26 | ||||
-rw-r--r-- | plugins/qrcode/qrcode.php | 2 | ||||
-rw-r--r-- | shaarli_version.php | 2 | ||||
-rw-r--r-- | tests/ApplicationUtilsTest.php | 228 | ||||
-rw-r--r-- | tests/CacheTest.php | 17 | ||||
-rw-r--r-- | tests/CachedPageTest.php | 2 | ||||
-rw-r--r-- | tests/LinkDBTest.php | 25 | ||||
-rw-r--r-- | tests/UtilsTest.php | 37 | ||||
-rw-r--r-- | tests/plugins/PlugQrcodeTest.php | 4 | ||||
-rw-r--r-- | tpl/daily.html | 2 | ||||
-rw-r--r-- | tpl/linklist.html | 6 | ||||
-rw-r--r-- | tpl/page.footer.html | 12 | ||||
-rw-r--r-- | tpl/picwall.html | 2 |
19 files changed, 567 insertions, 89 deletions
@@ -19,9 +19,8 @@ composer.lock | |||
19 | # Ignore development and test resources | 19 | # Ignore development and test resources |
20 | coverage | 20 | coverage |
21 | doxygen | 21 | doxygen |
22 | tests/datastore.php | 22 | sandbox |
23 | tests/dummycache/ | ||
24 | phpmd.html | 23 | phpmd.html |
25 | 24 | ||
26 | # Ignore user plugin configuration | 25 | # Ignore user plugin configuration |
27 | plugins/*/config.php \ No newline at end of file | 26 | plugins/*/config.php |
@@ -110,6 +110,7 @@ test: | |||
110 | @echo "-------" | 110 | @echo "-------" |
111 | @echo "PHPUNIT" | 111 | @echo "PHPUNIT" |
112 | @echo "-------" | 112 | @echo "-------" |
113 | @mkdir -p sandbox | ||
113 | @$(BIN)/phpunit tests | 114 | @$(BIN)/phpunit tests |
114 | 115 | ||
115 | ## | 116 | ## |
@@ -119,6 +120,7 @@ test: | |||
119 | ### remove all unversioned files | 120 | ### remove all unversioned files |
120 | clean: | 121 | clean: |
121 | @git clean -df | 122 | @git clean -df |
123 | @rm -rf sandbox | ||
122 | 124 | ||
123 | ### generate Doxygen documentation | 125 | ### generate Doxygen documentation |
124 | doxygen: clean | 126 | doxygen: clean |
diff --git a/application/ApplicationUtils.php b/application/ApplicationUtils.php index b0e94e24..274331e1 100644 --- a/application/ApplicationUtils.php +++ b/application/ApplicationUtils.php | |||
@@ -4,6 +4,110 @@ | |||
4 | */ | 4 | */ |
5 | class ApplicationUtils | 5 | class ApplicationUtils |
6 | { | 6 | { |
7 | private static $GIT_URL = 'https://raw.githubusercontent.com/shaarli/Shaarli'; | ||
8 | private static $GIT_BRANCHES = array('master', 'stable'); | ||
9 | private static $VERSION_FILE = 'shaarli_version.php'; | ||
10 | private static $VERSION_START_TAG = '<?php /* '; | ||
11 | private static $VERSION_END_TAG = ' */ ?>'; | ||
12 | |||
13 | /** | ||
14 | * Gets the latest version code from the Git repository | ||
15 | * | ||
16 | * The code is read from the raw content of the version file on the Git server. | ||
17 | * | ||
18 | * @return mixed the version code from the repository if available, else 'false' | ||
19 | */ | ||
20 | public static function getLatestGitVersionCode($url, $timeout=2) | ||
21 | { | ||
22 | list($headers, $data) = get_http_url($url, $timeout); | ||
23 | |||
24 | if (strpos($headers[0], '200 OK') === false) { | ||
25 | error_log('Failed to retrieve ' . $url); | ||
26 | return false; | ||
27 | } | ||
28 | |||
29 | return str_replace( | ||
30 | array(self::$VERSION_START_TAG, self::$VERSION_END_TAG, PHP_EOL), | ||
31 | array('', '', ''), | ||
32 | $data | ||
33 | ); | ||
34 | } | ||
35 | |||
36 | /** | ||
37 | * Checks if a new Shaarli version has been published on the Git repository | ||
38 | * | ||
39 | * Updates checks are run periodically, according to the following criteria: | ||
40 | * - the update checks are enabled (install, global config); | ||
41 | * - the user is logged in (or this is an open instance); | ||
42 | * - the last check is older than a given interval; | ||
43 | * - the check is non-blocking if the HTTPS connection to Git fails; | ||
44 | * - in case of failure, the update file's modification date is updated, | ||
45 | * to avoid intempestive connection attempts. | ||
46 | * | ||
47 | * @param string $currentVersion the current version code | ||
48 | * @param string $updateFile the file where to store the latest version code | ||
49 | * @param int $checkInterval the minimum interval between update checks (in seconds | ||
50 | * @param bool $enableCheck whether to check for new versions | ||
51 | * @param bool $isLoggedIn whether the user is logged in | ||
52 | * | ||
53 | * @throws Exception an invalid branch has been set for update checks | ||
54 | * | ||
55 | * @return mixed the new version code if available and greater, else 'false' | ||
56 | */ | ||
57 | public static function checkUpdate($currentVersion, | ||
58 | $updateFile, | ||
59 | $checkInterval, | ||
60 | $enableCheck, | ||
61 | $isLoggedIn, | ||
62 | $branch='stable') | ||
63 | { | ||
64 | if (! $isLoggedIn) { | ||
65 | // Do not check versions for visitors | ||
66 | return false; | ||
67 | } | ||
68 | |||
69 | if (empty($enableCheck)) { | ||
70 | // Do not check if the user doesn't want to | ||
71 | return false; | ||
72 | } | ||
73 | |||
74 | if (is_file($updateFile) && (filemtime($updateFile) > time() - $checkInterval)) { | ||
75 | // Shaarli has checked for updates recently - skip HTTP query | ||
76 | $latestKnownVersion = file_get_contents($updateFile); | ||
77 | |||
78 | if (version_compare($latestKnownVersion, $currentVersion) == 1) { | ||
79 | return $latestKnownVersion; | ||
80 | } | ||
81 | return false; | ||
82 | } | ||
83 | |||
84 | if (! in_array($branch, self::$GIT_BRANCHES)) { | ||
85 | throw new Exception( | ||
86 | 'Invalid branch selected for updates: "' . $branch . '"' | ||
87 | ); | ||
88 | } | ||
89 | |||
90 | // Late Static Binding allows overriding within tests | ||
91 | // See http://php.net/manual/en/language.oop5.late-static-bindings.php | ||
92 | $latestVersion = static::getLatestGitVersionCode( | ||
93 | self::$GIT_URL . '/' . $branch . '/' . self::$VERSION_FILE | ||
94 | ); | ||
95 | |||
96 | if (! $latestVersion) { | ||
97 | // Only update the file's modification date | ||
98 | file_put_contents($updateFile, $currentVersion); | ||
99 | return false; | ||
100 | } | ||
101 | |||
102 | // Update the file's content and modification date | ||
103 | file_put_contents($updateFile, $latestVersion); | ||
104 | |||
105 | if (version_compare($latestVersion, $currentVersion) == 1) { | ||
106 | return $latestVersion; | ||
107 | } | ||
108 | |||
109 | return false; | ||
110 | } | ||
7 | 111 | ||
8 | /** | 112 | /** |
9 | * Checks the PHP version to ensure Shaarli can run | 113 | * Checks the PHP version to ensure Shaarli can run |
diff --git a/application/LinkDB.php b/application/LinkDB.php index 15fadbc3..f771ac8b 100644 --- a/application/LinkDB.php +++ b/application/LinkDB.php | |||
@@ -57,18 +57,25 @@ class LinkDB implements Iterator, Countable, ArrayAccess | |||
57 | // Hide public links | 57 | // Hide public links |
58 | private $_hidePublicLinks; | 58 | private $_hidePublicLinks; |
59 | 59 | ||
60 | // link redirector set in user settings. | ||
61 | private $_redirector; | ||
62 | |||
60 | /** | 63 | /** |
61 | * Creates a new LinkDB | 64 | * Creates a new LinkDB |
62 | * | 65 | * |
63 | * Checks if the datastore exists; else, attempts to create a dummy one. | 66 | * Checks if the datastore exists; else, attempts to create a dummy one. |
64 | * | 67 | * |
65 | * @param $isLoggedIn is the user logged in? | 68 | * @param string $datastore datastore file path. |
69 | * @param boolean $isLoggedIn is the user logged in? | ||
70 | * @param boolean $hidePublicLinks if true all links are private. | ||
71 | * @param string $redirector link redirector set in user settings. | ||
66 | */ | 72 | */ |
67 | function __construct($datastore, $isLoggedIn, $hidePublicLinks) | 73 | function __construct($datastore, $isLoggedIn, $hidePublicLinks, $redirector = '') |
68 | { | 74 | { |
69 | $this->_datastore = $datastore; | 75 | $this->_datastore = $datastore; |
70 | $this->_loggedIn = $isLoggedIn; | 76 | $this->_loggedIn = $isLoggedIn; |
71 | $this->_hidePublicLinks = $hidePublicLinks; | 77 | $this->_hidePublicLinks = $hidePublicLinks; |
78 | $this->_redirector = $redirector; | ||
72 | $this->_checkDB(); | 79 | $this->_checkDB(); |
73 | $this->_readDB(); | 80 | $this->_readDB(); |
74 | } | 81 | } |
@@ -259,7 +266,14 @@ You use the community supported version of the original Shaarli project, by Seba | |||
259 | 266 | ||
260 | // Escape links data | 267 | // Escape links data |
261 | foreach($this->_links as &$link) { | 268 | foreach($this->_links as &$link) { |
262 | sanitizeLink($link); | 269 | sanitizeLink($link); |
270 | // Do not use the redirector for internal links (Shaarli note URL starting with a '?'). | ||
271 | if (!empty($this->_redirector) && !startsWith($link['url'], '?')) { | ||
272 | $link['real_url'] = $this->_redirector . urlencode($link['url']); | ||
273 | } | ||
274 | else { | ||
275 | $link['real_url'] = $link['url']; | ||
276 | } | ||
263 | } | 277 | } |
264 | } | 278 | } |
265 | 279 | ||
diff --git a/application/Utils.php b/application/Utils.php index b8579b48..f84f70e4 100644 --- a/application/Utils.php +++ b/application/Utils.php | |||
@@ -148,3 +148,56 @@ function is_session_id_valid($sessionId) | |||
148 | 148 | ||
149 | return true; | 149 | return true; |
150 | } | 150 | } |
151 | |||
152 | /** | ||
153 | * In a string, converts URLs to clickable links. | ||
154 | * | ||
155 | * @param string $text input string. | ||
156 | * @param string $redirector if a redirector is set, use it to gerenate links. | ||
157 | * | ||
158 | * @return string returns $text with all links converted to HTML links. | ||
159 | * | ||
160 | * @see Function inspired from http://www.php.net/manual/en/function.preg-replace.php#85722 | ||
161 | */ | ||
162 | function text2clickable($text, $redirector) | ||
163 | { | ||
164 | $regex = '!(((?:https?|ftp|file)://|apt:|magnet:)\S+[[:alnum:]]/?)!si'; | ||
165 | |||
166 | if (empty($redirector)) { | ||
167 | return preg_replace($regex, '<a href="$1">$1</a>', $text); | ||
168 | } | ||
169 | // Redirector is set, urlencode the final URL. | ||
170 | return preg_replace_callback( | ||
171 | $regex, | ||
172 | function ($matches) use ($redirector) { | ||
173 | return '<a href="' . $redirector . urlencode($matches[1]) .'">'. $matches[1] .'</a>'; | ||
174 | }, | ||
175 | $text | ||
176 | ); | ||
177 | } | ||
178 | |||
179 | /** | ||
180 | * This function inserts where relevant so that multiple spaces are properly displayed in HTML | ||
181 | * even in the absence of <pre> (This is used in description to keep text formatting). | ||
182 | * | ||
183 | * @param string $text input text. | ||
184 | * | ||
185 | * @return string formatted text. | ||
186 | */ | ||
187 | function space2nbsp($text) | ||
188 | { | ||
189 | return preg_replace('/(^| ) /m', '$1 ', $text); | ||
190 | } | ||
191 | |||
192 | /** | ||
193 | * Format Shaarli's description | ||
194 | * TODO: Move me to ApplicationUtils when it's ready. | ||
195 | * | ||
196 | * @param string $description shaare's description. | ||
197 | * @param string $redirector if a redirector is set, use it to gerenate links. | ||
198 | * | ||
199 | * @return string formatted description. | ||
200 | */ | ||
201 | function format_description($description, $redirector) { | ||
202 | return nl2br(space2nbsp(text2clickable($description, $redirector))); | ||
203 | } | ||
@@ -1,6 +1,6 @@ | |||
1 | <?php | 1 | <?php |
2 | /** | 2 | /** |
3 | * Shaarli v0.6.0 - Shaare your links... | 3 | * Shaarli v0.6.1 - Shaare your links... |
4 | * | 4 | * |
5 | * The personal, minimalist, super-fast, no-database Delicious clone. | 5 | * The personal, minimalist, super-fast, no-database Delicious clone. |
6 | * | 6 | * |
@@ -92,7 +92,8 @@ $GLOBALS['config']['ENABLE_THUMBNAILS'] = true; | |||
92 | $GLOBALS['config']['ENABLE_LOCALCACHE'] = true; | 92 | $GLOBALS['config']['ENABLE_LOCALCACHE'] = true; |
93 | 93 | ||
94 | // Update check frequency for Shaarli. 86400 seconds=24 hours | 94 | // Update check frequency for Shaarli. 86400 seconds=24 hours |
95 | $GLOBALS['config']['UPDATECHECK_INTERVAL'] = 86400 ; | 95 | $GLOBALS['config']['UPDATECHECK_BRANCH'] = 'stable'; |
96 | $GLOBALS['config']['UPDATECHECK_INTERVAL'] = 86400; | ||
96 | 97 | ||
97 | 98 | ||
98 | /* | 99 | /* |
@@ -118,7 +119,7 @@ $GLOBALS['config']['PUBSUBHUB_URL'] = ''; | |||
118 | /* | 119 | /* |
119 | * PHP configuration | 120 | * PHP configuration |
120 | */ | 121 | */ |
121 | define('shaarli_version', '0.6.0'); | 122 | define('shaarli_version', '0.6.1'); |
122 | 123 | ||
123 | // http://server.com/x/shaarli --> /shaarli/ | 124 | // http://server.com/x/shaarli --> /shaarli/ |
124 | define('WEB_PATH', substr($_SERVER["REQUEST_URI"], 0, 1+strrpos($_SERVER["REQUEST_URI"], '/', 0))); | 125 | define('WEB_PATH', substr($_SERVER["REQUEST_URI"], 0, 1+strrpos($_SERVER["REQUEST_URI"], '/', 0))); |
@@ -305,56 +306,15 @@ function setup_login_state() { | |||
305 | } | 306 | } |
306 | $userIsLoggedIn = setup_login_state(); | 307 | $userIsLoggedIn = setup_login_state(); |
307 | 308 | ||
308 | // Checks if an update is available for Shaarli. | ||
309 | // (at most once a day, and only for registered user.) | ||
310 | // Output: '' = no new version. | ||
311 | // other= the available version. | ||
312 | function checkUpdate() | ||
313 | { | ||
314 | if (!isLoggedIn()) return ''; // Do not check versions for visitors. | ||
315 | if (empty($GLOBALS['config']['ENABLE_UPDATECHECK'])) return ''; // Do not check if the user doesn't want to. | ||
316 | |||
317 | // Get latest version number at most once a day. | ||
318 | if (!is_file($GLOBALS['config']['UPDATECHECK_FILENAME']) || (filemtime($GLOBALS['config']['UPDATECHECK_FILENAME'])<time()-($GLOBALS['config']['UPDATECHECK_INTERVAL']))) | ||
319 | { | ||
320 | $version = shaarli_version; | ||
321 | list($headers, $data) = get_http_url('https://raw.githubusercontent.com/shaarli/Shaarli/master/shaarli_version.php', 2); | ||
322 | if (strpos($headers[0], '200 OK') !== false) { | ||
323 | $version = str_replace(' */ ?>', '', str_replace('<?php /* ', '', $data)); | ||
324 | } | ||
325 | // If failed, never mind. We don't want to bother the user with that. | ||
326 | file_put_contents($GLOBALS['config']['UPDATECHECK_FILENAME'],$version); // touch file date | ||
327 | } | ||
328 | // Compare versions: | ||
329 | $newestversion=file_get_contents($GLOBALS['config']['UPDATECHECK_FILENAME']); | ||
330 | if (version_compare($newestversion,shaarli_version)==1) return $newestversion; | ||
331 | return ''; | ||
332 | } | ||
333 | |||
334 | 309 | ||
335 | // ----------------------------------------------------------------------------------------------- | 310 | // ----------------------------------------------------------------------------------------------- |
336 | // Log to text file | 311 | // Log to text file |
337 | function logm($message) | 312 | function logm($message) |
338 | { | 313 | { |
339 | $t = strval(date('Y/m/d_H:i:s')).' - '.$_SERVER["REMOTE_ADDR"].' - '.strval($message)."\n"; | 314 | $t = strval(date('Y/m/d_H:i:s')).' - '.$_SERVER["REMOTE_ADDR"].' - '.strval($message)."\n"; |
340 | file_put_contents($GLOBAL['config']['LOG_FILE'], $t, FILE_APPEND); | 315 | file_put_contents($GLOBALS['config']['LOG_FILE'], $t, FILE_APPEND); |
341 | } | ||
342 | |||
343 | // In a string, converts URLs to clickable links. | ||
344 | // Function inspired from http://www.php.net/manual/en/function.preg-replace.php#85722 | ||
345 | function text2clickable($url) | ||
346 | { | ||
347 | $redir = empty($GLOBALS['redirector']) ? '' : $GLOBALS['redirector']; | ||
348 | return preg_replace('!(((?:https?|ftp|file)://|apt:|magnet:)\S+[[:alnum:]]/?)!si','<a href="'.$redir.'$1" rel="nofollow">$1</a>',$url); | ||
349 | } | 316 | } |
350 | 317 | ||
351 | // This function inserts where relevant so that multiple spaces are properly displayed in HTML | ||
352 | // even in the absence of <pre> (This is used in description to keep text formatting) | ||
353 | function keepMultipleSpaces($text) | ||
354 | { | ||
355 | return str_replace(' ',' ',$text); | ||
356 | |||
357 | } | ||
358 | // ------------------------------------------------------------------------------------------ | 318 | // ------------------------------------------------------------------------------------------ |
359 | // Sniff browser language to display dates in the right format automatically. | 319 | // Sniff browser language to display dates in the right format automatically. |
360 | // (Note that is may not work on your server if the corresponding local is not installed.) | 320 | // (Note that is may not work on your server if the corresponding local is not installed.) |
@@ -672,7 +632,25 @@ class pageBuilder | |||
672 | private function initialize() | 632 | private function initialize() |
673 | { | 633 | { |
674 | $this->tpl = new RainTPL; | 634 | $this->tpl = new RainTPL; |
675 | $this->tpl->assign('newversion', escape(checkUpdate())); | 635 | |
636 | try { | ||
637 | $version = ApplicationUtils::checkUpdate( | ||
638 | shaarli_version, | ||
639 | $GLOBALS['config']['UPDATECHECK_FILENAME'], | ||
640 | $GLOBALS['config']['UPDATECHECK_INTERVAL'], | ||
641 | $GLOBALS['config']['ENABLE_UPDATECHECK'], | ||
642 | isLoggedIn(), | ||
643 | $GLOBALS['config']['UPDATECHECK_BRANCH'] | ||
644 | ); | ||
645 | $this->tpl->assign('newVersion', escape($version)); | ||
646 | $this->tpl->assign('versionError', ''); | ||
647 | |||
648 | } catch (Exception $exc) { | ||
649 | logm($exc->getMessage()); | ||
650 | $this->tpl->assign('newVersion', ''); | ||
651 | $this->tpl->assign('versionError', escape($exc->getMessage())); | ||
652 | } | ||
653 | |||
676 | $this->tpl->assign('feedurl', escape(index_url($_SERVER))); | 654 | $this->tpl->assign('feedurl', escape(index_url($_SERVER))); |
677 | $searchcrits = ''; // Search criteria | 655 | $searchcrits = ''; // Search criteria |
678 | if (!empty($_GET['searchtags'])) { | 656 | if (!empty($_GET['searchtags'])) { |
@@ -746,7 +724,8 @@ function showRSS() | |||
746 | $LINKSDB = new LinkDB( | 724 | $LINKSDB = new LinkDB( |
747 | $GLOBALS['config']['DATASTORE'], | 725 | $GLOBALS['config']['DATASTORE'], |
748 | isLoggedIn(), | 726 | isLoggedIn(), |
749 | $GLOBALS['config']['HIDE_PUBLIC_LINKS'] | 727 | $GLOBALS['config']['HIDE_PUBLIC_LINKS'], |
728 | $GLOBALS['redirector'] | ||
750 | ); | 729 | ); |
751 | // Read links from database (and filter private links if user it not logged in). | 730 | // Read links from database (and filter private links if user it not logged in). |
752 | 731 | ||
@@ -797,7 +776,9 @@ function showRSS() | |||
797 | // If user wants permalinks first, put the final link in description | 776 | // If user wants permalinks first, put the final link in description |
798 | if ($usepermalinks===true) $descriptionlink = '(<a href="'.$absurl.'">Link</a>)'; | 777 | if ($usepermalinks===true) $descriptionlink = '(<a href="'.$absurl.'">Link</a>)'; |
799 | if (strlen($link['description'])>0) $descriptionlink = '<br>'.$descriptionlink; | 778 | if (strlen($link['description'])>0) $descriptionlink = '<br>'.$descriptionlink; |
800 | echo '<description><![CDATA['.nl2br(keepMultipleSpaces(text2clickable($link['description']))).$descriptionlink.']]></description>'."\n</item>\n"; | 779 | echo '<description><![CDATA['. |
780 | format_description($link['description'], $GLOBALS['redirector']) . | ||
781 | $descriptionlink . ']]></description>' . "\n</item>\n"; | ||
801 | $i++; | 782 | $i++; |
802 | } | 783 | } |
803 | echo '</channel></rss><!-- Cached version of '.escape(page_url($_SERVER)).' -->'; | 784 | echo '</channel></rss><!-- Cached version of '.escape(page_url($_SERVER)).' -->'; |
@@ -835,7 +816,8 @@ function showATOM() | |||
835 | $LINKSDB = new LinkDB( | 816 | $LINKSDB = new LinkDB( |
836 | $GLOBALS['config']['DATASTORE'], | 817 | $GLOBALS['config']['DATASTORE'], |
837 | isLoggedIn(), | 818 | isLoggedIn(), |
838 | $GLOBALS['config']['HIDE_PUBLIC_LINKS'] | 819 | $GLOBALS['config']['HIDE_PUBLIC_LINKS'], |
820 | $GLOBALS['redirector'] | ||
839 | ); | 821 | ); |
840 | 822 | ||
841 | // Optionally filter the results: | 823 | // Optionally filter the results: |
@@ -876,7 +858,9 @@ function showATOM() | |||
876 | if ($usepermalinks===true) $descriptionlink = '(<a href="'.$absurl.'">Link</a>)'; | 858 | if ($usepermalinks===true) $descriptionlink = '(<a href="'.$absurl.'">Link</a>)'; |
877 | if (strlen($link['description'])>0) $descriptionlink = '<br>'.$descriptionlink; | 859 | if (strlen($link['description'])>0) $descriptionlink = '<br>'.$descriptionlink; |
878 | 860 | ||
879 | $entries.='<content type="html"><![CDATA['.nl2br(keepMultipleSpaces(text2clickable($link['description']))).$descriptionlink."]]></content>\n"; | 861 | $entries .= '<content type="html"><![CDATA['. |
862 | format_description($link['description'], $GLOBALS['redirector']) . | ||
863 | $descriptionlink . "]]></content>\n"; | ||
880 | if ($link['tags']!='') // Adding tags to each ATOM entry (as mentioned in ATOM specification) | 864 | if ($link['tags']!='') // Adding tags to each ATOM entry (as mentioned in ATOM specification) |
881 | { | 865 | { |
882 | foreach(explode(' ',$link['tags']) as $tag) | 866 | foreach(explode(' ',$link['tags']) as $tag) |
@@ -929,7 +913,8 @@ function showDailyRSS() { | |||
929 | $LINKSDB = new LinkDB( | 913 | $LINKSDB = new LinkDB( |
930 | $GLOBALS['config']['DATASTORE'], | 914 | $GLOBALS['config']['DATASTORE'], |
931 | isLoggedIn(), | 915 | isLoggedIn(), |
932 | $GLOBALS['config']['HIDE_PUBLIC_LINKS'] | 916 | $GLOBALS['config']['HIDE_PUBLIC_LINKS'], |
917 | $GLOBALS['redirector'] | ||
933 | ); | 918 | ); |
934 | 919 | ||
935 | /* Some Shaarlies may have very few links, so we need to look | 920 | /* Some Shaarlies may have very few links, so we need to look |
@@ -983,7 +968,7 @@ function showDailyRSS() { | |||
983 | // We pre-format some fields for proper output. | 968 | // We pre-format some fields for proper output. |
984 | foreach ($linkdates as $linkdate) { | 969 | foreach ($linkdates as $linkdate) { |
985 | $l = $LINKSDB[$linkdate]; | 970 | $l = $LINKSDB[$linkdate]; |
986 | $l['formatedDescription'] = nl2br(keepMultipleSpaces(text2clickable($l['description']))); | 971 | $l['formatedDescription'] = format_description($l['description'], $GLOBALS['redirector']); |
987 | $l['thumbnail'] = thumbnail($l['url']); | 972 | $l['thumbnail'] = thumbnail($l['url']); |
988 | $l['timestamp'] = linkdate2timestamp($l['linkdate']); | 973 | $l['timestamp'] = linkdate2timestamp($l['linkdate']); |
989 | if (startsWith($l['url'], '?')) { | 974 | if (startsWith($l['url'], '?')) { |
@@ -1016,7 +1001,8 @@ function showDaily() | |||
1016 | $LINKSDB = new LinkDB( | 1001 | $LINKSDB = new LinkDB( |
1017 | $GLOBALS['config']['DATASTORE'], | 1002 | $GLOBALS['config']['DATASTORE'], |
1018 | isLoggedIn(), | 1003 | isLoggedIn(), |
1019 | $GLOBALS['config']['HIDE_PUBLIC_LINKS'] | 1004 | $GLOBALS['config']['HIDE_PUBLIC_LINKS'], |
1005 | $GLOBALS['redirector'] | ||
1020 | ); | 1006 | ); |
1021 | 1007 | ||
1022 | $day=Date('Ymd',strtotime('-1 day')); // Yesterday, in format YYYYMMDD. | 1008 | $day=Date('Ymd',strtotime('-1 day')); // Yesterday, in format YYYYMMDD. |
@@ -1047,7 +1033,7 @@ function showDaily() | |||
1047 | $taglist = explode(' ',$link['tags']); | 1033 | $taglist = explode(' ',$link['tags']); |
1048 | uasort($taglist, 'strcasecmp'); | 1034 | uasort($taglist, 'strcasecmp'); |
1049 | $linksToDisplay[$key]['taglist']=$taglist; | 1035 | $linksToDisplay[$key]['taglist']=$taglist; |
1050 | $linksToDisplay[$key]['formatedDescription']=nl2br(keepMultipleSpaces(text2clickable($link['description']))); | 1036 | $linksToDisplay[$key]['formatedDescription'] = format_description($link['description'], $GLOBALS['redirector']); |
1051 | $linksToDisplay[$key]['thumbnail'] = thumbnail($link['url']); | 1037 | $linksToDisplay[$key]['thumbnail'] = thumbnail($link['url']); |
1052 | $linksToDisplay[$key]['timestamp'] = linkdate2timestamp($link['linkdate']); | 1038 | $linksToDisplay[$key]['timestamp'] = linkdate2timestamp($link['linkdate']); |
1053 | } | 1039 | } |
@@ -1107,7 +1093,8 @@ function renderPage() | |||
1107 | $LINKSDB = new LinkDB( | 1093 | $LINKSDB = new LinkDB( |
1108 | $GLOBALS['config']['DATASTORE'], | 1094 | $GLOBALS['config']['DATASTORE'], |
1109 | isLoggedIn(), | 1095 | isLoggedIn(), |
1110 | $GLOBALS['config']['HIDE_PUBLIC_LINKS'] | 1096 | $GLOBALS['config']['HIDE_PUBLIC_LINKS'], |
1097 | $GLOBALS['redirector'] | ||
1111 | ); | 1098 | ); |
1112 | 1099 | ||
1113 | $PAGE = new pageBuilder; | 1100 | $PAGE = new pageBuilder; |
@@ -1781,7 +1768,8 @@ function importFile() | |||
1781 | $LINKSDB = new LinkDB( | 1768 | $LINKSDB = new LinkDB( |
1782 | $GLOBALS['config']['DATASTORE'], | 1769 | $GLOBALS['config']['DATASTORE'], |
1783 | isLoggedIn(), | 1770 | isLoggedIn(), |
1784 | $GLOBALS['config']['HIDE_PUBLIC_LINKS'] | 1771 | $GLOBALS['config']['HIDE_PUBLIC_LINKS'], |
1772 | $GLOBALS['redirector'] | ||
1785 | ); | 1773 | ); |
1786 | $filename=$_FILES['filetoupload']['name']; | 1774 | $filename=$_FILES['filetoupload']['name']; |
1787 | $filesize=$_FILES['filetoupload']['size']; | 1775 | $filesize=$_FILES['filetoupload']['size']; |
@@ -1932,8 +1920,7 @@ function buildLinkList($PAGE,$LINKSDB) | |||
1932 | while ($i<$end && $i<count($keys)) | 1920 | while ($i<$end && $i<count($keys)) |
1933 | { | 1921 | { |
1934 | $link = $linksToDisplay[$keys[$i]]; | 1922 | $link = $linksToDisplay[$keys[$i]]; |
1935 | $link['description']=nl2br(keepMultipleSpaces(text2clickable($link['description']))); | 1923 | $link['description'] = format_description($link['description'], $GLOBALS['redirector']); |
1936 | $title=$link['title']; | ||
1937 | $classLi = $i%2!=0 ? '' : 'publicLinkHightLight'; | 1924 | $classLi = $i%2!=0 ? '' : 'publicLinkHightLight'; |
1938 | $link['class'] = ($link['private']==0 ? $classLi : 'private'); | 1925 | $link['class'] = ($link['private']==0 ? $classLi : 'private'); |
1939 | $link['timestamp']=linkdate2timestamp($link['linkdate']); | 1926 | $link['timestamp']=linkdate2timestamp($link['linkdate']); |
@@ -1974,6 +1961,10 @@ function buildLinkList($PAGE,$LINKSDB) | |||
1974 | 'links' => $linkDisp, | 1961 | 'links' => $linkDisp, |
1975 | 'tags' => $LINKSDB->allTags(), | 1962 | 'tags' => $LINKSDB->allTags(), |
1976 | ); | 1963 | ); |
1964 | // FIXME! temporary fix - see #399. | ||
1965 | if (!empty($GLOBALS['pagetitle']) && count($linkDisp) == 1) { | ||
1966 | $data['pagetitle'] = $GLOBALS['pagetitle']; | ||
1967 | } | ||
1977 | 1968 | ||
1978 | $pluginManager = PluginManager::getInstance(); | 1969 | $pluginManager = PluginManager::getInstance(); |
1979 | $pluginManager->executeHooks('render_linklist', $data, array('loggedin' => isLoggedIn())); | 1970 | $pluginManager->executeHooks('render_linklist', $data, array('loggedin' => isLoggedIn())); |
diff --git a/plugins/playvideos/README.md b/plugins/playvideos/README.md index ec1ead8d..b1698470 100644 --- a/plugins/playvideos/README.md +++ b/plugins/playvideos/README.md | |||
@@ -1,21 +1,29 @@ | |||
1 | ### â–º Play Videos plugin for Shaarli | 1 | ### â–º Play Videos plugin for Shaarli |
2 | 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... | ||
3 | 2 | ||
4 | This uses code from https://zaius.github.io/youtube_playlist/ and is currently only compatible with Youtube videos. | 3 | 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... |
4 | |||
5 | <!-- TODO screenshot --> | ||
5 | 6 | ||
6 | ![](https://cdn.mediacru.sh/D_izf0zjAtxy.png) | 7 | This uses code from https://zaius.github.io/youtube_playlist/ and is currently only compatible with Youtube videos. |
7 | 8 | ||
8 | #### Installation and setup | 9 | #### Installation and setup |
9 | Place the files in the `tpl/plugins/playvideos/` directory of your Shaarli. | ||
10 | This is a default Shaarli plugin, you just have to enable it. | ||
11 | 10 | ||
12 | To enable the plugin, add `playvideos` to the `TOOLBAR_PLUGINS` config option in your `index.php` or `data/options.php`. Example: | 11 | This is a default Shaarli plugin, you just have to enable it. See https://github.com/shaarli/Shaarli/wiki/Shaarli-configuration/ |
13 | 12 | ||
14 | $GLOBALS['config']['TOOLBAR_PLUGINS'] = array('aplugins', 'anotherone', 'playvideos'); | ||
15 | 13 | ||
16 | #### Troubleshooting | 14 | #### Troubleshooting |
15 | |||
17 | 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: | 16 | 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: |
18 | `Header set Content-Security-Policy "script-src 'self' 'unsafe-inline' https://www.youtube.com https://s.ytimg.com 'unsafe-eval'"` | 17 | |
18 | In `/etc/apache2/conf-available/shaarli-csp.conf`: | ||
19 | |||
20 | ```apache | ||
21 | <Directory /path/to/shaarli> | ||
22 | Header set Content-Security-Policy "script-src 'self' 'unsafe-inline' https://www.youtube.com https://s.ytimg.com 'unsafe-eval'" | ||
23 | </Directory> | ||
24 | ``` | ||
25 | |||
26 | Then run `a2enconf shaarli-csp; service apache2 reload` | ||
19 | 27 | ||
20 | ### License | 28 | ### License |
21 | ``` | 29 | ``` |
@@ -68,4 +76,4 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |||
68 | THE SOFTWARE. | 76 | THE SOFTWARE. |
69 | 77 | ||
70 | ---------------------------------------------------- | 78 | ---------------------------------------------------- |
71 | ``` \ No newline at end of file | 79 | ``` |
diff --git a/plugins/qrcode/qrcode.php b/plugins/qrcode/qrcode.php index 1080c964..5f6e76a2 100644 --- a/plugins/qrcode/qrcode.php +++ b/plugins/qrcode/qrcode.php | |||
@@ -17,7 +17,7 @@ function hook_qrcode_render_linklist($data) | |||
17 | $qrcode_html = file_get_contents(PluginManager::$PLUGINS_PATH . '/qrcode/qrcode.html'); | 17 | $qrcode_html = file_get_contents(PluginManager::$PLUGINS_PATH . '/qrcode/qrcode.html'); |
18 | 18 | ||
19 | foreach ($data['links'] as &$value) { | 19 | foreach ($data['links'] as &$value) { |
20 | $qrcode = sprintf($qrcode_html, $value['url'], $value['url'], PluginManager::$PLUGINS_PATH); | 20 | $qrcode = sprintf($qrcode_html, $value['real_url'], $value['real_url'], PluginManager::$PLUGINS_PATH); |
21 | $value['link_plugin'][] = $qrcode; | 21 | $value['link_plugin'][] = $qrcode; |
22 | } | 22 | } |
23 | 23 | ||
diff --git a/shaarli_version.php b/shaarli_version.php index a5f0a095..11ad87d7 100644 --- a/shaarli_version.php +++ b/shaarli_version.php | |||
@@ -1 +1 @@ | |||
<?php /* 0.6.0 */ ?> | <?php /* 0.6.1 */ ?> | ||
diff --git a/tests/ApplicationUtilsTest.php b/tests/ApplicationUtilsTest.php index 01301e68..6064357d 100644 --- a/tests/ApplicationUtilsTest.php +++ b/tests/ApplicationUtilsTest.php | |||
@@ -5,12 +5,240 @@ | |||
5 | 5 | ||
6 | require_once 'application/ApplicationUtils.php'; | 6 | require_once 'application/ApplicationUtils.php'; |
7 | 7 | ||
8 | /** | ||
9 | * Fake ApplicationUtils class to avoid HTTP requests | ||
10 | */ | ||
11 | class FakeApplicationUtils extends ApplicationUtils | ||
12 | { | ||
13 | public static $VERSION_CODE = ''; | ||
14 | |||
15 | /** | ||
16 | * Toggle HTTP requests, allow overriding the version code | ||
17 | */ | ||
18 | public static function getLatestGitVersionCode($url, $timeout=0) | ||
19 | { | ||
20 | return self::$VERSION_CODE; | ||
21 | } | ||
22 | } | ||
23 | |||
8 | 24 | ||
9 | /** | 25 | /** |
10 | * Unitary tests for Shaarli utilities | 26 | * Unitary tests for Shaarli utilities |
11 | */ | 27 | */ |
12 | class ApplicationUtilsTest extends PHPUnit_Framework_TestCase | 28 | class ApplicationUtilsTest extends PHPUnit_Framework_TestCase |
13 | { | 29 | { |
30 | protected static $testUpdateFile = 'sandbox/update.txt'; | ||
31 | protected static $testVersion = '0.5.0'; | ||
32 | protected static $versionPattern = '/^\d+\.\d+\.\d+$/'; | ||
33 | |||
34 | /** | ||
35 | * Reset test data for each test | ||
36 | */ | ||
37 | public function setUp() | ||
38 | { | ||
39 | FakeApplicationUtils::$VERSION_CODE = ''; | ||
40 | if (file_exists(self::$testUpdateFile)) { | ||
41 | unlink(self::$testUpdateFile); | ||
42 | } | ||
43 | } | ||
44 | |||
45 | /** | ||
46 | * Retrieve the latest version code available on Git | ||
47 | * | ||
48 | * Expected format: Semantic Versioning - major.minor.patch | ||
49 | */ | ||
50 | public function testGetLatestGitVersionCode() | ||
51 | { | ||
52 | $testTimeout = 10; | ||
53 | |||
54 | $this->assertEquals( | ||
55 | '0.5.4', | ||
56 | ApplicationUtils::getLatestGitVersionCode( | ||
57 | 'https://raw.githubusercontent.com/shaarli/Shaarli/' | ||
58 | .'v0.5.4/shaarli_version.php', | ||
59 | $testTimeout | ||
60 | ) | ||
61 | ); | ||
62 | $this->assertRegexp( | ||
63 | self::$versionPattern, | ||
64 | ApplicationUtils::getLatestGitVersionCode( | ||
65 | 'https://raw.githubusercontent.com/shaarli/Shaarli/' | ||
66 | .'master/shaarli_version.php', | ||
67 | $testTimeout | ||
68 | ) | ||
69 | ); | ||
70 | } | ||
71 | |||
72 | /** | ||
73 | * Attempt to retrieve the latest version from an invalid URL | ||
74 | */ | ||
75 | public function testGetLatestGitVersionCodeInvalidUrl() | ||
76 | { | ||
77 | $this->assertFalse( | ||
78 | ApplicationUtils::getLatestGitVersionCode('htttp://null.io', 1) | ||
79 | ); | ||
80 | } | ||
81 | |||
82 | /** | ||
83 | * Test update checks - the user is logged off | ||
84 | */ | ||
85 | public function testCheckUpdateLoggedOff() | ||
86 | { | ||
87 | $this->assertFalse( | ||
88 | ApplicationUtils::checkUpdate(self::$testVersion, 'null', 0, false, false) | ||
89 | ); | ||
90 | } | ||
91 | |||
92 | /** | ||
93 | * Test update checks - the user has disabled updates | ||
94 | */ | ||
95 | public function testCheckUpdateUserDisabled() | ||
96 | { | ||
97 | $this->assertFalse( | ||
98 | ApplicationUtils::checkUpdate(self::$testVersion, 'null', 0, false, true) | ||
99 | ); | ||
100 | } | ||
101 | |||
102 | /** | ||
103 | * A newer version is available | ||
104 | */ | ||
105 | public function testCheckUpdateNewVersionAvailable() | ||
106 | { | ||
107 | $newVersion = '1.8.3'; | ||
108 | FakeApplicationUtils::$VERSION_CODE = $newVersion; | ||
109 | |||
110 | $version = FakeApplicationUtils::checkUpdate( | ||
111 | self::$testVersion, | ||
112 | self::$testUpdateFile, | ||
113 | 100, | ||
114 | true, | ||
115 | true | ||
116 | ); | ||
117 | |||
118 | $this->assertEquals($newVersion, $version); | ||
119 | } | ||
120 | |||
121 | /** | ||
122 | * No available information about versions | ||
123 | */ | ||
124 | public function testCheckUpdateNewVersionUnavailable() | ||
125 | { | ||
126 | $version = FakeApplicationUtils::checkUpdate( | ||
127 | self::$testVersion, | ||
128 | self::$testUpdateFile, | ||
129 | 100, | ||
130 | true, | ||
131 | true | ||
132 | ); | ||
133 | |||
134 | $this->assertFalse($version); | ||
135 | } | ||
136 | |||
137 | /** | ||
138 | * Test update checks - invalid Git branch | ||
139 | * @expectedException Exception | ||
140 | * @expectedExceptionMessageRegExp /Invalid branch selected for updates/ | ||
141 | */ | ||
142 | public function testCheckUpdateInvalidGitBranch() | ||
143 | { | ||
144 | ApplicationUtils::checkUpdate('', 'null', 0, true, true, 'unstable'); | ||
145 | } | ||
146 | |||
147 | /** | ||
148 | * Shaarli is up-to-date | ||
149 | */ | ||
150 | public function testCheckUpdateNewVersionUpToDate() | ||
151 | { | ||
152 | FakeApplicationUtils::$VERSION_CODE = self::$testVersion; | ||
153 | |||
154 | $version = FakeApplicationUtils::checkUpdate( | ||
155 | self::$testVersion, | ||
156 | self::$testUpdateFile, | ||
157 | 100, | ||
158 | true, | ||
159 | true | ||
160 | ); | ||
161 | |||
162 | $this->assertFalse($version); | ||
163 | } | ||
164 | |||
165 | /** | ||
166 | * Time-traveller's Shaarli | ||
167 | */ | ||
168 | public function testCheckUpdateNewVersionMaartiMcFly() | ||
169 | { | ||
170 | FakeApplicationUtils::$VERSION_CODE = '0.4.1'; | ||
171 | |||
172 | $version = FakeApplicationUtils::checkUpdate( | ||
173 | self::$testVersion, | ||
174 | self::$testUpdateFile, | ||
175 | 100, | ||
176 | true, | ||
177 | true | ||
178 | ); | ||
179 | |||
180 | $this->assertFalse($version); | ||
181 | } | ||
182 | |||
183 | /** | ||
184 | * The version has been checked recently and Shaarli is up-to-date | ||
185 | */ | ||
186 | public function testCheckUpdateNewVersionTwiceUpToDate() | ||
187 | { | ||
188 | FakeApplicationUtils::$VERSION_CODE = self::$testVersion; | ||
189 | |||
190 | // Create the update file | ||
191 | $version = FakeApplicationUtils::checkUpdate( | ||
192 | self::$testVersion, | ||
193 | self::$testUpdateFile, | ||
194 | 100, | ||
195 | true, | ||
196 | true | ||
197 | ); | ||
198 | |||
199 | $this->assertFalse($version); | ||
200 | |||
201 | // Reuse the update file | ||
202 | $version = FakeApplicationUtils::checkUpdate( | ||
203 | self::$testVersion, | ||
204 | self::$testUpdateFile, | ||
205 | 100, | ||
206 | true, | ||
207 | true | ||
208 | ); | ||
209 | |||
210 | $this->assertFalse($version); | ||
211 | } | ||
212 | |||
213 | /** | ||
214 | * The version has been checked recently and Shaarli is outdated | ||
215 | */ | ||
216 | public function testCheckUpdateNewVersionTwiceOutdated() | ||
217 | { | ||
218 | $newVersion = '1.8.3'; | ||
219 | FakeApplicationUtils::$VERSION_CODE = $newVersion; | ||
220 | |||
221 | // Create the update file | ||
222 | $version = FakeApplicationUtils::checkUpdate( | ||
223 | self::$testVersion, | ||
224 | self::$testUpdateFile, | ||
225 | 100, | ||
226 | true, | ||
227 | true | ||
228 | ); | ||
229 | $this->assertEquals($newVersion, $version); | ||
230 | |||
231 | // Reuse the update file | ||
232 | $version = FakeApplicationUtils::checkUpdate( | ||
233 | self::$testVersion, | ||
234 | self::$testUpdateFile, | ||
235 | 100, | ||
236 | true, | ||
237 | true | ||
238 | ); | ||
239 | $this->assertEquals($newVersion, $version); | ||
240 | } | ||
241 | |||
14 | /** | 242 | /** |
15 | * Check supported PHP versions | 243 | * Check supported PHP versions |
16 | */ | 244 | */ |
diff --git a/tests/CacheTest.php b/tests/CacheTest.php index aa5395b0..26c43225 100644 --- a/tests/CacheTest.php +++ b/tests/CacheTest.php | |||
@@ -11,10 +11,10 @@ require_once 'application/Cache.php'; | |||
11 | /** | 11 | /** |
12 | * Unitary tests for cached pages | 12 | * Unitary tests for cached pages |
13 | */ | 13 | */ |
14 | class CachedTest extends PHPUnit_Framework_TestCase | 14 | class CacheTest extends PHPUnit_Framework_TestCase |
15 | { | 15 | { |
16 | // test cache directory | 16 | // test cache directory |
17 | protected static $testCacheDir = 'tests/dummycache'; | 17 | protected static $testCacheDir = 'sandbox/dummycache'; |
18 | 18 | ||
19 | // dummy cached file names / content | 19 | // dummy cached file names / content |
20 | protected static $pages = array('a', 'toto', 'd7b59c'); | 20 | protected static $pages = array('a', 'toto', 'd7b59c'); |
@@ -30,7 +30,7 @@ class CachedTest extends PHPUnit_Framework_TestCase | |||
30 | } else { | 30 | } else { |
31 | array_map('unlink', glob(self::$testCacheDir.'/*')); | 31 | array_map('unlink', glob(self::$testCacheDir.'/*')); |
32 | } | 32 | } |
33 | 33 | ||
34 | foreach (self::$pages as $page) { | 34 | foreach (self::$pages as $page) { |
35 | file_put_contents(self::$testCacheDir.'/'.$page.'.cache', $page); | 35 | file_put_contents(self::$testCacheDir.'/'.$page.'.cache', $page); |
36 | } | 36 | } |
@@ -38,6 +38,15 @@ class CachedTest extends PHPUnit_Framework_TestCase | |||
38 | } | 38 | } |
39 | 39 | ||
40 | /** | 40 | /** |
41 | * Remove dummycache folder after each tests. | ||
42 | */ | ||
43 | public function tearDown() | ||
44 | { | ||
45 | array_map('unlink', glob(self::$testCacheDir.'/*')); | ||
46 | rmdir(self::$testCacheDir); | ||
47 | } | ||
48 | |||
49 | /** | ||
41 | * Purge cached pages | 50 | * Purge cached pages |
42 | */ | 51 | */ |
43 | public function testPurgeCachedPages() | 52 | public function testPurgeCachedPages() |
@@ -56,7 +65,7 @@ class CachedTest extends PHPUnit_Framework_TestCase | |||
56 | public function testPurgeCachedPagesMissingDir() | 65 | public function testPurgeCachedPagesMissingDir() |
57 | { | 66 | { |
58 | $this->assertEquals( | 67 | $this->assertEquals( |
59 | 'Cannot purge tests/dummycache_missing: no directory', | 68 | 'Cannot purge sandbox/dummycache_missing: no directory', |
60 | purgeCachedPages(self::$testCacheDir.'_missing') | 69 | purgeCachedPages(self::$testCacheDir.'_missing') |
61 | ); | 70 | ); |
62 | } | 71 | } |
diff --git a/tests/CachedPageTest.php b/tests/CachedPageTest.php index e97af030..51565cd6 100644 --- a/tests/CachedPageTest.php +++ b/tests/CachedPageTest.php | |||
@@ -11,7 +11,7 @@ require_once 'application/CachedPage.php'; | |||
11 | class CachedPageTest extends PHPUnit_Framework_TestCase | 11 | class CachedPageTest extends PHPUnit_Framework_TestCase |
12 | { | 12 | { |
13 | // test cache directory | 13 | // test cache directory |
14 | protected static $testCacheDir = 'tests/pagecache'; | 14 | protected static $testCacheDir = 'sandbox/pagecache'; |
15 | protected static $url = 'http://shaar.li/?do=atom'; | 15 | protected static $url = 'http://shaar.li/?do=atom'; |
16 | protected static $filename; | 16 | protected static $filename; |
17 | 17 | ||
diff --git a/tests/LinkDBTest.php b/tests/LinkDBTest.php index 8929713d..7b22b270 100644 --- a/tests/LinkDBTest.php +++ b/tests/LinkDBTest.php | |||
@@ -16,7 +16,7 @@ require_once 'tests/utils/ReferenceLinkDB.php'; | |||
16 | class LinkDBTest extends PHPUnit_Framework_TestCase | 16 | class LinkDBTest extends PHPUnit_Framework_TestCase |
17 | { | 17 | { |
18 | // datastore to test write operations | 18 | // datastore to test write operations |
19 | protected static $testDatastore = 'tests/datastore.php'; | 19 | protected static $testDatastore = 'sandbox/datastore.php'; |
20 | protected static $refDB = null; | 20 | protected static $refDB = null; |
21 | protected static $publicLinkDB = null; | 21 | protected static $publicLinkDB = null; |
22 | protected static $privateLinkDB = null; | 22 | protected static $privateLinkDB = null; |
@@ -511,4 +511,27 @@ class LinkDBTest extends PHPUnit_Framework_TestCase | |||
511 | sizeof(self::$publicLinkDB->filterFullText('free software')) | 511 | sizeof(self::$publicLinkDB->filterFullText('free software')) |
512 | ); | 512 | ); |
513 | } | 513 | } |
514 | |||
515 | /** | ||
516 | * Test real_url without redirector. | ||
517 | */ | ||
518 | public function testLinkRealUrlWithoutRedirector() | ||
519 | { | ||
520 | $db = new LinkDB(self::$testDatastore, false, false); | ||
521 | foreach($db as $link) { | ||
522 | $this->assertEquals($link['url'], $link['real_url']); | ||
523 | } | ||
524 | } | ||
525 | |||
526 | /** | ||
527 | * Test real_url with redirector. | ||
528 | */ | ||
529 | public function testLinkRealUrlWithRedirector() | ||
530 | { | ||
531 | $redirector = 'http://redirector.to?'; | ||
532 | $db = new LinkDB(self::$testDatastore, false, false, $redirector); | ||
533 | foreach($db as $link) { | ||
534 | $this->assertStringStartsWith($redirector, $link['real_url']); | ||
535 | } | ||
536 | } | ||
514 | } | 537 | } |
diff --git a/tests/UtilsTest.php b/tests/UtilsTest.php index 4847ea94..02eecda2 100644 --- a/tests/UtilsTest.php +++ b/tests/UtilsTest.php | |||
@@ -187,4 +187,41 @@ class UtilsTest extends PHPUnit_Framework_TestCase | |||
187 | is_session_id_valid('c0ZqcWF3VFE2NmJBdm1HMVQ0ZHJ3UmZPbTFsNGhkNHI=') | 187 | is_session_id_valid('c0ZqcWF3VFE2NmJBdm1HMVQ0ZHJ3UmZPbTFsNGhkNHI=') |
188 | ); | 188 | ); |
189 | } | 189 | } |
190 | |||
191 | /** | ||
192 | * Test text2clickable without a redirector being set. | ||
193 | */ | ||
194 | public function testText2clickableWithoutRedirector() | ||
195 | { | ||
196 | $text = 'stuff http://hello.there/is=someone#here otherstuff'; | ||
197 | $expectedText = 'stuff <a href="http://hello.there/is=someone#here">http://hello.there/is=someone#here</a> otherstuff'; | ||
198 | $processedText = text2clickable($text, ''); | ||
199 | $this->assertEquals($expectedText, $processedText); | ||
200 | } | ||
201 | |||
202 | /** | ||
203 | * Test text2clickable a redirector set. | ||
204 | */ | ||
205 | public function testText2clickableWithRedirector() | ||
206 | { | ||
207 | $text = 'stuff http://hello.there/is=someone#here otherstuff'; | ||
208 | $redirector = 'http://redirector.to'; | ||
209 | $expectedText = 'stuff <a href="'. | ||
210 | $redirector . | ||
211 | urlencode('http://hello.there/is=someone#here') . | ||
212 | '">http://hello.there/is=someone#here</a> otherstuff'; | ||
213 | $processedText = text2clickable($text, $redirector); | ||
214 | $this->assertEquals($expectedText, $processedText); | ||
215 | } | ||
216 | |||
217 | /** | ||
218 | * Test testSpace2nbsp. | ||
219 | */ | ||
220 | public function testSpace2nbsp() | ||
221 | { | ||
222 | $text = ' Are you thrilled by flags ?'. PHP_EOL .' Really?'; | ||
223 | $expectedText = ' Are you thrilled by flags ?'. PHP_EOL .' Really?'; | ||
224 | $processedText = space2nbsp($text); | ||
225 | $this->assertEquals($expectedText, $processedText); | ||
226 | } | ||
190 | } | 227 | } |
diff --git a/tests/plugins/PlugQrcodeTest.php b/tests/plugins/PlugQrcodeTest.php index 86dc7f29..c749fa86 100644 --- a/tests/plugins/PlugQrcodeTest.php +++ b/tests/plugins/PlugQrcodeTest.php | |||
@@ -30,7 +30,7 @@ class PlugQrcodeTest extends PHPUnit_Framework_TestCase | |||
30 | 'title' => $str, | 30 | 'title' => $str, |
31 | 'links' => array( | 31 | 'links' => array( |
32 | array( | 32 | array( |
33 | 'url' => $str, | 33 | 'real_url' => $str, |
34 | ) | 34 | ) |
35 | ) | 35 | ) |
36 | ); | 36 | ); |
@@ -39,7 +39,7 @@ class PlugQrcodeTest extends PHPUnit_Framework_TestCase | |||
39 | $link = $data['links'][0]; | 39 | $link = $data['links'][0]; |
40 | // data shouldn't be altered | 40 | // data shouldn't be altered |
41 | $this->assertEquals($str, $data['title']); | 41 | $this->assertEquals($str, $data['title']); |
42 | $this->assertEquals($str, $link['url']); | 42 | $this->assertEquals($str, $link['real_url']); |
43 | 43 | ||
44 | // plugin data | 44 | // plugin data |
45 | $this->assertEquals(1, count($link['link_plugin'])); | 45 | $this->assertEquals(1, count($link['link_plugin'])); |
diff --git a/tpl/daily.html b/tpl/daily.html index 93a3ab45..063dc89a 100644 --- a/tpl/daily.html +++ b/tpl/daily.html | |||
@@ -66,7 +66,7 @@ | |||
66 | </div> | 66 | </div> |
67 | {/if} | 67 | {/if} |
68 | <div class="dailyEntryTitle"> | 68 | <div class="dailyEntryTitle"> |
69 | <a href="{$link.url}">{$link.title}</a> | 69 | <a href="{$link.real_url}">{$link.title}</a> |
70 | </div> | 70 | </div> |
71 | {if="$link.thumbnail"} | 71 | {if="$link.thumbnail"} |
72 | <div class="dailyEntryThumbnail">{$link.thumbnail}</div> | 72 | <div class="dailyEntryThumbnail">{$link.thumbnail}</div> |
diff --git a/tpl/linklist.html b/tpl/linklist.html index f6e9e82b..666748a7 100644 --- a/tpl/linklist.html +++ b/tpl/linklist.html | |||
@@ -70,7 +70,9 @@ | |||
70 | </form> | 70 | </form> |
71 | </div> | 71 | </div> |
72 | {/if} | 72 | {/if} |
73 | <span class="linktitle"><a href="{$redirector}{$value.url}">{$value.title}</a></span> | 73 | <span class="linktitle"> |
74 | <a href="{$value.real_url}">{$value.title}</a> | ||
75 | </span> | ||
74 | <br> | 76 | <br> |
75 | {if="$value.description"}<div class="linkdescription">{$value.description}</div>{/if} | 77 | {if="$value.description"}<div class="linkdescription">{$value.description}</div>{/if} |
76 | {if="!$GLOBALS['config']['HIDE_TIMESTAMPS'] || isLoggedIn()"} | 78 | {if="!$GLOBALS['config']['HIDE_TIMESTAMPS'] || isLoggedIn()"} |
@@ -83,7 +85,7 @@ | |||
83 | <span>{$value}</span> - | 85 | <span>{$value}</span> - |
84 | {/loop} | 86 | {/loop} |
85 | 87 | ||
86 | <a href="{$value.url}"><span class="linkurl" title="Short link">{$value.url}</span></a><br> | 88 | <a href="{$value.real_url}"><span class="linkurl" title="Short link">{$value.url}</span></a><br> |
87 | {if="$value.tags"} | 89 | {if="$value.tags"} |
88 | <div class="linktaglist"> | 90 | <div class="linktaglist"> |
89 | {loop="value.taglist"}<span class="linktag" title="Add tag"><a href="?addtag={$value|urlencode}">{$value}</a></span> {/loop} | 91 | {loop="value.taglist"}<span class="linktag" title="Add tag"><a href="?addtag={$value|urlencode}">{$value}</a></span> {/loop} |
diff --git a/tpl/page.footer.html b/tpl/page.footer.html index 6c29850f..b20aae54 100644 --- a/tpl/page.footer.html +++ b/tpl/page.footer.html | |||
@@ -4,8 +4,16 @@ | |||
4 | {$value} | 4 | {$value} |
5 | {/loop} | 5 | {/loop} |
6 | </div> | 6 | </div> |
7 | {if="$newversion"} | 7 | {if="$newVersion"} |
8 | <div id="newversion"><span id="version_id">●</span> Shaarli {$newversion} is <a href="https://github.com/shaarli/Shaarli/releases">available</a>.</div> | 8 | <div id="newversion"> |
9 | <span id="version_id">●</span> Shaarli {$newVersion} is | ||
10 | <a href="https://github.com/shaarli/Shaarli/releases">available</a>. | ||
11 | </div> | ||
12 | {/if} | ||
13 | {if="$versionError"} | ||
14 | <div id="newversion"> | ||
15 | Error: {$versionError} | ||
16 | </div> | ||
9 | {/if} | 17 | {/if} |
10 | {if="isLoggedIn()"} | 18 | {if="isLoggedIn()"} |
11 | <script>function confirmDeleteLink() { var agree=confirm("Are you sure you want to delete this link ?"); if (agree) return true ; else return false ; }</script> | 19 | <script>function confirmDeleteLink() { var agree=confirm("Are you sure you want to delete this link ?"); if (agree) return true ; else return false ; }</script> |
diff --git a/tpl/picwall.html b/tpl/picwall.html index 97d5efdf..230c948b 100644 --- a/tpl/picwall.html +++ b/tpl/picwall.html | |||
@@ -16,7 +16,7 @@ | |||
16 | <div id="picwall_container"> | 16 | <div id="picwall_container"> |
17 | {loop="linksToDisplay"} | 17 | {loop="linksToDisplay"} |
18 | <div class="picwall_pictureframe"> | 18 | <div class="picwall_pictureframe"> |
19 | {$value.thumbnail}<a href="{$value.url}"><span class="info">{$value.title}</span></a> | 19 | {$value.thumbnail}<a href="{$value.real_url}"><span class="info">{$value.title}</span></a> |
20 | {loop="$value.picwall_plugin"} | 20 | {loop="$value.picwall_plugin"} |
21 | {$value} | 21 | {$value} |
22 | {/loop} | 22 | {/loop} |