aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--.gitattributes1
-rw-r--r--.github/mailmap13
-rw-r--r--.gitignore4
-rw-r--r--AUTHORS40
-rw-r--r--CHANGELOG.md5
-rw-r--r--COPYING30
-rw-r--r--Makefile8
-rw-r--r--application/ApplicationUtils.php1
-rw-r--r--application/Base64Url.php34
-rw-r--r--application/CachedPage.php4
-rw-r--r--application/HttpUtils.php2
-rw-r--r--application/LinkUtils.php4
-rw-r--r--application/PageBuilder.php2
-rw-r--r--application/ThemeUtils.php33
-rw-r--r--application/Updater.php47
-rw-r--r--application/api/ApiMiddleware.php11
-rw-r--r--application/api/ApiUtils.php12
-rw-r--r--application/config/ConfigIO.php6
-rw-r--r--application/config/ConfigJson.php6
-rw-r--r--application/config/ConfigManager.php1
-rw-r--r--application/config/ConfigPhp.php9
-rw-r--r--composer.json1
-rw-r--r--docker/development/nginx.conf9
-rw-r--r--docker/production/nginx.conf9
-rw-r--r--docker/production/stable/nginx.conf9
-rw-r--r--images/squiggle.pngbin684 -> 0 bytes
-rw-r--r--index.php11
-rw-r--r--plugins/wallabag/WallabagInstance.php2
-rw-r--r--tests/ApplicationUtilsTest.php3
-rw-r--r--tests/ThemeUtilsTest.php55
-rw-r--r--tests/Updater/UpdaterTest.php45
-rw-r--r--tests/Url/UrlTest.php8
-rw-r--r--tests/api/ApiMiddlewareTest.php29
-rw-r--r--tests/api/ApiUtilsTest.php15
-rw-r--r--tests/plugins/PluginAddlinkTest.php10
-rw-r--r--tests/plugins/PluginArchiveorgTest.php10
-rw-r--r--tests/plugins/PluginIssoTest.php14
-rw-r--r--tests/plugins/PluginMarkdownTest.php20
-rw-r--r--tests/plugins/PluginPlayvideosTest.php6
-rw-r--r--tests/plugins/PluginPubsubhubbubTest.php6
-rw-r--r--tests/plugins/PluginQrcodeTest.php (renamed from tests/plugins/PlugQrcodeTest.php)12
-rw-r--r--tests/plugins/PluginReadityourselfTest.php10
-rw-r--r--tests/plugins/PluginWallabagTest.php8
-rw-r--r--tests/plugins/WallabagInstanceTest.php8
-rw-r--r--tests/utils/config/configJson.json.php3
-rw-r--r--tpl/default/404.html (renamed from tpl/404.html)0
-rw-r--r--tpl/default/addlink.html (renamed from tpl/addlink.html)0
-rw-r--r--tpl/default/changepassword.html (renamed from tpl/changepassword.html)0
-rw-r--r--tpl/default/changetag.html (renamed from tpl/changetag.html)2
-rw-r--r--tpl/default/configure.html (renamed from tpl/configure.html)14
-rw-r--r--tpl/default/css/reset.css (renamed from inc/reset.css)0
-rw-r--r--tpl/default/css/shaarli.css (renamed from inc/shaarli.css)18
-rw-r--r--tpl/default/daily.html (renamed from tpl/daily.html)8
-rw-r--r--tpl/default/dailyrss.html (renamed from tpl/dailyrss.html)0
-rw-r--r--tpl/default/editlink.html (renamed from tpl/editlink.html)10
-rw-r--r--tpl/default/export.bookmarks.html (renamed from tpl/export.bookmarks.html)0
-rw-r--r--tpl/default/export.html (renamed from tpl/export.html)0
-rw-r--r--tpl/default/feed.atom.html (renamed from tpl/feed.atom.html)0
-rw-r--r--tpl/default/feed.rss.html (renamed from tpl/feed.rss.html)0
-rw-r--r--tpl/default/images/50pc_transparent.png (renamed from images/50pc_transparent.png)bin599 -> 599 bytes
-rw-r--r--tpl/default/images/Paper_texture_v5_by_bashcorpo_w1000.jpg (renamed from images/Paper_texture_v5_by_bashcorpo_w1000.jpg)bin127449 -> 127449 bytes
-rw-r--r--tpl/default/images/calendar.png (renamed from images/calendar.png)bin650 -> 650 bytes
-rw-r--r--tpl/default/images/floral_left.png (renamed from images/floral_left.png)bin1284 -> 1284 bytes
-rw-r--r--tpl/default/images/floral_right.png (renamed from images/floral_right.png)bin1309 -> 1309 bytes
-rw-r--r--tpl/default/images/private.png (renamed from images/private.png)bin813 -> 813 bytes
-rw-r--r--tpl/default/images/squiggle.png (renamed from images/squiggle2.png)bin720 -> 720 bytes
-rw-r--r--tpl/default/images/squiggle_closing.png (renamed from images/squiggle_closing.png)bin1244 -> 1244 bytes
-rw-r--r--tpl/default/images/tag_blue.png (renamed from images/tag_blue.png)bin714 -> 714 bytes
-rw-r--r--tpl/default/import.html (renamed from tpl/import.html)0
-rw-r--r--tpl/default/includes.html (renamed from tpl/includes.html)6
-rw-r--r--tpl/default/install.html (renamed from tpl/install.html)0
-rw-r--r--tpl/default/linklist.html (renamed from tpl/linklist.html)2
-rw-r--r--tpl/default/linklist.paging.html (renamed from tpl/linklist.paging.html)0
-rw-r--r--tpl/default/loginform.html (renamed from tpl/loginform.html)0
-rw-r--r--tpl/default/opensearch.html (renamed from tpl/opensearch.html)0
-rw-r--r--tpl/default/page.footer.html (renamed from tpl/page.footer.html)0
-rw-r--r--tpl/default/page.header.html (renamed from tpl/page.header.html)0
-rw-r--r--tpl/default/page.html (renamed from tpl/page.html)0
-rw-r--r--tpl/default/picwall.html (renamed from tpl/picwall.html)0
-rw-r--r--tpl/default/pluginsadmin.html (renamed from tpl/pluginsadmin.html)0
-rw-r--r--tpl/default/readme.txt (renamed from tpl/readme.txt)0
-rw-r--r--tpl/default/tagcloud.html (renamed from tpl/tagcloud.html)0
-rw-r--r--tpl/default/tools.html (renamed from tpl/tools.html)0
83 files changed, 491 insertions, 145 deletions
diff --git a/.gitattributes b/.gitattributes
index d753b1db..059fbb18 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -19,6 +19,7 @@ Dockerfile text
19 19
20# Exclude from Git archives 20# Exclude from Git archives
21.gitattributes export-ignore 21.gitattributes export-ignore
22.github export-ignore
22.gitignore export-ignore 23.gitignore export-ignore
23.travis.yml export-ignore 24.travis.yml export-ignore
24doc/**/*.json export-ignore 25doc/**/*.json export-ignore
diff --git a/.github/mailmap b/.github/mailmap
new file mode 100644
index 00000000..41d91e47
--- /dev/null
+++ b/.github/mailmap
@@ -0,0 +1,13 @@
1ArthurHoaro <arthur@hoa.ro>
2Florian Eula <eula.florian@gmail.com> feula
3Florian Eula <eula.florian@gmail.com> <mr.pikzen@gmail.com>
4Nicolas Danelon <hi@nicolasmd.com.ar> nicolasm
5Nicolas Danelon <hi@nicolasmd.com.ar> <nda@3818.com.ar>
6Nicolas Danelon <hi@nicolasmd.com.ar> <nicolasdanelon@gmail.com>
7Nicolas Danelon <hi@nicolasmd.com.ar> <nicolasdanelon@users.noreply.github.com>
8Sébastien Sauvage <sebsauvage@sebsauvage.net>
9Timo Van Neerden <fire@lehollandaisvolant.net>
10Timo Van Neerden <fire@lehollandaisvolant.net> lehollandaisvolant <levoltigeurhollandais@gmail.com>
11VirtualTam <virtualtam@flibidi.net> <tamisier.aurelien@gmail.com>
12VirtualTam <virtualtam@flibidi.net> <virtualtam+github@flibidi.net>
13VirtualTam <virtualtam@flibidi.net> <virtualtam@flibidi.org>
diff --git a/.gitignore b/.gitignore
index 9121905d..19f3dc83 100644
--- a/.gitignore
+++ b/.gitignore
@@ -28,3 +28,7 @@ phpmd.html
28 28
29# User plugin configuration 29# User plugin configuration
30plugins/*/config.php 30plugins/*/config.php
31
32# 3rd party themes
33tpl/*
34!tpl/default
diff --git a/AUTHORS b/AUTHORS
new file mode 100644
index 00000000..aa041ae9
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1,40 @@
1 327 ArthurHoaro <arthur@hoa.ro>
2 188 VirtualTam <virtualtam@flibidi.net>
3 132 nodiscc <nodiscc@gmail.com>
4 56 Sébastien Sauvage <sebsauvage@sebsauvage.net>
5 15 Florian Eula <eula.florian@gmail.com>
6 13 Emilien Klein <emilien@klein.st>
7 12 Nicolas Danelon <hi@nicolasmd.com.ar>
8 7 Christophe HENRY <christophe.henry@sbgodin.fr>
9 4 Alexandre Alapetite <alexandre@alapetite.fr>
10 4 David Sferruzza <david.sferruzza@gmail.com>
11 3 Teromene <teromene@teromene.fr>
12 2 Chris Kuethe <chris.kuethe@gmail.com>
13 2 Knah Tsaeb <Knah-Tsaeb@knah-tsaeb.org>
14 2 Mathieu Chabanon <git@matchab.fr>
15 2 Miloš Jovanović <mjovanovic@gmail.com>
16 2 Qwerty <champlywood@free.fr>
17 2 Timo Van Neerden <fire@lehollandaisvolant.net>
18 2 julienCXX <software@chmodplusx.eu>
19 2 kalvn <kalvnthereal@gmail.com>
20 1 Adrien Oliva <adrien.oliva@yapbreak.fr>
21 1 Alexis J <alexis@effingo.be>
22 1 BoboTiG <bobotig@gmail.com>
23 1 Bronco <bronco@warriordudimanche.net>
24 1 D Low <daniellowtw@gmail.com>
25 1 Dimtion <zizou.xena@gmail.com>
26 1 Fanch <fanch-github@qth.fr>
27 1 Felix Bartels <felix@host-consultants.de>
28 1 Felix Kästner <github.com-fpunktk@fpunktk.de>
29 1 Florian Voigt <flvoigt@me.com>
30 1 Gary Marigliano <gmarigliano93@gmail.com>
31 1 Guillaume Virlet <github@virlet.org>
32 1 Jonathan Druart <jonathan.druart@gmail.com>
33 1 Julien Pivotto <roidelapluie@inuits.eu>
34 1 Kevin Canévet <kevin@streamroot.io>
35 1 Knah Tsaeb <knah-tsaeb@knah-tsaeb.org>
36 1 Lionel Martin <renarddesmers@gmail.com>
37 1 Marsup <marsup@gmail.com>
38 1 Sbgodin <Sbgodin@users.noreply.github.com>
39 1 TsT <tst2005@gmail.com>
40 1 dimtion <zizou.xena@gmail.com>
diff --git a/CHANGELOG.md b/CHANGELOG.md
index fe775b3e..d3ecc1e6 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,14 +7,17 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
7 7
8## [v0.9.0](https://github.com/shaarli/Shaarli/releases/tag/v0.9.0) - UNPUBLISHED 8## [v0.9.0](https://github.com/shaarli/Shaarli/releases/tag/v0.9.0) - UNPUBLISHED
9 9
10**WARNING**: Shaarli now requires PHP 5.5+. 10**WARNING**: Shaarli now requires PHP 5.5+.
11 11
12### Added 12### Added
13 13
14- REST API: see [Shaarli API documentation](http://shaarli.github.io/api-documentation/) 14- REST API: see [Shaarli API documentation](http://shaarli.github.io/api-documentation/)
15- The theme can now be selected in the administration page.
15 16
16### Changed 17### Changed
17 18
19- Default template files are moved to a subfolder (`default`).
20
18### Fixed 21### Fixed
19 22
20 23
diff --git a/COPYING b/COPYING
index 22929463..4bbdf2b3 100644
--- a/COPYING
+++ b/COPYING
@@ -1,33 +1,7 @@
1Files: * 1Files: *
2License: zlib/libpng 2License: zlib/libpng
3Copyright: (c) 2011-2015 Sébastien SAUVAGE <sebsauvage@sebsauvage.net> 3Copyright: (c) 2011-2015 Sébastien SAUVAGE <sebsauvage@sebsauvage.net>
4 (c) 2011-2015 Alexandre Alapetite <alexandre@alapetite.fr> 4 (c) 2011-2017 The Shaarli Community, see AUTHORS
5 (c) 2011-2015 David Sferruzza <david.sferruzza@gmail.com>
6 (c) 2011-2015 Christophe HENRY <christophe.henry@sbgodin.fr>
7 (c) 2011-2015 Mathieu Chabanon <git@matchab.fr>
8 (c) 2011-2015 BoboTiG <bobotig@gmail.com>
9 (c) 2011-2015 Bronco <bronco@warriordudimanche.net>
10 (c) 2011-2015 Emilien Klein <emilien@klein.st>
11 (c) 2011-2015 Knah Tsaeb <knah-tsaeb@knah-tsaeb.org>
12 (c) 2011-2015 Lionel Martin <renarddesmers@gmail.com>
13 (c) 2011-2015 lehollandaisvolant <levoltigeurhollandais@gmail.com>
14 (c) 2011-2015 timo van neerden <fire@lehollandaisvolant.net>
15 (c) 2011-2015 nodiscc <nodiscc@gmail.com>
16 (c) 2011-2015 Florian Eula <mr.pikzen@gmail.com>
17 (c) 2011-2015 Arthur Hoaro <arthur@hoa.ro>
18 (c) 2011-2015 Aurélien "VirtualTam" Tamisier <virtualtam@flibidi.net>
19 (c) 2011-2015 qwertygc <champlywood@free.fr>
20 (c) 2011-2015 idleman <idleman@idleman.fr>
21 (c) 2015 Alexis Ju <alexis@effingo.be>
22 (c) 2015 dimtion <zizou.xena@gmail.com>
23 (c) 2015 Fanch <fanch-github@qth.fr>
24 (c) 2015 Guillaume Virlet <github@virlet.org>
25 (c) 2015 Felix Bartels <felix@host-consultants.de>
26 (c) 2015 Marsup <marsup@gmail.com>
27 (c) 2015 Miloš Jovanović <mjovanovic@gmail.com>
28 (c) 2015 Nicolás Danelón <hola@nicolasdanelon.com.ar>
29 (c) 2015 TsT <tst2005@gmail.com>
30
31 5
32Files: inc/reset.css 6Files: inc/reset.css
33License: BSD (http://opensource.org/licenses/BSD-3-Clause) 7License: BSD (http://opensource.org/licenses/BSD-3-Clause)
@@ -43,7 +17,7 @@ License: CC-BY (http://creativecommons.org/licenses/by/3.0/)
43Copyright: (c) 2014 Designmodo 17Copyright: (c) 2014 Designmodo
44Source: http://designmodo.com/linecons-free/ 18Source: http://designmodo.com/linecons-free/
45 19
46Files: images/floral_left.png, images/floral_right.png, images/squiggle.png, images/squiggle2.png, images/squiggle_closing.png 20Files: images/floral_left.png, images/floral_right.png, images/squiggle.png, images/squiggle_closing.png
47Licence: Public Domain 21Licence: Public Domain
48Source: https://openclipart.org/people/j4p4n/j4p4n_ornimental_bookend_-_left.svg 22Source: https://openclipart.org/people/j4p4n/j4p4n_ornimental_bookend_-_left.svg
49 23
diff --git a/Makefile b/Makefile
index 60aec9a0..f3065b77 100644
--- a/Makefile
+++ b/Makefile
@@ -169,6 +169,12 @@ clean:
169 @git clean -df 169 @git clean -df
170 @rm -rf sandbox 170 @rm -rf sandbox
171 171
172### generate the AUTHORS file from Git commit information
173authors:
174 @cp .github/mailmap .mailmap
175 @git shortlog -sne > AUTHORS
176 @rm .mailmap
177
172### generate Doxygen documentation 178### generate Doxygen documentation
173doxygen: clean 179doxygen: clean
174 @rm -rf doxygen 180 @rm -rf doxygen
@@ -214,4 +220,4 @@ htmlpages:
214 -o doc/$$base.html $$file; \ 220 -o doc/$$base.html $$file; \
215 done; 221 done;
216 222
217htmldoc: doc htmlsidebar htmlpages 223htmldoc: authors doc htmlsidebar htmlpages
diff --git a/application/ApplicationUtils.php b/application/ApplicationUtils.php
index 7f963e97..a0f482b0 100644
--- a/application/ApplicationUtils.php
+++ b/application/ApplicationUtils.php
@@ -150,6 +150,7 @@ class ApplicationUtils
150 'inc', 150 'inc',
151 'plugins', 151 'plugins',
152 $conf->get('resource.raintpl_tpl'), 152 $conf->get('resource.raintpl_tpl'),
153 $conf->get('resource.raintpl_tpl').'/'.$conf->get('resource.theme'),
153 ) as $path) { 154 ) as $path) {
154 if (! is_readable(realpath($path))) { 155 if (! is_readable(realpath($path))) {
155 $errors[] = '"'.$path.'" directory is not readable'; 156 $errors[] = '"'.$path.'" directory is not readable';
diff --git a/application/Base64Url.php b/application/Base64Url.php
new file mode 100644
index 00000000..61590e43
--- /dev/null
+++ b/application/Base64Url.php
@@ -0,0 +1,34 @@
1<?php
2
3namespace Shaarli;
4
5
6/**
7 * URL-safe Base64 operations
8 *
9 * @see https://en.wikipedia.org/wiki/Base64#URL_applications
10 */
11class Base64Url
12{
13 /**
14 * Base64Url-encodes data
15 *
16 * @param string $data Data to encode
17 *
18 * @return string Base64Url-encoded data
19 */
20 public static function encode($data) {
21 return rtrim(strtr(base64_encode($data), '+/', '-_'), '=');
22 }
23
24 /**
25 * Decodes Base64Url-encoded data
26 *
27 * @param string $data Data to decode
28 *
29 * @return string Decoded data
30 */
31 public static function decode($data) {
32 return base64_decode(str_pad(strtr($data, '-_', '+/'), strlen($data) % 4, '=', STR_PAD_RIGHT));
33 }
34}
diff --git a/application/CachedPage.php b/application/CachedPage.php
index 5087d0c4..e11cc52d 100644
--- a/application/CachedPage.php
+++ b/application/CachedPage.php
@@ -7,9 +7,6 @@ class CachedPage
7 // Directory containing page caches 7 // Directory containing page caches
8 private $cacheDir; 8 private $cacheDir;
9 9
10 // Full URL of the page to cache -typically the value returned by pageUrl()
11 private $url;
12
13 // Should this URL be cached (boolean)? 10 // Should this URL be cached (boolean)?
14 private $shouldBeCached; 11 private $shouldBeCached;
15 12
@@ -27,7 +24,6 @@ class CachedPage
27 { 24 {
28 // TODO: check write access to the cache directory 25 // TODO: check write access to the cache directory
29 $this->cacheDir = $cacheDir; 26 $this->cacheDir = $cacheDir;
30 $this->url = $url;
31 $this->filename = $this->cacheDir.'/'.sha1($url).'.cache'; 27 $this->filename = $this->cacheDir.'/'.sha1($url).'.cache';
32 $this->shouldBeCached = $shouldBeCached; 28 $this->shouldBeCached = $shouldBeCached;
33 } 29 }
diff --git a/application/HttpUtils.php b/application/HttpUtils.php
index e8fc1f5d..a81f9056 100644
--- a/application/HttpUtils.php
+++ b/application/HttpUtils.php
@@ -122,7 +122,7 @@ function get_http_response($url, $timeout = 30, $maxBytes = 4194304)
122 $content = substr($response, $headSize); 122 $content = substr($response, $headSize);
123 $headers = array(); 123 $headers = array();
124 foreach (preg_split('~[\r\n]+~', $rawHeadersLastRedir) as $line) { 124 foreach (preg_split('~[\r\n]+~', $rawHeadersLastRedir) as $line) {
125 if (empty($line) or ctype_space($line)) { 125 if (empty($line) || ctype_space($line)) {
126 continue; 126 continue;
127 } 127 }
128 $splitLine = explode(': ', $line, 2); 128 $splitLine = explode(': ', $line, 2);
diff --git a/application/LinkUtils.php b/application/LinkUtils.php
index cf58f808..976474de 100644
--- a/application/LinkUtils.php
+++ b/application/LinkUtils.php
@@ -89,7 +89,9 @@ function count_private($links)
89{ 89{
90 $cpt = 0; 90 $cpt = 0;
91 foreach ($links as $link) { 91 foreach ($links as $link) {
92 $cpt = $link['private'] == true ? $cpt + 1 : $cpt; 92 if ($link['private']) {
93 $cpt += 1;
94 }
93 } 95 }
94 96
95 return $cpt; 97 return $cpt;
diff --git a/application/PageBuilder.php b/application/PageBuilder.php
index 32c7f9f1..544aba7c 100644
--- a/application/PageBuilder.php
+++ b/application/PageBuilder.php
@@ -25,7 +25,7 @@ class PageBuilder
25 * 25 *
26 * @param ConfigManager $conf Configuration Manager instance (reference). 26 * @param ConfigManager $conf Configuration Manager instance (reference).
27 */ 27 */
28 function __construct(&$conf) 28 public function __construct(&$conf)
29 { 29 {
30 $this->tpl = false; 30 $this->tpl = false;
31 $this->conf = $conf; 31 $this->conf = $conf;
diff --git a/application/ThemeUtils.php b/application/ThemeUtils.php
new file mode 100644
index 00000000..2718ed13
--- /dev/null
+++ b/application/ThemeUtils.php
@@ -0,0 +1,33 @@
1<?php
2
3namespace Shaarli;
4
5/**
6 * Class ThemeUtils
7 *
8 * Utility functions related to theme management.
9 *
10 * @package Shaarli
11 */
12class ThemeUtils
13{
14 /**
15 * Get a list of available themes.
16 *
17 * It will return the name of any directory present in the template folder.
18 *
19 * @param string $tplDir Templates main directory.
20 *
21 * @return array List of theme names.
22 */
23 public static function getThemes($tplDir)
24 {
25 $allTheme = glob($tplDir.'/*', GLOB_ONLYDIR);
26 $themes = [];
27 foreach ($allTheme as $value) {
28 $themes[] = str_replace($tplDir.'/', '', $value);
29 }
30
31 return $themes;
32 }
33}
diff --git a/application/Updater.php b/application/Updater.php
index 38de3350..eb03c6d3 100644
--- a/application/Updater.php
+++ b/application/Updater.php
@@ -69,7 +69,7 @@ class Updater
69 return $updatesRan; 69 return $updatesRan;
70 } 70 }
71 71
72 if ($this->methods == null) { 72 if ($this->methods === null) {
73 throw new UpdaterException('Couldn\'t retrieve Updater class methods.'); 73 throw new UpdaterException('Couldn\'t retrieve Updater class methods.');
74 } 74 }
75 75
@@ -279,6 +279,51 @@ class Updater
279 $this->conf->write($this->isLoggedIn); 279 $this->conf->write($this->isLoggedIn);
280 return true; 280 return true;
281 } 281 }
282
283 /**
284 * New setting: theme name. If the default theme is used, nothing to do.
285 *
286 * If the user uses a custom theme, raintpl_tpl dir is updated to the parent directory,
287 * and the current theme is set as default in the theme setting.
288 *
289 * @return bool true if the update is successful, false otherwise.
290 */
291 public function updateMethodDefaultTheme()
292 {
293 // raintpl_tpl isn't the root template directory anymore.
294 // We run the update only if this folder still contains the template files.
295 $tplDir = $this->conf->get('resource.raintpl_tpl');
296 $tplFile = $tplDir . '/linklist.html';
297 if (! file_exists($tplFile)) {
298 return true;
299 }
300
301 $parent = dirname($tplDir);
302 $this->conf->set('resource.raintpl_tpl', $parent);
303 $this->conf->set('resource.theme', trim(str_replace($parent, '', $tplDir), '/'));
304 $this->conf->write($this->isLoggedIn);
305
306 // Dependency injection gore
307 RainTPL::$tpl_dir = $tplDir;
308
309 return true;
310 }
311
312 /**
313 * Move the file to inc/user.css to data/user.css.
314 *
315 * Note: Due to hardcoded paths, it's not unit testable. But one line of code should be fine.
316 *
317 * @return bool true if the update is successful, false otherwise.
318 */
319 public function updateMethodMoveUserCss()
320 {
321 if (! is_file('inc/user.css')) {
322 return true;
323 }
324
325 return rename('inc/user.css', 'data/user.css');
326 }
282} 327}
283 328
284/** 329/**
diff --git a/application/api/ApiMiddleware.php b/application/api/ApiMiddleware.php
index 162e88e0..522091ca 100644
--- a/application/api/ApiMiddleware.php
+++ b/application/api/ApiMiddleware.php
@@ -98,8 +98,7 @@ class ApiMiddleware
98 * @throws ApiAuthorizationException The token couldn't be validated. 98 * @throws ApiAuthorizationException The token couldn't be validated.
99 */ 99 */
100 protected function checkToken($request) { 100 protected function checkToken($request) {
101 $jwt = $request->getHeaderLine('jwt'); 101 if (! $request->hasHeader('Authorization')) {
102 if (empty($jwt)) {
103 throw new ApiAuthorizationException('JWT token not provided'); 102 throw new ApiAuthorizationException('JWT token not provided');
104 } 103 }
105 104
@@ -107,7 +106,13 @@ class ApiMiddleware
107 throw new ApiAuthorizationException('Token secret must be set in Shaarli\'s administration'); 106 throw new ApiAuthorizationException('Token secret must be set in Shaarli\'s administration');
108 } 107 }
109 108
110 ApiUtils::validateJwtToken($jwt, $this->conf->get('api.secret')); 109 $authorization = $request->getHeaderLine('Authorization');
110
111 if (! preg_match('/^Bearer (.*)/i', $authorization, $matches)) {
112 throw new ApiAuthorizationException('Invalid JWT header');
113 }
114
115 ApiUtils::validateJwtToken($matches[1], $this->conf->get('api.secret'));
111 } 116 }
112 117
113 /** 118 /**
diff --git a/application/api/ApiUtils.php b/application/api/ApiUtils.php
index d0242919..d4015865 100644
--- a/application/api/ApiUtils.php
+++ b/application/api/ApiUtils.php
@@ -1,13 +1,11 @@
1<?php 1<?php
2
3namespace Shaarli\Api; 2namespace Shaarli\Api;
4 3
4use Shaarli\Base64Url;
5use Shaarli\Api\Exceptions\ApiAuthorizationException; 5use Shaarli\Api\Exceptions\ApiAuthorizationException;
6 6
7/** 7/**
8 * Class ApiUtils 8 * REST API utilities
9 *
10 * Utility functions for the API.
11 */ 9 */
12class ApiUtils 10class ApiUtils
13{ 11{
@@ -26,17 +24,17 @@ class ApiUtils
26 throw new ApiAuthorizationException('Malformed JWT token'); 24 throw new ApiAuthorizationException('Malformed JWT token');
27 } 25 }
28 26
29 $genSign = hash_hmac('sha512', $parts[0] .'.'. $parts[1], $secret); 27 $genSign = Base64Url::encode(hash_hmac('sha512', $parts[0] .'.'. $parts[1], $secret, true));
30 if ($parts[2] != $genSign) { 28 if ($parts[2] != $genSign) {
31 throw new ApiAuthorizationException('Invalid JWT signature'); 29 throw new ApiAuthorizationException('Invalid JWT signature');
32 } 30 }
33 31
34 $header = json_decode(base64_decode($parts[0])); 32 $header = json_decode(Base64Url::decode($parts[0]));
35 if ($header === null) { 33 if ($header === null) {
36 throw new ApiAuthorizationException('Invalid JWT header'); 34 throw new ApiAuthorizationException('Invalid JWT header');
37 } 35 }
38 36
39 $payload = json_decode(base64_decode($parts[1])); 37 $payload = json_decode(Base64Url::decode($parts[1]));
40 if ($payload === null) { 38 if ($payload === null) {
41 throw new ApiAuthorizationException('Invalid JWT payload'); 39 throw new ApiAuthorizationException('Invalid JWT payload');
42 } 40 }
diff --git a/application/config/ConfigIO.php b/application/config/ConfigIO.php
index 2b68fe6a..be78b1c7 100644
--- a/application/config/ConfigIO.php
+++ b/application/config/ConfigIO.php
@@ -14,7 +14,7 @@ interface ConfigIO
14 * 14 *
15 * @return array All configuration in an array. 15 * @return array All configuration in an array.
16 */ 16 */
17 function read($filepath); 17 public function read($filepath);
18 18
19 /** 19 /**
20 * Write configuration. 20 * Write configuration.
@@ -22,12 +22,12 @@ interface ConfigIO
22 * @param string $filepath Config file absolute path. 22 * @param string $filepath Config file absolute path.
23 * @param array $conf All configuration in an array. 23 * @param array $conf All configuration in an array.
24 */ 24 */
25 function write($filepath, $conf); 25 public function write($filepath, $conf);
26 26
27 /** 27 /**
28 * Get config file extension according to config type. 28 * Get config file extension according to config type.
29 * 29 *
30 * @return string Config file extension. 30 * @return string Config file extension.
31 */ 31 */
32 function getExtension(); 32 public function getExtension();
33} 33}
diff --git a/application/config/ConfigJson.php b/application/config/ConfigJson.php
index 30007eb4..6b5d73f1 100644
--- a/application/config/ConfigJson.php
+++ b/application/config/ConfigJson.php
@@ -10,7 +10,7 @@ class ConfigJson implements ConfigIO
10 /** 10 /**
11 * @inheritdoc 11 * @inheritdoc
12 */ 12 */
13 function read($filepath) 13 public function read($filepath)
14 { 14 {
15 if (! is_readable($filepath)) { 15 if (! is_readable($filepath)) {
16 return array(); 16 return array();
@@ -29,7 +29,7 @@ class ConfigJson implements ConfigIO
29 /** 29 /**
30 * @inheritdoc 30 * @inheritdoc
31 */ 31 */
32 function write($filepath, $conf) 32 public function write($filepath, $conf)
33 { 33 {
34 // JSON_PRETTY_PRINT is available from PHP 5.4. 34 // JSON_PRETTY_PRINT is available from PHP 5.4.
35 $print = defined('JSON_PRETTY_PRINT') ? JSON_PRETTY_PRINT : 0; 35 $print = defined('JSON_PRETTY_PRINT') ? JSON_PRETTY_PRINT : 0;
@@ -46,7 +46,7 @@ class ConfigJson implements ConfigIO
46 /** 46 /**
47 * @inheritdoc 47 * @inheritdoc
48 */ 48 */
49 function getExtension() 49 public function getExtension()
50 { 50 {
51 return '.json.php'; 51 return '.json.php';
52 } 52 }
diff --git a/application/config/ConfigManager.php b/application/config/ConfigManager.php
index ca8918b5..a401887c 100644
--- a/application/config/ConfigManager.php
+++ b/application/config/ConfigManager.php
@@ -299,6 +299,7 @@ class ConfigManager
299 $this->setEmpty('resource.log', 'data/log.txt'); 299 $this->setEmpty('resource.log', 'data/log.txt');
300 $this->setEmpty('resource.update_check', 'data/lastupdatecheck.txt'); 300 $this->setEmpty('resource.update_check', 'data/lastupdatecheck.txt');
301 $this->setEmpty('resource.raintpl_tpl', 'tpl/'); 301 $this->setEmpty('resource.raintpl_tpl', 'tpl/');
302 $this->setEmpty('resource.theme', 'default');
302 $this->setEmpty('resource.raintpl_tmp', 'tmp/'); 303 $this->setEmpty('resource.raintpl_tmp', 'tmp/');
303 $this->setEmpty('resource.thumbnails_cache', 'cache'); 304 $this->setEmpty('resource.thumbnails_cache', 'cache');
304 $this->setEmpty('resource.page_cache', 'pagecache'); 305 $this->setEmpty('resource.page_cache', 'pagecache');
diff --git a/application/config/ConfigPhp.php b/application/config/ConfigPhp.php
index 27187b66..d7fd4baf 100644
--- a/application/config/ConfigPhp.php
+++ b/application/config/ConfigPhp.php
@@ -41,6 +41,7 @@ class ConfigPhp implements ConfigIO
41 'resource.log' => 'config.LOG_FILE', 41 'resource.log' => 'config.LOG_FILE',
42 'resource.update_check' => 'config.UPDATECHECK_FILENAME', 42 'resource.update_check' => 'config.UPDATECHECK_FILENAME',
43 'resource.raintpl_tpl' => 'config.RAINTPL_TPL', 43 'resource.raintpl_tpl' => 'config.RAINTPL_TPL',
44 'resource.theme' => 'config.theme',
44 'resource.raintpl_tmp' => 'config.RAINTPL_TMP', 45 'resource.raintpl_tmp' => 'config.RAINTPL_TMP',
45 'resource.thumbnails_cache' => 'config.CACHEDIR', 46 'resource.thumbnails_cache' => 'config.CACHEDIR',
46 'resource.page_cache' => 'config.PAGECACHE', 47 'resource.page_cache' => 'config.PAGECACHE',
@@ -71,7 +72,7 @@ class ConfigPhp implements ConfigIO
71 /** 72 /**
72 * @inheritdoc 73 * @inheritdoc
73 */ 74 */
74 function read($filepath) 75 public function read($filepath)
75 { 76 {
76 if (! file_exists($filepath) || ! is_readable($filepath)) { 77 if (! file_exists($filepath) || ! is_readable($filepath)) {
77 return array(); 78 return array();
@@ -91,7 +92,7 @@ class ConfigPhp implements ConfigIO
91 /** 92 /**
92 * @inheritdoc 93 * @inheritdoc
93 */ 94 */
94 function write($filepath, $conf) 95 public function write($filepath, $conf)
95 { 96 {
96 $configStr = '<?php '. PHP_EOL; 97 $configStr = '<?php '. PHP_EOL;
97 foreach (self::$ROOT_KEYS as $key) { 98 foreach (self::$ROOT_KEYS as $key) {
@@ -99,7 +100,7 @@ class ConfigPhp implements ConfigIO
99 $configStr .= '$GLOBALS[\'' . $key . '\'] = ' . var_export($conf[$key], true) . ';' . PHP_EOL; 100 $configStr .= '$GLOBALS[\'' . $key . '\'] = ' . var_export($conf[$key], true) . ';' . PHP_EOL;
100 } 101 }
101 } 102 }
102 103
103 // Store all $conf['config'] 104 // Store all $conf['config']
104 foreach ($conf['config'] as $key => $value) { 105 foreach ($conf['config'] as $key => $value) {
105 $configStr .= '$GLOBALS[\'config\'][\''. $key .'\'] = '.var_export($conf['config'][$key], true).';'. PHP_EOL; 106 $configStr .= '$GLOBALS[\'config\'][\''. $key .'\'] = '.var_export($conf['config'][$key], true).';'. PHP_EOL;
@@ -125,7 +126,7 @@ class ConfigPhp implements ConfigIO
125 /** 126 /**
126 * @inheritdoc 127 * @inheritdoc
127 */ 128 */
128 function getExtension() 129 public function getExtension()
129 { 130 {
130 return '.php'; 131 return '.php';
131 } 132 }
diff --git a/composer.json b/composer.json
index cfbde1a0..2fed0df7 100644
--- a/composer.json
+++ b/composer.json
@@ -24,6 +24,7 @@
24 }, 24 },
25 "autoload": { 25 "autoload": {
26 "psr-4": { 26 "psr-4": {
27 "Shaarli\\": "application",
27 "Shaarli\\Api\\": "application/api/", 28 "Shaarli\\Api\\": "application/api/",
28 "Shaarli\\Api\\Controllers\\": "application/api/controllers", 29 "Shaarli\\Api\\Controllers\\": "application/api/controllers",
29 "Shaarli\\Api\\Exceptions\\": "application/api/exceptions" 30 "Shaarli\\Api\\Exceptions\\": "application/api/exceptions"
diff --git a/docker/development/nginx.conf b/docker/development/nginx.conf
index ac0c6c61..79c45bfe 100644
--- a/docker/development/nginx.conf
+++ b/docker/development/nginx.conf
@@ -56,7 +56,16 @@ http {
56 alias /var/www/shaarli/images/favicon.ico; 56 alias /var/www/shaarli/images/favicon.ico;
57 } 57 }
58 58
59 location / {
60 # Slim - rewrite URLs
61 try_files $uri /index.php$is_args$args;
62 }
63
59 location ~ (index)\.php$ { 64 location ~ (index)\.php$ {
65 # Slim - split URL path into (script_filename, path_info)
66 try_files $uri =404;
67 fastcgi_split_path_info ^(.+\.php)(/.+)$;
68
60 # filter and proxy PHP requests to PHP-FPM 69 # filter and proxy PHP requests to PHP-FPM
61 fastcgi_pass unix:/var/run/php5-fpm.sock; 70 fastcgi_pass unix:/var/run/php5-fpm.sock;
62 fastcgi_index index.php; 71 fastcgi_index index.php;
diff --git a/docker/production/nginx.conf b/docker/production/nginx.conf
index 5ffa02d0..e8754d9b 100644
--- a/docker/production/nginx.conf
+++ b/docker/production/nginx.conf
@@ -48,7 +48,16 @@ http {
48 alias /var/www/shaarli/images/favicon.ico; 48 alias /var/www/shaarli/images/favicon.ico;
49 } 49 }
50 50
51 location / {
52 # Slim - rewrite URLs
53 try_files $uri /index.php$is_args$args;
54 }
55
51 location ~ (index)\.php$ { 56 location ~ (index)\.php$ {
57 # Slim - split URL path into (script_filename, path_info)
58 try_files $uri =404;
59 fastcgi_split_path_info ^(.+\.php)(/.+)$;
60
52 # filter and proxy PHP requests to PHP-FPM 61 # filter and proxy PHP requests to PHP-FPM
53 fastcgi_pass unix:/var/run/php5-fpm.sock; 62 fastcgi_pass unix:/var/run/php5-fpm.sock;
54 fastcgi_index index.php; 63 fastcgi_index index.php;
diff --git a/docker/production/stable/nginx.conf b/docker/production/stable/nginx.conf
index 5ffa02d0..e8754d9b 100644
--- a/docker/production/stable/nginx.conf
+++ b/docker/production/stable/nginx.conf
@@ -48,7 +48,16 @@ http {
48 alias /var/www/shaarli/images/favicon.ico; 48 alias /var/www/shaarli/images/favicon.ico;
49 } 49 }
50 50
51 location / {
52 # Slim - rewrite URLs
53 try_files $uri /index.php$is_args$args;
54 }
55
51 location ~ (index)\.php$ { 56 location ~ (index)\.php$ {
57 # Slim - split URL path into (script_filename, path_info)
58 try_files $uri =404;
59 fastcgi_split_path_info ^(.+\.php)(/.+)$;
60
52 # filter and proxy PHP requests to PHP-FPM 61 # filter and proxy PHP requests to PHP-FPM
53 fastcgi_pass unix:/var/run/php5-fpm.sock; 62 fastcgi_pass unix:/var/run/php5-fpm.sock;
54 fastcgi_index index.php; 63 fastcgi_index index.php;
diff --git a/images/squiggle.png b/images/squiggle.png
deleted file mode 100644
index a6ce218c..00000000
--- a/images/squiggle.png
+++ /dev/null
Binary files differ
diff --git a/index.php b/index.php
index ff24ed7e..beb1cbca 100644
--- a/index.php
+++ b/index.php
@@ -79,6 +79,7 @@ require_once 'application/Utils.php';
79require_once 'application/PluginManager.php'; 79require_once 'application/PluginManager.php';
80require_once 'application/Router.php'; 80require_once 'application/Router.php';
81require_once 'application/Updater.php'; 81require_once 'application/Updater.php';
82use \Shaarli\ThemeUtils;
82 83
83// Ensure the PHP version is supported 84// Ensure the PHP version is supported
84try { 85try {
@@ -122,7 +123,7 @@ if (isset($_COOKIE['shaarli']) && !is_session_id_valid($_COOKIE['shaarli'])) {
122$conf = new ConfigManager(); 123$conf = new ConfigManager();
123$conf->setEmpty('general.timezone', date_default_timezone_get()); 124$conf->setEmpty('general.timezone', date_default_timezone_get());
124$conf->setEmpty('general.title', 'Shared links on '. escape(index_url($_SERVER))); 125$conf->setEmpty('general.title', 'Shared links on '. escape(index_url($_SERVER)));
125RainTPL::$tpl_dir = $conf->get('resource.raintpl_tpl'); // template directory 126RainTPL::$tpl_dir = $conf->get('resource.raintpl_tpl').'/'.$conf->get('resource.theme').'/'; // template directory
126RainTPL::$cache_dir = $conf->get('resource.raintpl_tmp'); // cache directory 127RainTPL::$cache_dir = $conf->get('resource.raintpl_tmp'); // cache directory
127 128
128$pluginManager = new PluginManager($conf); 129$pluginManager = new PluginManager($conf);
@@ -203,7 +204,7 @@ function setup_login_state($conf)
203 } 204 }
204 // If session does not exist on server side, or IP address has changed, or session has expired, logout. 205 // If session does not exist on server side, or IP address has changed, or session has expired, logout.
205 if (empty($_SESSION['uid']) 206 if (empty($_SESSION['uid'])
206 || ($conf->get('security.session_protection_disabled') == false && $_SESSION['ip'] != allIPs()) 207 || ($conf->get('security.session_protection_disabled') === false && $_SESSION['ip'] != allIPs())
207 || time() >= $_SESSION['expires_on']) 208 || time() >= $_SESSION['expires_on'])
208 { 209 {
209 logout(); 210 logout();
@@ -617,7 +618,7 @@ function showDailyRSS($conf) {
617 $tpl->assign('links', $links); 618 $tpl->assign('links', $links);
618 $tpl->assign('rssdate', escape($dayDate->format(DateTime::RSS))); 619 $tpl->assign('rssdate', escape($dayDate->format(DateTime::RSS)));
619 $tpl->assign('hide_timestamps', $conf->get('privacy.hide_timestamps', false)); 620 $tpl->assign('hide_timestamps', $conf->get('privacy.hide_timestamps', false));
620 $html = $tpl->draw('dailyrss', $return_string=true); 621 $html = $tpl->draw('dailyrss', true);
621 622
622 echo $html . PHP_EOL; 623 echo $html . PHP_EOL;
623 } 624 }
@@ -1124,6 +1125,7 @@ function renderPage($conf, $pluginManager, $LINKSDB)
1124 $conf->set('general.timezone', $tz); 1125 $conf->set('general.timezone', $tz);
1125 $conf->set('general.title', escape($_POST['title'])); 1126 $conf->set('general.title', escape($_POST['title']));
1126 $conf->set('general.header_link', escape($_POST['titleLink'])); 1127 $conf->set('general.header_link', escape($_POST['titleLink']));
1128 $conf->set('resource.theme', escape($_POST['theme']));
1127 $conf->set('redirector.url', escape($_POST['redirector'])); 1129 $conf->set('redirector.url', escape($_POST['redirector']));
1128 $conf->set('security.session_protection_disabled', !empty($_POST['disablesessionprotection'])); 1130 $conf->set('security.session_protection_disabled', !empty($_POST['disablesessionprotection']));
1129 $conf->set('privacy.default_private_links', !empty($_POST['privateLinkByDefault'])); 1131 $conf->set('privacy.default_private_links', !empty($_POST['privateLinkByDefault']));
@@ -1134,6 +1136,7 @@ function renderPage($conf, $pluginManager, $LINKSDB)
1134 $conf->set('api.secret', escape($_POST['apiSecret'])); 1136 $conf->set('api.secret', escape($_POST['apiSecret']));
1135 try { 1137 try {
1136 $conf->write(isLoggedIn()); 1138 $conf->write(isLoggedIn());
1139 invalidateCaches($conf->get('resource.page_cache'));
1137 } 1140 }
1138 catch(Exception $e) { 1141 catch(Exception $e) {
1139 error_log( 1142 error_log(
@@ -1151,6 +1154,8 @@ function renderPage($conf, $pluginManager, $LINKSDB)
1151 else // Show the configuration form. 1154 else // Show the configuration form.
1152 { 1155 {
1153 $PAGE->assign('title', $conf->get('general.title')); 1156 $PAGE->assign('title', $conf->get('general.title'));
1157 $PAGE->assign('theme', $conf->get('resource.theme'));
1158 $PAGE->assign('theme_available', ThemeUtils::getThemes($conf->get('resource.raintpl_tpl')));
1154 $PAGE->assign('redirector', $conf->get('redirector.url')); 1159 $PAGE->assign('redirector', $conf->get('redirector.url'));
1155 list($timezone_form, $timezone_js) = generateTimeZoneForm($conf->get('general.timezone')); 1160 list($timezone_form, $timezone_js) = generateTimeZoneForm($conf->get('general.timezone'));
1156 $PAGE->assign('timezone_form', $timezone_form); 1161 $PAGE->assign('timezone_form', $timezone_form);
diff --git a/plugins/wallabag/WallabagInstance.php b/plugins/wallabag/WallabagInstance.php
index 72cc2e5e..eb8ab618 100644
--- a/plugins/wallabag/WallabagInstance.php
+++ b/plugins/wallabag/WallabagInstance.php
@@ -35,7 +35,7 @@ class WallabagInstance
35 */ 35 */
36 private $apiVersion; 36 private $apiVersion;
37 37
38 function __construct($instance, $version) 38 public function __construct($instance, $version)
39 { 39 {
40 if ($this->isVersionAllowed($version)) { 40 if ($this->isVersionAllowed($version)) {
41 $this->apiVersion = self::$wallabagVersions[$version]; 41 $this->apiVersion = self::$wallabagVersions[$version];
diff --git a/tests/ApplicationUtilsTest.php b/tests/ApplicationUtilsTest.php
index 861b8d4e..634bd0ed 100644
--- a/tests/ApplicationUtilsTest.php
+++ b/tests/ApplicationUtilsTest.php
@@ -289,6 +289,7 @@ class ApplicationUtilsTest extends PHPUnit_Framework_TestCase
289 $conf->set('resource.page_cache', 'pagecache'); 289 $conf->set('resource.page_cache', 'pagecache');
290 $conf->set('resource.raintpl_tmp', 'tmp'); 290 $conf->set('resource.raintpl_tmp', 'tmp');
291 $conf->set('resource.raintpl_tpl', 'tpl'); 291 $conf->set('resource.raintpl_tpl', 'tpl');
292 $conf->set('resource.theme', 'default');
292 $conf->set('resource.update_check', 'data/lastupdatecheck.txt'); 293 $conf->set('resource.update_check', 'data/lastupdatecheck.txt');
293 294
294 $this->assertEquals( 295 $this->assertEquals(
@@ -312,10 +313,12 @@ class ApplicationUtilsTest extends PHPUnit_Framework_TestCase
312 $conf->set('resource.page_cache', 'null/pagecache'); 313 $conf->set('resource.page_cache', 'null/pagecache');
313 $conf->set('resource.raintpl_tmp', 'null/tmp'); 314 $conf->set('resource.raintpl_tmp', 'null/tmp');
314 $conf->set('resource.raintpl_tpl', 'null/tpl'); 315 $conf->set('resource.raintpl_tpl', 'null/tpl');
316 $conf->set('resource.raintpl_theme', 'null/tpl/default');
315 $conf->set('resource.update_check', 'null/data/lastupdatecheck.txt'); 317 $conf->set('resource.update_check', 'null/data/lastupdatecheck.txt');
316 $this->assertEquals( 318 $this->assertEquals(
317 array( 319 array(
318 '"null/tpl" directory is not readable', 320 '"null/tpl" directory is not readable',
321 '"null/tpl/default" directory is not readable',
319 '"null/cache" directory is not readable', 322 '"null/cache" directory is not readable',
320 '"null/cache" directory is not writable', 323 '"null/cache" directory is not writable',
321 '"null/data" directory is not readable', 324 '"null/data" directory is not readable',
diff --git a/tests/ThemeUtilsTest.php b/tests/ThemeUtilsTest.php
new file mode 100644
index 00000000..e44564be
--- /dev/null
+++ b/tests/ThemeUtilsTest.php
@@ -0,0 +1,55 @@
1<?php
2
3namespace Shaarli;
4
5/**
6 * Class ThemeUtilsTest
7 *
8 * @package Shaarli
9 */
10class ThemeUtilsTest extends \PHPUnit_Framework_TestCase
11{
12 /**
13 * Test getThemes() with existing theme directories.
14 */
15 public function testGetThemes()
16 {
17 $themes = ['theme1', 'default', 'Bl1p_- bL0p'];
18 foreach ($themes as $theme) {
19 mkdir('sandbox/tpl/'. $theme, 0755, true);
20 }
21
22 // include a file which should be ignored
23 touch('sandbox/tpl/supertheme');
24
25 $res = ThemeUtils::getThemes('sandbox/tpl/');
26 foreach ($res as $theme) {
27 $this->assertTrue(in_array($theme, $themes));
28 }
29 $this->assertFalse(in_array('supertheme', $res));
30
31 foreach ($themes as $theme) {
32 rmdir('sandbox/tpl/'. $theme);
33 }
34 unlink('sandbox/tpl/supertheme');
35 rmdir('sandbox/tpl');
36 }
37
38 /**
39 * Test getThemes() without any theme dir.
40 */
41 public function testGetThemesEmpty()
42 {
43 mkdir('sandbox/tpl/', 0755, true);
44 $this->assertEquals([], ThemeUtils::getThemes('sandbox/tpl/'));
45 rmdir('sandbox/tpl/');
46 }
47
48 /**
49 * Test getThemes() with an invalid path.
50 */
51 public function testGetThemesInvalid()
52 {
53 $this->assertEquals([], ThemeUtils::getThemes('nope'));
54 }
55}
diff --git a/tests/Updater/UpdaterTest.php b/tests/Updater/UpdaterTest.php
index 0171daad..1d15cfaa 100644
--- a/tests/Updater/UpdaterTest.php
+++ b/tests/Updater/UpdaterTest.php
@@ -2,6 +2,7 @@
2 2
3require_once 'application/config/ConfigManager.php'; 3require_once 'application/config/ConfigManager.php';
4require_once 'tests/Updater/DummyUpdater.php'; 4require_once 'tests/Updater/DummyUpdater.php';
5require_once 'inc/rain.tpl.class.php';
5 6
6/** 7/**
7 * Class UpdaterTest. 8 * Class UpdaterTest.
@@ -421,4 +422,48 @@ $GLOBALS[\'privateLinkByDefault\'] = true;';
421 $this->assertTrue($updater->updateMethodDatastoreIds()); 422 $this->assertTrue($updater->updateMethodDatastoreIds());
422 $this->assertEquals($checksum, hash_file('sha1', self::$testDatastore)); 423 $this->assertEquals($checksum, hash_file('sha1', self::$testDatastore));
423 } 424 }
425
426 /**
427 * Test defaultTheme update with default settings: nothing to do.
428 */
429 public function testDefaultThemeWithDefaultSettings()
430 {
431 $sandbox = 'sandbox/config';
432 copy(self::$configFile . '.json.php', $sandbox . '.json.php');
433 $this->conf = new ConfigManager($sandbox);
434 $updater = new Updater([], [], $this->conf, true);
435 $this->assertTrue($updater->updateMethodDefaultTheme());
436
437 $this->assertEquals('tpl/', $this->conf->get('resource.raintpl_tpl'));
438 $this->assertEquals('default', $this->conf->get('resource.theme'));
439 $this->conf = new ConfigManager($sandbox);
440 $this->assertEquals('tpl/', $this->conf->get('resource.raintpl_tpl'));
441 $this->assertEquals('default', $this->conf->get('resource.theme'));
442 unlink($sandbox . '.json.php');
443 }
444
445 /**
446 * Test defaultTheme update with a custom theme in a subfolder
447 */
448 public function testDefaultThemeWithCustomTheme()
449 {
450 $theme = 'iamanartist';
451 $sandbox = 'sandbox/config';
452 copy(self::$configFile . '.json.php', $sandbox . '.json.php');
453 $this->conf = new ConfigManager($sandbox);
454 mkdir('sandbox/'. $theme);
455 touch('sandbox/'. $theme .'/linklist.html');
456 $this->conf->set('resource.raintpl_tpl', 'sandbox/'. $theme .'/');
457 $updater = new Updater([], [], $this->conf, true);
458 $this->assertTrue($updater->updateMethodDefaultTheme());
459
460 $this->assertEquals('sandbox', $this->conf->get('resource.raintpl_tpl'));
461 $this->assertEquals($theme, $this->conf->get('resource.theme'));
462 $this->conf = new ConfigManager($sandbox);
463 $this->assertEquals('sandbox', $this->conf->get('resource.raintpl_tpl'));
464 $this->assertEquals($theme, $this->conf->get('resource.theme'));
465 unlink($sandbox . '.json.php');
466 unlink('sandbox/'. $theme .'/linklist.html');
467 rmdir('sandbox/'. $theme);
468 }
424} 469}
diff --git a/tests/Url/UrlTest.php b/tests/Url/UrlTest.php
index 05862372..aa2f2234 100644
--- a/tests/Url/UrlTest.php
+++ b/tests/Url/UrlTest.php
@@ -157,7 +157,7 @@ class UrlTest extends PHPUnit_Framework_TestCase
157 /** 157 /**
158 * Test add trailing slash. 158 * Test add trailing slash.
159 */ 159 */
160 function testAddTrailingSlash() 160 public function testAddTrailingSlash()
161 { 161 {
162 $strOn = 'http://randomstr.com/test/'; 162 $strOn = 'http://randomstr.com/test/';
163 $strOff = 'http://randomstr.com/test'; 163 $strOff = 'http://randomstr.com/test';
@@ -168,7 +168,7 @@ class UrlTest extends PHPUnit_Framework_TestCase
168 /** 168 /**
169 * Test valid HTTP url. 169 * Test valid HTTP url.
170 */ 170 */
171 function testUrlIsHttp() 171 public function testUrlIsHttp()
172 { 172 {
173 $url = new Url(self::$baseUrl); 173 $url = new Url(self::$baseUrl);
174 $this->assertTrue($url->isHttp()); 174 $this->assertTrue($url->isHttp());
@@ -177,7 +177,7 @@ class UrlTest extends PHPUnit_Framework_TestCase
177 /** 177 /**
178 * Test non HTTP url. 178 * Test non HTTP url.
179 */ 179 */
180 function testUrlIsNotHttp() 180 public function testUrlIsNotHttp()
181 { 181 {
182 $url = new Url('ftp://save.tld/mysave'); 182 $url = new Url('ftp://save.tld/mysave');
183 $this->assertFalse($url->isHttp()); 183 $this->assertFalse($url->isHttp());
@@ -186,7 +186,7 @@ class UrlTest extends PHPUnit_Framework_TestCase
186 /** 186 /**
187 * Test International Domain Name to ASCII conversion 187 * Test International Domain Name to ASCII conversion
188 */ 188 */
189 function testIdnToAscii() 189 public function testIdnToAscii()
190 { 190 {
191 $ind = 'http://www.académie-française.fr/'; 191 $ind = 'http://www.académie-française.fr/';
192 $expected = 'http://www.xn--acadmie-franaise-npb1a.fr/'; 192 $expected = 'http://www.xn--acadmie-franaise-npb1a.fr/';
diff --git a/tests/api/ApiMiddlewareTest.php b/tests/api/ApiMiddlewareTest.php
index 4d4dd9b9..d9753b1d 100644
--- a/tests/api/ApiMiddlewareTest.php
+++ b/tests/api/ApiMiddlewareTest.php
@@ -143,7 +143,7 @@ class ApiMiddlewareTest extends \PHPUnit_Framework_TestCase
143 $env = Environment::mock([ 143 $env = Environment::mock([
144 'REQUEST_METHOD' => 'GET', 144 'REQUEST_METHOD' => 'GET',
145 'REQUEST_URI' => '/echo', 145 'REQUEST_URI' => '/echo',
146 'HTTP_JWT'=> 'jwt', 146 'HTTP_AUTHORIZATION'=> 'Bearer jwt',
147 ]); 147 ]);
148 $request = Request::createFromEnvironment($env); 148 $request = Request::createFromEnvironment($env);
149 $response = new Response(); 149 $response = new Response();
@@ -157,7 +157,30 @@ class ApiMiddlewareTest extends \PHPUnit_Framework_TestCase
157 } 157 }
158 158
159 /** 159 /**
160 * Invoke the middleware without an invalid JWT token (debug): 160 * Invoke the middleware with an invalid JWT token header
161 */
162 public function testInvalidJwtAuthHeaderDebug()
163 {
164 $this->conf->set('dev.debug', true);
165 $mw = new ApiMiddleware($this->container);
166 $env = Environment::mock([
167 'REQUEST_METHOD' => 'GET',
168 'REQUEST_URI' => '/echo',
169 'HTTP_AUTHORIZATION'=> 'PolarBearer jwt',
170 ]);
171 $request = Request::createFromEnvironment($env);
172 $response = new Response();
173 /** @var Response $response */
174 $response = $mw($request, $response, null);
175
176 $this->assertEquals(401, $response->getStatusCode());
177 $body = json_decode((string) $response->getBody());
178 $this->assertEquals('Not authorized: Invalid JWT header', $body->message);
179 $this->assertContains('ApiAuthorizationException', $body->stacktrace);
180 }
181
182 /**
183 * Invoke the middleware with an invalid JWT token (debug):
161 * should return a 401 error Unauthorized - with a specific message and a stacktrace. 184 * should return a 401 error Unauthorized - with a specific message and a stacktrace.
162 * 185 *
163 * Note: specific JWT errors tests are handled in ApiUtilsTest. 186 * Note: specific JWT errors tests are handled in ApiUtilsTest.
@@ -169,7 +192,7 @@ class ApiMiddlewareTest extends \PHPUnit_Framework_TestCase
169 $env = Environment::mock([ 192 $env = Environment::mock([
170 'REQUEST_METHOD' => 'GET', 193 'REQUEST_METHOD' => 'GET',
171 'REQUEST_URI' => '/echo', 194 'REQUEST_URI' => '/echo',
172 'HTTP_JWT'=> 'bad jwt', 195 'HTTP_AUTHORIZATION'=> 'Bearer jwt',
173 ]); 196 ]);
174 $request = Request::createFromEnvironment($env); 197 $request = Request::createFromEnvironment($env);
175 $response = new Response(); 198 $response = new Response();
diff --git a/tests/api/ApiUtilsTest.php b/tests/api/ApiUtilsTest.php
index 516ee686..b4431d1b 100644
--- a/tests/api/ApiUtilsTest.php
+++ b/tests/api/ApiUtilsTest.php
@@ -2,6 +2,9 @@
2 2
3namespace Shaarli\Api; 3namespace Shaarli\Api;
4 4
5use Shaarli\Base64Url;
6
7
5/** 8/**
6 * Class ApiUtilsTest 9 * Class ApiUtilsTest
7 */ 10 */
@@ -24,14 +27,14 @@ class ApiUtilsTest extends \PHPUnit_Framework_TestCase
24 */ 27 */
25 public static function generateValidJwtToken($secret) 28 public static function generateValidJwtToken($secret)
26 { 29 {
27 $header = base64_encode('{ 30 $header = Base64Url::encode('{
28 "typ": "JWT", 31 "typ": "JWT",
29 "alg": "HS512" 32 "alg": "HS512"
30 }'); 33 }');
31 $payload = base64_encode('{ 34 $payload = Base64Url::encode('{
32 "iat": '. time() .' 35 "iat": '. time() .'
33 }'); 36 }');
34 $signature = hash_hmac('sha512', $header .'.'. $payload , $secret); 37 $signature = Base64Url::encode(hash_hmac('sha512', $header .'.'. $payload , $secret, true));
35 return $header .'.'. $payload .'.'. $signature; 38 return $header .'.'. $payload .'.'. $signature;
36 } 39 }
37 40
@@ -46,9 +49,9 @@ class ApiUtilsTest extends \PHPUnit_Framework_TestCase
46 */ 49 */
47 public static function generateCustomJwtToken($header, $payload, $secret) 50 public static function generateCustomJwtToken($header, $payload, $secret)
48 { 51 {
49 $header = base64_encode($header); 52 $header = Base64Url::encode($header);
50 $payload = base64_encode($payload); 53 $payload = Base64Url::encode($payload);
51 $signature = hash_hmac('sha512', $header . '.' . $payload, $secret); 54 $signature = Base64Url::encode(hash_hmac('sha512', $header . '.' . $payload, $secret, true));
52 return $header . '.' . $payload . '.' . $signature; 55 return $header . '.' . $payload . '.' . $signature;
53 } 56 }
54 57
diff --git a/tests/plugins/PluginAddlinkTest.php b/tests/plugins/PluginAddlinkTest.php
index a2f25bec..b77fe12a 100644
--- a/tests/plugins/PluginAddlinkTest.php
+++ b/tests/plugins/PluginAddlinkTest.php
@@ -16,7 +16,7 @@ class PluginAddlinkTest extends PHPUnit_Framework_TestCase
16 /** 16 /**
17 * Reset plugin path. 17 * Reset plugin path.
18 */ 18 */
19 function setUp() 19 public function setUp()
20 { 20 {
21 PluginManager::$PLUGINS_PATH = 'plugins'; 21 PluginManager::$PLUGINS_PATH = 'plugins';
22 } 22 }
@@ -24,7 +24,7 @@ class PluginAddlinkTest extends PHPUnit_Framework_TestCase
24 /** 24 /**
25 * Test render_header hook while logged in. 25 * Test render_header hook while logged in.
26 */ 26 */
27 function testAddlinkHeaderLoggedIn() 27 public function testAddlinkHeaderLoggedIn()
28 { 28 {
29 $str = 'stuff'; 29 $str = 'stuff';
30 $data = array($str => $str); 30 $data = array($str => $str);
@@ -46,7 +46,7 @@ class PluginAddlinkTest extends PHPUnit_Framework_TestCase
46 /** 46 /**
47 * Test render_header hook while logged out. 47 * Test render_header hook while logged out.
48 */ 48 */
49 function testAddlinkHeaderLoggedOut() 49 public function testAddlinkHeaderLoggedOut()
50 { 50 {
51 $str = 'stuff'; 51 $str = 'stuff';
52 $data = array($str => $str); 52 $data = array($str => $str);
@@ -61,7 +61,7 @@ class PluginAddlinkTest extends PHPUnit_Framework_TestCase
61 /** 61 /**
62 * Test render_includes hook while logged in. 62 * Test render_includes hook while logged in.
63 */ 63 */
64 function testAddlinkIncludesLoggedIn() 64 public function testAddlinkIncludesLoggedIn()
65 { 65 {
66 $str = 'stuff'; 66 $str = 'stuff';
67 $data = array($str => $str); 67 $data = array($str => $str);
@@ -86,7 +86,7 @@ class PluginAddlinkTest extends PHPUnit_Framework_TestCase
86 * Test render_includes hook. 86 * Test render_includes hook.
87 * Should not affect css files while logged out. 87 * Should not affect css files while logged out.
88 */ 88 */
89 function testAddlinkIncludesLoggedOut() 89 public function testAddlinkIncludesLoggedOut()
90 { 90 {
91 $str = 'stuff'; 91 $str = 'stuff';
92 $data = array($str => $str); 92 $data = array($str => $str);
diff --git a/tests/plugins/PluginArchiveorgTest.php b/tests/plugins/PluginArchiveorgTest.php
index 4daa4c9d..fecd5f2c 100644
--- a/tests/plugins/PluginArchiveorgTest.php
+++ b/tests/plugins/PluginArchiveorgTest.php
@@ -15,7 +15,7 @@ class PluginArchiveorgTest extends PHPUnit_Framework_TestCase
15 /** 15 /**
16 * Reset plugin path 16 * Reset plugin path
17 */ 17 */
18 function setUp() 18 public function setUp()
19 { 19 {
20 PluginManager::$PLUGINS_PATH = 'plugins'; 20 PluginManager::$PLUGINS_PATH = 'plugins';
21 } 21 }
@@ -23,7 +23,7 @@ class PluginArchiveorgTest extends PHPUnit_Framework_TestCase
23 /** 23 /**
24 * Test render_linklist hook on external links. 24 * Test render_linklist hook on external links.
25 */ 25 */
26 function testArchiveorgLinklistOnExternalLinks() 26 public function testArchiveorgLinklistOnExternalLinks()
27 { 27 {
28 $str = 'http://randomstr.com/test'; 28 $str = 'http://randomstr.com/test';
29 29
@@ -48,13 +48,12 @@ class PluginArchiveorgTest extends PHPUnit_Framework_TestCase
48 // plugin data 48 // plugin data
49 $this->assertEquals(1, count($link['link_plugin'])); 49 $this->assertEquals(1, count($link['link_plugin']));
50 $this->assertNotFalse(strpos($link['link_plugin'][0], $str)); 50 $this->assertNotFalse(strpos($link['link_plugin'][0], $str));
51
52 } 51 }
53 52
54 /** 53 /**
55 * Test render_linklist hook on internal links. 54 * Test render_linklist hook on internal links.
56 */ 55 */
57 function testArchiveorgLinklistOnInternalLinks() 56 public function testArchiveorgLinklistOnInternalLinks()
58 { 57 {
59 $internalLink1 = 'http://shaarli.shaarli/?qvMAqg'; 58 $internalLink1 = 'http://shaarli.shaarli/?qvMAqg';
60 $internalLinkRealURL1 = '?qvMAqg'; 59 $internalLinkRealURL1 = '?qvMAqg';
@@ -101,7 +100,6 @@ class PluginArchiveorgTest extends PHPUnit_Framework_TestCase
101 ) 100 )
102 ); 101 );
103 102
104
105 $data = hook_archiveorg_render_linklist($data); 103 $data = hook_archiveorg_render_linklist($data);
106 104
107 // Case n°1: first link type, public 105 // Case n°1: first link type, public
@@ -136,7 +134,5 @@ class PluginArchiveorgTest extends PHPUnit_Framework_TestCase
136 $link = $data['links'][5]; 134 $link = $data['links'][5];
137 135
138 $this->assertArrayNotHasKey('link_plugin', $link); 136 $this->assertArrayNotHasKey('link_plugin', $link);
139
140 } 137 }
141
142} 138}
diff --git a/tests/plugins/PluginIssoTest.php b/tests/plugins/PluginIssoTest.php
index 6b7904dd..03def208 100644
--- a/tests/plugins/PluginIssoTest.php
+++ b/tests/plugins/PluginIssoTest.php
@@ -12,7 +12,7 @@ class PluginIssoTest extends PHPUnit_Framework_TestCase
12 /** 12 /**
13 * Reset plugin path 13 * Reset plugin path
14 */ 14 */
15 function setUp() 15 public function setUp()
16 { 16 {
17 PluginManager::$PLUGINS_PATH = 'plugins'; 17 PluginManager::$PLUGINS_PATH = 'plugins';
18 } 18 }
@@ -20,7 +20,7 @@ class PluginIssoTest extends PHPUnit_Framework_TestCase
20 /** 20 /**
21 * Test Isso init without errors. 21 * Test Isso init without errors.
22 */ 22 */
23 function testWallabagInitNoError() 23 public function testWallabagInitNoError()
24 { 24 {
25 $conf = new ConfigManager(''); 25 $conf = new ConfigManager('');
26 $conf->set('plugins.ISSO_SERVER', 'value'); 26 $conf->set('plugins.ISSO_SERVER', 'value');
@@ -31,7 +31,7 @@ class PluginIssoTest extends PHPUnit_Framework_TestCase
31 /** 31 /**
32 * Test Isso init with errors. 32 * Test Isso init with errors.
33 */ 33 */
34 function testWallabagInitError() 34 public function testWallabagInitError()
35 { 35 {
36 $conf = new ConfigManager(''); 36 $conf = new ConfigManager('');
37 $errors = isso_init($conf); 37 $errors = isso_init($conf);
@@ -41,7 +41,7 @@ class PluginIssoTest extends PHPUnit_Framework_TestCase
41 /** 41 /**
42 * Test render_linklist hook with valid settings to display the comment form. 42 * Test render_linklist hook with valid settings to display the comment form.
43 */ 43 */
44 function testIssoDisplayed() 44 public function testIssoDisplayed()
45 { 45 {
46 $conf = new ConfigManager(''); 46 $conf = new ConfigManager('');
47 $conf->set('plugins.ISSO_SERVER', 'value'); 47 $conf->set('plugins.ISSO_SERVER', 'value');
@@ -81,7 +81,7 @@ class PluginIssoTest extends PHPUnit_Framework_TestCase
81 /** 81 /**
82 * Test isso plugin when multiple links are displayed (shouldn't be displayed). 82 * Test isso plugin when multiple links are displayed (shouldn't be displayed).
83 */ 83 */
84 function testIssoMultipleLinks() 84 public function testIssoMultipleLinks()
85 { 85 {
86 $conf = new ConfigManager(''); 86 $conf = new ConfigManager('');
87 $conf->set('plugins.ISSO_SERVER', 'value'); 87 $conf->set('plugins.ISSO_SERVER', 'value');
@@ -113,7 +113,7 @@ class PluginIssoTest extends PHPUnit_Framework_TestCase
113 /** 113 /**
114 * Test isso plugin when using search (shouldn't be displayed). 114 * Test isso plugin when using search (shouldn't be displayed).
115 */ 115 */
116 function testIssoNotDisplayedWhenSearch() 116 public function testIssoNotDisplayedWhenSearch()
117 { 117 {
118 $conf = new ConfigManager(''); 118 $conf = new ConfigManager('');
119 $conf->set('plugins.ISSO_SERVER', 'value'); 119 $conf->set('plugins.ISSO_SERVER', 'value');
@@ -141,7 +141,7 @@ class PluginIssoTest extends PHPUnit_Framework_TestCase
141 /** 141 /**
142 * Test isso plugin without server configuration (shouldn't be displayed). 142 * Test isso plugin without server configuration (shouldn't be displayed).
143 */ 143 */
144 function testIssoWithoutConf() 144 public function testIssoWithoutConf()
145 { 145 {
146 $data = 'abc'; 146 $data = 'abc';
147 $conf = new ConfigManager(''); 147 $conf = new ConfigManager('');
diff --git a/tests/plugins/PluginMarkdownTest.php b/tests/plugins/PluginMarkdownTest.php
index 17ef2280..d359b2a1 100644
--- a/tests/plugins/PluginMarkdownTest.php
+++ b/tests/plugins/PluginMarkdownTest.php
@@ -16,7 +16,7 @@ class PluginMarkdownTest extends PHPUnit_Framework_TestCase
16 /** 16 /**
17 * Reset plugin path 17 * Reset plugin path
18 */ 18 */
19 function setUp() 19 public function setUp()
20 { 20 {
21 PluginManager::$PLUGINS_PATH = 'plugins'; 21 PluginManager::$PLUGINS_PATH = 'plugins';
22 } 22 }
@@ -25,7 +25,7 @@ class PluginMarkdownTest extends PHPUnit_Framework_TestCase
25 * Test render_linklist hook. 25 * Test render_linklist hook.
26 * Only check that there is basic markdown rendering. 26 * Only check that there is basic markdown rendering.
27 */ 27 */
28 function testMarkdownLinklist() 28 public function testMarkdownLinklist()
29 { 29 {
30 $markdown = '# My title' . PHP_EOL . 'Very interesting content.'; 30 $markdown = '# My title' . PHP_EOL . 'Very interesting content.';
31 $data = array( 31 $data = array(
@@ -45,7 +45,7 @@ class PluginMarkdownTest extends PHPUnit_Framework_TestCase
45 * Test render_daily hook. 45 * Test render_daily hook.
46 * Only check that there is basic markdown rendering. 46 * Only check that there is basic markdown rendering.
47 */ 47 */
48 function testMarkdownDaily() 48 public function testMarkdownDaily()
49 { 49 {
50 $markdown = '# My title' . PHP_EOL . 'Very interesting content.'; 50 $markdown = '# My title' . PHP_EOL . 'Very interesting content.';
51 $data = array( 51 $data = array(
@@ -69,7 +69,7 @@ class PluginMarkdownTest extends PHPUnit_Framework_TestCase
69 /** 69 /**
70 * Test reverse_text2clickable(). 70 * Test reverse_text2clickable().
71 */ 71 */
72 function testReverseText2clickable() 72 public function testReverseText2clickable()
73 { 73 {
74 $text = 'stuff http://hello.there/is=someone#here otherstuff'; 74 $text = 'stuff http://hello.there/is=someone#here otherstuff';
75 $clickableText = text2clickable($text, ''); 75 $clickableText = text2clickable($text, '');
@@ -80,7 +80,7 @@ class PluginMarkdownTest extends PHPUnit_Framework_TestCase
80 /** 80 /**
81 * Test reverse_nl2br(). 81 * Test reverse_nl2br().
82 */ 82 */
83 function testReverseNl2br() 83 public function testReverseNl2br()
84 { 84 {
85 $text = 'stuff' . PHP_EOL . 'otherstuff'; 85 $text = 'stuff' . PHP_EOL . 'otherstuff';
86 $processedText = nl2br($text); 86 $processedText = nl2br($text);
@@ -91,7 +91,7 @@ class PluginMarkdownTest extends PHPUnit_Framework_TestCase
91 /** 91 /**
92 * Test reverse_space2nbsp(). 92 * Test reverse_space2nbsp().
93 */ 93 */
94 function testReverseSpace2nbsp() 94 public function testReverseSpace2nbsp()
95 { 95 {
96 $text = ' stuff' . PHP_EOL . ' otherstuff and another'; 96 $text = ' stuff' . PHP_EOL . ' otherstuff and another';
97 $processedText = space2nbsp($text); 97 $processedText = space2nbsp($text);
@@ -102,7 +102,7 @@ class PluginMarkdownTest extends PHPUnit_Framework_TestCase
102 /** 102 /**
103 * Test sanitize_html(). 103 * Test sanitize_html().
104 */ 104 */
105 function testSanitizeHtml() 105 public function testSanitizeHtml()
106 { 106 {
107 $input = '< script src="js.js"/>'; 107 $input = '< script src="js.js"/>';
108 $input .= '< script attr>alert(\'xss\');</script>'; 108 $input .= '< script attr>alert(\'xss\');</script>';
@@ -119,7 +119,7 @@ class PluginMarkdownTest extends PHPUnit_Framework_TestCase
119 /** 119 /**
120 * Test the no markdown tag. 120 * Test the no markdown tag.
121 */ 121 */
122 function testNoMarkdownTag() 122 public function testNoMarkdownTag()
123 { 123 {
124 $str = 'All _work_ and `no play` makes Jack a *dull* boy.'; 124 $str = 'All _work_ and `no play` makes Jack a *dull* boy.';
125 $data = array( 125 $data = array(
@@ -158,7 +158,7 @@ class PluginMarkdownTest extends PHPUnit_Framework_TestCase
158 /** 158 /**
159 * Test that a close value to nomarkdown is not understand as nomarkdown (previous value `.nomarkdown`). 159 * Test that a close value to nomarkdown is not understand as nomarkdown (previous value `.nomarkdown`).
160 */ 160 */
161 function testNoMarkdownNotExcactlyMatching() 161 public function testNoMarkdownNotExcactlyMatching()
162 { 162 {
163 $str = 'All _work_ and `no play` makes Jack a *dull* boy.'; 163 $str = 'All _work_ and `no play` makes Jack a *dull* boy.';
164 $data = array( 164 $data = array(
@@ -176,7 +176,7 @@ class PluginMarkdownTest extends PHPUnit_Framework_TestCase
176 /** 176 /**
177 * Test hashtag links processed with markdown. 177 * Test hashtag links processed with markdown.
178 */ 178 */
179 function testMarkdownHashtagLinks() 179 public function testMarkdownHashtagLinks()
180 { 180 {
181 $md = file_get_contents('tests/plugins/resources/markdown.md'); 181 $md = file_get_contents('tests/plugins/resources/markdown.md');
182 $md = format_description($md); 182 $md = format_description($md);
diff --git a/tests/plugins/PluginPlayvideosTest.php b/tests/plugins/PluginPlayvideosTest.php
index be1ef774..29ad047f 100644
--- a/tests/plugins/PluginPlayvideosTest.php
+++ b/tests/plugins/PluginPlayvideosTest.php
@@ -16,7 +16,7 @@ class PluginPlayvideosTest extends PHPUnit_Framework_TestCase
16 /** 16 /**
17 * Reset plugin path 17 * Reset plugin path
18 */ 18 */
19 function setUp() 19 public function setUp()
20 { 20 {
21 PluginManager::$PLUGINS_PATH = 'plugins'; 21 PluginManager::$PLUGINS_PATH = 'plugins';
22 } 22 }
@@ -24,7 +24,7 @@ class PluginPlayvideosTest extends PHPUnit_Framework_TestCase
24 /** 24 /**
25 * Test render_linklist hook. 25 * Test render_linklist hook.
26 */ 26 */
27 function testPlayvideosHeader() 27 public function testPlayvideosHeader()
28 { 28 {
29 $str = 'stuff'; 29 $str = 'stuff';
30 $data = array($str => $str); 30 $data = array($str => $str);
@@ -43,7 +43,7 @@ class PluginPlayvideosTest extends PHPUnit_Framework_TestCase
43 /** 43 /**
44 * Test render_footer hook. 44 * Test render_footer hook.
45 */ 45 */
46 function testPlayvideosFooter() 46 public function testPlayvideosFooter()
47 { 47 {
48 $str = 'stuff'; 48 $str = 'stuff';
49 $data = array($str => $str); 49 $data = array($str => $str);
diff --git a/tests/plugins/PluginPubsubhubbubTest.php b/tests/plugins/PluginPubsubhubbubTest.php
index 24dd7a11..1bd87935 100644
--- a/tests/plugins/PluginPubsubhubbubTest.php
+++ b/tests/plugins/PluginPubsubhubbubTest.php
@@ -17,7 +17,7 @@ class PluginPubsubhubbubTest extends PHPUnit_Framework_TestCase
17 /** 17 /**
18 * Reset plugin path 18 * Reset plugin path
19 */ 19 */
20 function setUp() 20 public function setUp()
21 { 21 {
22 PluginManager::$PLUGINS_PATH = 'plugins'; 22 PluginManager::$PLUGINS_PATH = 'plugins';
23 } 23 }
@@ -25,7 +25,7 @@ class PluginPubsubhubbubTest extends PHPUnit_Framework_TestCase
25 /** 25 /**
26 * Test render_feed hook with an RSS feed. 26 * Test render_feed hook with an RSS feed.
27 */ 27 */
28 function testPubSubRssRenderFeed() 28 public function testPubSubRssRenderFeed()
29 { 29 {
30 $hub = 'http://domain.hub'; 30 $hub = 'http://domain.hub';
31 $conf = new ConfigManager(self::$configFile); 31 $conf = new ConfigManager(self::$configFile);
@@ -40,7 +40,7 @@ class PluginPubsubhubbubTest extends PHPUnit_Framework_TestCase
40 /** 40 /**
41 * Test render_feed hook with an ATOM feed. 41 * Test render_feed hook with an ATOM feed.
42 */ 42 */
43 function testPubSubAtomRenderFeed() 43 public function testPubSubAtomRenderFeed()
44 { 44 {
45 $hub = 'http://domain.hub'; 45 $hub = 'http://domain.hub';
46 $conf = new ConfigManager(self::$configFile); 46 $conf = new ConfigManager(self::$configFile);
diff --git a/tests/plugins/PlugQrcodeTest.php b/tests/plugins/PluginQrcodeTest.php
index 86dc7f29..211ee89c 100644
--- a/tests/plugins/PlugQrcodeTest.php
+++ b/tests/plugins/PluginQrcodeTest.php
@@ -1,29 +1,29 @@
1<?php 1<?php
2 2
3/** 3/**
4 * PlugQrcodeTest.php 4 * PluginQrcodeTest.php
5 */ 5 */
6 6
7require_once 'plugins/qrcode/qrcode.php'; 7require_once 'plugins/qrcode/qrcode.php';
8require_once 'application/Router.php'; 8require_once 'application/Router.php';
9 9
10/** 10/**
11 * Class PlugQrcodeTest 11 * Class PluginQrcodeTest
12 * Unit test for the QR-Code plugin 12 * Unit test for the QR-Code plugin
13 */ 13 */
14class PlugQrcodeTest extends PHPUnit_Framework_TestCase 14class PluginQrcodeTest extends PHPUnit_Framework_TestCase
15{ 15{
16 /** 16 /**
17 * Reset plugin path 17 * Reset plugin path
18 */ 18 */
19 function setUp() { 19 public function setUp() {
20 PluginManager::$PLUGINS_PATH = 'plugins'; 20 PluginManager::$PLUGINS_PATH = 'plugins';
21 } 21 }
22 22
23 /** 23 /**
24 * Test render_linklist hook. 24 * Test render_linklist hook.
25 */ 25 */
26 function testQrcodeLinklist() 26 public function testQrcodeLinklist()
27 { 27 {
28 $str = 'http://randomstr.com/test'; 28 $str = 'http://randomstr.com/test';
29 $data = array( 29 $data = array(
@@ -49,7 +49,7 @@ class PlugQrcodeTest extends PHPUnit_Framework_TestCase
49 /** 49 /**
50 * Test render_footer hook. 50 * Test render_footer hook.
51 */ 51 */
52 function testQrcodeFooter() 52 public function testQrcodeFooter()
53 { 53 {
54 $str = 'stuff'; 54 $str = 'stuff';
55 $data = array($str => $str); 55 $data = array($str => $str);
diff --git a/tests/plugins/PluginReadityourselfTest.php b/tests/plugins/PluginReadityourselfTest.php
index 532db146..30470ab7 100644
--- a/tests/plugins/PluginReadityourselfTest.php
+++ b/tests/plugins/PluginReadityourselfTest.php
@@ -15,7 +15,7 @@ class PluginReadityourselfTest extends PHPUnit_Framework_TestCase
15 /** 15 /**
16 * Reset plugin path 16 * Reset plugin path
17 */ 17 */
18 function setUp() 18 public function setUp()
19 { 19 {
20 PluginManager::$PLUGINS_PATH = 'plugins'; 20 PluginManager::$PLUGINS_PATH = 'plugins';
21 } 21 }
@@ -23,7 +23,7 @@ class PluginReadityourselfTest extends PHPUnit_Framework_TestCase
23 /** 23 /**
24 * Test Readityourself init without errors. 24 * Test Readityourself init without errors.
25 */ 25 */
26 function testReadityourselfInitNoError() 26 public function testReadityourselfInitNoError()
27 { 27 {
28 $conf = new ConfigManager(''); 28 $conf = new ConfigManager('');
29 $conf->set('plugins.READITYOUSELF_URL', 'value'); 29 $conf->set('plugins.READITYOUSELF_URL', 'value');
@@ -34,7 +34,7 @@ class PluginReadityourselfTest extends PHPUnit_Framework_TestCase
34 /** 34 /**
35 * Test Readityourself init with errors. 35 * Test Readityourself init with errors.
36 */ 36 */
37 function testReadityourselfInitError() 37 public function testReadityourselfInitError()
38 { 38 {
39 $conf = new ConfigManager(''); 39 $conf = new ConfigManager('');
40 $errors = readityourself_init($conf); 40 $errors = readityourself_init($conf);
@@ -44,7 +44,7 @@ class PluginReadityourselfTest extends PHPUnit_Framework_TestCase
44 /** 44 /**
45 * Test render_linklist hook. 45 * Test render_linklist hook.
46 */ 46 */
47 function testReadityourselfLinklist() 47 public function testReadityourselfLinklist()
48 { 48 {
49 $conf = new ConfigManager(''); 49 $conf = new ConfigManager('');
50 $conf->set('plugins.READITYOUSELF_URL', 'value'); 50 $conf->set('plugins.READITYOUSELF_URL', 'value');
@@ -72,7 +72,7 @@ class PluginReadityourselfTest extends PHPUnit_Framework_TestCase
72 /** 72 /**
73 * Test without config: nothing should happened. 73 * Test without config: nothing should happened.
74 */ 74 */
75 function testReadityourselfLinklistWithoutConfig() 75 public function testReadityourselfLinklistWithoutConfig()
76 { 76 {
77 $conf = new ConfigManager(''); 77 $conf = new ConfigManager('');
78 $conf->set('plugins.READITYOUSELF_URL', null); 78 $conf->set('plugins.READITYOUSELF_URL', null);
diff --git a/tests/plugins/PluginWallabagTest.php b/tests/plugins/PluginWallabagTest.php
index 2c268cbd..30351f46 100644
--- a/tests/plugins/PluginWallabagTest.php
+++ b/tests/plugins/PluginWallabagTest.php
@@ -15,7 +15,7 @@ class PluginWallabagTest extends PHPUnit_Framework_TestCase
15 /** 15 /**
16 * Reset plugin path 16 * Reset plugin path
17 */ 17 */
18 function setUp() 18 public function setUp()
19 { 19 {
20 PluginManager::$PLUGINS_PATH = 'plugins'; 20 PluginManager::$PLUGINS_PATH = 'plugins';
21 } 21 }
@@ -23,7 +23,7 @@ class PluginWallabagTest extends PHPUnit_Framework_TestCase
23 /** 23 /**
24 * Test wallabag init without errors. 24 * Test wallabag init without errors.
25 */ 25 */
26 function testWallabagInitNoError() 26 public function testWallabagInitNoError()
27 { 27 {
28 $conf = new ConfigManager(''); 28 $conf = new ConfigManager('');
29 $conf->set('plugins.WALLABAG_URL', 'value'); 29 $conf->set('plugins.WALLABAG_URL', 'value');
@@ -34,7 +34,7 @@ class PluginWallabagTest extends PHPUnit_Framework_TestCase
34 /** 34 /**
35 * Test wallabag init with errors. 35 * Test wallabag init with errors.
36 */ 36 */
37 function testWallabagInitError() 37 public function testWallabagInitError()
38 { 38 {
39 $conf = new ConfigManager(''); 39 $conf = new ConfigManager('');
40 $errors = wallabag_init($conf); 40 $errors = wallabag_init($conf);
@@ -44,7 +44,7 @@ class PluginWallabagTest extends PHPUnit_Framework_TestCase
44 /** 44 /**
45 * Test render_linklist hook. 45 * Test render_linklist hook.
46 */ 46 */
47 function testWallabagLinklist() 47 public function testWallabagLinklist()
48 { 48 {
49 $conf = new ConfigManager(''); 49 $conf = new ConfigManager('');
50 $conf->set('plugins.WALLABAG_URL', 'value'); 50 $conf->set('plugins.WALLABAG_URL', 'value');
diff --git a/tests/plugins/WallabagInstanceTest.php b/tests/plugins/WallabagInstanceTest.php
index 7c14c1df..2c466871 100644
--- a/tests/plugins/WallabagInstanceTest.php
+++ b/tests/plugins/WallabagInstanceTest.php
@@ -15,7 +15,7 @@ class WallabagInstanceTest extends PHPUnit_Framework_TestCase
15 /** 15 /**
16 * Reset plugin path 16 * Reset plugin path
17 */ 17 */
18 function setUp() 18 public function setUp()
19 { 19 {
20 $this->instance = 'http://some.url'; 20 $this->instance = 'http://some.url';
21 } 21 }
@@ -23,7 +23,7 @@ class WallabagInstanceTest extends PHPUnit_Framework_TestCase
23 /** 23 /**
24 * Test WallabagInstance with API V1. 24 * Test WallabagInstance with API V1.
25 */ 25 */
26 function testWallabagInstanceV1() 26 public function testWallabagInstanceV1()
27 { 27 {
28 $instance = new WallabagInstance($this->instance, 1); 28 $instance = new WallabagInstance($this->instance, 1);
29 $expected = $this->instance . '/?plainurl='; 29 $expected = $this->instance . '/?plainurl=';
@@ -34,7 +34,7 @@ class WallabagInstanceTest extends PHPUnit_Framework_TestCase
34 /** 34 /**
35 * Test WallabagInstance with API V2. 35 * Test WallabagInstance with API V2.
36 */ 36 */
37 function testWallabagInstanceV2() 37 public function testWallabagInstanceV2()
38 { 38 {
39 $instance = new WallabagInstance($this->instance, 2); 39 $instance = new WallabagInstance($this->instance, 2);
40 $expected = $this->instance . '/bookmarklet?url='; 40 $expected = $this->instance . '/bookmarklet?url=';
@@ -45,7 +45,7 @@ class WallabagInstanceTest extends PHPUnit_Framework_TestCase
45 /** 45 /**
46 * Test WallabagInstance with an invalid API version. 46 * Test WallabagInstance with an invalid API version.
47 */ 47 */
48 function testWallabagInstanceInvalidVersion() 48 public function testWallabagInstanceInvalidVersion()
49 { 49 {
50 $instance = new WallabagInstance($this->instance, false); 50 $instance = new WallabagInstance($this->instance, false);
51 $expected = $this->instance . '/?plainurl='; 51 $expected = $this->instance . '/?plainurl=';
diff --git a/tests/utils/config/configJson.json.php b/tests/utils/config/configJson.json.php
index 06a302e8..13d38c66 100644
--- a/tests/utils/config/configJson.json.php
+++ b/tests/utils/config/configJson.json.php
@@ -24,7 +24,8 @@
24 }, 24 },
25 "resource": { 25 "resource": {
26 "datastore": "tests\/utils\/config\/datastore.php", 26 "datastore": "tests\/utils\/config\/datastore.php",
27 "data_dir": "tests\/utils\/config" 27 "data_dir": "tests\/utils\/config",
28 "raintpl_tpl": "tpl/"
28 }, 29 },
29 "plugins": { 30 "plugins": {
30 "WALLABAG_VERSION": 1 31 "WALLABAG_VERSION": 1
diff --git a/tpl/404.html b/tpl/default/404.html
index 53e98e2e..53e98e2e 100644
--- a/tpl/404.html
+++ b/tpl/default/404.html
diff --git a/tpl/addlink.html b/tpl/default/addlink.html
index da50f45e..da50f45e 100644
--- a/tpl/addlink.html
+++ b/tpl/default/addlink.html
diff --git a/tpl/changepassword.html b/tpl/default/changepassword.html
index c40daf9d..c40daf9d 100644
--- a/tpl/changepassword.html
+++ b/tpl/default/changepassword.html
diff --git a/tpl/changetag.html b/tpl/default/changetag.html
index 13cc5cf1..a0df3328 100644
--- a/tpl/changetag.html
+++ b/tpl/default/changetag.html
@@ -1,7 +1,7 @@
1<!DOCTYPE html> 1<!DOCTYPE html>
2<html> 2<html>
3<head>{include="includes"} 3<head>{include="includes"}
4 <link type="text/css" rel="stylesheet" href="../inc/awesomplete.css" /> 4 <link type="text/css" rel="stylesheet" href="inc/awesomplete.css#" />
5 <script src="inc/awesomplete.min.js#"></script> 5 <script src="inc/awesomplete.min.js#"></script>
6</head> 6</head>
7<body onload="document.changetag.fromtag.focus();"> 7<body onload="document.changetag.fromtag.focus();">
diff --git a/tpl/configure.html b/tpl/default/configure.html
index b4197bf9..5820e6e4 100644
--- a/tpl/configure.html
+++ b/tpl/default/configure.html
@@ -19,6 +19,20 @@
19 <td><input type="text" name="titleLink" id="titleLink" size="50" value="{$titleLink}"><br/><label 19 <td><input type="text" name="titleLink" id="titleLink" size="50" value="{$titleLink}"><br/><label
20 for="titleLink">(default value is: ?)</label></td> 20 for="titleLink">(default value is: ?)</label></td>
21 </tr> 21 </tr>
22
23 <tr>
24 <td><b>Theme:</b></td>
25 <td>
26 <select name="theme" id="theme">
27 {loop="$theme_available"}
28 <option value="{$value}" {if="$value===$theme"}selected{/if}>
29 {$value|ucfirst}
30 </option>
31 {/loop}
32 </select>
33 </td>
34 </tr>
35
22 <tr> 36 <tr>
23 <td><b>Timezone:</b></td> 37 <td><b>Timezone:</b></td>
24 <td>{$timezone_form}</td> 38 <td>{$timezone_form}</td>
diff --git a/inc/reset.css b/tpl/default/css/reset.css
index e29699e2..e29699e2 100644
--- a/inc/reset.css
+++ b/tpl/default/css/reset.css
diff --git a/inc/shaarli.css b/tpl/default/css/shaarli.css
index a24d4b7c..6d73af3e 100644
--- a/inc/shaarli.css
+++ b/tpl/default/css/shaarli.css
@@ -42,7 +42,7 @@ strong {
42} 42}
43 43
44/* Buttons */ 44/* Buttons */
45.bigbutton { 45.bigbutton, #pageheader a.bigbutton {
46 background-color: #c0c0c0; 46 background-color: #c0c0c0;
47 background: -moz-linear-gradient(#c0c0c0, #ffffff) repeat scroll 0 0 transparent; 47 background: -moz-linear-gradient(#c0c0c0, #ffffff) repeat scroll 0 0 transparent;
48 background: -webkit-gradient(linear, 0 0, 0 bottom, from(#c0c0c0), to(#ffffff)); 48 background: -webkit-gradient(linear, 0 0, 0 bottom, from(#c0c0c0), to(#ffffff));
@@ -54,11 +54,17 @@ strong {
54 box-shadow: 0 1px 1px rgba(0, 0, 0, 0.5); 54 box-shadow: 0 1px 1px rgba(0, 0, 0, 0.5);
55 cursor: pointer; 55 cursor: pointer;
56 height: 24px; 56 height: 24px;
57 margin-left: 5px;
58 padding: 0 5px; 57 padding: 0 5px;
58 margin: 5px 5px 0 0;
59 color: #606060; 59 color: #606060;
60 border-style: outset; 60 border-style: outset;
61 border-width: 1px; 61 border-width: 1px;
62 display: inline-block;
63}
64
65a.bigbutton, #pageheader a.bigbutton {
66 height: 22px;
67 line-height: 22px;
62} 68}
63 69
64.smallbutton { 70.smallbutton {
@@ -103,7 +109,7 @@ strong {
103} 109}
104 110
105#pageheader #logo { 111#pageheader #logo {
106 background-image: url('../images/logo.png'); 112 background-image: url('../../../images/logo.png');
107 background-repeat: no-repeat; 113 background-repeat: no-repeat;
108 float: left; 114 float: left;
109 margin: 0 10px 0 10px; 115 margin: 0 10px 0 10px;
@@ -803,6 +809,10 @@ div.dailyAbout img {
803 height: 14px; 809 height: 14px;
804} 810}
805 811
812div.dailyEntryPermalink {
813 float: right;
814}
815
806div.dailyTitle { 816div.dailyTitle {
807 font-weight: bold; 817 font-weight: bold;
808 font-size: 44pt; 818 font-size: 44pt;
@@ -1005,7 +1015,7 @@ div.dailyNoEntry {
1005 display: inline !important; 1015 display: inline !important;
1006 } 1016 }
1007 1017
1008 .tagfilter input.bigbutton, .searchform input.bigbutton, .addform input.bigbutton { 1018 .tagfilter input.bigbutton, .searchform input.bigbutton, .addform input.bigbutton, a.bigbutton {
1009 width: 30%; 1019 width: 30%;
1010 font-size: smaller; 1020 font-size: smaller;
1011 } 1021 }
diff --git a/tpl/daily.html b/tpl/default/daily.html
index eba0af3b..e86e90b1 100644
--- a/tpl/daily.html
+++ b/tpl/default/daily.html
@@ -28,9 +28,9 @@
28 </div> 28 </div>
29 29
30 <div class="dailyTitle"> 30 <div class="dailyTitle">
31 <img src="../images/floral_left.png" width="51" height="50" class="nomobile" alt="floral_left"> 31 <img src="images/floral_left.png" width="51" height="50" class="nomobile" alt="floral_left">
32 The Daily Shaarli 32 The Daily Shaarli
33 <img src="../images/floral_right.png" width="51" height="50" class="nomobile" alt="floral_right"> 33 <img src="images/floral_right.png" width="51" height="50" class="nomobile" alt="floral_right">
34 </div> 34 </div>
35 35
36 <div class="dailyDate"> 36 <div class="dailyDate">
@@ -50,7 +50,7 @@
50 <div class="dailyEntry"> 50 <div class="dailyEntry">
51 <div class="dailyEntryPermalink"> 51 <div class="dailyEntryPermalink">
52 <a href="?{$value.shorturl}"> 52 <a href="?{$value.shorturl}">
53 <img src="../images/squiggle2.png" width="25" height="26" title="permalink" alt="permalink"> 53 <img src="images/squiggle.png" width="25" height="26" title="permalink" alt="permalink">
54 </a> 54 </a>
55 </div> 55 </div>
56 {if="!$hide_timestamps || isLoggedIn()"} 56 {if="!$hide_timestamps || isLoggedIn()"}
@@ -94,7 +94,7 @@
94 {$value} 94 {$value}
95 {/loop} 95 {/loop}
96 </div> 96 </div>
97 <div id="closing"><img src="../images/squiggle_closing.png" width="66" height="61" alt="-"></div> 97 <div id="closing"><img src="images/squiggle_closing.png" width="66" height="61" alt="-"></div>
98</div> 98</div>
99{include="page.footer"} 99{include="page.footer"}
100</body> 100</body>
diff --git a/tpl/dailyrss.html b/tpl/default/dailyrss.html
index ddbd6c5e..ddbd6c5e 100644
--- a/tpl/dailyrss.html
+++ b/tpl/default/dailyrss.html
diff --git a/tpl/editlink.html b/tpl/default/editlink.html
index 870cc168..a2d9b78f 100644
--- a/tpl/editlink.html
+++ b/tpl/default/editlink.html
@@ -1,7 +1,7 @@
1<!DOCTYPE html> 1<!DOCTYPE html>
2<html> 2<html>
3<head>{include="includes"} 3<head>{include="includes"}
4 <link type="text/css" rel="stylesheet" href="../inc/awesomplete.css" /> 4 <link type="text/css" rel="stylesheet" href="inc/awesomplete.css#" />
5</head> 5</head>
6<body 6<body
7{if="$link.title==''"}onload="document.linkform.lf_title.focus();" 7{if="$link.title==''"}onload="document.linkform.lf_title.focus();"
@@ -39,7 +39,13 @@
39 {/if} 39 {/if}
40 <input type="submit" value="Save" name="save_edit" class="bigbutton"> 40 <input type="submit" value="Save" name="save_edit" class="bigbutton">
41 <input type="submit" value="Cancel" name="cancel_edit" class="bigbutton"> 41 <input type="submit" value="Cancel" name="cancel_edit" class="bigbutton">
42 {if="!$link_is_new"}<input type="submit" value="Delete" name="delete_link" class="bigbutton delete" onClick="return confirmDeleteLink();">{/if} 42 {if="!$link_is_new && isset($link.id)"}
43 <a href="?delete_link&amp;lf_linkdate={$link.id}&amp;token={$token}"
44 name="delete_link" class="bigbutton"
45 onClick="return confirmDeleteLink();">
46 {'Delete'|t}
47 </a>
48 {/if}
43 <input type="hidden" name="token" value="{$token}"> 49 <input type="hidden" name="token" value="{$token}">
44 {if="$http_referer"}<input type="hidden" name="returnurl" value="{$http_referer}">{/if} 50 {if="$http_referer"}<input type="hidden" name="returnurl" value="{$http_referer}">{/if}
45 </form> 51 </form>
diff --git a/tpl/export.bookmarks.html b/tpl/default/export.bookmarks.html
index 127a5c20..127a5c20 100644
--- a/tpl/export.bookmarks.html
+++ b/tpl/default/export.bookmarks.html
diff --git a/tpl/export.html b/tpl/default/export.html
index 67c3d05f..67c3d05f 100644
--- a/tpl/export.html
+++ b/tpl/default/export.html
diff --git a/tpl/feed.atom.html b/tpl/default/feed.atom.html
index 49798e85..49798e85 100644
--- a/tpl/feed.atom.html
+++ b/tpl/default/feed.atom.html
diff --git a/tpl/feed.rss.html b/tpl/default/feed.rss.html
index ee3fef88..ee3fef88 100644
--- a/tpl/feed.rss.html
+++ b/tpl/default/feed.rss.html
diff --git a/images/50pc_transparent.png b/tpl/default/images/50pc_transparent.png
index 8d8f99de..8d8f99de 100644
--- a/images/50pc_transparent.png
+++ b/tpl/default/images/50pc_transparent.png
Binary files differ
diff --git a/images/Paper_texture_v5_by_bashcorpo_w1000.jpg b/tpl/default/images/Paper_texture_v5_by_bashcorpo_w1000.jpg
index dd8e67ac..dd8e67ac 100644
--- a/images/Paper_texture_v5_by_bashcorpo_w1000.jpg
+++ b/tpl/default/images/Paper_texture_v5_by_bashcorpo_w1000.jpg
Binary files differ
diff --git a/images/calendar.png b/tpl/default/images/calendar.png
index 81c74519..81c74519 100644
--- a/images/calendar.png
+++ b/tpl/default/images/calendar.png
Binary files differ
diff --git a/images/floral_left.png b/tpl/default/images/floral_left.png
index f09a861d..f09a861d 100644
--- a/images/floral_left.png
+++ b/tpl/default/images/floral_left.png
Binary files differ
diff --git a/images/floral_right.png b/tpl/default/images/floral_right.png
index 0dfb6112..0dfb6112 100644
--- a/images/floral_right.png
+++ b/tpl/default/images/floral_right.png
Binary files differ
diff --git a/images/private.png b/tpl/default/images/private.png
index 8919d658..8919d658 100644
--- a/images/private.png
+++ b/tpl/default/images/private.png
Binary files differ
diff --git a/images/squiggle2.png b/tpl/default/images/squiggle.png
index c795f0a3..c795f0a3 100644
--- a/images/squiggle2.png
+++ b/tpl/default/images/squiggle.png
Binary files differ
diff --git a/images/squiggle_closing.png b/tpl/default/images/squiggle_closing.png
index 3f9d02b1..3f9d02b1 100644
--- a/images/squiggle_closing.png
+++ b/tpl/default/images/squiggle_closing.png
Binary files differ
diff --git a/images/tag_blue.png b/tpl/default/images/tag_blue.png
index 7ec902fc..7ec902fc 100644
--- a/images/tag_blue.png
+++ b/tpl/default/images/tag_blue.png
Binary files differ
diff --git a/tpl/import.html b/tpl/default/import.html
index 071e1160..071e1160 100644
--- a/tpl/import.html
+++ b/tpl/default/import.html
diff --git a/tpl/includes.html b/tpl/default/includes.html
index 7b2997ce..17b78b17 100644
--- a/tpl/includes.html
+++ b/tpl/default/includes.html
@@ -6,9 +6,9 @@
6<link rel="alternate" type="application/rss+xml" href="{$feedurl}?do=rss{$searchcrits}#" title="RSS Feed" /> 6<link rel="alternate" type="application/rss+xml" href="{$feedurl}?do=rss{$searchcrits}#" title="RSS Feed" />
7<link rel="alternate" type="application/atom+xml" href="{$feedurl}?do=atom{$searchcrits}#" title="ATOM Feed" /> 7<link rel="alternate" type="application/atom+xml" href="{$feedurl}?do=atom{$searchcrits}#" title="ATOM Feed" />
8<link href="images/favicon.ico#" rel="shortcut icon" type="image/x-icon" /> 8<link href="images/favicon.ico#" rel="shortcut icon" type="image/x-icon" />
9<link type="text/css" rel="stylesheet" href="../inc/reset.css" /> 9<link type="text/css" rel="stylesheet" href="css/reset.css" />
10<link type="text/css" rel="stylesheet" href="../inc/shaarli.css" /> 10<link type="text/css" rel="stylesheet" href="css/shaarli.css" />
11{if="is_file('inc/user.css')"}<link type="text/css" rel="stylesheet" href="../inc/user.css" />{/if} 11{if="is_file('data/user.css')"}<link type="text/css" rel="stylesheet" href="data/user.css#" />{/if}
12{loop="$plugins_includes.css_files"} 12{loop="$plugins_includes.css_files"}
13<link type="text/css" rel="stylesheet" href="{$value}#"/> 13<link type="text/css" rel="stylesheet" href="{$value}#"/>
14{/loop} 14{/loop}
diff --git a/tpl/install.html b/tpl/default/install.html
index 42874dcd..42874dcd 100644
--- a/tpl/install.html
+++ b/tpl/default/install.html
diff --git a/tpl/linklist.html b/tpl/default/linklist.html
index d4232342..5accc92f 100644
--- a/tpl/linklist.html
+++ b/tpl/default/linklist.html
@@ -1,7 +1,7 @@
1<!DOCTYPE html> 1<!DOCTYPE html>
2<html> 2<html>
3<head> 3<head>
4 <link type="text/css" rel="stylesheet" href="../inc/awesomplete.css" /> 4 <link type="text/css" rel="stylesheet" href="inc/awesomplete.css#" />
5 {include="includes"} 5 {include="includes"}
6</head> 6</head>
7<body> 7<body>
diff --git a/tpl/linklist.paging.html b/tpl/default/linklist.paging.html
index 86019c01..86019c01 100644
--- a/tpl/linklist.paging.html
+++ b/tpl/default/linklist.paging.html
diff --git a/tpl/loginform.html b/tpl/default/loginform.html
index 84176385..84176385 100644
--- a/tpl/loginform.html
+++ b/tpl/default/loginform.html
diff --git a/tpl/opensearch.html b/tpl/default/opensearch.html
index 3fcc30b7..3fcc30b7 100644
--- a/tpl/opensearch.html
+++ b/tpl/default/opensearch.html
diff --git a/tpl/page.footer.html b/tpl/default/page.footer.html
index 006d1d68..006d1d68 100644
--- a/tpl/page.footer.html
+++ b/tpl/default/page.footer.html
diff --git a/tpl/page.header.html b/tpl/default/page.header.html
index cce61ec4..cce61ec4 100644
--- a/tpl/page.header.html
+++ b/tpl/default/page.header.html
diff --git a/tpl/page.html b/tpl/default/page.html
index 834915ec..834915ec 100644
--- a/tpl/page.html
+++ b/tpl/default/page.html
diff --git a/tpl/picwall.html b/tpl/default/picwall.html
index 4e227e37..4e227e37 100644
--- a/tpl/picwall.html
+++ b/tpl/default/picwall.html
diff --git a/tpl/pluginsadmin.html b/tpl/default/pluginsadmin.html
index ead1734e..ead1734e 100644
--- a/tpl/pluginsadmin.html
+++ b/tpl/default/pluginsadmin.html
diff --git a/tpl/readme.txt b/tpl/default/readme.txt
index b18deaed..b18deaed 100644
--- a/tpl/readme.txt
+++ b/tpl/default/readme.txt
diff --git a/tpl/tagcloud.html b/tpl/default/tagcloud.html
index 05e45273..05e45273 100644
--- a/tpl/tagcloud.html
+++ b/tpl/default/tagcloud.html
diff --git a/tpl/tools.html b/tpl/default/tools.html
index e06d239d..e06d239d 100644
--- a/tpl/tools.html
+++ b/tpl/default/tools.html