From fb7bc50673f226070c5399bd6bbf07b91eeda01e Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Sat, 15 Feb 2014 10:44:37 +0100 Subject: Fix bug token The token should appear in RSS feed url when anonymous are not allowed --- app/Controllers/indexController.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'app/Controllers/indexController.php') diff --git a/app/Controllers/indexController.php b/app/Controllers/indexController.php index 986a322a1..af08edb46 100755 --- a/app/Controllers/indexController.php +++ b/app/Controllers/indexController.php @@ -5,18 +5,15 @@ class FreshRSS_index_Controller extends Minz_ActionController { public function indexAction () { $output = Minz_Request::param ('output'); - $token = ''; + $token = $this->view->conf->token; // check if user is logged in - if (!$this->view->loginOk && !Minz_Configuration::allowAnonymous()) - { - $token = $this->view->conf->token; + if (!$this->view->loginOk && !Minz_Configuration::allowAnonymous()) { $token_param = Minz_Request::param ('token', ''); $token_is_ok = ($token != '' && $token === $token_param); if (!($output === 'rss' && $token_is_ok)) { return; } - $params['token'] = $token; } // construction of RSS url of this feed @@ -25,6 +22,9 @@ class FreshRSS_index_Controller extends Minz_ActionController { if (isset ($params['search'])) { $params['search'] = urlencode ($params['search']); } + if (!Minz_Configuration::allowAnonymous()) { + $params['token'] = $token; + } $this->view->rss_url = array ( 'c' => 'index', 'a' => 'index', -- cgit v1.2.3 From a34941f41875bcc9d260c8dfcf9d44a00f835bc9 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Sat, 15 Feb 2014 11:43:07 +0100 Subject: Improve code redirection for indexController - add comments - forward request is done in the controller (no Minz_Request::forward() in the view, please) - "soft" forward to the login form (no need of 302) - show a 403 page (no authenticated) for rss output when token is wrong --- app/Controllers/feedController.php | 5 ++++- app/Controllers/indexController.php | 11 ++++++++++- app/views/index/index.phtml | 19 +++++-------------- 3 files changed, 19 insertions(+), 16 deletions(-) (limited to 'app/Controllers/indexController.php') diff --git a/app/Controllers/feedController.php b/app/Controllers/feedController.php index 7114fc196..c718fcd5c 100755 --- a/app/Controllers/feedController.php +++ b/app/Controllers/feedController.php @@ -3,7 +3,10 @@ class FreshRSS_feed_Controller extends Minz_ActionController { public function firstAction () { if (!$this->view->loginOk) { - $token = $this->view->conf->token; //TODO: check the token logic again, and if it is still needed + // Token is useful in the case that anonymous refresh is forbidden + // and CRON task cannot be used with php command so the user can + // set a CRON task to refresh his feeds by using token inside url + $token = $this->view->conf->token; $token_param = Minz_Request::param ('token', ''); $token_is_ok = ($token != '' && $token == $token_param); $action = Minz_Request::actionName (); diff --git a/app/Controllers/indexController.php b/app/Controllers/indexController.php index af08edb46..a680c914a 100755 --- a/app/Controllers/indexController.php +++ b/app/Controllers/indexController.php @@ -11,7 +11,16 @@ class FreshRSS_index_Controller extends Minz_ActionController { if (!$this->view->loginOk && !Minz_Configuration::allowAnonymous()) { $token_param = Minz_Request::param ('token', ''); $token_is_ok = ($token != '' && $token === $token_param); - if (!($output === 'rss' && $token_is_ok)) { + if ($output === 'rss' && !$token_is_ok) { + Minz_Error::error ( + 403, + array ('error' => array (Minz_Translate::t ('access_denied'))) + ); + return; + } elseif ($output !== 'rss') { + // "hard" redirection is not required, just ask dispatcher to + // forward to the login form without 302 redirection + Minz_Request::forward(array('c' => 'index', 'a' => 'formLogin')); return; } } diff --git a/app/views/index/index.phtml b/app/views/index/index.phtml index 1810a95b3..78271291e 100644 --- a/app/views/index/index.phtml +++ b/app/views/index/index.phtml @@ -3,9 +3,7 @@ $output = Minz_Request::param ('output', 'normal'); if ($this->loginOk || Minz_Configuration::allowAnonymous()) { - if ($output === 'normal') { - $this->renderHelper ('view/normal_view'); - } elseif ($output === 'rss') { + if ($output === 'rss') { $this->renderHelper ('view/rss_view'); } elseif ($output === 'reader') { $this->renderHelper ('view/reader_view'); @@ -17,16 +15,9 @@ if ($this->loginOk || Minz_Configuration::allowAnonymous()) { $this->renderHelper ('view/normal_view'); } } elseif ($output === 'rss') { - // TODO: verification of token and redirection must be done in the - // controller, not in the view - $token = $this->conf->token; - $token_param = Minz_Request::param ('token', ''); - $token_is_ok = ($token != '' && $token == $token_param); - if ($token_is_ok) { - $this->renderHelper ('view/rss_view'); - } else { - Minz_Request::forward(array('c' => 'index', 'a' => 'formLogin'), true); - } + // token has already been checked in the controller so we can show the view + $this->renderHelper ('view/rss_view'); } else { - Minz_Request::forward(array('c' => 'index', 'a' => 'formLogin'), true); + // Normally, it should not happen, but log it anyway + Minz_Log::record ('Something is wrong in ' . __FILE__ . ' line ' . __LINE__, Minz_Log::ERROR); } -- cgit v1.2.3 From cddec2d76f2c5d25d3008d5e2a60fddad6028a5d Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Sat, 15 Feb 2014 12:25:06 +0100 Subject: Improve login page - if user cannot log in, a 403 error is showed (and it is done in controller) - 403 error message has been changed to match with the error - add blank spaces on persona login page --- app/Controllers/indexController.php | 5 ++++ app/i18n/en.php | 3 +- app/i18n/fr.php | 3 +- app/views/error/index.phtml | 10 ++++++- app/views/index/formLogin.phtml | 56 ++++++++++++++++++------------------- p/themes/Dark/global.css | 30 ++++++++++---------- p/themes/Flat/global.css | 30 ++++++++++---------- p/themes/Origine/global.css | 30 ++++++++++---------- 8 files changed, 93 insertions(+), 74 deletions(-) (limited to 'app/Controllers/indexController.php') diff --git a/app/Controllers/indexController.php b/app/Controllers/indexController.php index a680c914a..38f4c0e7c 100755 --- a/app/Controllers/indexController.php +++ b/app/Controllers/indexController.php @@ -351,6 +351,11 @@ class FreshRSS_index_Controller extends Minz_ActionController { } $this->view->_useLayout(false); Minz_Request::forward(array('c' => 'index', 'a' => 'index'), true); + } elseif (!Minz_Configuration::canLogIn()) { + Minz_Error::error ( + 403, + array ('error' => array (Minz_Translate::t ('access_denied'))) + ); } invalidateHttpCache(); } diff --git a/app/i18n/en.php b/app/i18n/en.php index fd51eb1ca..790e853f5 100644 --- a/app/i18n/en.php +++ b/app/i18n/en.php @@ -3,6 +3,7 @@ return array ( // LAYOUT 'login' => 'Login', + 'login_with_persona' => 'Login with Persona', 'logout' => 'Logout', 'search' => 'Search words or #tags', 'search_short' => 'Search', @@ -276,7 +277,7 @@ return array ( 'logs_empty' => 'Log file is empty', 'clear_logs' => 'Clear the logs', - 'forbidden_access' => 'Access forbidden! (%s)', + 'forbidden_access' => 'Access is forbidden!', 'login_required' => 'Login required:', 'confirm_action' => 'Are you sure you want to perform this action? It cannot be cancelled!', diff --git a/app/i18n/fr.php b/app/i18n/fr.php index 17e26f493..572bc1628 100644 --- a/app/i18n/fr.php +++ b/app/i18n/fr.php @@ -3,6 +3,7 @@ return array ( // LAYOUT 'login' => 'Connexion', + 'login_with_persona' => 'Connexion avec Persona', 'logout' => 'Déconnexion', 'search' => 'Rechercher des mots ou des #tags', 'search_short' => 'Rechercher', @@ -276,7 +277,7 @@ return array ( 'logs_empty' => 'Les logs sont vides', 'clear_logs' => 'Effacer les logs', - 'forbidden_access' => 'Accès interdit ! (%s)', + 'forbidden_access' => 'L’accès vous est interdit !', 'login_required' => 'Accès protégé par mot de passe :', 'confirm_action' => 'Êtes-vous sûr(e) de vouloir continuer ? Cette action ne peut être annulée !', diff --git a/app/views/error/index.phtml b/app/views/error/index.phtml index 36fcb56f9..6a09c3aa2 100644 --- a/app/views/error/index.phtml +++ b/app/views/error/index.phtml @@ -3,7 +3,15 @@

code; ?>

-
+

diff --git a/app/views/index/formLogin.phtml b/app/views/index/formLogin.phtml index e4560c1a0..cc925ea59 100644 --- a/app/views/index/formLogin.phtml +++ b/app/views/index/formLogin.phtml @@ -1,34 +1,32 @@
-

-

- - -

- - -
- -

- -

-
+
+ + +
+
+ + +
+ +
+
+ +
+

FreshRSS

-

+ case 'persona': + ?>

+ + +

-

+

diff --git a/p/themes/Dark/global.css b/p/themes/Dark/global.css index a6acd740a..e296f2188 100644 --- a/p/themes/Dark/global.css +++ b/p/themes/Dark/global.css @@ -512,18 +512,20 @@ input, select, textarea { } /* Prompt (centré) */ -.prompt > h1, .prompt > p { - text-align:center; -} -.prompt > form { - margin:1em auto 2.5em auto; - width:10em; -} -.prompt .btn { - display:block; - margin:.5em auto; -} -.prompt input { - margin:.4em auto 1.1em auto; - width:99%; +.prompt { + text-align: center; } + .prompt label { + text-align: left; + } + .prompt form { + margin: 1em auto 2.5em auto; + width: 10em; + } + .prompt input { + margin: .4em auto 1.1em auto; + width: 100%; + } + .prompt p { + margin: 20px 0; + } diff --git a/p/themes/Flat/global.css b/p/themes/Flat/global.css index 75c328fcb..4044dd781 100644 --- a/p/themes/Flat/global.css +++ b/p/themes/Flat/global.css @@ -515,18 +515,20 @@ input, select, textarea { } /* Prompt (centré) */ -.prompt > h1, .prompt > p { - text-align:center; -} -.prompt > form { - margin:1em auto 2.5em auto; - width:10em; -} -.prompt .btn { - display:block; - margin:.5em auto; -} -.prompt input { - margin:.4em auto 1.1em auto; - width:99%; +.prompt { + text-align: center; } + .prompt label { + text-align: left; + } + .prompt form { + margin: 1em auto 2.5em auto; + width: 10em; + } + .prompt input { + margin: .4em auto 1.1em auto; + width: 100%; + } + .prompt p { + margin: 20px 0; + } diff --git a/p/themes/Origine/global.css b/p/themes/Origine/global.css index c1892d042..5792c9e4d 100644 --- a/p/themes/Origine/global.css +++ b/p/themes/Origine/global.css @@ -528,18 +528,20 @@ input, select, textarea { } /* Prompt (centré) */ -.prompt > h1, .prompt > p { - text-align:center; -} -.prompt > form { - margin:1em auto 2.5em auto; - width:10em; -} -.prompt .btn { - display:block; - margin:.5em auto; -} -.prompt input { - margin:.4em auto 1.1em auto; - width:99%; +.prompt { + text-align: center; } + .prompt label { + text-align: left; + } + .prompt form { + margin: 1em auto 2.5em auto; + width: 10em; + } + .prompt input { + margin: .4em auto 1.1em auto; + width: 100%; + } + .prompt p { + margin: 20px 0; + } -- cgit v1.2.3 From 736ee492a0fe723b0d6ce9ea59fb3f3eef7ecf23 Mon Sep 17 00:00:00 2001 From: Alexis Degrugillier Date: Sat, 1 Mar 2014 14:30:55 -0500 Subject: Show only unread when selecting unread Before, when there was no unread articles, all articles where displayed. This behaviour was not the one intended. Now, when there is no unread articles, a message is displayed to alert that there is no article. See #428 Correction after comment --- app/Controllers/indexController.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'app/Controllers/indexController.php') diff --git a/app/Controllers/indexController.php b/app/Controllers/indexController.php index 38f4c0e7c..c760e0f01 100755 --- a/app/Controllers/indexController.php +++ b/app/Controllers/indexController.php @@ -84,6 +84,7 @@ class FreshRSS_index_Controller extends Minz_ActionController { // On récupère les différents éléments de filtrage $this->view->state = $state = Minz_Request::param ('state', $this->view->conf->default_view); + $state_param = Minz_Request::param ('state', null); $filter = Minz_Request::param ('search', ''); if (!empty($filter)) { $state = 'all'; //Search always in read and unread articles @@ -111,7 +112,7 @@ class FreshRSS_index_Controller extends Minz_ActionController { $hasUnread = true; break; } - if (!$hasUnread) { + if (!$hasUnread && is_null($state_param)) { $this->view->state = $state = 'all'; } } @@ -129,7 +130,7 @@ class FreshRSS_index_Controller extends Minz_ActionController { // Si on a récupéré aucun article "non lus" // on essaye de récupérer tous les articles - if ($state === 'not_read' && empty($entries)) { + if ($state === 'not_read' && empty($entries) && is_null($state_param)) { Minz_Log::record ('Conflicting information about nbNotRead!', Minz_Log::DEBUG); $this->view->state = 'all'; $entries = $entryDAO->listWhere($getType, $getId, 'all', $order, $nb, $first, $filter, $date_min, $keepHistoryDefault); -- cgit v1.2.3 From a8d06d12705a6467f2d11a8a6afc51ae2ea7088a Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sat, 1 Mar 2014 20:56:27 +0100 Subject: Micro-optimisation is_null https://github.com/marienfressinaud/FreshRSS/pull/434 https://github.com/marienfressinaud/FreshRSS/issues/428 --- app/Controllers/indexController.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'app/Controllers/indexController.php') diff --git a/app/Controllers/indexController.php b/app/Controllers/indexController.php index c760e0f01..c83c5b630 100755 --- a/app/Controllers/indexController.php +++ b/app/Controllers/indexController.php @@ -112,7 +112,7 @@ class FreshRSS_index_Controller extends Minz_ActionController { $hasUnread = true; break; } - if (!$hasUnread && is_null($state_param)) { + if (!$hasUnread && ($state_param === null)) { $this->view->state = $state = 'all'; } } @@ -130,7 +130,7 @@ class FreshRSS_index_Controller extends Minz_ActionController { // Si on a récupéré aucun article "non lus" // on essaye de récupérer tous les articles - if ($state === 'not_read' && empty($entries) && is_null($state_param)) { + if ($state === 'not_read' && empty($entries) && ($state_param === null)) { Minz_Log::record ('Conflicting information about nbNotRead!', Minz_Log::DEBUG); $this->view->state = 'all'; $entries = $entryDAO->listWhere($getType, $getId, 'all', $order, $nb, $first, $filter, $date_min, $keepHistoryDefault); -- cgit v1.2.3 From b07f9157b18bffdb28833ed1363284571be3644e Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sun, 2 Mar 2014 13:35:09 +0100 Subject: New unsafe autologin mode https://github.com/marienfressinaud/FreshRSS/issues/440 --- app/Controllers/indexController.php | 26 ++++++++++++++++++++++++++ lib/Minz/Configuration.php | 14 ++++++++++++++ p/i/install.php | 3 +++ 3 files changed, 43 insertions(+) (limited to 'app/Controllers/indexController.php') diff --git a/app/Controllers/indexController.php b/app/Controllers/indexController.php index c83c5b630..0905e591a 100755 --- a/app/Controllers/indexController.php +++ b/app/Controllers/indexController.php @@ -352,6 +352,32 @@ class FreshRSS_index_Controller extends Minz_ActionController { } $this->view->_useLayout(false); Minz_Request::forward(array('c' => 'index', 'a' => 'index'), true); + } elseif (Minz_Configuration::unsafeAutologinEnabled() && isset($_GET['u']) && isset($_GET['p'])) { + Minz_Session::_param('currentUser'); + Minz_Session::_param('mail'); + Minz_Session::_param('passwordHash'); + $username = ctype_alnum($_GET['u']) ? $_GET['u'] : ''; + $passwordPlain = $_GET['p']; + Minz_Request::_param('p'); //Discard plain-text password ASAP + $_GET['p'] = ''; + if (!function_exists('password_verify')) { + include_once(LIB_PATH . '/password_compat.php'); + } + try { + $conf = new FreshRSS_Configuration($username); + $s = $conf->passwordHash; + $ok = password_verify($passwordPlain, $s); + unset($passwordPlain); + if ($ok) { + Minz_Session::_param('currentUser', $username); + Minz_Session::_param('passwordHash', $s); + } else { + Minz_Log::record('Unsafe password mismatch for user ' . $username, Minz_Log::WARNING); + } + } catch (Minz_Exception $me) { + Minz_Log::record('Unsafe login failure: ' . $me->getMessage(), Minz_Log::WARNING); + } + Minz_Request::forward(array('c' => 'index', 'a' => 'index'), true); } elseif (!Minz_Configuration::canLogIn()) { Minz_Error::error ( 403, diff --git a/lib/Minz/Configuration.php b/lib/Minz/Configuration.php index ff71d747c..324aae881 100644 --- a/lib/Minz/Configuration.php +++ b/lib/Minz/Configuration.php @@ -55,6 +55,7 @@ class Minz_Configuration { private static $allow_anonymous_refresh = false; private static $auth_type = 'none'; private static $api_enabled = false; + private static $unsafe_autologin_enabled = false; private static $db = array ( 'type' => 'mysql', @@ -135,6 +136,9 @@ class Minz_Configuration { public static function apiEnabled() { return self::$api_enabled; } + public static function unsafeAutologinEnabled() { + return self::$unsafe_autologin_enabled; + } public static function _allowAnonymous($allow = false) { self::$allow_anonymous = ((bool)$allow) && self::canLogIn(); @@ -158,6 +162,9 @@ class Minz_Configuration { public static function _enableApi($value = false) { self::$api_enabled = (bool)$value; } + public static function _enableAutologin($value = false) { + self::$unsafe_autologin_enabled = (bool)$value; + } /** * Initialise les variables de configuration @@ -188,6 +195,7 @@ class Minz_Configuration { 'allow_anonymous_refresh' => self::$allow_anonymous_refresh, 'auth_type' => self::$auth_type, 'api_enabled' => self::$api_enabled, + 'unsafe_autologin_enabled' => self::$unsafe_autologin_enabled, ), 'db' => self::$db, ); @@ -310,6 +318,12 @@ class Minz_Configuration { ($general['api_enabled'] !== 'no') ); } + if (isset ($general['unsafe_autologin_enabled'])) { + self::$unsafe_autologin_enabled = ( + ((bool)($general['unsafe_autologin_enabled'])) && + ($general['unsafe_autologin_enabled'] !== 'no') + ); + } // Base de données if (isset ($ini_array['db'])) { diff --git a/p/i/install.php b/p/i/install.php index 720813323..a7563d5ee 100644 --- a/p/i/install.php +++ b/p/i/install.php @@ -235,6 +235,9 @@ function saveStep3 () { 'default_user' => $_SESSION['default_user'], 'auth_type' => $_SESSION['auth_type'], 'allow_anonymous' => isset($_SESSION['allow_anonymous']) ? $_SESSION['allow_anonymous'] : false, + 'allow_anonymous_refresh' => false, + 'unsafe_autologin_enabled' => false, + 'api_enabled' => false, ), 'db' => array( 'type' => $_SESSION['bd_type'], -- cgit v1.2.3 From fc6769c1b10314b50be4a3d970c5c4917be6305c Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Mon, 3 Mar 2014 21:25:14 +0100 Subject: API: Add continuation mode https://github.com/marienfressinaud/FreshRSS/issues/443 Needed for e.g. EasyRSS --- app/Controllers/indexController.php | 2 +- app/Models/EntryDAO.php | 22 +++++++++++++--------- p/api/greader.php | 30 ++++++++++++++++++++++-------- 3 files changed, 36 insertions(+), 18 deletions(-) (limited to 'app/Controllers/indexController.php') diff --git a/app/Controllers/indexController.php b/app/Controllers/indexController.php index 0905e591a..2f263dff0 100755 --- a/app/Controllers/indexController.php +++ b/app/Controllers/indexController.php @@ -126,7 +126,7 @@ class FreshRSS_index_Controller extends Minz_ActionController { $keepHistoryDefault = $this->view->conf->keep_history_default; try { - $entries = $entryDAO->listWhere($getType, $getId, $state, $order, $nb + 1, $first, $filter, $date_min, $keepHistoryDefault); + $entries = $entryDAO->listWhere($getType, $getId, $state, $order, $nb + 1, $first, $filter, $date_min, true, $keepHistoryDefault); // Si on a récupéré aucun article "non lus" // on essaye de récupérer tous les articles diff --git a/app/Models/EntryDAO.php b/app/Models/EntryDAO.php index cc52ea120..e4cf128ea 100644 --- a/app/Models/EntryDAO.php +++ b/app/Models/EntryDAO.php @@ -376,7 +376,7 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo { return isset ($entries[0]) ? $entries[0] : null; } - private function sqlListWhere($type = 'a', $id = '', $state = 'all', $order = 'DESC', $limit = 1, $firstId = '', $filter = '', $date_min = 0, $keepHistoryDefault = 0) { + private function sqlListWhere($type = 'a', $id = '', $state = 'all', $order = 'DESC', $limit = 1, $firstId = '', $filter = '', $date_min = 0, $showOlderUnreadsorFavorites = false, $keepHistoryDefault = 0) { $where = ''; $joinFeed = false; $values = array(); @@ -429,11 +429,15 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo { $where .= 'AND e1.id ' . ($order === 'DESC' ? '<=' : '>=') . $firstId . ' '; } if (($date_min > 0) && ($type !== 's')) { - $where .= 'AND (e1.id >= ' . $date_min . '000000 OR e1.is_read = 0 OR e1.is_favorite = 1 OR (f.keep_history <> 0'; - if (intval($keepHistoryDefault) === 0) { - $where .= ' AND f.keep_history <> -2'; //default + $where .= 'AND (e1.id >= ' . $date_min . '000000'; + if ($showOlderUnreadsorFavorites) { //Lax date constraint + $where .= ' OR e1.is_read = 0 OR e1.is_favorite = 1 OR (f.keep_history <> 0'; + if (intval($keepHistoryDefault) === 0) { + $where .= ' AND f.keep_history <> -2'; //default + } + $where .= ')'; } - $where .= ')) '; + $where .= ') '; $joinFeed = true; } $search = ''; @@ -494,8 +498,8 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo { . ($limit > 0 ? ' LIMIT ' . $limit : '')); //TODO: See http://explainextended.com/2009/10/23/mysql-order-by-limit-performance-late-row-lookups/ } - public function listWhere($type = 'a', $id = '', $state = 'all', $order = 'DESC', $limit = 1, $firstId = '', $filter = '', $date_min = 0, $keepHistoryDefault = 0) { - list($values, $sql) = $this->sqlListWhere($type, $id, $state, $order, $limit, $firstId, $filter, $date_min, $keepHistoryDefault); + public function listWhere($type = 'a', $id = '', $state = 'all', $order = 'DESC', $limit = 1, $firstId = '', $filter = '', $date_min = 0, $showOlderUnreadsorFavorites = false, $keepHistoryDefault = 0) { + list($values, $sql) = $this->sqlListWhere($type, $id, $state, $order, $limit, $firstId, $filter, $date_min, $showOlderUnreadsorFavorites, $keepHistoryDefault); $sql = 'SELECT e.id, e.guid, e.title, e.author, UNCOMPRESS(e.content_bin) AS content, e.link, e.date, e.is_read, e.is_favorite, e.id_feed, e.tags ' . 'FROM `' . $this->prefix . 'entry` e ' @@ -510,8 +514,8 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo { return self::daoToEntry ($stm->fetchAll (PDO::FETCH_ASSOC)); } - public function listIdsWhere($type = 'a', $id = '', $state = 'all', $order = 'DESC', $limit = 1, $firstId = '', $filter = '', $date_min = 0, $keepHistoryDefault = 0) { //For API - list($values, $sql) = $this->sqlListWhere($type, $id, $state, $order, $limit, $firstId, $filter, $date_min, $keepHistoryDefault); + public function listIdsWhere($type = 'a', $id = '', $state = 'all', $order = 'DESC', $limit = 1, $firstId = '', $filter = '', $date_min = 0, $showOlderUnreadsorFavorites = false, $keepHistoryDefault = 0) { //For API + list($values, $sql) = $this->sqlListWhere($type, $id, $state, $order, $limit, $firstId, $filter, $date_min, $showOlderUnreadsorFavorites, $keepHistoryDefault); $stm = $this->bd->prepare($sql); $stm->execute($values); diff --git a/p/api/greader.php b/p/api/greader.php index f26217279..b1ed34d27 100644 --- a/p/api/greader.php +++ b/p/api/greader.php @@ -288,7 +288,7 @@ function unreadCount() { exit(); } -function streamContents($path, $include_target, $start_time, $count, $order, $exclude_target) +function streamContents($path, $include_target, $start_time, $count, $order, $exclude_target, $continuation) {//http://code.google.com/p/pyrfeed/wiki/GoogleReaderAPI http://blog.martindoms.com/2009/10/16/using-the-google-reader-api-part-2/#feed logMe('streamContents(' . $include_target . ")\n"); header('Content-Type: application/json; charset=UTF-8'); @@ -326,8 +326,12 @@ function streamContents($path, $include_target, $start_time, $count, $order, $ex break; } + if (!empty($continuation)) { + $count++; //Shift by one element + } + $entryDAO = new FreshRSS_EntryDAO(); - $entries = $entryDAO->listWhere($type, $include_target, $state, $order === 'o' ? 'ASC' : 'DESC', $count, '', '', $start_time); + $entries = $entryDAO->listWhere($type, $include_target, $state, $order === 'o' ? 'ASC' : 'DESC', $count, $continuation, '', $start_time); $items = array(); foreach ($entries as $entry) { @@ -371,11 +375,20 @@ function streamContents($path, $include_target, $start_time, $count, $order, $ex $items[] = $item; } - echo json_encode(array( + if (!empty($continuation)) { + array_shift($items); //Discard first element that was already sent in the previous response + } + + $response = array( 'id' => 'user/-/state/com.google/reading-list', 'updated' => time(), 'items' => $items, - )), "\n"; + ); + if ((count($entries) >= $count) && (!empty($entry))) { + $response['continuation'] = $entry->id(); + } + + echo json_encode($response), "\n"; exit(); } @@ -520,27 +533,28 @@ elseif ($pathInfos[1] === 'reader' && $pathInfos[2] === 'api' && isset($pathInfo $count = isset($_GET['n']) ? intval($_GET['n']) : 20; //n=[integer] : The maximum number of results to return. $order = isset($_GET['r']) ? $_GET['r'] : 'd'; //r=[d|n|o] : Sort order of item results. d or n gives items in descending date order, o in ascending order. $start_time = isset($_GET['ot']) ? intval($_GET['ot']) : 0; //ot=[unix timestamp] : The time from which you want to retrieve items. Only items that have been crawled by Google Reader after this time will be returned. + $continuation = isset($_GET['c']) ? $_GET['c'] : ''; //Continuation token. If a StreamContents response does not represent all items in a timestamp range, it will have a continuation attribute. The same request can be re-issued with the value of that attribute put in this parameter to get more items if (isset($pathInfos[5]) && $pathInfos[5] === 'contents' && isset($pathInfos[6])) { if (isset($pathInfos[7])) { if ($pathInfos[6] === 'feed') { $include_target = $pathInfos[7]; - StreamContents($pathInfos[6], $include_target, $start_time, $count, $order, $exclude_target); + StreamContents($pathInfos[6], $include_target, $start_time, $count, $order, $exclude_target, $continuation); } elseif ($pathInfos[6] === 'user' && isset($pathInfos[8]) && isset($pathInfos[9])) { if ($pathInfos[8] === 'state') { if ($pathInfos[9] === 'com.google' && isset($pathInfos[10])) { if ($pathInfos[10] === 'reading-list' || $pathInfos[10] === 'starred') { $include_target = ''; - streamContents($pathInfos[10], $include_target, $start_time, $count, $order, $exclude_target); + streamContents($pathInfos[10], $include_target, $start_time, $count, $order, $exclude_target, $continuation); } } } elseif ($pathInfos[8] === 'label') { $include_target = $pathInfos[9]; - streamContents($pathInfos[8], $include_target, $start_time, $count, $order, $exclude_target); + streamContents($pathInfos[8], $include_target, $start_time, $count, $order, $exclude_target, $continuation); } } } else { //EasyRSS $include_target = ''; - streamContents('reading-list', $include_target, $start_time, $count, $order, $exclude_target); + streamContents('reading-list', $include_target, $start_time, $count, $order, $exclude_target, $continuation); } } elseif ($pathInfos[5] === 'items') { if ($pathInfos[6] === 'ids' && isset($_GET['s'])) { -- cgit v1.2.3 From ff8fd9565413d8b690e0027bd6a091d8e74165b1 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Mon, 3 Mar 2014 21:27:45 +0100 Subject: API: Bug previous commit https://github.com/marienfressinaud/FreshRSS/issues/443 Bug in https://github.com/marienfressinaud/FreshRSS/commit/fc6769c1b10314b50be4a3d970c5c4917be6305c --- app/Controllers/indexController.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'app/Controllers/indexController.php') diff --git a/app/Controllers/indexController.php b/app/Controllers/indexController.php index 2f263dff0..73f454715 100755 --- a/app/Controllers/indexController.php +++ b/app/Controllers/indexController.php @@ -133,7 +133,7 @@ class FreshRSS_index_Controller extends Minz_ActionController { if ($state === 'not_read' && empty($entries) && ($state_param === null)) { Minz_Log::record ('Conflicting information about nbNotRead!', Minz_Log::DEBUG); $this->view->state = 'all'; - $entries = $entryDAO->listWhere($getType, $getId, 'all', $order, $nb, $first, $filter, $date_min, $keepHistoryDefault); + $entries = $entryDAO->listWhere($getType, $getId, 'all', $order, $nb, $first, $filter, $date_min, true, $keepHistoryDefault); } if (count($entries) <= $nb) { -- cgit v1.2.3 From f31747ee7bdaebf02e7e58d51c27102e0c7c9ef1 Mon Sep 17 00:00:00 2001 From: Alexis Degrugillier Date: Fri, 14 Mar 2014 06:15:52 -0400 Subject: Refresh page after getting new articles. Change the URL to the refresh link. Before it was redirecting to the home page. Now it is redirecting to the same page, which make more sense. See #457 --- app/Controllers/indexController.php | 4 +--- app/layout/nav_menu.phtml | 20 +++++--------------- app/views/helpers/view/normal_view.phtml | 2 +- 3 files changed, 7 insertions(+), 19 deletions(-) (limited to 'app/Controllers/indexController.php') diff --git a/app/Controllers/indexController.php b/app/Controllers/indexController.php index 73f454715..9da1e5022 100755 --- a/app/Controllers/indexController.php +++ b/app/Controllers/indexController.php @@ -25,16 +25,14 @@ class FreshRSS_index_Controller extends Minz_ActionController { } } - // construction of RSS url of this feed $params = Minz_Request::params (); - $params['output'] = 'rss'; if (isset ($params['search'])) { $params['search'] = urlencode ($params['search']); } if (!Minz_Configuration::allowAnonymous()) { $params['token'] = $token; } - $this->view->rss_url = array ( + $this->view->url = array ( 'c' => 'index', 'a' => 'index', 'params' => $params diff --git a/app/layout/nav_menu.phtml b/app/layout/nav_menu.phtml index 097809e08..ffdc95b24 100644 --- a/app/layout/nav_menu.phtml +++ b/app/layout/nav_menu.phtml @@ -99,17 +99,6 @@ - 'index', - 'a' => 'index', - 'params' => $params - ); - ?> diff --git a/p/themes/Dark/freshrss.css b/p/themes/Dark/freshrss.css index be8d6b86a..d7da91bb8 100644 --- a/p/themes/Dark/freshrss.css +++ b/p/themes/Dark/freshrss.css @@ -88,6 +88,11 @@ .nav_menu .search { display:none; } + .nav_menu .btn[aria-checked="true"]:before{ + content: '✓'; + font-size: 2.5rem; + position: absolute; + } .favicon { height: 16px; diff --git a/p/themes/Dark/global.css b/p/themes/Dark/global.css index e296f2188..0f1baa216 100644 --- a/p/themes/Dark/global.css +++ b/p/themes/Dark/global.css @@ -416,12 +416,6 @@ input, select, textarea { background: #26303F; color: #888; } - .dropdown-menu > .item[aria-checked="true"] > a:before { - content: '✓ '; - font-weight: bold; - margin: 0 0 0 -1.2em; - padding: 0 0.2em 0 0; - } .dropdown-menu > .item:hover > a { color: #888; text-decoration: none; diff --git a/p/themes/Flat/freshrss.css b/p/themes/Flat/freshrss.css index 1f297309b..f1737d23e 100644 --- a/p/themes/Flat/freshrss.css +++ b/p/themes/Flat/freshrss.css @@ -87,6 +87,11 @@ body { .nav_menu .search { display:none; } + .nav_menu .btn[aria-checked="true"]:before{ + content: '✓'; + font-size: 2.5rem; + position: absolute; + } .favicon { height: 16px; diff --git a/p/themes/Flat/global.css b/p/themes/Flat/global.css index 4044dd781..68e9fa359 100644 --- a/p/themes/Flat/global.css +++ b/p/themes/Flat/global.css @@ -412,12 +412,6 @@ input, select, textarea { background: #2980b9; color: #fff; } - .dropdown-menu > .item[aria-checked="true"] > a:before { - content: '✓ '; - font-weight: bold; - margin: 0 0 0 -1.2em; - padding: 0 0.2em 0 0; - } .dropdown-menu > .item:hover > a { color: #fff; text-decoration: none; diff --git a/p/themes/Origine/freshrss.css b/p/themes/Origine/freshrss.css index 662e085d6..d33ee4f54 100644 --- a/p/themes/Origine/freshrss.css +++ b/p/themes/Origine/freshrss.css @@ -89,6 +89,11 @@ .nav_menu .search { display:none; } + .nav_menu .btn[aria-checked="true"]:before{ + content: '✓'; + font-size: 2.5rem; + position: absolute; + } .favicon { height: 16px; diff --git a/p/themes/Origine/global.css b/p/themes/Origine/global.css index 5792c9e4d..7fb3a8f95 100644 --- a/p/themes/Origine/global.css +++ b/p/themes/Origine/global.css @@ -428,12 +428,6 @@ input, select, textarea { background: #0062BE; color: #fff; } - .dropdown-menu > .item[aria-checked="true"] > a:before { - content: '✓ '; - font-weight: bold; - margin: 0 0 0 -1.2em; - padding: 0 0.2em 0 0; - } .dropdown-menu > .item:hover > a { color: #fff; text-decoration: none; -- cgit v1.2.3 From 86066b1659e33eb5fdfbcae5fb7f0bd93604d442 Mon Sep 17 00:00:00 2001 From: Alexis Degrugillier Date: Sun, 13 Apr 2014 07:28:41 -0400 Subject: Add a new status for 'ALL' I made the conversion in every file I can think of. It should not have any reference to the string 'all' for the state context --- app/Controllers/importExportController.php | 4 ++-- app/Controllers/indexController.php | 8 ++++---- app/Models/Configuration.php | 3 ++- app/Models/EntryDAO.php | 9 ++++++--- app/views/configure/reading.phtml | 2 +- p/api/greader.php | 8 ++++---- 6 files changed, 19 insertions(+), 15 deletions(-) (limited to 'app/Controllers/indexController.php') diff --git a/app/Controllers/importExportController.php b/app/Controllers/importExportController.php index a9b103a34..b8253b7bd 100644 --- a/app/Controllers/importExportController.php +++ b/app/Controllers/importExportController.php @@ -370,7 +370,7 @@ class FreshRSS_importExport_Controller extends Minz_ActionController { $this->view->type = 'starred'; $unread_fav = $this->entryDAO->countUnreadReadFavorites(); $this->view->entries = $this->entryDAO->listWhere( - 's', '', 'all', 'ASC', + 's', '', FreshRSS_Configuration::STATE_ALL, 'ASC', $unread_fav['all'] ); } elseif ($type == 'feed' && !is_null($feed)) { @@ -379,7 +379,7 @@ class FreshRSS_importExport_Controller extends Minz_ActionController { ); $this->view->type = 'feed/' . $feed->id(); $this->view->entries = $this->entryDAO->listWhere( - 'f', $feed->id(), 'all', 'ASC', + 'f', $feed->id(), FreshRSS_Configuration::STATE_ALL, 'ASC', $this->view->conf->posts_per_page ); $this->view->feed = $feed; diff --git a/app/Controllers/indexController.php b/app/Controllers/indexController.php index 243d887ac..48471b480 100755 --- a/app/Controllers/indexController.php +++ b/app/Controllers/indexController.php @@ -85,7 +85,7 @@ class FreshRSS_index_Controller extends Minz_ActionController { $state_param = Minz_Request::param ('state', null); $filter = Minz_Request::param ('search', ''); if (!empty($filter)) { - $state = 'all'; //Search always in read and unread articles + $state = FreshRSS_Configuration::STATE_ALL; //Search always in read and unread articles } $this->view->order = $order = Minz_Request::param ('order', $this->view->conf->sort_order); $nb = Minz_Request::param ('nb', $this->view->conf->posts_per_page); @@ -108,7 +108,7 @@ class FreshRSS_index_Controller extends Minz_ActionController { break; } if (!$hasUnread && ($state_param === null)) { - $this->view->state = $state = 'all'; + $this->view->state = $state = FreshRSS_Configuration::STATE_ALL; } } @@ -127,8 +127,8 @@ class FreshRSS_index_Controller extends Minz_ActionController { // on essaye de récupérer tous les articles if ($state === FreshRSS_Configuration::STATE_NOT_READ && empty($entries) && ($state_param === null)) { Minz_Log::record ('Conflicting information about nbNotRead!', Minz_Log::DEBUG); - $this->view->state = 'all'; - $entries = $entryDAO->listWhere($getType, $getId, 'all', $order, $nb, $first, $filter, $date_min, true, $keepHistoryDefault); + $this->view->state = FreshRSS_Configuration::STATE_ALL; + $entries = $entryDAO->listWhere($getType, $getId, $this->view->state, $order, $nb, $first, $filter, $date_min, true, $keepHistoryDefault); } if (count($entries) <= $nb) { diff --git a/app/Models/Configuration.php b/app/Models/Configuration.php index f9ea47be6..e693542e0 100644 --- a/app/Models/Configuration.php +++ b/app/Models/Configuration.php @@ -1,6 +1,7 @@ data['default_view'] = $value === 'all' ? 'all' : self::STATE_NOT_READ; + $this->data['default_view'] = $value === self::STATE_ALL ? self::STATE_ALL : self::STATE_NOT_READ; } public function _display_posts ($value) { $this->data['display_posts'] = ((bool)$value) && $value !== 'no'; diff --git a/app/Models/EntryDAO.php b/app/Models/EntryDAO.php index 2f5a9e1f6..b9cbfd584 100644 --- a/app/Models/EntryDAO.php +++ b/app/Models/EntryDAO.php @@ -406,7 +406,10 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo { return isset ($entries[0]) ? $entries[0] : null; } - private function sqlListWhere($type = 'a', $id = '', $state = 'all', $order = 'DESC', $limit = 1, $firstId = '', $filter = '', $date_min = 0, $showOlderUnreadsorFavorites = false, $keepHistoryDefault = 0) { + private function sqlListWhere($type = 'a', $id = '', $state = null , $order = 'DESC', $limit = 1, $firstId = '', $filter = '', $date_min = 0, $showOlderUnreadsorFavorites = false, $keepHistoryDefault = 0) { + if (!$state) { + $state = FreshRSS_Configuration::STATE_ALL; + } $where = ''; $joinFeed = false; $values = array(); @@ -532,7 +535,7 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo { . ($limit > 0 ? ' LIMIT ' . $limit : '')); //TODO: See http://explainextended.com/2009/10/23/mysql-order-by-limit-performance-late-row-lookups/ } - public function listWhere($type = 'a', $id = '', $state = 'all', $order = 'DESC', $limit = 1, $firstId = '', $filter = '', $date_min = 0, $showOlderUnreadsorFavorites = false, $keepHistoryDefault = 0) { + public function listWhere($type = 'a', $id = '', $state = null, $order = 'DESC', $limit = 1, $firstId = '', $filter = '', $date_min = 0, $showOlderUnreadsorFavorites = false, $keepHistoryDefault = 0) { list($values, $sql) = $this->sqlListWhere($type, $id, $state, $order, $limit, $firstId, $filter, $date_min, $showOlderUnreadsorFavorites, $keepHistoryDefault); $sql = 'SELECT e.id, e.guid, e.title, e.author, UNCOMPRESS(e.content_bin) AS content, e.link, e.date, e.is_read, e.is_favorite, e.id_feed, e.tags ' @@ -548,7 +551,7 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo { return self::daoToEntry ($stm->fetchAll (PDO::FETCH_ASSOC)); } - public function listIdsWhere($type = 'a', $id = '', $state = 'all', $order = 'DESC', $limit = 1, $firstId = '', $filter = '', $date_min = 0, $showOlderUnreadsorFavorites = false, $keepHistoryDefault = 0) { //For API + public function listIdsWhere($type = 'a', $id = '', $state = null, $order = 'DESC', $limit = 1, $firstId = '', $filter = '', $date_min = 0, $showOlderUnreadsorFavorites = false, $keepHistoryDefault = 0) { //For API list($values, $sql) = $this->sqlListWhere($type, $id, $state, $order, $limit, $firstId, $filter, $date_min, $showOlderUnreadsorFavorites, $keepHistoryDefault); $stm = $this->bd->prepare($sql); diff --git a/app/views/configure/reading.phtml b/app/views/configure/reading.phtml index b778a4d22..b277397b1 100644 --- a/app/views/configure/reading.phtml +++ b/app/views/configure/reading.phtml @@ -32,7 +32,7 @@