diff options
author | Nicolas Lœuillet <nicolas@loeuillet.org> | 2014-02-03 10:03:41 -0800 |
---|---|---|
committer | Nicolas Lœuillet <nicolas@loeuillet.org> | 2014-02-03 10:03:41 -0800 |
commit | 38dafee05d52948fba4a06066d7b0343c8e3de9d (patch) | |
tree | 2e3f7bd3a58bfdb046742c3e65ff082e31a9859b /inc/poche/Poche.class.php | |
parent | f355d2c87fa441221ca8a9339c426c1c95e7c2ac (diff) | |
parent | fa0bfb775a53a074e0a9d642298685b5ed1af83f (diff) | |
download | wallabag-1.4.0.tar.gz wallabag-1.4.0.tar.zst wallabag-1.4.0.zip |
Merge pull request #427 from wallabag/dev1.4.0
changelog 1.4
Diffstat (limited to 'inc/poche/Poche.class.php')
-rw-r--r-- | inc/poche/Poche.class.php | 214 |
1 files changed, 150 insertions, 64 deletions
diff --git a/inc/poche/Poche.class.php b/inc/poche/Poche.class.php index 76a73be2..4df90067 100644 --- a/inc/poche/Poche.class.php +++ b/inc/poche/Poche.class.php | |||
@@ -1,9 +1,9 @@ | |||
1 | <?php | 1 | <?php |
2 | /** | 2 | /** |
3 | * poche, a read it later open source system | 3 | * wallabag, self hostable application allowing you to not miss any content anymore |
4 | * | 4 | * |
5 | * @category poche | 5 | * @category wallabag |
6 | * @author Nicolas Lœuillet <support@inthepoche.com> | 6 | * @author Nicolas Lœuillet <nicolas@loeuillet.org> |
7 | * @copyright 2013 | 7 | * @copyright 2013 |
8 | * @license http://www.wtfpl.net/ see COPYING file | 8 | * @license http://www.wtfpl.net/ see COPYING file |
9 | */ | 9 | */ |
@@ -22,15 +22,6 @@ class Poche | |||
22 | private $currentTheme = ''; | 22 | private $currentTheme = ''; |
23 | private $currentLanguage = ''; | 23 | private $currentLanguage = ''; |
24 | private $notInstalledMessage = array(); | 24 | private $notInstalledMessage = array(); |
25 | |||
26 | # @todo make this dynamic (actually install themes and save them in the database including author information et cetera) | ||
27 | private $installedThemes = array( | ||
28 | 'default' => array('requires' => array()), | ||
29 | 'dark' => array('requires' => array('default')), | ||
30 | 'dmagenta' => array('requires' => array('default')), | ||
31 | 'solarized' => array('requires' => array('default')), | ||
32 | 'solarized-dark' => array('requires' => array('default')) | ||
33 | ); | ||
34 | 25 | ||
35 | public function __construct() | 26 | public function __construct() |
36 | { | 27 | { |
@@ -110,7 +101,7 @@ class Poche | |||
110 | $passTheme = TRUE; | 101 | $passTheme = TRUE; |
111 | # Twig is an absolute requirement for Poche to function. Abort immediately if the Composer installer hasn't been run yet | 102 | # Twig is an absolute requirement for Poche to function. Abort immediately if the Composer installer hasn't been run yet |
112 | if (! self::$canRenderTemplates) { | 103 | if (! self::$canRenderTemplates) { |
113 | $this->notInstalledMessage[] = 'Twig does not seem to be installed. Please initialize the Composer installation to automatically fetch dependencies. Have a look at <a href="http://doc.inthepoche.com/doku.php?id=users:begin:install">the documentation.</a>'; | 104 | $this->notInstalledMessage[] = 'Twig does not seem to be installed. Please initialize the Composer installation to automatically fetch dependencies. Have a look at <a href="http://doc.wallabag.org/doku.php?id=users:begin:install">the documentation.</a>'; |
114 | $passTheme = FALSE; | 105 | $passTheme = FALSE; |
115 | } | 106 | } |
116 | 107 | ||
@@ -123,21 +114,26 @@ class Poche | |||
123 | } | 114 | } |
124 | 115 | ||
125 | # Check if the selected theme and its requirements are present | 116 | # Check if the selected theme and its requirements are present |
126 | if ($this->getTheme() != '' && ! is_dir(THEME . '/' . $this->getTheme())) { | 117 | $theme = $this->getTheme(); |
127 | $this->notInstalledMessage[] = 'The currently selected theme (' . $this->getTheme() . ') does not seem to be properly installed (Missing directory: ' . THEME . '/' . $this->getTheme() . ')'; | 118 | |
119 | if ($theme != '' && ! is_dir(THEME . '/' . $theme)) { | ||
120 | $this->notInstalledMessage[] = 'The currently selected theme (' . $theme . ') does not seem to be properly installed (Missing directory: ' . THEME . '/' . $theme . ')'; | ||
128 | 121 | ||
129 | self::$canRenderTemplates = false; | 122 | self::$canRenderTemplates = false; |
130 | 123 | ||
131 | $passTheme = FALSE; | 124 | $passTheme = FALSE; |
132 | } | 125 | } |
133 | 126 | ||
134 | foreach ($this->installedThemes[$this->getTheme()]['requires'] as $requiredTheme) { | 127 | $themeInfo = $this->getThemeInfo($theme); |
135 | if (! is_dir(THEME . '/' . $requiredTheme)) { | 128 | if (isset($themeInfo['requirements']) && is_array($themeInfo['requirements'])) { |
136 | $this->notInstalledMessage[] = 'The required "' . $requiredTheme . '" theme is missing for the current theme (' . $this->getTheme() . ')'; | 129 | foreach ($themeInfo['requirements'] as $requiredTheme) { |
130 | if (! is_dir(THEME . '/' . $requiredTheme)) { | ||
131 | $this->notInstalledMessage[] = 'The required "' . $requiredTheme . '" theme is missing for the current theme (' . $theme . ')'; | ||
137 | 132 | ||
138 | self::$canRenderTemplates = false; | 133 | self::$canRenderTemplates = false; |
139 | 134 | ||
140 | $passTheme = FALSE; | 135 | $passTheme = FALSE; |
136 | } | ||
141 | } | 137 | } |
142 | } | 138 | } |
143 | 139 | ||
@@ -193,32 +189,36 @@ class Poche | |||
193 | private function initTpl() | 189 | private function initTpl() |
194 | { | 190 | { |
195 | $loaderChain = new Twig_Loader_Chain(); | 191 | $loaderChain = new Twig_Loader_Chain(); |
192 | $theme = $this->getTheme(); | ||
196 | 193 | ||
197 | # add the current theme as first to the loader chain so Twig will look there first for overridden template files | 194 | # add the current theme as first to the loader chain so Twig will look there first for overridden template files |
198 | try { | 195 | try { |
199 | $loaderChain->addLoader(new Twig_Loader_Filesystem(THEME . '/' . $this->getTheme())); | 196 | $loaderChain->addLoader(new Twig_Loader_Filesystem(THEME . '/' . $theme)); |
200 | } catch (Twig_Error_Loader $e) { | 197 | } catch (Twig_Error_Loader $e) { |
201 | # @todo isInstalled() should catch this, inject Twig later | 198 | # @todo isInstalled() should catch this, inject Twig later |
202 | die('The currently selected theme (' . $this->getTheme() . ') does not seem to be properly installed (' . THEME . '/' . $this->getTheme() .' is missing)'); | 199 | die('The currently selected theme (' . $theme . ') does not seem to be properly installed (' . THEME . '/' . $theme .' is missing)'); |
203 | } | 200 | } |
204 | 201 | ||
205 | # add all required themes to the loader chain | 202 | # add all required themes to the loader chain |
206 | foreach ($this->installedThemes[$this->getTheme()]['requires'] as $requiredTheme) { | 203 | $themeInfo = $this->getThemeInfo($theme); |
207 | try { | 204 | if (isset($themeInfo['requirements']) && is_array($themeInfo['requirements'])) { |
208 | $loaderChain->addLoader(new Twig_Loader_Filesystem(THEME . '/' . DEFAULT_THEME)); | 205 | foreach ($themeInfo['requirements'] as $requiredTheme) { |
209 | } catch (Twig_Error_Loader $e) { | 206 | try { |
210 | # @todo isInstalled() should catch this, inject Twig later | 207 | $loaderChain->addLoader(new Twig_Loader_Filesystem(THEME . '/' . $requiredTheme)); |
211 | die('The required "' . $requiredTheme . '" theme is missing for the current theme (' . $this->getTheme() . ')'); | 208 | } catch (Twig_Error_Loader $e) { |
209 | # @todo isInstalled() should catch this, inject Twig later | ||
210 | die('The required "' . $requiredTheme . '" theme is missing for the current theme (' . $theme . ')'); | ||
211 | } | ||
212 | } | 212 | } |
213 | } | 213 | } |
214 | 214 | ||
215 | if (DEBUG_POCHE) { | 215 | if (DEBUG_POCHE) { |
216 | $twig_params = array(); | 216 | $twigParams = array(); |
217 | } else { | 217 | } else { |
218 | $twig_params = array('cache' => CACHE); | 218 | $twigParams = array('cache' => CACHE); |
219 | } | 219 | } |
220 | 220 | ||
221 | $this->tpl = new Twig_Environment($loaderChain, $twig_params); | 221 | $this->tpl = new Twig_Environment($loaderChain, $twigParams); |
222 | $this->tpl->addExtension(new Twig_Extensions_Extension_I18n()); | 222 | $this->tpl->addExtension(new Twig_Extensions_Extension_I18n()); |
223 | 223 | ||
224 | # filter to display domain name of an url | 224 | # filter to display domain name of an url |
@@ -234,7 +234,7 @@ class Poche | |||
234 | $this->tpl->addFilter($filter); | 234 | $this->tpl->addFilter($filter); |
235 | } | 235 | } |
236 | 236 | ||
237 | private function install() | 237 | private function install() |
238 | { | 238 | { |
239 | Tools::logm('poche still not installed'); | 239 | Tools::logm('poche still not installed'); |
240 | echo $this->tpl->render('install.twig', array( | 240 | echo $this->tpl->render('install.twig', array( |
@@ -265,34 +265,59 @@ class Poche | |||
265 | return $this->currentTheme; | 265 | return $this->currentTheme; |
266 | } | 266 | } |
267 | 267 | ||
268 | public function getLanguage() { | 268 | /** |
269 | return $this->currentLanguage; | 269 | * Provides theme information by parsing theme.ini file if present in the theme's root directory. |
270 | * In all cases, the following data will be returned: | ||
271 | * - name: theme's name, or key if the theme is unnamed, | ||
272 | * - current: boolean informing if the theme is the current user theme. | ||
273 | * | ||
274 | * @param string $theme Theme key (directory name) | ||
275 | * @return array|boolean Theme information, or false if the theme doesn't exist. | ||
276 | */ | ||
277 | public function getThemeInfo($theme) { | ||
278 | if (!is_dir(THEME . '/' . $theme)) { | ||
279 | return false; | ||
280 | } | ||
281 | |||
282 | $themeIniFile = THEME . '/' . $theme . '/theme.ini'; | ||
283 | $themeInfo = array(); | ||
284 | |||
285 | if (is_file($themeIniFile) && is_readable($themeIniFile)) { | ||
286 | $themeInfo = parse_ini_file($themeIniFile); | ||
287 | } | ||
288 | |||
289 | if ($themeInfo === false) { | ||
290 | $themeInfo = array(); | ||
291 | } | ||
292 | if (!isset($themeInfo['name'])) { | ||
293 | $themeInfo['name'] = $theme; | ||
294 | } | ||
295 | $themeInfo['current'] = ($theme === $this->getTheme()); | ||
296 | |||
297 | return $themeInfo; | ||
270 | } | 298 | } |
271 | 299 | ||
272 | public function getInstalledThemes() { | 300 | public function getInstalledThemes() { |
273 | $handle = opendir(THEME); | 301 | $handle = opendir(THEME); |
274 | $themes = array(); | 302 | $themes = array(); |
275 | 303 | ||
276 | while (($theme = readdir($handle)) !== false) { | 304 | while (($theme = readdir($handle)) !== false) { |
277 | # Themes are stored in a directory, so all directory names are themes | 305 | # Themes are stored in a directory, so all directory names are themes |
278 | # @todo move theme installation data to database | 306 | # @todo move theme installation data to database |
279 | if (! is_dir(THEME . '/' . $theme) || in_array($theme, array('..', '.'))) { | 307 | if (!is_dir(THEME . '/' . $theme) || in_array($theme, array('.', '..'))) { |
280 | continue; | 308 | continue; |
281 | } | 309 | } |
282 | 310 | ||
283 | $current = false; | 311 | $themes[$theme] = $this->getThemeInfo($theme); |
284 | |||
285 | if ($theme === $this->getTheme()) { | ||
286 | $current = true; | ||
287 | } | ||
288 | |||
289 | $themes[] = array('name' => $theme, 'current' => $current); | ||
290 | } | 312 | } |
291 | 313 | ||
292 | sort($themes); | ||
293 | return $themes; | 314 | return $themes; |
294 | } | 315 | } |
295 | 316 | ||
317 | public function getLanguage() { | ||
318 | return $this->currentLanguage; | ||
319 | } | ||
320 | |||
296 | public function getInstalledLanguages() { | 321 | public function getInstalledLanguages() { |
297 | $handle = opendir(LOCALE); | 322 | $handle = opendir(LOCALE); |
298 | $languages = array(); | 323 | $languages = array(); |
@@ -325,6 +350,22 @@ class Poche | |||
325 | ); | 350 | ); |
326 | } | 351 | } |
327 | 352 | ||
353 | protected function getPageContent(Url $url) | ||
354 | { | ||
355 | $options = array('http' => array('user_agent' => 'poche')); | ||
356 | if (isset($_SERVER['AUTH_TYPE']) && "basic" === strtolower($_SERVER['AUTH_TYPE'])) { | ||
357 | $options['http']['header'] = sprintf( | ||
358 | "Authorization: Basic %s", | ||
359 | base64_encode( | ||
360 | sprintf('%s:%s', $_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW']) | ||
361 | ) | ||
362 | ); | ||
363 | } | ||
364 | $context = stream_context_create($options); | ||
365 | $json = file_get_contents(Tools::getPocheUrl() . '/inc/3rdparty/makefulltextfeed.php?url='.urlencode($url->getUrl()).'&max=5&links=preserve&exc=&format=json&submit=Create+Feed', false, $context); | ||
366 | return json_decode($json, true); | ||
367 | } | ||
368 | |||
328 | /** | 369 | /** |
329 | * Call action (mark as fav, archive, delete, etc.) | 370 | * Call action (mark as fav, archive, delete, etc.) |
330 | */ | 371 | */ |
@@ -333,11 +374,8 @@ class Poche | |||
333 | switch ($action) | 374 | switch ($action) |
334 | { | 375 | { |
335 | case 'add': | 376 | case 'add': |
336 | $options = array('http' => array('user_agent' => 'poche')); | 377 | $content = $this->getPageContent($url); |
337 | $context = stream_context_create($options); | 378 | $title = ($content['rss']['channel']['item']['title'] != '') ? $content['rss']['channel']['item']['title'] : _('Untitled'); |
338 | $json = file_get_contents(Tools::getPocheUrl() . '/inc/3rdparty/makefulltextfeed.php?url='.urlencode($url->getUrl()).'&max=5&links=preserve&exc=&format=json&submit=Create+Feed', false, $context); | ||
339 | $content = json_decode($json, true); | ||
340 | $title = $content['rss']['channel']['item']['title']; | ||
341 | $body = $content['rss']['channel']['item']['description']; | 379 | $body = $content['rss']['channel']['item']['description']; |
342 | 380 | ||
343 | if ($this->store->add($url->getUrl(), $title, $body, $this->user->getId())) { | 381 | if ($this->store->add($url->getUrl(), $title, $body, $this->user->getId())) { |
@@ -586,8 +624,8 @@ class Poche | |||
586 | $themes = $this->getInstalledThemes(); | 624 | $themes = $this->getInstalledThemes(); |
587 | $actualTheme = false; | 625 | $actualTheme = false; |
588 | 626 | ||
589 | foreach ($themes as $theme) { | 627 | foreach (array_keys($themes) as $theme) { |
590 | if ($theme['name'] == $_POST['theme']) { | 628 | if ($theme == $_POST['theme']) { |
591 | $actualTheme = true; | 629 | $actualTheme = true; |
592 | break; | 630 | break; |
593 | } | 631 | } |
@@ -654,17 +692,17 @@ class Poche | |||
654 | */ | 692 | */ |
655 | private function credentials() { | 693 | private function credentials() { |
656 | if(isset($_SERVER['PHP_AUTH_USER'])) { | 694 | if(isset($_SERVER['PHP_AUTH_USER'])) { |
657 | return array($_SERVER['PHP_AUTH_USER'],'php_auth'); | 695 | return array($_SERVER['PHP_AUTH_USER'],'php_auth',true); |
658 | } | 696 | } |
659 | if(!empty($_POST['login']) && !empty($_POST['password'])) { | 697 | if(!empty($_POST['login']) && !empty($_POST['password'])) { |
660 | return array($_POST['login'],$_POST['password']); | 698 | return array($_POST['login'],$_POST['password'],false); |
661 | } | 699 | } |
662 | if(isset($_SERVER['REMOTE_USER'])) { | 700 | if(isset($_SERVER['REMOTE_USER'])) { |
663 | return array($_SERVER['REMOTE_USER'],'http_auth'); | 701 | return array($_SERVER['REMOTE_USER'],'http_auth',true); |
664 | } | 702 | } |
665 | 703 | ||
666 | return array(false,false); | 704 | return array(false,false,false); |
667 | } | 705 | } |
668 | 706 | ||
669 | /** | 707 | /** |
670 | * checks if login & password are correct and save the user in session. | 708 | * checks if login & password are correct and save the user in session. |
@@ -675,18 +713,19 @@ class Poche | |||
675 | */ | 713 | */ |
676 | public function login($referer) | 714 | public function login($referer) |
677 | { | 715 | { |
678 | list($login,$password)=$this->credentials(); | 716 | list($login,$password,$isauthenticated)=$this->credentials(); |
679 | if($login === false || $password === false) { | 717 | if($login === false || $password === false) { |
680 | $this->messages->add('e', _('login failed: you have to fill all fields')); | 718 | $this->messages->add('e', _('login failed: you have to fill all fields')); |
681 | Tools::logm('login failed'); | 719 | Tools::logm('login failed'); |
682 | Tools::redirect(); | 720 | Tools::redirect(); |
683 | } | 721 | } |
684 | if (!empty($login) && !empty($password)) { | 722 | if (!empty($login) && !empty($password)) { |
685 | $user = $this->store->login($login, Tools::encodeString($password . $login)); | 723 | $user = $this->store->login($login, Tools::encodeString($password . $login), $isauthenticated); |
686 | if ($user != array()) { | 724 | if ($user != array()) { |
687 | # Save login into Session | 725 | # Save login into Session |
688 | $longlastingsession = isset($_POST['longlastingsession']); | 726 | $longlastingsession = isset($_POST['longlastingsession']); |
689 | Session::login($user['username'], $user['password'], $login, Tools::encodeString($password . $login), $longlastingsession, array('poche_user' => new User($user))); | 727 | $passwordTest = ($isauthenticated) ? $user['password'] : Tools::encodeString($password . $login); |
728 | Session::login($user['username'], $user['password'], $login, $passwordTest, $longlastingsession, array('poche_user' => new User($user))); | ||
690 | $this->messages->add('s', _('welcome to your poche')); | 729 | $this->messages->add('s', _('welcome to your poche')); |
691 | Tools::logm('login successful'); | 730 | Tools::logm('login successful'); |
692 | Tools::redirect($referer); | 731 | Tools::redirect($referer); |
@@ -848,6 +887,52 @@ class Poche | |||
848 | } | 887 | } |
849 | 888 | ||
850 | /** | 889 | /** |
890 | * import from Poche exported file | ||
891 | * @param string $targetFile the file used for importing | ||
892 | * @return boolean | ||
893 | */ | ||
894 | private function importFromPoche($targetFile) | ||
895 | { | ||
896 | $str_data = file_get_contents($targetFile); | ||
897 | $data = json_decode($str_data,true); | ||
898 | Tools::logm('starting import from Poche'); | ||
899 | |||
900 | |||
901 | $sequence = ''; | ||
902 | if (STORAGE == 'postgres') { | ||
903 | $sequence = 'entries_id_seq'; | ||
904 | } | ||
905 | |||
906 | $count = 0; | ||
907 | foreach ($data as $value) { | ||
908 | |||
909 | $url = new Url(base64_encode($value['url'])); | ||
910 | $favorite = ($value['is_fav'] == -1); | ||
911 | $archive = ($value['is_read'] == -1); | ||
912 | |||
913 | # we can add the url | ||
914 | if (!is_null($url) && $url->isCorrect()) { | ||
915 | |||
916 | $this->action('add', $url, 0, TRUE); | ||
917 | |||
918 | $count++; | ||
919 | if ($favorite) { | ||
920 | $last_id = $this->store->getLastId($sequence); | ||
921 | $this->action('toggle_fav', $url, $last_id, TRUE); | ||
922 | } | ||
923 | if ($archive) { | ||
924 | $last_id = $this->store->getLastId($sequence); | ||
925 | $this->action('toggle_archive', $url, $last_id, TRUE); | ||
926 | } | ||
927 | } | ||
928 | |||
929 | } | ||
930 | $this->messages->add('s', _('import from Poche completed. ' . $count . ' new links.')); | ||
931 | Tools::logm('import from Poche completed'); | ||
932 | Tools::redirect(); | ||
933 | } | ||
934 | |||
935 | /** | ||
851 | * import datas into your poche | 936 | * import datas into your poche |
852 | * @param string $from name of the service to import : pocket, instapaper or readability | 937 | * @param string $from name of the service to import : pocket, instapaper or readability |
853 | * @todo add the return value | 938 | * @todo add the return value |
@@ -858,7 +943,8 @@ class Poche | |||
858 | $providers = array( | 943 | $providers = array( |
859 | 'pocket' => 'importFromPocket', | 944 | 'pocket' => 'importFromPocket', |
860 | 'readability' => 'importFromReadability', | 945 | 'readability' => 'importFromReadability', |
861 | 'instapaper' => 'importFromInstapaper' | 946 | 'instapaper' => 'importFromInstapaper', |
947 | 'poche' => 'importFromPoche', | ||
862 | ); | 948 | ); |
863 | 949 | ||
864 | if (! isset($providers[$from])) { | 950 | if (! isset($providers[$from])) { |
@@ -908,7 +994,7 @@ class Poche | |||
908 | if (file_exists($cache_file) && (filemtime($cache_file) > (time() - 86400 ))) { | 994 | if (file_exists($cache_file) && (filemtime($cache_file) > (time() - 86400 ))) { |
909 | $version = file_get_contents($cache_file); | 995 | $version = file_get_contents($cache_file); |
910 | } else { | 996 | } else { |
911 | $version = file_get_contents('http://static.inthepoche.com/versions/' . $which); | 997 | $version = file_get_contents('http://static.wallabag.org/versions/' . $which); |
912 | file_put_contents($cache_file, $version, LOCK_EX); | 998 | file_put_contents($cache_file, $version, LOCK_EX); |
913 | } | 999 | } |
914 | return $version; | 1000 | return $version; |