From cd88414abcffd94cfce933cf578ecc640b691381 Mon Sep 17 00:00:00 2001 From: Alexis Degrugillier Date: Mon, 29 Sep 2014 18:54:03 -0400 Subject: Add an average per day for the 30 day period --- app/Models/StatsDAO.php | 27 ++++++++++++++++++++++++--- app/Models/StatsDAOSQLite.php | 23 +++++++++++++++++++++++ 2 files changed, 47 insertions(+), 3 deletions(-) (limited to 'app/Models') diff --git a/app/Models/StatsDAO.php b/app/Models/StatsDAO.php index 40505ab3e..08dd4cd5c 100644 --- a/app/Models/StatsDAO.php +++ b/app/Models/StatsDAO.php @@ -79,6 +79,27 @@ SQL; return $this->convertToSerie($count); } + /** + * Calculates entry average per day on a 30 days period. + * + * @return integer + */ + public function calculateEntryAverage() { + $period = self::ENTRY_COUNT_PERIOD; + + // Get stats per day for the last 30 days + $sql = <<prefix}entry AS e +WHERE FROM_UNIXTIME(e.date, '%Y%m%d') BETWEEN DATE_FORMAT(DATE_ADD(NOW(), INTERVAL -{$period} DAY), '%Y%m%d') AND DATE_FORMAT(DATE_ADD(NOW(), INTERVAL -1 DAY), '%Y%m%d') +SQL; + $stm = $this->bd->prepare($sql); + $stm->execute(); + $res = $stm->fetch(PDO::FETCH_NAMED); + + return round($res['average'], 2); + } + /** * Initialize an array for the entry count. * @@ -160,7 +181,7 @@ SQL; public function calculateEntryAveragePerFeedPerHour($feed = null) { return $this->calculateEntryAveragePerFeedPerPeriod(1/24, $feed); } - + /** * Calculates the average number of article per day of week per feed * @@ -180,10 +201,10 @@ SQL; public function calculateEntryAveragePerFeedPerMonth($feed = null) { return $this->calculateEntryAveragePerFeedPerPeriod(30, $feed); } - + /** * Calculates the average number of article per feed - * + * * @param float $period number used to divide the number of day in the period * @param integer $feed id * @return integer diff --git a/app/Models/StatsDAOSQLite.php b/app/Models/StatsDAOSQLite.php index 3b1256de1..bb2336532 100644 --- a/app/Models/StatsDAOSQLite.php +++ b/app/Models/StatsDAOSQLite.php @@ -34,6 +34,29 @@ SQL; return $this->convertToSerie($count); } + /** + * Calculates entry average per day on a 30 days period. + * + * @return integer + */ + public function calculateEntryAverage() { + $period = self::ENTRY_COUNT_PERIOD; + + // Get stats per day for the last 30 days + $sql = <<prefix}entry AS e +WHERE strftime('%Y%m%d', e.date, 'unixepoch') + BETWEEN strftime('%Y%m%d', 'now', '-{$period} days') + AND strftime('%Y%m%d', 'now', '-1 day') +SQL; + $stm = $this->bd->prepare($sql); + $stm->execute(); + $res = $stm->fetch(PDO::FETCH_NAMED); + + return round($res['average'], 2); + } + protected function calculateEntryRepartitionPerFeedPerPeriod($period, $feed = null) { if ($feed) { $restrict = "WHERE e.id_feed = {$feed}"; -- cgit v1.2.3 From edb02c8fefdb292c96d7b37ad4e2c311e9d43b44 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Tue, 30 Sep 2014 15:02:56 +0200 Subject: Move creation of categories in a new Controller Category names are 255 chars max --- app/Controllers/categoryController.php | 64 +++++++++++++++++++++++++++++++++ app/Controllers/configureController.php | 12 ------- app/Models/Category.php | 2 +- app/views/configure/categorize.phtml | 2 +- 4 files changed, 66 insertions(+), 14 deletions(-) create mode 100644 app/Controllers/categoryController.php (limited to 'app/Models') diff --git a/app/Controllers/categoryController.php b/app/Controllers/categoryController.php new file mode 100644 index 000000000..e2d98a509 --- /dev/null +++ b/app/Controllers/categoryController.php @@ -0,0 +1,64 @@ +view->loginOk) { + Minz_Error::error( + 403, + array('error' => array(_t('access_denied'))) + ); + } + + $catDAO = new FreshRSS_CategoryDAO(); + $catDAO->checkDefault(); + } + + /** + * This action creates a new category. + * + * URL parameter is: + * - new-category + */ + public function createAction() { + $catDAO = new FreshRSS_CategoryDAO(); + $url_redirect = array('c' => 'configure', 'a' => 'categorize'); + + if (Minz_Request::isPost()) { + invalidateHttpCache(); + + $cat_name = Minz_Request::param('new-category'); + if (!$cat_name) { + Minz_Request::bad(_t('category_no_name'), $url_redirect); + } + + $cat = new FreshRSS_Category($cat_name); + + if ($catDAO->searchByName($cat->name()) != null) { + Minz_Request::bad(_t('category_name_exists'), $url_redirect); + } + + $values = array( + 'id' => $cat->id(), + 'name' => $cat->name(), + ); + + if ($catDAO->addCategory($values)) { + Minz_Request::good(_t('category_created', $cat->name()), $url_redirect); + } else { + Minz_Request::bad(_t('category_not_created'), $url_redirect); + } + } + + Minz_Request::forward($url_redirect, true); + } +} diff --git a/app/Controllers/configureController.php b/app/Controllers/configureController.php index 231865bd7..7ef144090 100755 --- a/app/Controllers/configureController.php +++ b/app/Controllers/configureController.php @@ -45,7 +45,6 @@ class FreshRSS_configure_Controller extends Minz_ActionController { if (Minz_Request::isPost()) { $cats = Minz_Request::param('categories', array()); $ids = Minz_Request::param('ids', array()); - $newCat = trim(Minz_Request::param('new_category', '')); foreach ($cats as $key => $name) { if (strlen($name) > 0) { @@ -64,17 +63,6 @@ class FreshRSS_configure_Controller extends Minz_ActionController { } } - if ($newCat != '') { - $cat = new FreshRSS_Category($newCat); - $values = array( - 'id' => $cat->id(), - 'name' => $cat->name(), - ); - - if ($catDAO->searchByName($newCat) == null) { - $catDAO->addCategory($values); - } - } invalidateHttpCache(); Minz_Request::good(_t('categories_updated'), diff --git a/app/Models/Category.php b/app/Models/Category.php index 0a0dbd3ca..e5f6c4334 100644 --- a/app/Models/Category.php +++ b/app/Models/Category.php @@ -61,7 +61,7 @@ class FreshRSS_Category extends Minz_Model { $this->id = $value; } public function _name ($value) { - $this->name = $value; + $this->name = substr(trim($value), 0, 255); } public function _feeds ($values) { if (!is_array ($values)) { diff --git a/app/views/configure/categorize.phtml b/app/views/configure/categorize.phtml index 7091ff1cf..e7435e1c7 100644 --- a/app/views/configure/categorize.phtml +++ b/app/views/configure/categorize.phtml @@ -7,7 +7,7 @@
-
+
-- cgit v1.2.3 From a5a0bd9a350836cb7e504fdb501c82cda37d2562 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Tue, 30 Sep 2014 22:28:47 +0200 Subject: SQL performance: Removed filter to hide old articles As discussed on https://github.com/marienfressinaud/FreshRSS/issues/493#issuecomment-56266415 For performance, but this is also a good simplification. Will help with PostgreSQL https://github.com/marienfressinaud/FreshRSS/issues/416 and SQLite too https://github.com/marienfressinaud/FreshRSS/issues/100 because the main query becomes simpler. Me may need to introduce another system to hide old articles, if this is a problem for some users. Also, the feature showing "empty feeds" in another colour may need to be adapted. --- app/Controllers/indexController.php | 12 +++--------- app/Models/EntryDAO.php | 29 ++++++++++------------------- 2 files changed, 13 insertions(+), 28 deletions(-) (limited to 'app/Models') diff --git a/app/Controllers/indexController.php b/app/Controllers/indexController.php index e8e26b142..1b6563bb3 100755 --- a/app/Controllers/indexController.php +++ b/app/Controllers/indexController.php @@ -113,16 +113,10 @@ class FreshRSS_index_Controller extends Minz_ActionController { } } - $today = @strtotime('today'); - $this->view->today = $today; - - // on calcule la date des articles les plus anciens qu'on affiche - $nb_month_old = $this->view->conf->old_entries; - $date_min = $today - (3600 * 24 * 30 * $nb_month_old); //Do not use a fast changing value such as time() to allow SQL caching - $keepHistoryDefault = $this->view->conf->keep_history_default; + $this->view->today = @strtotime('today'); try { - $entries = $entryDAO->listWhere($getType, $getId, $this->view->state, $order, $nb + 1, $first, $filter, $date_min, true, $keepHistoryDefault); + $entries = $entryDAO->listWhere($getType, $getId, $this->view->state, $order, $nb + 1, $first, $filter); // Si on a récupéré aucun article "non lus" // on essaye de récupérer tous les articles @@ -135,7 +129,7 @@ class FreshRSS_index_Controller extends Minz_ActionController { Minz_Log::record('Failed to automatically correct nbNotRead! ' + $ex->getMessage(), Minz_Log::NOTICE); } $this->view->state = FreshRSS_Entry::STATE_ALL; - $entries = $entryDAO->listWhere($getType, $getId, $this->view->state, $order, $nb, $first, $filter, $date_min, true, $keepHistoryDefault); + $entries = $entryDAO->listWhere($getType, $getId, $this->view->state, $order, $nb, $first, $filter); } Minz_Request::_param('state', $this->view->state); diff --git a/app/Models/EntryDAO.php b/app/Models/EntryDAO.php index c1f87ee34..751ee6da7 100644 --- a/app/Models/EntryDAO.php +++ b/app/Models/EntryDAO.php @@ -299,7 +299,7 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo { return 'CONCAT(' . $s1 . ',' . $s2 . ')'; //MySQL } - private function sqlListWhere($type = 'a', $id = '', $state = FreshRSS_Entry::STATE_ALL, $order = 'DESC', $limit = 1, $firstId = '', $filter = '', $date_min = 0, $showOlderUnreadsorFavorites = false, $keepHistoryDefault = 0) { + private function sqlListWhere($type = 'a', $id = '', $state = FreshRSS_Entry::STATE_ALL, $order = 'DESC', $limit = 1, $firstId = '', $filter = '', $date_min = 0) { if (!$state) { $state = FreshRSS_Entry::STATE_ALL; } @@ -356,23 +356,14 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo { default: throw new FreshRSS_EntriesGetter_Exception('Bad order in Entry->listByType: [' . $order . ']!'); } - if ($firstId === '' && parent::$sharedDbType === 'mysql') { - $firstId = $order === 'DESC' ? '9000000000'. '000000' : '0'; //MySQL optimization. Tested on MySQL 5.5 with 150k articles - } + /*if ($firstId === '' && parent::$sharedDbType === 'mysql') { + $firstId = $order === 'DESC' ? '9000000000'. '000000' : '0'; //MySQL optimization. TODO: check if this is needed again, after the filtering for old articles has been removed in 0.9-dev + }*/ if ($firstId !== '') { $where .= 'AND e1.id ' . ($order === 'DESC' ? '<=' : '>=') . $firstId . ' '; } - if (($date_min > 0) && ($type !== 's')) { - $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 .= ') '; - $joinFeed = true; + if ($date_min > 0) { + $where .= 'AND e1.id >= ' . $date_min . '000000 '; } $search = ''; if ($filter !== '') { @@ -434,8 +425,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 = FreshRSS_Entry::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); + public function listWhere($type = 'a', $id = '', $state = FreshRSS_Entry::STATE_ALL, $order = 'DESC', $limit = 1, $firstId = '', $filter = '', $date_min = 0) { + list($values, $sql) = $this->sqlListWhere($type, $id, $state, $order, $limit, $firstId, $filter, $date_min); $sql = 'SELECT e.id, e.guid, e.title, e.author, ' . ($this->isCompressed() ? 'UNCOMPRESS(content_bin) AS content' : 'content') @@ -452,8 +443,8 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo { return self::daoToEntry($stm->fetchAll(PDO::FETCH_ASSOC)); } - public function listIdsWhere($type = 'a', $id = '', $state = FreshRSS_Entry::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); + public function listIdsWhere($type = 'a', $id = '', $state = FreshRSS_Entry::STATE_ALL, $order = 'DESC', $limit = 1, $firstId = '', $filter = '', $date_min = 0) { //For API + list($values, $sql) = $this->sqlListWhere($type, $id, $state, $order, $limit, $firstId, $filter, $date_min); $stm = $this->bd->prepare($sql); $stm->execute($values); -- cgit v1.2.3 From 1eef7893068655f8d145a3e06061a9e6296ac1f3 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Wed, 1 Oct 2014 11:27:41 +0200 Subject: Reorganize subscription management code There is still a lot of work to do. Some links are broken. See https://github.com/marienfressinaud/FreshRSS/issues/646 --- app/Controllers/configureController.php | 116 ------------------ app/Controllers/subscriptionController.php | 130 ++++++++++++++++++++ app/Models/Themes.php | 1 + app/layout/aside_feed.phtml | 60 ---------- app/layout/aside_flux.phtml | 4 +- app/layout/aside_subscription.phtml | 17 +++ app/views/configure/categorize.phtml | 90 -------------- app/views/configure/feed.phtml | 186 ----------------------------- app/views/importExport/index.phtml | 2 +- app/views/subscription/feed.phtml | 186 +++++++++++++++++++++++++++++ app/views/subscription/index.phtml | 132 ++++++++++++++++++++ p/themes/icons/import.svg | 9 ++ 12 files changed, 478 insertions(+), 455 deletions(-) create mode 100644 app/Controllers/subscriptionController.php delete mode 100644 app/layout/aside_feed.phtml create mode 100644 app/layout/aside_subscription.phtml delete mode 100644 app/views/configure/categorize.phtml delete mode 100644 app/views/configure/feed.phtml create mode 100644 app/views/subscription/feed.phtml create mode 100644 app/views/subscription/index.phtml create mode 100644 p/themes/icons/import.svg (limited to 'app/Models') diff --git a/app/Controllers/configureController.php b/app/Controllers/configureController.php index 3fd1d5149..b7b88b3ba 100755 --- a/app/Controllers/configureController.php +++ b/app/Controllers/configureController.php @@ -8,9 +8,6 @@ class FreshRSS_configure_Controller extends Minz_ActionController { * This action is called before every other action in that class. It is * the common boiler plate for every action. It is triggered by the * underlying framework. - * - * @todo see if the category default configuration is needed here or if - * we can move it to the categorize action */ public function firstAction() { if (!$this->view->loginOk) { @@ -19,119 +16,6 @@ class FreshRSS_configure_Controller extends Minz_ActionController { array('error' => array(_t('access_denied'))) ); } - - $catDAO = new FreshRSS_CategoryDAO(); - $catDAO->checkDefault(); - } - - /** - * This action handles the category configuration page - * - * It displays the category configuration page. - */ - public function categorizeAction() { - $catDAO = new FreshRSS_CategoryDAO(); - - $this->view->categories = $catDAO->listCategories(false); - $this->view->default_category = $catDAO->getDefault(); - - Minz_View::prependTitle(_t('categories_management') . ' · '); - } - - /** - * This action handles the feed configuration page. - * - * It displays the feed configuration page. - * If this action is reached through a POST request, it stores all new - * configuraiton values then sends a notification to the user. - * - * The options available on the page are: - * - name - * - description - * - website URL - * - feed URL - * - category id (default: default category id) - * - CSS path to article on website - * - display in main stream (default: 0) - * - HTTP authentication - * - number of article to retain (default: -2) - * - refresh frequency (default: -2) - * Default values are empty strings unless specified. - */ - public function feedAction() { - if (Minz_Request::param('ajax')) { - $this->view->_useLayout(false); - } - - $catDAO = new FreshRSS_CategoryDAO(); - $this->view->categories = $catDAO->listCategories(false); - - $feedDAO = FreshRSS_Factory::createFeedDao(); - $this->view->feeds = $feedDAO->listFeeds(); - - $id = Minz_Request::param('id'); - if ($id == false && !empty($this->view->feeds)) { - $id = current($this->view->feeds)->id(); - } - - $this->view->flux = false; - if ($id != false) { - $this->view->flux = $this->view->feeds[$id]; - - if (!$this->view->flux) { - Minz_Error::error( - 404, - array('error' => array(_t('page_not_found'))) - ); - } else { - if (Minz_Request::isPost() && $this->view->flux) { - $user = Minz_Request::param('http_user', ''); - $pass = Minz_Request::param('http_pass', ''); - - $httpAuth = ''; - if ($user != '' || $pass != '') { - $httpAuth = $user . ':' . $pass; - } - - $cat = intval(Minz_Request::param('category', 0)); - - $values = array( - 'name' => Minz_Request::param('name', ''), - 'description' => sanitizeHTML(Minz_Request::param('description', '', true)), - 'website' => Minz_Request::param('website', ''), - 'url' => Minz_Request::param('url', ''), - 'category' => $cat, - 'pathEntries' => Minz_Request::param('path_entries', ''), - 'priority' => intval(Minz_Request::param('priority', 0)), - 'httpAuth' => $httpAuth, - 'keep_history' => intval(Minz_Request::param('keep_history', -2)), - 'ttl' => intval(Minz_Request::param('ttl', -2)), - ); - - if ($feedDAO->updateFeed($id, $values)) { - $this->view->flux->_category($cat); - $this->view->flux->faviconPrepare(); - $notif = array( - 'type' => 'good', - 'content' => _t('feed_updated') - ); - } else { - $notif = array( - 'type' => 'bad', - 'content' => _t('error_occurred_update') - ); - } - invalidateHttpCache(); - - Minz_Session::_param('notification', $notif); - Minz_Request::forward(array('c' => 'configure', 'a' => 'feed', 'params' => array('id' => $id)), true); - } - - Minz_View::prependTitle(_t('rss_feed_management') . ' — ' . $this->view->flux->name() . ' · '); - } - } else { - Minz_View::prependTitle(_t('rss_feed_management') . ' · '); - } } /** diff --git a/app/Controllers/subscriptionController.php b/app/Controllers/subscriptionController.php new file mode 100644 index 000000000..ab00f3e6a --- /dev/null +++ b/app/Controllers/subscriptionController.php @@ -0,0 +1,130 @@ +view->loginOk) { + Minz_Error::error( + 403, + array('error' => array(_t('access_denied'))) + ); + } + } + + /** + * This action handles the main subscription page + * + * It displays categories and associated feeds. + */ + public function indexAction() { + $catDAO = new FreshRSS_CategoryDAO(); + + $this->view->categories = $catDAO->listCategories(false); + $this->view->default_category = $catDAO->getDefault(); + + Minz_View::prependTitle(_t('subscription_management') . ' · '); + } + + /** + * This action handles the feed configuration page. + * + * It displays the feed configuration page. + * If this action is reached through a POST request, it stores all new + * configuraiton values then sends a notification to the user. + * + * The options available on the page are: + * - name + * - description + * - website URL + * - feed URL + * - category id (default: default category id) + * - CSS path to article on website + * - display in main stream (default: 0) + * - HTTP authentication + * - number of article to retain (default: -2) + * - refresh frequency (default: -2) + * Default values are empty strings unless specified. + */ + public function feedAction() { + if (Minz_Request::param('ajax')) { + $this->view->_useLayout(false); + } + + $catDAO = new FreshRSS_CategoryDAO(); + $this->view->categories = $catDAO->listCategories(false); + + $feedDAO = FreshRSS_Factory::createFeedDao(); + $this->view->feeds = $feedDAO->listFeeds(); + + $id = Minz_Request::param('id'); + if ($id == false && !empty($this->view->feeds)) { + $id = current($this->view->feeds)->id(); + } + + $this->view->flux = false; + if ($id != false) { + $this->view->flux = $this->view->feeds[$id]; + + if (!$this->view->flux) { + Minz_Error::error( + 404, + array('error' => array(_t('page_not_found'))) + ); + } else { + if (Minz_Request::isPost() && $this->view->flux) { + $user = Minz_Request::param('http_user', ''); + $pass = Minz_Request::param('http_pass', ''); + + $httpAuth = ''; + if ($user != '' || $pass != '') { + $httpAuth = $user . ':' . $pass; + } + + $cat = intval(Minz_Request::param('category', 0)); + + $values = array( + 'name' => Minz_Request::param('name', ''), + 'description' => sanitizeHTML(Minz_Request::param('description', '', true)), + 'website' => Minz_Request::param('website', ''), + 'url' => Minz_Request::param('url', ''), + 'category' => $cat, + 'pathEntries' => Minz_Request::param('path_entries', ''), + 'priority' => intval(Minz_Request::param('priority', 0)), + 'httpAuth' => $httpAuth, + 'keep_history' => intval(Minz_Request::param('keep_history', -2)), + 'ttl' => intval(Minz_Request::param('ttl', -2)), + ); + + if ($feedDAO->updateFeed($id, $values)) { + $this->view->flux->_category($cat); + $this->view->flux->faviconPrepare(); + $notif = array( + 'type' => 'good', + 'content' => _t('feed_updated') + ); + } else { + $notif = array( + 'type' => 'bad', + 'content' => _t('error_occurred_update') + ); + } + invalidateHttpCache(); + + Minz_Session::_param('notification', $notif); + Minz_Request::forward(array('c' => 'subscription'), true); + } + + Minz_View::prependTitle(_t('rss_feed_management') . ' · ' . $this->view->flux->name() . ' · '); + } + } else { + Minz_View::prependTitle(_t('rss_feed_management') . ' · '); + } + } +} diff --git a/app/Models/Themes.php b/app/Models/Themes.php index 68fc17a2b..e3b260261 100644 --- a/app/Models/Themes.php +++ b/app/Models/Themes.php @@ -82,6 +82,7 @@ class FreshRSS_Themes extends Minz_Model { 'favorite' => '★', 'help' => 'ⓘ', 'icon' => '⊚', + 'import' => '⤓', 'key' => '⚿', 'link' => '↗', 'login' => '🔒', diff --git a/app/layout/aside_feed.phtml b/app/layout/aside_feed.phtml deleted file mode 100644 index c028c4918..000000000 --- a/app/layout/aside_feed.phtml +++ /dev/null @@ -1,60 +0,0 @@ - diff --git a/app/layout/aside_flux.phtml b/app/layout/aside_flux.phtml index aac3c0896..341697103 100644 --- a/app/layout/aside_flux.phtml +++ b/app/layout/aside_flux.phtml @@ -7,8 +7,8 @@
  • - - + +
  • diff --git a/app/layout/aside_subscription.phtml b/app/layout/aside_subscription.phtml new file mode 100644 index 000000000..9a95763c3 --- /dev/null +++ b/app/layout/aside_subscription.phtml @@ -0,0 +1,17 @@ + diff --git a/app/views/configure/categorize.phtml b/app/views/configure/categorize.phtml deleted file mode 100644 index f5030ef2c..000000000 --- a/app/views/configure/categorize.phtml +++ /dev/null @@ -1,90 +0,0 @@ -partial('aside_feed'); ?> - -
    - - -

    - -

    - default_category->name()); ?> -

    - -
    -
    - -
      -
      -
    • -
    • -
      -
    -
    - - - - categories as $cat) { - $feeds = $cat->feeds(); - ?> -
    -
    -
    - - - -
    -
    - -
      - - inError() ? ' error' : ''; - $empty = $feed->nbEntries() == 0 ? ' empty' : ''; - ?> -
    • - - ✇ name(); ?> -
    • - -
    • - -
    -
    - -
    - -
    -
    diff --git a/app/views/configure/feed.phtml b/app/views/configure/feed.phtml deleted file mode 100644 index f58ac65af..000000000 --- a/app/views/configure/feed.phtml +++ /dev/null @@ -1,186 +0,0 @@ -partial('aside_feed'); - } -?> - -flux) { ?> -
    - - -

    flux->name (); ?>

    - flux->description (); ?> - - flux->nbEntries (); ?> - - flux->inError ()) { ?> -

    - -

    - - -
    - -
    - -
    - -
    -
    -
    - -
    - -
    -
    -
    - -
    -
    - - -
    -
    -
    -
    - -
    -
    - - -
    - - -
    -
    -
    - -
    - -
    -
    -
    - -
    - -
    -
    -
    -
    - - - -
    -
    -
    -
    - - -
    -
    - - - -
    -
    -
    - - - - -
    -
    -
    -
    - -
    - -
    -
    -
    - -
    - -
    -
    -
    -
    - - -
    -
    - - - flux->httpAuth (false); ?> -
    - -
    - - -
    - - -
    - -
    -
    - -
    -
    - - -
    -
    - - -
    - -
    - - -
    -
    - -
    -
    - - -
    -
    -
    -
    - - -
    - diff --git a/app/views/importExport/index.phtml b/app/views/importExport/index.phtml index 35371faca..36c0eab4e 100644 --- a/app/views/importExport/index.phtml +++ b/app/views/importExport/index.phtml @@ -1,4 +1,4 @@ -partial('aside_feed'); ?> +partial('aside_subscription'); ?>
    diff --git a/app/views/subscription/feed.phtml b/app/views/subscription/feed.phtml new file mode 100644 index 000000000..e047741a1 --- /dev/null +++ b/app/views/subscription/feed.phtml @@ -0,0 +1,186 @@ +partial('aside_subscription'); + } +?> + +flux) { ?> +
    + + +

    flux->name (); ?>

    + flux->description (); ?> + + flux->nbEntries (); ?> + + flux->inError ()) { ?> +

    + +

    + + +
    + +
    + +
    + +
    +
    +
    + +
    + +
    +
    +
    + +
    +
    + + +
    +
    +
    +
    + +
    +
    + + +
    + + +
    +
    +
    + +
    + +
    +
    +
    + +
    + +
    +
    +
    +
    + + + +
    +
    +
    +
    + + +
    +
    + + + +
    +
    +
    + + + + +
    +
    +
    +
    + +
    + +
    +
    +
    + +
    + +
    +
    +
    +
    + + +
    +
    + + + flux->httpAuth (false); ?> +
    + +
    + + +
    + + +
    + +
    +
    + +
    +
    + + +
    +
    + + +
    + +
    + + +
    +
    + +
    +
    + + +
    +
    +
    +
    + + +
    + diff --git a/app/views/subscription/index.phtml b/app/views/subscription/index.phtml new file mode 100644 index 000000000..444dc9d9b --- /dev/null +++ b/app/views/subscription/index.phtml @@ -0,0 +1,132 @@ +partial('aside_subscription'); ?> + +
    + + +

    + +
    +
    + + + +
    +
    + +

    + default_category->name()); ?> +

    + +
    +
    + +
      +
      +
    • +
    • +
      +
    +
    + + + + categories as $cat) { + $feeds = $cat->feeds(); + ?> +
    +
    +
    + + + +
    +
    + +
      + + inError() ? ' error' : ''; + $empty = $feed->nbEntries() == 0 ? ' empty' : ''; + ?> +
    • + + ✇ name(); ?> +
    • + +
    • + +
    +
    + +
    + +
    +
    diff --git a/p/themes/icons/import.svg b/p/themes/icons/import.svg new file mode 100644 index 000000000..a7f20c909 --- /dev/null +++ b/p/themes/icons/import.svg @@ -0,0 +1,9 @@ + + + + + + + + + -- cgit v1.2.3 From 38a6f0c4b29e5a53c21f345dd839a4fa0b2a6f47 Mon Sep 17 00:00:00 2001 From: Alexis Degrugillier Date: Sat, 4 Oct 2014 09:06:35 -0400 Subject: Add a shortcut to close drop-down lists --- app/Models/Configuration.php | 1 + app/i18n/en.php | 1 + app/i18n/fr.php | 1 + app/views/configure/shortcut.phtml | 7 +++++++ app/views/helpers/javascript_vars.phtml | 3 ++- p/scripts/main.js | 6 ++++++ 6 files changed, 18 insertions(+), 1 deletion(-) (limited to 'app/Models') diff --git a/app/Models/Configuration.php b/app/Models/Configuration.php index 95f819779..feba3d2f6 100644 --- a/app/Models/Configuration.php +++ b/app/Models/Configuration.php @@ -47,6 +47,7 @@ class FreshRSS_Configuration { 'focus_search' => 'a', 'user_filter' => 'u', 'help' => 'f1', + 'close_dropdown' => 'escape', ), 'topline_read' => true, 'topline_favorite' => true, diff --git a/app/i18n/en.php b/app/i18n/en.php index 28104196e..0456049a9 100644 --- a/app/i18n/en.php +++ b/app/i18n/en.php @@ -191,6 +191,7 @@ return array ( 'user_filter' => 'Access user filters', 'user_filter_help' => 'If there is only one user filter, it is used. Else filters are accessible by their number.', 'help' => 'Display documentation', + 'close_dropdown' => 'Close drop-down lists', 'file_to_import' => 'File to import
    (OPML, Json or Zip)', 'file_to_import_no_zip' => 'File to import
    (OPML or Json)', diff --git a/app/i18n/fr.php b/app/i18n/fr.php index c72fc3e93..adc79d0e2 100644 --- a/app/i18n/fr.php +++ b/app/i18n/fr.php @@ -191,6 +191,7 @@ return array ( 'user_filter' => 'Accéder aux filtres utilisateur', 'user_filter_help' => 'S’il n’y a qu’un filtre utilisateur, celui ci est utilisé automatiquement. Sinon ils sont accessibles par leur numéro.', 'help' => 'Afficher la documentation', + 'close_dropdown' => 'Fermer les listes déroulantes', 'file_to_import' => 'Fichier à importer
    (OPML, Json ou Zip)', 'file_to_import_no_zip' => 'Fichier à importer
    (OPML ou Json)', diff --git a/app/views/configure/shortcut.phtml b/app/views/configure/shortcut.phtml index a4029b676..44727e62b 100644 --- a/app/views/configure/shortcut.phtml +++ b/app/views/configure/shortcut.phtml @@ -111,6 +111,13 @@
    +
    + +
    + +
    +
    +
    diff --git a/app/views/helpers/javascript_vars.phtml b/app/views/helpers/javascript_vars.phtml index 71798369d..4f7e3db0c 100644 --- a/app/views/helpers/javascript_vars.phtml +++ b/app/views/helpers/javascript_vars.phtml @@ -28,7 +28,8 @@ echo ',shortcuts={', 'auto_share:"', $s['auto_share'], '",', 'focus_search:"', $s['focus_search'], '",', 'user_filter:"', $s['user_filter'], '",', - 'help:"', $s['help'], '"', + 'help:"', $s['help'], '",', + 'close_dropdown:"', $s['close_dropdown'], '"', "},\n"; if (Minz_Request::param ('output') === 'global') { diff --git a/p/scripts/main.js b/p/scripts/main.js index 37281a907..0d90d3d39 100644 --- a/p/scripts/main.js +++ b/p/scripts/main.js @@ -663,6 +663,12 @@ function init_shortcuts() { 'disable_in_input': true }); + shortcut.add(shortcuts.close_dropdown, function () { + window.location.hash = null; + }, { + 'disable_in_input': true + }); + } function init_stream(divStream) { -- cgit v1.2.3 From 6c8b36f04ea1bc2c022c331bb0980b6c9dccb83c Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Sun, 5 Oct 2014 15:55:20 +0200 Subject: Let's begin the big refactoring! Minz_Translate::t\s? replaces by _t See https://github.com/marienfressinaud/FreshRSS/issues/655 --- app/Controllers/entryController.php | 8 ++-- app/Controllers/errorController.php | 4 +- app/Controllers/feedController.php | 30 ++++++------- app/Controllers/indexController.php | 22 +++++----- app/Controllers/statsController.php | 4 +- app/Controllers/usersController.php | 8 ++-- app/FreshRSS.php | 2 +- app/Models/CategoryDAO.php | 2 +- app/Models/StatsDAO.php | 2 +- app/Models/UserDAO.php | 4 +- app/layout/aside_stats.phtml | 14 +++--- app/views/configure/archiving.phtml | 36 ++++++++-------- app/views/configure/display.phtml | 44 +++++++++---------- app/views/configure/reading.phtml | 64 +++++++++++++-------------- app/views/configure/sharing.phtml | 24 +++++------ app/views/configure/users.phtml | 74 ++++++++++++++++---------------- app/views/error/index.phtml | 2 +- app/views/feed/add.phtml | 34 +++++++-------- app/views/helpers/feed/update.phtml | 60 +++++++++++++------------- app/views/helpers/javascript_vars.phtml | 8 ++-- app/views/helpers/logs_pagination.phtml | 8 ++-- app/views/helpers/view/normal_view.phtml | 14 +++--- app/views/helpers/view/reader_view.phtml | 2 +- app/views/helpers/view/rss_view.phtml | 2 +- app/views/index/about.phtml | 26 +++++------ app/views/index/logs.phtml | 8 ++-- lib/lib_rss.php | 8 ++-- 27 files changed, 256 insertions(+), 258 deletions(-) (limited to 'app/Models') diff --git a/app/Controllers/entryController.php b/app/Controllers/entryController.php index ab66d9198..048ac1c69 100755 --- a/app/Controllers/entryController.php +++ b/app/Controllers/entryController.php @@ -5,7 +5,7 @@ class FreshRSS_entry_Controller extends Minz_ActionController { if (!$this->view->loginOk) { Minz_Error::error ( 403, - array ('error' => array (Minz_Translate::t ('access_denied'))) + array ('error' => array (_t('access_denied'))) ); } @@ -75,7 +75,7 @@ class FreshRSS_entry_Controller extends Minz_ActionController { $notif = array ( 'type' => 'good', - 'content' => Minz_Translate::t ('feeds_marked_read') + 'content' => _t('feeds_marked_read') ); Minz_Session::_param ('notification', $notif); } else { @@ -111,7 +111,7 @@ class FreshRSS_entry_Controller extends Minz_ActionController { $notif = array ( 'type' => 'good', - 'content' => Minz_Translate::t ('optimization_complete') + 'content' => _t('optimization_complete') ); Minz_Session::_param ('notification', $notif); } @@ -155,7 +155,7 @@ class FreshRSS_entry_Controller extends Minz_ActionController { $notif = array( 'type' => 'good', - 'content' => Minz_Translate::t('purge_completed', $nbTotal) + 'content' => _t('purge_completed', $nbTotal) ); Minz_Session::_param('notification', $notif); diff --git a/app/Controllers/errorController.php b/app/Controllers/errorController.php index 922650b3d..64a5c06fd 100644 --- a/app/Controllers/errorController.php +++ b/app/Controllers/errorController.php @@ -24,11 +24,11 @@ class FreshRSS_error_Controller extends Minz_ActionController { if ($this->view->errorMessage == '') { switch(Minz_Request::param('code')) { case 403: - $this->view->errorMessage = Minz_Translate::t('forbidden_access'); + $this->view->errorMessage = _t('forbidden_access'); break; case 404: default: - $this->view->errorMessage = Minz_Translate::t('page_not_found'); + $this->view->errorMessage = _t('page_not_found'); break; } } diff --git a/app/Controllers/feedController.php b/app/Controllers/feedController.php index 92ce40634..029f9fa68 100755 --- a/app/Controllers/feedController.php +++ b/app/Controllers/feedController.php @@ -15,7 +15,7 @@ class FreshRSS_feed_Controller extends Minz_ActionController { ) { Minz_Error::error ( 403, - array ('error' => array (Minz_Translate::t ('access_denied'))) + array ('error' => array (_t('access_denied'))) ); } } @@ -84,7 +84,7 @@ class FreshRSS_feed_Controller extends Minz_ActionController { // on est déjà abonné à ce flux $notif = array ( 'type' => 'bad', - 'content' => Minz_Translate::t ('already_subscribed', $feed->name ()) + 'content' => _t('already_subscribed', $feed->name ()) ); Minz_Session::_param ('notification', $notif); } else { @@ -93,7 +93,7 @@ class FreshRSS_feed_Controller extends Minz_ActionController { // problème au niveau de la base de données $notif = array ( 'type' => 'bad', - 'content' => Minz_Translate::t ('feed_not_added', $feed->name ()) + 'content' => _t('feed_not_added', $feed->name ()) ); Minz_Session::_param ('notification', $notif); } else { @@ -131,7 +131,7 @@ class FreshRSS_feed_Controller extends Minz_ActionController { // ok, ajout terminé $notif = array ( 'type' => 'good', - 'content' => Minz_Translate::t ('feed_added', $feed->name ()) + 'content' => _t('feed_added', $feed->name ()) ); Minz_Session::_param ('notification', $notif); @@ -143,14 +143,14 @@ class FreshRSS_feed_Controller extends Minz_ActionController { Minz_Log::record ($e->getMessage (), Minz_Log::WARNING); $notif = array ( 'type' => 'bad', - 'content' => Minz_Translate::t ('invalid_url', $url) + 'content' => _t('invalid_url', $url) ); Minz_Session::_param ('notification', $notif); } catch (FreshRSS_Feed_Exception $e) { Minz_Log::record ($e->getMessage (), Minz_Log::WARNING); $notif = array ( 'type' => 'bad', - 'content' => Minz_Translate::t ('internal_problem_feed', Minz_Url::display(array('a' => 'logs'))) + 'content' => _t('internal_problem_feed', Minz_Url::display(array('a' => 'logs'))) ); Minz_Session::_param ('notification', $notif); } catch (Minz_FileNotExistException $e) { @@ -158,7 +158,7 @@ class FreshRSS_feed_Controller extends Minz_ActionController { Minz_Log::record ($e->getMessage (), Minz_Log::ERROR); $notif = array ( 'type' => 'bad', - 'content' => Minz_Translate::t ('internal_problem_feed', Minz_Url::display(array('a' => 'logs'))) + 'content' => _t('internal_problem_feed', Minz_Url::display(array('a' => 'logs'))) ); Minz_Session::_param ('notification', $notif); } @@ -170,7 +170,7 @@ class FreshRSS_feed_Controller extends Minz_ActionController { } else { // GET request so we must ask confirmation to user - Minz_View::prependTitle(Minz_Translate::t('add_rss_feed') . ' · '); + Minz_View::prependTitle(_t('add_rss_feed') . ' · '); $this->view->categories = $this->catDAO->listCategories(false); $this->view->feed = new FreshRSS_Feed($url); try { @@ -186,9 +186,7 @@ class FreshRSS_feed_Controller extends Minz_ActionController { // Already subscribe so we redirect to the feed configuration page $notif = array( 'type' => 'bad', - 'content' => Minz_Translate::t( - 'already_subscribed', $feed->name() - ) + 'content' => _t('already_subscribed', $feed->name()) ); Minz_Session::_param('notification', $notif); @@ -210,7 +208,7 @@ class FreshRSS_feed_Controller extends Minz_ActionController { $n = $feedDAO->truncate($id); $notif = array( 'type' => $n === false ? 'bad' : 'good', - 'content' => Minz_Translate::t ('n_entries_deleted', $n) + 'content' => _t('n_entries_deleted', $n) ); Minz_Session::_param ('notification', $notif); invalidateHttpCache(); @@ -336,19 +334,19 @@ class FreshRSS_feed_Controller extends Minz_ActionController { $feed = reset ($feeds); $notif = array ( 'type' => 'good', - 'content' => Minz_Translate::t ('feed_actualized', $feed->name ()) + 'content' => _t('feed_actualized', $feed->name ()) ); } elseif ($flux_update > 1) { // plusieurs flux on été mis à jour $notif = array ( 'type' => 'good', - 'content' => Minz_Translate::t ('n_feeds_actualized', $flux_update) + 'content' => _t('n_feeds_actualized', $flux_update) ); } else { // aucun flux n'a été mis à jour, oups $notif = array ( 'type' => 'good', - 'content' => Minz_Translate::t ('no_feed_to_refresh') + 'content' => _t('no_feed_to_refresh') ); } @@ -370,7 +368,7 @@ class FreshRSS_feed_Controller extends Minz_ActionController { // ressenti utilisateur $notif = array ( 'type' => 'good', - 'content' => Minz_Translate::t ('feeds_actualized') + 'content' => _t('feeds_actualized') ); Minz_Session::_param ('notification', $notif); // et on désactive le layout car ne sert à rien diff --git a/app/Controllers/indexController.php b/app/Controllers/indexController.php index 1b6563bb3..346739523 100755 --- a/app/Controllers/indexController.php +++ b/app/Controllers/indexController.php @@ -14,7 +14,7 @@ class FreshRSS_index_Controller extends Minz_ActionController { if ($output === 'rss' && !$token_is_ok) { Minz_Error::error ( 403, - array ('error' => array (Minz_Translate::t ('access_denied'))) + array ('error' => array (_t('access_denied'))) ); return; } elseif ($output !== 'rss') { @@ -62,7 +62,7 @@ class FreshRSS_index_Controller extends Minz_ActionController { Minz_Log::record ('Not found [' . $getType . '][' . $getId . ']', Minz_Log::DEBUG); Minz_Error::error ( 404, - array ('error' => array (Minz_Translate::t ('page_not_found'))) + array ('error' => array (_t('page_not_found'))) ); return; } @@ -145,7 +145,7 @@ class FreshRSS_index_Controller extends Minz_ActionController { Minz_Log::record ($e->getMessage (), Minz_Log::NOTICE); Minz_Error::error ( 404, - array ('error' => array (Minz_Translate::t ('page_not_found'))) + array ('error' => array (_t('page_not_found'))) ); } } @@ -158,12 +158,12 @@ class FreshRSS_index_Controller extends Minz_ActionController { private function checkAndProcessType ($getType, $getId) { switch ($getType) { case 'a': - $this->view->currentName = Minz_Translate::t ('your_rss_feeds'); + $this->view->currentName = _t('your_rss_feeds'); $this->nb_not_read_cat = $this->view->nb_not_read; $this->view->get_c = $getType; return true; case 's': - $this->view->currentName = Minz_Translate::t ('your_favorites'); + $this->view->currentName = _t('your_favorites'); $this->nb_not_read_cat = $this->view->nb_favorites['unread']; $this->view->get_c = $getType; return true; @@ -202,18 +202,18 @@ class FreshRSS_index_Controller extends Minz_ActionController { } public function aboutAction () { - Minz_View::prependTitle (Minz_Translate::t ('about') . ' · '); + Minz_View::prependTitle (_t('about') . ' · '); } public function logsAction () { if (!$this->view->loginOk) { Minz_Error::error ( 403, - array ('error' => array (Minz_Translate::t ('access_denied'))) + array ('error' => array (_t('access_denied'))) ); } - Minz_View::prependTitle (Minz_Translate::t ('logs') . ' · '); + Minz_View::prependTitle (_t('logs') . ' · '); if (Minz_Request::isPost ()) { FreshRSS_LogDAO::truncate(); @@ -279,7 +279,7 @@ class FreshRSS_index_Controller extends Minz_ActionController { } else { $res = array (); $res['status'] = 'failure'; - $res['reason'] = $reason == '' ? Minz_Translate::t ('invalid_login') : $reason; + $res['reason'] = $reason == '' ? _t('invalid_login') : $reason; Minz_Log::record ('Persona: ' . $res['reason'], Minz_Log::WARNING); } @@ -368,7 +368,7 @@ class FreshRSS_index_Controller extends Minz_ActionController { if (!$ok) { $notif = array( 'type' => 'bad', - 'content' => Minz_Translate::t('invalid_login') + 'content' => _t('invalid_login') ); Minz_Session::_param('notification', $notif); } @@ -403,7 +403,7 @@ class FreshRSS_index_Controller extends Minz_ActionController { } elseif (!Minz_Configuration::canLogIn()) { Minz_Error::error ( 403, - array ('error' => array (Minz_Translate::t ('access_denied'))) + array ('error' => array (_t('access_denied'))) ); } invalidateHttpCache(); diff --git a/app/Controllers/statsController.php b/app/Controllers/statsController.php index 3069be34d..4adb5e75d 100644 --- a/app/Controllers/statsController.php +++ b/app/Controllers/statsController.php @@ -120,11 +120,11 @@ class FreshRSS_stats_Controller extends Minz_ActionController { public function firstAction() { if (!$this->view->loginOk) { Minz_Error::error( - 403, array('error' => array(Minz_Translate::t('access_denied'))) + 403, array('error' => array(_t('access_denied'))) ); } - Minz_View::prependTitle(Minz_Translate::t('stats') . ' · '); + Minz_View::prependTitle(_t('stats') . ' · '); } } diff --git a/app/Controllers/usersController.php b/app/Controllers/usersController.php index a9e6c32bc..8eb82f5d5 100644 --- a/app/Controllers/usersController.php +++ b/app/Controllers/usersController.php @@ -8,7 +8,7 @@ class FreshRSS_users_Controller extends Minz_ActionController { if (!$this->view->loginOk) { Minz_Error::error( 403, - array('error' => array(Minz_Translate::t('access_denied'))) + array('error' => array(_t('access_denied'))) ); } } @@ -90,7 +90,7 @@ class FreshRSS_users_Controller extends Minz_ActionController { $notif = array( 'type' => $ok ? 'good' : 'bad', - 'content' => Minz_Translate::t($ok ? 'configuration_updated' : 'error_occurred') + 'content' => _t($ok ? 'configuration_updated' : 'error_occurred') ); Minz_Session::_param('notification', $notif); } @@ -162,7 +162,7 @@ class FreshRSS_users_Controller extends Minz_ActionController { $notif = array( 'type' => $ok ? 'good' : 'bad', - 'content' => Minz_Translate::t($ok ? 'user_created' : 'error_occurred', $new_user_name) + 'content' => _t($ok ? 'user_created' : 'error_occurred', $new_user_name) ); Minz_Session::_param('notification', $notif); } @@ -194,7 +194,7 @@ class FreshRSS_users_Controller extends Minz_ActionController { $notif = array( 'type' => $ok ? 'good' : 'bad', - 'content' => Minz_Translate::t($ok ? 'user_deleted' : 'error_occurred', $username) + 'content' => _t($ok ? 'user_deleted' : 'error_occurred', $username) ); Minz_Session::_param('notification', $notif); } diff --git a/app/FreshRSS.php b/app/FreshRSS.php index 58aac4059..16f64fd8b 100644 --- a/app/FreshRSS.php +++ b/app/FreshRSS.php @@ -10,7 +10,7 @@ class FreshRSS extends Minz_FrontController { $loginOk = false; //Basic protection against XSRF attacks Minz_Error::error( 403, - array('error' => array(Minz_Translate::t('access_denied') . ' [HTTP_REFERER=' . + array('error' => array(_t('access_denied') . ' [HTTP_REFERER=' . htmlspecialchars(empty($_SERVER['HTTP_REFERER']) ? '' : $_SERVER['HTTP_REFERER']) . ']')) ); } diff --git a/app/Models/CategoryDAO.php b/app/Models/CategoryDAO.php index f11f87f47..5def50a26 100644 --- a/app/Models/CategoryDAO.php +++ b/app/Models/CategoryDAO.php @@ -134,7 +134,7 @@ class FreshRSS_CategoryDAO extends Minz_ModelPdo { $def_cat = $this->searchById (1); if ($def_cat == null) { - $cat = new FreshRSS_Category (Minz_Translate::t ('default_category')); + $cat = new FreshRSS_Category (_t('default_category')); $cat->_id (1); $values = array ( diff --git a/app/Models/StatsDAO.php b/app/Models/StatsDAO.php index 08dd4cd5c..113944508 100644 --- a/app/Models/StatsDAO.php +++ b/app/Models/StatsDAO.php @@ -416,7 +416,7 @@ SQL; */ private function convertToTranslatedJson($data = array()) { $translated = array_map(function ($a) { - return Minz_Translate::t($a); + return _t($a); }, $data); return json_encode($translated); diff --git a/app/Models/UserDAO.php b/app/Models/UserDAO.php index 9f64fb4a7..0c96d7175 100644 --- a/app/Models/UserDAO.php +++ b/app/Models/UserDAO.php @@ -9,7 +9,7 @@ class FreshRSS_UserDAO extends Minz_ModelPdo { $ok = false; if (defined('SQL_CREATE_TABLES')) { //E.g. MySQL - $sql = sprintf(SQL_CREATE_TABLES, $db['prefix'] . $username . '_', Minz_Translate::t('default_category')); + $sql = sprintf(SQL_CREATE_TABLES, $db['prefix'] . $username . '_', _t('default_category')); $stm = $userPDO->bd->prepare($sql); $ok = $stm && $stm->execute(); } else { //E.g. SQLite @@ -17,7 +17,7 @@ class FreshRSS_UserDAO extends Minz_ModelPdo { if (is_array($SQL_CREATE_TABLES)) { $ok = true; foreach ($SQL_CREATE_TABLES as $instruction) { - $sql = sprintf($instruction, '', Minz_Translate::t('default_category')); + $sql = sprintf($instruction, '', _t('default_category')); $stm = $userPDO->bd->prepare($sql); $ok &= ($stm && $stm->execute()); } diff --git a/app/layout/aside_stats.phtml b/app/layout/aside_stats.phtml index fbfb9d84d..1cd31a99c 100644 --- a/app/layout/aside_stats.phtml +++ b/app/layout/aside_stats.phtml @@ -1,12 +1,12 @@ diff --git a/app/views/configure/archiving.phtml b/app/views/configure/archiving.phtml index c9cc7fe02..3180fe933 100644 --- a/app/views/configure/archiving.phtml +++ b/app/views/configure/archiving.phtml @@ -1,31 +1,31 @@ partial('aside_configure'); ?>
    - +
    - -

    + +

    - +
    - -   + +  
    - +
    () + ?> ()
    - +
    () + ?> ()
    - - + +
    - +
    -

    +

    -

    nb_total), ' ', Minz_Translate::t('articles'), ', ', formatBytes($this->size_user); ?>

    +

    nb_total), ' ', _t('articles'), ', ', formatBytes($this->size_user); ?>

    - - + +
    -

    +

    size_total); ?>

    diff --git a/app/views/configure/display.phtml b/app/views/configure/display.phtml index 8eb3a156b..f1b80ab15 100644 --- a/app/views/configure/display.phtml +++ b/app/views/configure/display.phtml @@ -1,13 +1,13 @@ partial ('aside_configure'); ?>
    - + - +
    - +
    themes as $theme) { ?>conf->content_width; ?>
    - +
    - + - - - - - + + + + + - + @@ -80,7 +80,7 @@ - + @@ -93,16 +93,16 @@
    - +
    - +
    - - + +
    diff --git a/app/views/configure/reading.phtml b/app/views/configure/reading.phtml index 8b2da2a28..7e4efc264 100644 --- a/app/views/configure/reading.phtml +++ b/app/views/configure/reading.phtml @@ -1,13 +1,13 @@ partial ('aside_configure'); ?>
    - +
    - +
    - +
    @@ -15,22 +15,22 @@
    - +
    - +
    @@ -50,7 +50,7 @@
    @@ -59,8 +59,8 @@
    @@ -69,8 +69,8 @@
    @@ -79,8 +79,8 @@
    @@ -89,8 +89,8 @@
    @@ -99,8 +99,8 @@
    @@ -109,48 +109,48 @@
    - +
    - +
    - - + +
    diff --git a/app/views/configure/sharing.phtml b/app/views/configure/sharing.phtml index 02ce331da..ee276a94e 100644 --- a/app/views/configure/sharing.phtml +++ b/app/views/configure/sharing.phtml @@ -1,7 +1,7 @@ partial ('aside_configure'); ?>
    - + @@ -9,28 +9,28 @@ data-advanced='
    - - + +
    - +
    '> - + conf->sharing as $key => $sharing): ?> conf->shares[$sharing['type']]; ?>
    ' />
    - - + +
    - + @@ -42,7 +42,7 @@
    @@ -51,8 +51,8 @@
    - - + +
    diff --git a/app/views/configure/users.phtml b/app/views/configure/users.phtml index 272896fb2..04e662fa3 100644 --- a/app/views/configure/users.phtml +++ b/app/views/configure/users.phtml @@ -1,36 +1,36 @@ partial('aside_configure'); ?>
    - +
    - +
    - +
    - +
    />
    - +
    - +
    /> @@ -41,36 +41,36 @@
    - + conf->mail_login; ?>
    placeholder="alice@example.net" /> - +
    - - + +
    - +
    - +
    @@ -80,7 +80,7 @@
    @@ -90,7 +90,7 @@
    @@ -100,7 +100,7 @@
    @@ -108,12 +108,12 @@
    - + conf->token; ?>
    - /> - +
    @@ -123,24 +123,24 @@
    - - + +
    - +
    - +
    conf->availableLanguages (); ?> @@ -173,25 +173,25 @@
    - +
    - +
    - +
    - + conf->mail_login; ?>
    @@ -200,8 +200,8 @@
    - - + +
    diff --git a/app/views/error/index.phtml b/app/views/error/index.phtml index ef4fbd39d..5e1949800 100644 --- a/app/views/error/index.phtml +++ b/app/views/error/index.phtml @@ -3,7 +3,7 @@

    code; ?>

    errorMessage; ?>
    - +

    diff --git a/app/views/feed/add.phtml b/app/views/feed/add.phtml index 849dacac6..17e52a571 100644 --- a/app/views/feed/add.phtml +++ b/app/views/feed/add.phtml @@ -1,16 +1,16 @@ feed) { ?>
    -

    +

    load_ok) { ?> -

    +

    - + load_ok) { ?>
    - +
    @@ -18,7 +18,7 @@ feed->description(); if ($desc != '') { ?>
    - +
    @@ -26,7 +26,7 @@
    - +
    feed->website(); ?> @@ -35,17 +35,17 @@
    - +
    - +
    - +
    - +
    - + feed->httpAuth(false); ?>
    - +
    - +
    - +
    - - + +
    diff --git a/app/views/helpers/feed/update.phtml b/app/views/helpers/feed/update.phtml index 678c5f132..8bd645d11 100644 --- a/app/views/helpers/feed/update.phtml +++ b/app/views/helpers/feed/update.phtml @@ -12,27 +12,27 @@ feed->nbEntries (); ?> feed->inError ()) { ?> -

    +

    -

    +

    - +
    - +
    - +
    - +
    @@ -41,18 +41,18 @@
    - +
    - +
    - +
    feed->priority () > 0 ? ' checked="checked"' : ''; ?> /> - +
    @@ -83,7 +83,7 @@
    - +
    @@ -96,21 +96,21 @@
    - +
    - +
    - +
    - +
    @@ -150,24 +150,24 @@
    - - + +
    - +
    - +
    - - + +
    - - + +
    diff --git a/app/views/helpers/javascript_vars.phtml b/app/views/helpers/javascript_vars.phtml index 4f7e3db0c..ba02b9fad 100644 --- a/app/views/helpers/javascript_vars.phtml +++ b/app/views/helpers/javascript_vars.phtml @@ -52,10 +52,10 @@ echo 'authType="', $authType, '",', 'url_login="', _url ('index', 'login'), '",', 'url_logout="', _url ('index', 'logout'), '",'; -echo 'str_confirmation_default="', Minz_Translate::t('confirm_action'), '"', ",\n"; -echo 'str_notif_title_articles="', Minz_Translate::t('notif_title_new_articles'), '"', ",\n"; -echo 'str_notif_body_articles="', Minz_Translate::t('notif_body_new_articles'), '"', ",\n"; -echo 'str_category_empty="', Minz_Translate::t('category_empty'), '"', ",\n"; +echo 'str_confirmation_default="', _t('confirm_action'), '"', ",\n"; +echo 'str_notif_title_articles="', _t('notif_title_new_articles'), '"', ",\n"; +echo 'str_notif_body_articles="', _t('notif_body_new_articles'), '"', ",\n"; +echo 'str_category_empty="', _t('category_empty'), '"', ",\n"; echo 'html5_notif_timeout=', $this->conf->html5_notif_timeout,",\n"; diff --git a/app/views/helpers/logs_pagination.phtml b/app/views/helpers/logs_pagination.phtml index e3d14810e..191cfa8de 100755 --- a/app/views/helpers/logs_pagination.phtml +++ b/app/views/helpers/logs_pagination.phtml @@ -9,14 +9,14 @@
  • currentPage > 1) { ?> - « + «
  • currentPage - 1; ?>
  • currentPage > 1) { ?> - +
  • @@ -34,13 +34,13 @@ currentPage + 1; ?>
  • currentPage < $this->nbPage) { ?> - +
  • nbPage; ?>
  • currentPage < $this->nbPage) { ?> - » + »
  • diff --git a/app/views/helpers/view/normal_view.phtml b/app/views/helpers/view/normal_view.phtml index e469edf58..ee745144f 100644 --- a/app/views/helpers/view/normal_view.phtml +++ b/app/views/helpers/view/normal_view.phtml @@ -30,12 +30,12 @@ if (!empty($this->entries)) {
    - +
    entries as $item) { if ($display_today && $item->isDay (FreshRSS_Days::TODAY, $this->today)) { ?>
    currentName; ?>
    entries)) { } if ($display_yesterday && $item->isDay (FreshRSS_Days::YESTERDAY, $this->today)) { ?>
    currentName; ?>
    entries)) { } if ($display_others && $item->isDay (FreshRSS_Days::BEFORE_YESTERDAY, $this->today)) { ?>
    currentName; ?>
    entries)) {

    title (); ?>

    author(); - echo $author != '' ? '
    ' . Minz_Translate::t('by_author', $author) . '
    ' : '', + echo $author != '' ? '
    ' . _t('by_author', $author) . '
    ' : '', $lazyload && $hidePosts ? lazyimg($item->content()) : $item->content(); ?>
    @@ -133,7 +133,7 @@ if (!empty($this->entries)) { - +
    diff --git a/lib/lib_rss.php b/lib/lib_rss.php index 31c9cdbc1..4f6beb9fd 100644 --- a/lib/lib_rss.php +++ b/lib/lib_rss.php @@ -77,11 +77,11 @@ function formatBytes($bytes, $precision = 2, $system = 'IEC') { } function timestamptodate ($t, $hour = true) { - $month = Minz_Translate::t (date('M', $t)); + $month = _t(date('M', $t)); if ($hour) { - $date = Minz_Translate::t ('format_date_hour', $month); + $date = _t('format_date_hour', $month); } else { - $date = Minz_Translate::t ('format_date', $month); + $date = _t('format_date', $month); } return @date ($date, $t); @@ -107,7 +107,7 @@ function html_only_entity_decode($text) { function customSimplePie() { $simplePie = new SimplePie(); - $simplePie->set_useragent(Minz_Translate::t('freshrss') . '/' . FRESHRSS_VERSION . ' (' . PHP_OS . '; ' . FRESHRSS_WEBSITE . ') ' . SIMPLEPIE_NAME . '/' . SIMPLEPIE_VERSION); + $simplePie->set_useragent(_t('freshrss') . '/' . FRESHRSS_VERSION . ' (' . PHP_OS . '; ' . FRESHRSS_WEBSITE . ') ' . SIMPLEPIE_NAME . '/' . SIMPLEPIE_VERSION); $simplePie->set_cache_location(CACHE_PATH); $simplePie->set_cache_duration(800); $simplePie->strip_htmltags(array( -- cgit v1.2.3 From 70131f776a5fa30fdf26c64578039aeeb41333c7 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sun, 5 Oct 2014 16:53:43 +0200 Subject: SimplePie enclosure bug workaround https://github.com/marienfressinaud/FreshRSS/issues/504 --- app/Models/Feed.php | 2 ++ 1 file changed, 2 insertions(+) (limited to 'app/Models') diff --git a/app/Models/Feed.php b/app/Models/Feed.php index 2a5ea45ac..03baf3ad2 100644 --- a/app/Models/Feed.php +++ b/app/Models/Feed.php @@ -288,6 +288,8 @@ class FreshRSS_Feed extends Minz_Model { $content .= '
    - +

    diff --git a/app/views/users/index.phtml b/app/views/users/index.phtml index 95659f727..f1cdf01a3 100644 --- a/app/views/users/index.phtml +++ b/app/views/users/index.phtml @@ -11,7 +11,7 @@
    @@ -44,7 +44,7 @@ conf->mail_login; ?>
    - placeholder="alice@example.net" /> + placeholder="alice@example.net" />
    @@ -56,7 +56,7 @@
    - + diff --git a/lib/Minz/Configuration.php b/lib/Minz/Configuration.php index 4e9da58b4..554bc8c96 100644 --- a/lib/Minz/Configuration.php +++ b/lib/Minz/Configuration.php @@ -100,9 +100,6 @@ class Minz_Configuration { public static function defaultUser () { return self::$default_user; } - public static function isAdmin($currentUser) { - return $currentUser === self::$default_user; - } public static function allowAnonymous() { return self::$allow_anonymous; } -- cgit v1.2.3 From 1252b3dd867e59917cf303f0c39c7da938b8ce32 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Tue, 7 Oct 2014 16:37:10 +0200 Subject: Authentication system moved + Persona comes back! AuthController is dedicated to auhentication. Persona is back, greater than ever! See https://github.com/marienfressinaud/FreshRSS/issues/655 --- app/Controllers/authController.php | 182 ++++++++++++++++++++++++++++++++ app/Controllers/indexController.php | 90 +--------------- app/FreshRSS.php | 8 ++ app/Models/Auth.php | 21 +++- app/layout/header.phtml | 23 ++-- app/views/auth/formLogin.phtml | 28 +++++ app/views/auth/logout.phtml | 0 app/views/auth/personaLogin.phtml | 24 +++++ app/views/helpers/javascript_vars.phtml | 13 ++- app/views/index/formLogin.phtml | 46 -------- p/scripts/main.js | 65 ------------ p/scripts/persona.js | 76 +++++++++++++ 12 files changed, 356 insertions(+), 220 deletions(-) create mode 100644 app/Controllers/authController.php create mode 100644 app/views/auth/formLogin.phtml create mode 100644 app/views/auth/logout.phtml create mode 100644 app/views/auth/personaLogin.phtml delete mode 100644 app/views/index/formLogin.phtml create mode 100644 p/scripts/persona.js (limited to 'app/Models') diff --git a/app/Controllers/authController.php b/app/Controllers/authController.php new file mode 100644 index 000000000..2b67e34b8 --- /dev/null +++ b/app/Controllers/authController.php @@ -0,0 +1,182 @@ + 'index', 'a' => 'index'), true); + } + + $auth_type = Minz_Configuration::authType(); + switch ($auth_type) { + case 'form': + Minz_Request::forward(array('c' => 'auth', 'a' => 'formLogin')); + break; + case 'persona': + Minz_Request::forward(array('c' => 'auth', 'a' => 'personaLogin')); + break; + case 'http_auth': + case 'none': + // It should not happened! + Minz_Error::error(404); + default: + // TODO load plugin instead + Minz_Error::error(404); + } + } + + /** + * This action handles form login page. + * + * If this action is reached through a POST request, username and password + * are compared to login the current user. + * + * Parameters are: + * - nonce (default: false) + * - username (default: '') + * - challenge (default: '') + * - keep_logged_in (default: false) + */ + public function formLoginAction() { + invalidateHttpCache(); + + $file_mtime = @filemtime(PUBLIC_PATH . '/scripts/bcrypt.min.js'); + Minz_View::appendScript(Minz_Url::display('/scripts/bcrypt.min.js?' . $file_mtime)); + + if (Minz_Request::isPost()) { + $nonce = Minz_Session::param('nonce'); + $username = Minz_Request::param('username', ''); + $challenge = Minz_Request::param('challenge', ''); + try { + $conf = new FreshRSS_Configuration($username); + } catch(Minz_Exception $e) { + // $username is not a valid user, nor the configuration file! + Minz_Log::warning('Login failure: ' . $e->getMessage()); + Minz_Request::bad(_t('invalid_login'), + array('c' => 'auth', 'a' => 'login')); + } + + $ok = FreshRSS_FormAuth::checkCredentials( + $username, $conf->passwordHash, $nonce, $challenge + ); + if ($ok) { + // Set session parameter to give access to the user. + Minz_Session::_param('currentUser', $username); + Minz_Session::_param('passwordHash', $conf->passwordHash); + FreshRSS_Auth::giveAccess(); + + // Set cookie parameter if nedded. + if (Minz_Request::param('keep_logged_in')) { + FreshRSS_FormAuth::makeCookie($username, $conf->passwordHash); + } else { + FreshRSS_FormAuth::deleteCookie(); + } + + // All is good, go back to the index. + Minz_Request::good(_t('login'), + array('c' => 'index', 'a' => 'index')); + } else { + Minz_Log::warning('Password mismatch for' . + ' user=' . $username . + ', nonce=' . $nonce . + ', c=' . $challenge); + Minz_Request::bad(_t('invalid_login'), + array('c' => 'auth', 'a' => 'login')); + } + } + } + + /** + * This action handles Persona login page. + * + * If this action is reached through a POST request, assertion from Persona + * is verificated and user connected if all is ok. + * + * Parameter is: + * - assertion (default: false) + * + * @todo: Persona system should be moved to a plugin + */ + public function personaLoginAction() { + $this->view->res = false; + + if (Minz_Request::isPost()) { + $this->view->_useLayout(false); + + $assert = Minz_Request::param('assertion'); + $url = 'https://verifier.login.persona.org/verify'; + $params = 'assertion=' . $assert . '&audience=' . + urlencode(Minz_Url::display(null, 'php', true)); + $ch = curl_init(); + $options = array( + CURLOPT_URL => $url, + CURLOPT_RETURNTRANSFER => TRUE, + CURLOPT_POST => 2, + CURLOPT_POSTFIELDS => $params + ); + curl_setopt_array($ch, $options); + $result = curl_exec($ch); + curl_close($ch); + + $res = json_decode($result, true); + + $login_ok = false; + $reason = ''; + if ($res['status'] === 'okay') { + $email = filter_var($res['email'], FILTER_VALIDATE_EMAIL); + if ($email != '') { + $persona_file = DATA_PATH . '/persona/' . $email . '.txt'; + if (($current_user = @file_get_contents($persona_file)) !== false) { + $current_user = trim($current_user); + try { + $conf = new FreshRSS_Configuration($current_user); + $login_ok = strcasecmp($email, $conf->mail_login) === 0; + } catch (Minz_Exception $e) { + //Permission denied or conf file does not exist + $reason = 'Invalid configuration for user ' . + '[' . $current_user . '] ' . $e->getMessage(); + } + } + } else { + $reason = 'Invalid email format [' . $res['email'] . ']'; + } + } else { + $reason = $res['reason']; + } + + if ($login_ok) { + Minz_Session::_param('currentUser', $current_user); + Minz_Session::_param('mail', $email); + FreshRSS_Auth::giveAccess(); + invalidateHttpCache(); + } else { + Minz_Log::error($reason); + + $res = array(); + $res['status'] = 'failure'; + $res['reason'] = _t('invalid_login'); + } + + header('Content-Type: application/json; charset=UTF-8'); + $this->view->res = $res; + } + } + + /** + * This action removes all accesses of the current user. + */ + public function logoutAction() { + invalidateHttpCache(); + FreshRSS_Auth::removeAccess(); + Minz_Request::good(_t('disconnected'), + array('c' => 'index', 'a' => 'index')); + } +} diff --git a/app/Controllers/indexController.php b/app/Controllers/indexController.php index 3006480f9..5b490e672 100755 --- a/app/Controllers/indexController.php +++ b/app/Controllers/indexController.php @@ -20,7 +20,7 @@ class FreshRSS_index_Controller extends Minz_ActionController { } 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' => 'login')); + Minz_Request::forward(array('c' => 'auth', 'a' => 'login')); return; } } @@ -228,92 +228,4 @@ class FreshRSS_index_Controller extends Minz_ActionController { $this->view->logsPaginator->_nbItemsPerPage(50); $this->view->logsPaginator->_currentPage($page); } - - /** - * This action handles the login page. - */ - public function loginAction() { - if (FreshRSS_Auth::hasAccess()) { - Minz_Request::forward(array('c' => 'index', 'a' => 'index'), true); - } - - invalidateHttpCache(); - - $auth_type = Minz_Configuration::authType(); - switch ($auth_type) { - case 'form': - Minz_Request::forward(array('c' => 'index', 'a' => 'formLogin')); - break; - case 'http_auth': - case 'none': - // It should not happened! - Minz_Error::error(404); - default: - // TODO load plugin instead - Minz_Error::error(404); - } - } - - /** - * - */ - public function formLoginAction() { - if (FreshRSS_Auth::hasAccess()) { - Minz_Request::forward(array('c' => 'index', 'a' => 'index'), true); - } - - invalidateHttpCache(); - - $file_mtime = @filemtime(PUBLIC_PATH . '/scripts/bcrypt.min.js'); - Minz_View::appendScript(Minz_Url::display('/scripts/bcrypt.min.js?' . $file_mtime)); - - if (Minz_Request::isPost()) { - $nonce = Minz_Session::param('nonce'); - $username = Minz_Request::param('username', ''); - $challenge = Minz_Request::param('challenge', ''); - try { - $conf = new FreshRSS_Configuration($username); - } catch(Minz_Exception $e) { - // $username is not a valid user, nor the configuration file! - Minz_Log::warning('Login failure: ' . $e->getMessage()); - Minz_Request::bad(_t('invalid_login'), - array('c' => 'index', 'a' => 'login')); - } - - $ok = FreshRSS_FormAuth::checkCredentials( - $username, $conf->passwordHash, $nonce, $challenge - ); - if ($ok) { - // Set session parameter to give access to the user. - Minz_Session::_param('currentUser', $username); - Minz_Session::_param('passwordHash', $conf->passwordHash); - FreshRSS_Auth::giveAccess(); - - // Set cookie parameter if nedded. - if (Minz_Request::param('keep_logged_in', false)) { - FreshRSS_FormAuth::makeCookie($username, $conf->passwordHash); - } else { - FreshRSS_FormAuth::deleteCookie(); - } - - // All is good, go back to the index. - Minz_Request::good(_t('login'), - array('c' => 'index', 'a' => 'index')); - } else { - Minz_Log::warning('Password mismatch for' . - ' user=' . $username . - ', nonce=' . $nonce . - ', c=' . $challenge); - Minz_Request::bad(_t('invalid_login'), - array('c' => 'index', 'a' => 'login')); - } - } - } - - public function logoutAction() { - invalidateHttpCache(); - FreshRSS_Auth::removeAccess(); - Minz_Request::good(_t('disconnected'), - array('c' => 'index', 'a' => 'index')); - } } diff --git a/app/FreshRSS.php b/app/FreshRSS.php index 35a37b887..6b7a813bf 100644 --- a/app/FreshRSS.php +++ b/app/FreshRSS.php @@ -64,6 +64,14 @@ class FreshRSS extends Minz_FrontController { Minz_View::appendScript(Minz_Url::display('/scripts/jquery.min.js?' . @filemtime(PUBLIC_PATH . '/scripts/jquery.min.js'))); Minz_View::appendScript(Minz_Url::display('/scripts/shortcut.js?' . @filemtime(PUBLIC_PATH . '/scripts/shortcut.js'))); Minz_View::appendScript(Minz_Url::display('/scripts/main.js?' . @filemtime(PUBLIC_PATH . '/scripts/main.js'))); + + if (Minz_Configuration::authType() === 'persona') { + // TODO move it in a plugin + // Needed for login AND logout with Persona. + Minz_View::appendScript('https://login.persona.org/include.js'); + $file_mtime = @filemtime(PUBLIC_PATH . '/scripts/persona.js'); + Minz_View::appendScript(Minz_Url::display('/scripts/persona.js?' . $file_mtime)); + } } private function loadNotifications() { diff --git a/app/Models/Auth.php b/app/Models/Auth.php index 992b444a5..cc23d7974 100644 --- a/app/Models/Auth.php +++ b/app/Models/Auth.php @@ -20,7 +20,7 @@ class FreshRSS_Auth { Minz_Session::_param('currentUser', $current_user); } - $access_ok = self::accessControl($current_user); + $access_ok = self::accessControl(); if ($access_ok) { self::giveAccess(); @@ -36,10 +36,9 @@ class FreshRSS_Auth { * Required session parameters are also set in this method (such as * currentUser). * - * @param string $username username of the user to check access. * @return boolean true if user can be connected, false else. */ - public static function accessControl($username) { + public static function accessControl() { if (self::$login_ok) { return true; } @@ -61,6 +60,16 @@ class FreshRSS_Auth { Minz_Session::_param('currentUser', $current_user); } return $login_ok; + case 'persona': + $email = filter_var(Minz_Session::param('mail'), FILTER_VALIDATE_EMAIL); + $persona_file = DATA_PATH . '/persona/' . $email . '.txt'; + if (($current_user = @file_get_contents($persona_file)) !== false) { + $current_user = trim($current_user); + Minz_Session::_param('currentUser', $current_user); + Minz_Session::_param('mail', $email); + return true; + } + return false; case 'none': return true; default: @@ -87,6 +96,9 @@ class FreshRSS_Auth { case 'http_auth': self::$login_ok = strcasecmp($current_user, httpAuthUser()) === 0; break; + case 'persona': + self::$login_ok = strcasecmp(Minz_Session::param('mail'), $conf->mail_login) === 0; + break; case 'none': self::$login_ok = true; break; @@ -131,6 +143,9 @@ class FreshRSS_Auth { Minz_Session::_param('passwordHash'); FreshRSS_FormAuth::deleteCookie(); break; + case 'persona': + Minz_Session::_param('mail'); + break; case 'http_auth': case 'none': // Nothing to do... diff --git a/app/layout/header.phtml b/app/layout/header.phtml index 12c86d61d..deb21edc9 100644 --- a/app/layout/header.phtml +++ b/app/layout/header.phtml @@ -2,9 +2,9 @@ if (Minz_Configuration::canLogIn()) { ?>
  • -
  • -
    + +
    + +
    +
    diff --git a/app/views/auth/formLogin.phtml b/app/views/auth/formLogin.phtml new file mode 100644 index 000000000..0194a11a5 --- /dev/null +++ b/app/views/auth/formLogin.phtml @@ -0,0 +1,28 @@ +
    +

    + +
    +
    + + +
    +
    + + +
    + +
    +
    + +
    +
    +
    + +
    + + +

    +
    diff --git a/app/views/auth/logout.phtml b/app/views/auth/logout.phtml new file mode 100644 index 000000000..e69de29bb diff --git a/app/views/auth/personaLogin.phtml b/app/views/auth/personaLogin.phtml new file mode 100644 index 000000000..d62fe5818 --- /dev/null +++ b/app/views/auth/personaLogin.phtml @@ -0,0 +1,24 @@ +res === false) { ?> +
    +

    + +

    + + +

    + + + + + +

    + +

    +
    +res); +} +?> diff --git a/app/views/helpers/javascript_vars.phtml b/app/views/helpers/javascript_vars.phtml index 8f615ed87..3bbcc3848 100644 --- a/app/views/helpers/javascript_vars.phtml +++ b/app/views/helpers/javascript_vars.phtml @@ -8,6 +8,15 @@ $hide_posts = ($this->conf->display_posts || Minz_Request::param('output') === 'reader'); $s = $this->conf->shortcuts; +$url_login = Minz_Url::display(array( + 'c' => 'auth', + 'a' => 'login' +), 'php'); +$url_logout = Minz_Url::display(array( + 'c' => 'auth', + 'a' => 'logout' +), 'php'); + echo 'var context={', 'hide_posts:', $hide_posts ? 'false' : 'true', ',', 'display_order:"', Minz_Request::param('order', $this->conf->sort_order), '",', @@ -43,8 +52,8 @@ echo 'shortcuts={', echo 'url={', 'index:"', _url('index', 'index'), '",', - 'login:"', _url('index', 'login'), '",', - 'logout:"', _url('index', 'logout'), '",', + 'login:"', $url_login, '",', + 'logout:"', $url_logout, '",', 'help:"', FRESHRSS_WIKI, '"', "},\n"; diff --git a/app/views/index/formLogin.phtml b/app/views/index/formLogin.phtml deleted file mode 100644 index b05cdced4..000000000 --- a/app/views/index/formLogin.phtml +++ /dev/null @@ -1,46 +0,0 @@ -
    -

    -
    - - -
    -
    - - -
    - -
    -
    - -
    -
    -
    - -
    -

    -

    - - - - - -

    - -

    -
    diff --git a/p/scripts/main.js b/p/scripts/main.js index b01a3a34d..77e1e3f77 100644 --- a/p/scripts/main.js +++ b/p/scripts/main.js @@ -1034,67 +1034,7 @@ function init_crypto_form() { } // -// -function init_persona() { - if (!(navigator.id)) { - if (window.console) { - console.log('FreshRSS waiting for Persona…'); - } - window.setTimeout(init_persona, 100); - return; - } - $('a.signin').click(function() { - navigator.id.request(); - return false; - }); - - $('a.signout').click(function() { - navigator.id.logout(); - return false; - }); - navigator.id.watch({ - loggedInUser: context['current_user_mail'], - - onlogin: function(assertion) { - // A user has logged in! Here you need to: - // 1. Send the assertion to your backend for verification and to create a session. - // 2. Update your UI. - $.ajax ({ - type: 'POST', - url: url['login'], - data: {assertion: assertion}, - success: function(res, status, xhr) { - /*if (res.status === 'failure') { - alert (res_obj.reason); - } else*/ if (res.status === 'okay') { - location.href = url['index']; - } - }, - error: function(res, status, xhr) { - alert("Login failure: " + res); - } - }); - }, - onlogout: function() { - // A user has logged out! Here you need to: - // Tear down the user's session by redirecting the user or making a call to your backend. - // Also, make sure loggedInUser will get set to null on the next page load. - // (That's a literal JavaScript null. Not false, 0, or undefined. null.) - $.ajax ({ - type: 'POST', - url: url['logout'], - success: function(res, status, xhr) { - location.href = url['index']; - }, - error: function(res, status, xhr) { - //alert("logout failure" + res); - } - }); - } - }); -} -// function init_confirm_action() { $('body').on('click', '.confirm', function () { @@ -1274,11 +1214,6 @@ function init_all() { return; } init_notifications(); - switch (context['auth_type']) { - case 'persona': - init_persona(); - break; - } init_confirm_action(); $stream = $('#stream'); if ($stream.length > 0) { diff --git a/p/scripts/persona.js b/p/scripts/persona.js new file mode 100644 index 000000000..36aeeaf56 --- /dev/null +++ b/p/scripts/persona.js @@ -0,0 +1,76 @@ +"use strict"; + +function init_persona() { + if (!(navigator.id && window.$)) { + if (window.console) { + console.log('FreshRSS (Persona) waiting for JS…'); + } + window.setTimeout(init_persona, 100); + return; + } + + $('a.signin').click(function() { + navigator.id.request(); + return false; + }); + + $('a.signout').click(function() { + navigator.id.logout(); + return false; + }); + + navigator.id.watch({ + loggedInUser: context['current_user_mail'], + + onlogin: function(assertion) { + // A user has logged in! Here you need to: + // 1. Send the assertion to your backend for verification and to create a session. + // 2. Update your UI. + $.ajax ({ + type: 'POST', + url: url['login'], + data: {assertion: assertion}, + success: function(res, status, xhr) { + if (res.status === 'failure') { + openNotification(res.reason, 'bad'); + } else if (res.status === 'okay') { + location.href = url['index']; + } + }, + error: function(res, status, xhr) { + // alert(res); + } + }); + }, + onlogout: function() { + // A user has logged out! Here you need to: + // Tear down the user's session by redirecting the user or making a call to your backend. + // Also, make sure loggedInUser will get set to null on the next page load. + // (That's a literal JavaScript null. Not false, 0, or undefined. null.) + $.ajax ({ + type: 'POST', + url: url['logout'], + success: function(res, status, xhr) { + location.href = url['index']; + }, + error: function(res, status, xhr) { + // alert(res); + } + }); + } + }); +} + +if (document.readyState && document.readyState !== 'loading') { + if (window.console) { + console.log('FreshRSS (Persona) immediate init…'); + } + init_persona(); +} else if (document.addEventListener) { + document.addEventListener('DOMContentLoaded', function () { + if (window.console) { + console.log('FreshRSS (Persona) waiting for DOMContentLoaded…'); + } + init_persona(); + }, false); +} -- cgit v1.2.3 From eb40dbccdb1e0830fcad96d333b242870cc0d0a7 Mon Sep 17 00:00:00 2001 From: Alexis Degrugillier Date: Thu, 9 Oct 2014 21:44:44 -0400 Subject: Change statistic average I was using the stats and it feels that the stat average was useless in that form since the line is always at the same position no matter what is the value. So I deleted that line and added the average in the title. It is way more useful this way. I updated some translations both on i18n files and on http://i18n.freshrss.org --- app/Models/StatsDAO.php | 2 +- app/i18n/en.php | 6 +++--- app/i18n/fr.php | 6 +++--- app/views/stats/repartition.phtml | 36 +++--------------------------------- 4 files changed, 10 insertions(+), 40 deletions(-) (limited to 'app/Models') diff --git a/app/Models/StatsDAO.php b/app/Models/StatsDAO.php index 99d4e2148..283d5dcb1 100644 --- a/app/Models/StatsDAO.php +++ b/app/Models/StatsDAO.php @@ -237,7 +237,7 @@ SQL; $interval_in_days = $period; } - return round($res['count'] / ($interval_in_days / $period), 2); + return $res['count'] / ($interval_in_days / $period); } /** diff --git a/app/i18n/en.php b/app/i18n/en.php index 9e968998a..ebc25ba0c 100644 --- a/app/i18n/en.php +++ b/app/i18n/en.php @@ -398,9 +398,9 @@ 'stats_entry_count' => 'Entry count', 'stats_entry_per_category' => 'Entries per category', 'stats_entry_per_day' => 'Entries per day (last 30 days)', - 'stats_entry_per_day_of_week' => 'Per day of week', - 'stats_entry_per_hour' => 'Per hour', - 'stats_entry_per_month' => 'Per month', + 'stats_entry_per_day_of_week' => 'Per day of week (average: %.2f messages)', + 'stats_entry_per_hour' => 'Per hour (average: %.2f messages)', + 'stats_entry_per_month' => 'Per month (average: %.2f messages)', 'stats_entry_repartition' => 'Entries repartition', 'stats_feed_per_category' => 'Feeds per category', 'stats_idle' => 'Idle feeds', diff --git a/app/i18n/fr.php b/app/i18n/fr.php index 072094026..220f8b12d 100644 --- a/app/i18n/fr.php +++ b/app/i18n/fr.php @@ -398,9 +398,9 @@ 'stats_entry_count' => 'Nombre d’articles', 'stats_entry_per_category' => 'Articles par catégorie', 'stats_entry_per_day' => 'Nombre d’articles par jour (30 derniers jours)', - 'stats_entry_per_day_of_week' => 'Par jour de la semaine', - 'stats_entry_per_hour' => 'Par heure', - 'stats_entry_per_month' => 'Par mois', + 'stats_entry_per_day_of_week' => 'Par jour de la semaine (moyenne : %.2f messages)', + 'stats_entry_per_hour' => 'Par heure (moyenne : %.2f messages)', + 'stats_entry_per_month' => 'Par mois (moyenne : %.2f messages)', 'stats_entry_repartition' => 'Répartition des articles', 'stats_feed_per_category' => 'Flux par catégorie', 'stats_idle' => 'Flux inactifs', diff --git a/app/views/stats/repartition.phtml b/app/views/stats/repartition.phtml index a181ae251..670714707 100644 --- a/app/views/stats/repartition.phtml +++ b/app/views/stats/repartition.phtml @@ -30,17 +30,17 @@
    -

    +

    averageHour); ?>

    -

    +

    averageDayOfWeek); ?>

    -

    +

    averageMonth); ?>

    @@ -56,19 +56,10 @@ function initStats() { return; } // Entry per hour - var avg_h = []; - for (var i = -1; i <= 24; i++) { - avg_h.push([i, averageHour?>]); - } Flotr.draw(document.getElementById('statsEntryPerHour'), [{ data: repartitionHour ?>, bars: {horizontal: false, show: true} - }, { - data: avg_h, - lines: {show: true}, - label: "averageHour?>", - yaxis: 2 }], { grid: {verticalLines: false}, @@ -81,23 +72,13 @@ function initStats() { max: 23.9, tickDecimals: 0}, yaxis: {min: 0}, - y2axis: {showLabels: false}, mouse: {relative: true, track: true, trackDecimals: 0, trackFormatter: function(obj) {return numberFormat(obj.y);}} }); // Entry per day of week - var avg_dow = []; - for (var i = -1; i <= 7; i++) { - avg_dow.push([i, averageDayOfWeek?>]); - } Flotr.draw(document.getElementById('statsEntryPerDayOfWeek'), [{ data: repartitionDayOfWeek ?>, bars: {horizontal: false, show: true} - }, { - data: avg_dow, - lines: {show: true}, - label: "averageDayOfWeek?>", - yaxis: 2 }], { grid: {verticalLines: false}, @@ -111,23 +92,13 @@ function initStats() { max: 6.9, tickDecimals: 0}, yaxis: {min: 0}, - y2axis: {showLabels: false}, mouse: {relative: true, track: true, trackDecimals: 0, trackFormatter: function(obj) {return numberFormat(obj.y);}} }); // Entry per month - var avg_m = []; - for (var i = 0; i <= 13; i++) { - avg_m.push([i, averageMonth?>]); - } Flotr.draw(document.getElementById('statsEntryPerMonth'), [{ data: repartitionMonth ?>, bars: {horizontal: false, show: true} - }, { - data: avg_m, - lines: {show: true}, - label: "averageMonth?>", - yaxis: 2 }], { grid: {verticalLines: false}, @@ -141,7 +112,6 @@ function initStats() { max: 12.9, tickDecimals: 0}, yaxis: {min: 0}, - y2axis: {showLabels: false}, mouse: {relative: true, track: true, trackDecimals: 0, trackFormatter: function(obj) {return numberFormat(obj.y);}} }); -- cgit v1.2.3 From d4ad951b9b686f387056bda8f3fa6ede8d9ca3f1 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Thu, 16 Oct 2014 17:08:48 +0200 Subject: Show more information about user when selected --- app/Controllers/userController.php | 19 ++++++++++++++++--- app/Models/Factory.php | 18 +++++++++--------- app/Models/UserDAO.php | 4 ++++ app/views/configure/archiving.phtml | 2 +- app/views/user/manage.phtml | 2 ++ 5 files changed, 32 insertions(+), 13 deletions(-) (limited to 'app/Models') diff --git a/app/Controllers/userController.php b/app/Controllers/userController.php index 00b51cc3d..4a04737f2 100644 --- a/app/Controllers/userController.php +++ b/app/Controllers/userController.php @@ -87,11 +87,24 @@ class FreshRSS_user_Controller extends Minz_ActionController { * This action displays the user management page. */ public function manageAction() { + if (!FreshRSS_Auth::hasAccess('admin')) { + Minz_Error::error(403, + array('error' => array(_t('access_denied')))); + } + Minz_View::prependTitle(_t('users.manage') . ' · '); - $this->view->current_user = Minz_Request::param( - 'u', Minz_Session::param('currentUser', '_') - ); + $userDAO = new FreshRSS_UserDAO(); + + $username = Minz_Request::param('u', Minz_Session::param('currentUser')); + if (!$userDAO->exist($username)) { + $username = Minz_Session::param('currentUser'); + } + $this->view->current_user = $username; + + $entryDAO = FreshRSS_Factory::createEntryDao($this->view->current_user); + $this->view->nb_articles = $entryDAO->count(); + $this->view->size_user = $entryDAO->size(); } public function createAction() { diff --git a/app/Models/Factory.php b/app/Models/Factory.php index 08569b2e2..93f4552f7 100644 --- a/app/Models/Factory.php +++ b/app/Models/Factory.php @@ -2,30 +2,30 @@ class FreshRSS_Factory { - public static function createFeedDao() { + public static function createFeedDao($username = null) { $db = Minz_Configuration::dataBase(); if ($db['type'] === 'sqlite') { - return new FreshRSS_FeedDAOSQLite(); + return new FreshRSS_FeedDAOSQLite($username); } else { - return new FreshRSS_FeedDAO(); + return new FreshRSS_FeedDAO($username); } } - public static function createEntryDao() { + public static function createEntryDao($username = null) { $db = Minz_Configuration::dataBase(); if ($db['type'] === 'sqlite') { - return new FreshRSS_EntryDAOSQLite(); + return new FreshRSS_EntryDAOSQLite($username); } else { - return new FreshRSS_EntryDAO(); + return new FreshRSS_EntryDAO($username); } } - public static function createStatsDAO() { + public static function createStatsDAO($username = null) { $db = Minz_Configuration::dataBase(); if ($db['type'] === 'sqlite') { - return new FreshRSS_StatsDAOSQLite(); + return new FreshRSS_StatsDAOSQLite($username); } else { - return new FreshRSS_StatsDAO(); + return new FreshRSS_StatsDAO($username); } } diff --git a/app/Models/UserDAO.php b/app/Models/UserDAO.php index 15215258c..85b45c4a7 100644 --- a/app/Models/UserDAO.php +++ b/app/Models/UserDAO.php @@ -53,4 +53,8 @@ class FreshRSS_UserDAO extends Minz_ModelPdo { } } } + + public function exist($username) { + return file_exists(DATA_PATH . '/' . $username . '_user.php'); + } } diff --git a/app/views/configure/archiving.phtml b/app/views/configure/archiving.phtml index adbfdb77e..8f424c126 100644 --- a/app/views/configure/archiving.phtml +++ b/app/views/configure/archiving.phtml @@ -60,7 +60,7 @@

    -

    nb_total), ' ', _t('articles'), ', ', formatBytes($this->size_user); ?>

    +

    nb_total)), ' — ', formatBytes($this->size_user); ?>

    diff --git a/app/views/user/manage.phtml b/app/views/user/manage.phtml index fb569872b..65e60add5 100644 --- a/app/views/user/manage.phtml +++ b/app/views/user/manage.phtml @@ -63,6 +63,8 @@ + +

    nb_articles)), ', ', formatBytes($this->size_user); ?>

    -- cgit v1.2.3 From 5797344aff9ceebbdeb6e49305f3984a5c89f82c Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Thu, 16 Oct 2014 17:15:51 +0200 Subject: Fix a bug to get size of user (SQLite) --- app/Controllers/userController.php | 3 ++- app/Models/EntryDAOSQLite.php | 2 +- lib/Minz/ModelPdo.php | 2 ++ 3 files changed, 5 insertions(+), 2 deletions(-) (limited to 'app/Models') diff --git a/app/Controllers/userController.php b/app/Controllers/userController.php index 4a04737f2..d5c90a382 100644 --- a/app/Controllers/userController.php +++ b/app/Controllers/userController.php @@ -94,14 +94,15 @@ class FreshRSS_user_Controller extends Minz_ActionController { Minz_View::prependTitle(_t('users.manage') . ' · '); + // Get the correct current user. $userDAO = new FreshRSS_UserDAO(); - $username = Minz_Request::param('u', Minz_Session::param('currentUser')); if (!$userDAO->exist($username)) { $username = Minz_Session::param('currentUser'); } $this->view->current_user = $username; + // Get information about the current user. $entryDAO = FreshRSS_Factory::createEntryDao($this->view->current_user); $this->view->nb_articles = $entryDAO->count(); $this->view->size_user = $entryDAO->size(); diff --git a/app/Models/EntryDAOSQLite.php b/app/Models/EntryDAOSQLite.php index 66078aca9..4a3fe24a2 100644 --- a/app/Models/EntryDAOSQLite.php +++ b/app/Models/EntryDAOSQLite.php @@ -124,6 +124,6 @@ class FreshRSS_EntryDAOSQLite extends FreshRSS_EntryDAO { } public function size($all = false) { - return @filesize(DATA_PATH . '/' . Minz_Session::param('currentUser', '_') . '.sqlite'); + return @filesize(DATA_PATH . '/' . $this->current_user . '.sqlite'); } } diff --git a/lib/Minz/ModelPdo.php b/lib/Minz/ModelPdo.php index 66127ea22..827c89c69 100644 --- a/lib/Minz/ModelPdo.php +++ b/lib/Minz/ModelPdo.php @@ -24,6 +24,7 @@ class Minz_ModelPdo { */ protected $bd; + protected $current_user; protected $prefix; public function dbType() { @@ -46,6 +47,7 @@ class Minz_ModelPdo { if ($currentUser === null) { $currentUser = Minz_Session::param('currentUser', '_'); } + $this->current_user = $currentUser; try { $type = $db['type']; -- cgit v1.2.3 From 7080a32650ab8b19e917d8add944a75cc98381bc Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Mon, 20 Oct 2014 11:54:31 +0200 Subject: Add checking installation feature --- app/Controllers/updateController.php | 14 +++++- app/Models/DatabaseDAO.php | 83 ++++++++++++++++++++++++++++++++++++ app/Models/DatabaseDAOSQLite.php | 48 +++++++++++++++++++++ app/Models/Factory.php | 9 ++++ app/SQL/install.sql.mysql.php | 2 - app/SQL/install.sql.sqlite.php | 2 - app/layout/aside_configure.phtml | 7 ++- app/layout/header.phtml | 1 + app/views/update/checkInstall.phtml | 30 +++++++++++++ lib/lib_rss.php | 62 +++++++++++++++++++++++++++ 10 files changed, 252 insertions(+), 6 deletions(-) create mode 100644 app/Models/DatabaseDAO.php create mode 100644 app/Models/DatabaseDAOSQLite.php create mode 100644 app/views/update/checkInstall.phtml (limited to 'app/Models') diff --git a/app/Controllers/updateController.php b/app/Controllers/updateController.php index 9d1e1ddf5..4ebb11f51 100644 --- a/app/Controllers/updateController.php +++ b/app/Controllers/updateController.php @@ -12,7 +12,6 @@ class FreshRSS_update_Controller extends Minz_ActionController { invalidateHttpCache(); - Minz_View::prependTitle(_t('update_system') . ' · '); $this->view->update_to_apply = false; $this->view->last_update_time = 'unknown'; $this->view->check_last_hour = false; @@ -24,6 +23,8 @@ class FreshRSS_update_Controller extends Minz_ActionController { } public function indexAction() { + Minz_View::prependTitle(_t('update_system') . ' · '); + if (file_exists(UPDATE_FILENAME) && !is_writable(FRESHRSS_PATH)) { $this->view->message = array( 'status' => 'bad', @@ -126,4 +127,15 @@ class FreshRSS_update_Controller extends Minz_ActionController { } } } + + /** + * This action displays information about installation. + */ + public function checkInstallAction() { + Minz_View::prependTitle(_t('gen.title.check_install') . ' · '); + + $this->view->status_php = check_install_php(); + $this->view->status_files = check_install_files(); + $this->view->status_database = check_install_database(); + } } diff --git a/app/Models/DatabaseDAO.php b/app/Models/DatabaseDAO.php new file mode 100644 index 000000000..0d85718e3 --- /dev/null +++ b/app/Models/DatabaseDAO.php @@ -0,0 +1,83 @@ +bd->prepare($sql); + $stm->execute(); + $res = $stm->fetchAll(PDO::FETCH_ASSOC); + + $tables = array( + $this->prefix . 'category' => false, + $this->prefix . 'feed' => false, + $this->prefix . 'entry' => false, + ); + foreach ($res as $value) { + $tables[array_pop($value)] = true; + } + + return count(array_keys($tables, true, true)) == count($tables); + } + + public function getSchema($table) { + $sql = 'DESC ' . $this->prefix . $table; + $stm = $this->bd->prepare($sql); + $stm->execute(); + + return $this->listDaoToSchema($stm->fetchAll(PDO::FETCH_ASSOC)); + } + + public function checkTable($table, $schema) { + $columns = $this->getSchema($table); + + $ok = (count($columns) == count($schema)); + foreach ($columns as $c) { + $ok &= in_array($c['name'], $schema); + } + + return $ok; + } + + public function categoryIsCorrect() { + return $this->checkTable('category', array( + 'id', 'name' + )); + } + + public function feedIsCorrect() { + return $this->checkTable('feed', array( + 'id', 'url', 'category', 'name', 'website', 'description', 'lastUpdate', + 'priority', 'pathEntries', 'httpAuth', 'error', 'keep_history', 'ttl', + 'cache_nbEntries', 'cache_nbUnreads' + )); + } + + public function entryIsCorrect() { + return $this->checkTable('entry', array( + 'id', 'guid', 'title', 'author', 'content_bin', 'link', 'date', 'is_read', + 'is_favorite', 'id_feed', 'tags' + )); + } + + public function daoToSchema($dao) { + return array( + 'name' => $dao['Field'], + 'type' => strtolower($dao['Type']), + 'notnull' => (bool)$dao['Null'], + 'default' => $dao['Default'], + ); + } + + public function listDaoToSchema($listDAO) { + $list = array(); + + foreach ($listDAO as $dao) { + $list[] = $this->daoToSchema($dao); + } + + return $list; + } +} diff --git a/app/Models/DatabaseDAOSQLite.php b/app/Models/DatabaseDAOSQLite.php new file mode 100644 index 000000000..7f53f967d --- /dev/null +++ b/app/Models/DatabaseDAOSQLite.php @@ -0,0 +1,48 @@ +bd->prepare($sql); + $stm->execute(); + $res = $stm->fetchAll(PDO::FETCH_ASSOC); + + $tables = array( + 'category' => false, + 'feed' => false, + 'entry' => false, + ); + foreach ($res as $value) { + $tables[$value['name']] = true; + } + + return count(array_keys($tables, true, true)) == count($tables); + } + + public function getSchema($table) { + $sql = 'PRAGMA table_info(' . $table . ')'; + $stm = $this->bd->prepare($sql); + $stm->execute(); + + return $this->listDaoToSchema($stm->fetchAll(PDO::FETCH_ASSOC)); + } + + public function entryIsCorrect() { + return $this->checkTable('entry', array( + 'id', 'guid', 'title', 'author', 'content', 'link', 'date', 'is_read', + 'is_favorite', 'id_feed', 'tags' + )); + } + + public function daoToSchema($dao) { + return array( + 'name' => $dao['name'], + 'type' => strtolower($dao['type']), + 'notnull' => $dao['notnull'] === '1' ? true : false, + 'default' => $dao['dflt_value'], + ); + } +} diff --git a/app/Models/Factory.php b/app/Models/Factory.php index 93f4552f7..91cb84998 100644 --- a/app/Models/Factory.php +++ b/app/Models/Factory.php @@ -29,4 +29,13 @@ class FreshRSS_Factory { } } + public static function createDatabaseDAO($username = null) { + $db = Minz_Configuration::dataBase(); + if ($db['type'] === 'sqlite') { + return new FreshRSS_DatabaseDAOSQLite($username); + } else { + return new FreshRSS_DatabaseDAO($username); + } + } + } diff --git a/app/SQL/install.sql.mysql.php b/app/SQL/install.sql.mysql.php index 16cb3a3b8..cf0159199 100644 --- a/app/SQL/install.sql.mysql.php +++ b/app/SQL/install.sql.mysql.php @@ -57,5 +57,3 @@ INSERT IGNORE INTO `%1$scategory` (id, name) VALUES(1, "%2$s"); '); define('SQL_DROP_TABLES', 'DROP TABLES %1$sentry, %1$sfeed, %1$scategory'); - -define('SQL_SHOW_TABLES', 'SHOW tables;'); diff --git a/app/SQL/install.sql.sqlite.php b/app/SQL/install.sql.sqlite.php index 7988ada04..30bca2810 100644 --- a/app/SQL/install.sql.sqlite.php +++ b/app/SQL/install.sql.sqlite.php @@ -55,5 +55,3 @@ $SQL_CREATE_TABLES = array( ); define('SQL_DROP_TABLES', 'DROP TABLES %1$sentry, %1$sfeed, %1$scategory'); - -define('SQL_SHOW_TABLES', 'SELECT name FROM sqlite_master WHERE type="table"'); diff --git a/app/layout/aside_configure.phtml b/app/layout/aside_configure.phtml index 20446c877..32dc19a4e 100644 --- a/app/layout/aside_configure.phtml +++ b/app/layout/aside_configure.phtml @@ -31,7 +31,12 @@
  • -
  • +
  • + +
  • +
  • diff --git a/app/layout/header.phtml b/app/layout/header.phtml index e848ac4eb..506cec175 100644 --- a/app/layout/header.phtml +++ b/app/layout/header.phtml @@ -68,6 +68,7 @@ if (Minz_Configuration::canLogIn()) {
  • +
  • diff --git a/app/views/update/checkInstall.phtml b/app/views/update/checkInstall.phtml new file mode 100644 index 000000000..32058714e --- /dev/null +++ b/app/views/update/checkInstall.phtml @@ -0,0 +1,30 @@ +partial('aside_configure'); ?> + +
    + + +

    + + status_php as $key => $status) { ?> +

    + +

    + + +

    + + status_files as $key => $status) { ?> +

    + +

    + + +

    + + status_database as $key => $status) { ?> +

    + +

    + + +
    diff --git a/lib/lib_rss.php b/lib/lib_rss.php index 2f9a2ea45..dbed207d0 100644 --- a/lib/lib_rss.php +++ b/lib/lib_rss.php @@ -245,3 +245,65 @@ function is_referer_from_same_domain() { } return (isset($host['port']) ? $host['port'] : 0) === (isset($referer['port']) ? $referer['port'] : 0); } + + +/** + * + */ +function check_install_php() { + return array( + 'php' => version_compare(PHP_VERSION, '5.2.1') >= 0, + 'minz' => file_exists(LIB_PATH . '/Minz'), + 'curl' => extension_loaded('curl'), + 'pdo_mysql' => extension_loaded('pdo_mysql'), + 'pdo_sqlite' => extension_loaded('pdo_sqlite'), + 'pdo' => extension_loaded('pdo_mysql') || extension_loaded('pdo_sqlite'), + 'pcre' => extension_loaded('pcre'), + 'ctype' => extension_loaded('ctype'), + 'dom' => class_exists('DOMDocument'), + 'json' => extension_loaded('json'), + 'zip' => extension_loaded('zip'), + ); +} + + +/** + * + */ +function check_install_files() { + return array( + 'data' => DATA_PATH && is_writable(DATA_PATH), + 'cache' => CACHE_PATH && is_writable(CACHE_PATH), + 'logs' => LOG_PATH && is_writable(LOG_PATH), + 'favicons' => is_writable(DATA_PATH . '/favicons'), + 'persona' => is_writable(DATA_PATH . '/persona'), + 'tokens' => is_writable(DATA_PATH . '/tokens'), + ); +} + + +/** + * + */ +function check_install_database() { + $status = array( + 'connection' => true, + 'tables' => false, + 'categories' => false, + 'feeds' => false, + 'entries' => false, + ); + + try { + $dbDAO = FreshRSS_Factory::createDatabaseDAO(); + + $status['tables'] = $dbDAO->tablesAreCorrect(); + $status['categories'] = $dbDAO->categoryIsCorrect(); + $status['feeds'] = $dbDAO->feedIsCorrect(); + $status['entries'] = $dbDAO->entryIsCorrect(); + } catch(Minz_PDOConnectionException $e) { + $status['connection'] = false; + } + + return $status; +} -- cgit v1.2.3 From ad92dd7dae35e7205da3172d4ba35ea01da2bc8b Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Mon, 20 Oct 2014 18:21:10 +0200 Subject: First draft for Context object. See https://github.com/marienfressinaud/FreshRSS/issues/634 --- app/FreshRSS.php | 40 ++++++++++++++++++++-------------------- app/Models/Context.php | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+), 20 deletions(-) create mode 100644 app/Models/Context.php (limited to 'app/Models') diff --git a/app/FreshRSS.php b/app/FreshRSS.php index 6b7a813bf..e1399ad78 100644 --- a/app/FreshRSS.php +++ b/app/FreshRSS.php @@ -1,50 +1,50 @@ loadConfiguration(); - $this->loadParamsView(); + if (Minz_Request::isPost() && !is_referer_from_same_domain()) { - //Basic protection against XSRF attacks + // Basic protection against XSRF attacks FreshRSS_Auth::removeAccess(); + $http_referer = empty($_SERVER['HTTP_REFERER']) ? '' : $_SERVER['HTTP_REFERER']; Minz_Error::error( 403, - array('error' => array(_t('access_denied') . ' [HTTP_REFERER=' . - htmlspecialchars(empty($_SERVER['HTTP_REFERER']) ? '' : $_SERVER['HTTP_REFERER']) . ']')) + array('error' => array( + _t('access_denied'), + ' [HTTP_REFERER=' . htmlspecialchars($http_referer) . ']' + )) ); } + + // Load context and configuration. + // TODO: remove $this->view->conf variable which is contained in context + FreshRSS_Context::init(); + Minz_View::_param('conf', FreshRSS_Context::$conf); + + $this->loadParamsView(); $this->loadStylesAndScripts(); $this->loadNotifications(); $this->loadExtensions(); } - private function loadConfiguration() { - $current_user = Minz_Session::param('currentUser'); - try { - $this->conf = new FreshRSS_Configuration($current_user); - Minz_View::_param('conf', $this->conf); - } catch(Minz_Exception $e) { - Minz_Log::error('Cannot load configuration file of user `' . $current_user . '`'); - die($e->getMessage()); - } - } - private function loadParamsView() { - Minz_Session::_param('language', $this->conf->language); - Minz_Translate::init(); + // TODO: outputs should be different actions. $output = Minz_Request::param('output', ''); if (($output === '') || ($output !== 'normal' && $output !== 'rss' && $output !== 'reader' && $output !== 'global')) { - $output = $this->conf->view_mode; + $output = FreshRSS_Context::$conf->view_mode; Minz_Request::_param('output', $output); } } private function loadStylesAndScripts() { - $theme = FreshRSS_Themes::load($this->conf->theme); + $theme = FreshRSS_Themes::load(FreshRSS_Context::$conf->theme); if ($theme) { foreach($theme['files'] as $file) { if ($file[0] === '_') { diff --git a/app/Models/Context.php b/app/Models/Context.php new file mode 100644 index 000000000..d984fece7 --- /dev/null +++ b/app/Models/Context.php @@ -0,0 +1,32 @@ +getMessage()); + } + + // Init i18n. + Minz_Session::_param('language', self::$conf->language); + Minz_Translate::init(); + + // Get the current state. + self::$state = self::$conf->default_view; + } + + public static function stateEnabled($state) { + return self::$state & $state; + } +} -- cgit v1.2.3 From 80cffa6de51771cd80995fb1c4f1e04ee868eb45 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Tue, 21 Oct 2014 16:46:36 +0200 Subject: Views are in dedicated actions + improve Context - Seperate normal, global and rss outputs in dedicated actions (NOT WORKING YET!) - Rewrite aside_flux and nav_menu to use Context object - Improve Context object See https://github.com/marienfressinaud/FreshRSS/issues/634 --- app/Controllers/indexController.php | 97 ++++++++------- app/FreshRSS.php | 10 -- app/Models/Context.php | 65 +++++++++- app/layout/aside_flux.phtml | 103 ++++++---------- app/layout/nav_menu.phtml | 205 +++++++------------------------ app/views/helpers/view/normal_view.phtml | 191 ---------------------------- app/views/helpers/view/rss_view.phtml | 29 ----- app/views/index/global.phtml | 4 +- app/views/index/normal.phtml | 191 ++++++++++++++++++++++++++++ app/views/index/rss.phtml | 29 +++++ lib/Minz/Request.php | 7 ++ 11 files changed, 425 insertions(+), 506 deletions(-) delete mode 100644 app/views/helpers/view/normal_view.phtml delete mode 100755 app/views/helpers/view/rss_view.phtml create mode 100644 app/views/index/normal.phtml create mode 100755 app/views/index/rss.phtml (limited to 'app/Models') diff --git a/app/Controllers/indexController.php b/app/Controllers/indexController.php index e1ce71b28..d348ea1d0 100755 --- a/app/Controllers/indexController.php +++ b/app/Controllers/indexController.php @@ -7,47 +7,17 @@ class FreshRSS_index_Controller extends Minz_ActionController { private $nb_not_read_cat = 0; public function indexAction() { - $output = Minz_Request::param('output'); - $token = FreshRSS_Context::$conf->token; - - // check if user is logged in - if (!FreshRSS_Auth::hasAccess() && !Minz_Configuration::allowAnonymous()) { - $token_param = Minz_Request::param('token', ''); - $token_is_ok = ($token != '' && $token === $token_param); - if ($output === 'rss' && !$token_is_ok) { - Minz_Error::error(403); - 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' => 'auth', 'a' => 'login')); - return; - } - } + // TODO: update the context with information from request. + // TODO: then, in dedicated action, get corresponding entries - $params = Minz_Request::params(); - if (isset($params['search'])) { - $params['search'] = urlencode($params['search']); - } - - $this->view->url = array( + $prefered_output = FreshRSS_Context::$conf->view_mode; + Minz_Request::forward(array( 'c' => 'index', - 'a' => 'index', - 'params' => $params - ); + 'a' => $prefered_output + )); - if ($output === 'rss') { - // no layout for RSS output - $this->view->_useLayout(false); - header('Content-Type: application/rss+xml; charset=utf-8'); - } elseif ($output === 'global') { - Minz_View::appendScript(Minz_Url::display('/scripts/global_view.js?' . @filemtime(PUBLIC_PATH . '/scripts/global_view.js'))); - } + return; - $catDAO = new FreshRSS_CategoryDAO(); - $entryDAO = FreshRSS_Factory::createEntryDao(); - - $this->view->cat_aside = $catDAO->listCategories(); $this->view->nb_favorites = $entryDAO->countUnreadReadFavorites(); $this->view->nb_not_read = FreshRSS_CategoryDAO::CountUnreads($this->view->cat_aside, 1); $this->view->currentName = ''; @@ -60,10 +30,7 @@ class FreshRSS_index_Controller extends Minz_ActionController { $getId = substr($get, 2); if (!$this->checkAndProcessType($getType, $getId)) { Minz_Log::debug('Not found [' . $getType . '][' . $getId . ']'); - Minz_Error::error( - 404, - array('error' => array(_t('page_not_found'))) - ); + Minz_Error::error(404); return; } @@ -144,10 +111,7 @@ class FreshRSS_index_Controller extends Minz_ActionController { $this->view->entries = $entries; } catch (FreshRSS_EntriesGetter_Exception $e) { Minz_Log::notice($e->getMessage()); - Minz_Error::error( - 404, - array('error' => array(_t('page_not_found'))) - ); + Minz_Error::error(404); } } @@ -202,20 +166,59 @@ class FreshRSS_index_Controller extends Minz_ActionController { } } + /** + * This action displays the normal view of FreshRSS. + */ + public function normalAction() { + if (!FreshRSS_Auth::hasAccess() && !Minz_Configuration::allowAnonymous()) { + Minz_Request::forward(array('c' => 'auth', 'a' => 'login')); + return; + } + + $catDAO = new FreshRSS_CategoryDAO(); + $entryDAO = FreshRSS_Factory::createEntryDao(); + + $this->view->categories = $catDAO->listCategories(); + + } + /** * This action displays the global view of FreshRSS. */ public function globalAction() { if (!FreshRSS_Auth::hasAccess() && !Minz_Configuration::allowAnonymous()) { - Minz_Error::error(403); + Minz_Request::forward(array('c' => 'auth', 'a' => 'login')); + return; } Minz_View::appendScript(Minz_Url::display('/scripts/global_view.js?' . @filemtime(PUBLIC_PATH . '/scripts/global_view.js'))); $catDAO = new FreshRSS_CategoryDAO(); $this->view->categories = $catDAO->listCategories(); + + Minz_View::prependTitle(_t('gen.title.global_view') . ' · '); } - + + /** + * This action displays the RSS feed of FreshRSS. + */ + public function rssAction() { + $token = FreshRSS_Context::$conf->token; + $token_param = Minz_Request::param('token', ''); + $token_is_ok = ($token != '' && $token === $token_param); + + // Check if user has access. + if (!FreshRSS_Auth::hasAccess() && + !Minz_Configuration::allowAnonymous() && + !$token_is_ok) { + Minz_Error::error(403); + } + + // No layout for RSS output. + $this->view->_useLayout(false); + header('Content-Type: application/rss+xml; charset=utf-8'); + } + /** * This action displays the about page of FreshRSS. */ diff --git a/app/FreshRSS.php b/app/FreshRSS.php index 752b14e31..b997433bf 100644 --- a/app/FreshRSS.php +++ b/app/FreshRSS.php @@ -26,21 +26,11 @@ class FreshRSS extends Minz_FrontController { // Load context and configuration. FreshRSS_Context::init(); - $this->loadParamsView(); $this->loadStylesAndScripts(); $this->loadNotifications(); $this->loadExtensions(); } - private function loadParamsView() { - // TODO: outputs should be different actions. - $output = Minz_Request::param('output', ''); - if (($output === '') || ($output !== 'normal' && $output !== 'rss' && $output !== 'reader' && $output !== 'global')) { - $output = FreshRSS_Context::$conf->view_mode; - Minz_Request::_param('output', $output); - } - } - private function loadStylesAndScripts() { $theme = FreshRSS_Themes::load(FreshRSS_Context::$conf->theme); if ($theme) { diff --git a/app/Models/Context.php b/app/Models/Context.php index d984fece7..b85179652 100644 --- a/app/Models/Context.php +++ b/app/Models/Context.php @@ -6,7 +6,22 @@ */ class FreshRSS_Context { public static $conf = null; + + public static $total_unread = 0; + public static $total_starred = array( + 'all' => 0, + 'read' => 0, + 'unread' => 0, + ); + public static $state = 0; + public static $current_get = array( + 'all' => false, + 'starred' => false, + 'feed' => false, + 'category' => false, + ); + public static $order = 'DESC'; public static function init() { // Init configuration. @@ -23,10 +38,56 @@ class FreshRSS_Context { Minz_Translate::init(); // Get the current state. - self::$state = self::$conf->default_view; + // self::$state = self::$conf->default_view; } - public static function stateEnabled($state) { + public static function isStateEnabled($state) { return self::$state & $state; } + + public static function getRevertState($state) { + if (self::$state & $state) { + return self::$state & ~$state; + } else { + return self::$state | $state; + } + } + + public static function currentGet() { + if (self::$current_get['all']) { + return 'a'; + } elseif (self::$current_get['starred']) { + return 's'; + } elseif (self::$current_get['feed']) { + return 'f_' . self::$current_get['feed']; + } elseif (self::$current_get['category']) { + return 'c_' . self::$current_get['category']; + } + } + + public static function isCurrentGet($get) { + $type = $get[0]; + $id = substr($get, 2); + + switch($type) { + case 'a': + return self::$current_get['all']; + case 's': + return self::$current_get['starred']; + case 'f': + return self::$current_get['feed'] === $id; + case 'c': + return self::$current_get['category'] === $id; + default: + return false; + } + } + + public static function nextStep() { + // TODO: fix this method. + return array( + 'get' => 'a', + 'idMax' => (time() - 1) . '000000' + ); + } } diff --git a/app/layout/aside_flux.phtml b/app/layout/aside_flux.phtml index 114ccbf56..e572e9d48 100644 --- a/app/layout/aside_flux.phtml +++ b/app/layout/aside_flux.phtml @@ -1,82 +1,53 @@ -
    +
    -
      - - + +
      + + +
      + + + + + -
    • -
      - - -
      +
        +
      • + +
      • + +
      • +
      • - -
      • - 'index', 'a' => 'index', 'params' => array()); - if (FreshRSS_Context::$conf->view_mode !== Minz_Request::param('output', 'normal')) { - $arUrl['params']['output'] = 'normal'; - } + foreach ($this->categories as $cat) { + $feeds = $cat->feeds(); + if (!empty($feeds)) { ?> -
      • - -
      • +
      • + name(); ?> -
      • - +
      • - cat_aside as $cat) { - $feeds = $cat->feeds(); - if (!empty($feeds)) { - $c_active = false; - $c_show = false; - if ($this->get_c == $cat->id()) { - $c_active = true; - if (!FreshRSS_Context::$conf->display_categories || $this->get_f) { - $c_show = true; - } } - ?>
      • >
          id(); - $nbEntries = $feed->nbEntries(); - $f_active = ($this->get_f == $feed_id); - ?>
        • ✇ name(); ?>
      • + ?>
      -
    nextId)) { + if (FreshRSS_Context::$next_id !== '') { $params = Minz_Request::params(); - $params['next'] = $this->nextId; + $params['next'] = FreshRSS_Context::$next_id; $params['ajax'] = 1; ?> diff --git a/app/views/index/normal.phtml b/app/views/index/normal.phtml index c39dba0a9..36adef2f2 100644 --- a/app/views/index/normal.phtml +++ b/app/views/index/normal.phtml @@ -32,14 +32,14 @@ if (!empty($this->entries)) {
    - +
    entries as $item) { if ($display_today && $item->isDay(FreshRSS_Days::TODAY, $today)) { ?>
    currentName; ?>
    entries)) { ?>
    currentName; ?>
    isDay(FreshRSS_Days::BEFORE_YESTERDAY, $today)) { ?>
    currentName; ?>
    Date: Wed, 22 Oct 2014 17:57:22 +0200 Subject: Fix a set of TODO and bugs - Context object raises correct Exception if get is invalid - RSS feed is well-indicated on the home page - State is better calculated - Add some comments See https://github.com/marienfressinaud/FreshRSS/issues/634 --- app/Controllers/indexController.php | 39 +++++++++++++++++++++++++------------ app/Exceptions/ContextException.php | 10 ++++++++++ app/Models/Context.php | 16 ++++++--------- app/layout/layout.phtml | 17 ++++++++-------- 4 files changed, 52 insertions(+), 30 deletions(-) create mode 100644 app/Exceptions/ContextException.php (limited to 'app/Models') diff --git a/app/Controllers/indexController.php b/app/Controllers/indexController.php index d711997be..f9af2d0bb 100755 --- a/app/Controllers/indexController.php +++ b/app/Controllers/indexController.php @@ -5,10 +5,10 @@ */ class FreshRSS_index_Controller extends Minz_ActionController { + /** + * This action only redirect on the default view mode (normal or global) + */ public function indexAction() { - // TODO: update the context with information from request. - // TODO: then, in dedicated action, get corresponding entries - $prefered_output = FreshRSS_Context::$conf->view_mode; Minz_Request::forward(array( 'c' => 'index', @@ -27,12 +27,12 @@ class FreshRSS_index_Controller extends Minz_ActionController { try { $this->updateContext(); - } catch (Minz_Exception $e) { + } catch (FreshRSS_Context_Exception $e) { Minz_Error::error(404); } try { - $entries = $this->listByContext(); + $entries = $this->listEntriesByContext(); if (count($entries) > FreshRSS_Context::$number) { // We have more elements for pagination @@ -48,6 +48,7 @@ class FreshRSS_index_Controller extends Minz_ActionController { $this->view->categories = FreshRSS_Context::$categories; + $this->view->rss_title = FreshRSS_Context::$name . ' | ' . Minz_View::title(); $title = FreshRSS_Context::$name; if (FreshRSS_Context::$get_unread > 0) { $title = '(' . FreshRSS_Context::$get_unread . ') · ' . $title; @@ -68,12 +69,13 @@ class FreshRSS_index_Controller extends Minz_ActionController { try { $this->updateContext(); - } catch (Minz_Exception $e) { + } catch (FreshRSS_Context_Exception $e) { Minz_Error::error(404); } $this->view->categories = FreshRSS_Context::$categories; + $this->view->rss_title = FreshRSS_Context::$name . ' | ' . Minz_View::title(); Minz_View::prependTitle(_t('gen.title.global_view') . ' · '); } @@ -94,12 +96,12 @@ class FreshRSS_index_Controller extends Minz_ActionController { try { $this->updateContext(); - } catch (Minz_Exception $e) { + } catch (FreshRSS_Context_Exception $e) { Minz_Error::error(404); } try { - $this->view->entries = $this->listByContext(); + $this->view->entries = $this->listEntriesByContext(); } catch (FreshRSS_EntriesGetter_Exception $e) { Minz_Log::notice($e->getMessage()); Minz_Error::error(404); @@ -113,15 +115,25 @@ class FreshRSS_index_Controller extends Minz_ActionController { /** * This action updates the Context object by using request parameters. + * + * Parameters are: + * - state (default: conf->default_view) + * - search (default: empty string) + * - order (default: conf->sort_order) + * - nb (default: conf->posts_per_page) + * - next (default: empty string) */ private function updateContext() { FreshRSS_Context::_get(Minz_Request::param('get', 'a')); - FreshRSS_Context::$state |= Minz_Request::param( + // TODO: change default_view by default_state. + FreshRSS_Context::$state = Minz_Request::param( 'state', FreshRSS_Context::$conf->default_view ); - if (FreshRSS_Context::$state & FreshRSS_Entry::STATE_NOT_READ && - FreshRSS_Context::$get_unread <= 0) { + $state_forced_by_user = Minz_Request::param('state', false) !== false; + if (FreshRSS_Context::isStateEnabled(FreshRSS_Entry::STATE_NOT_READ) && + FreshRSS_Context::$get_unread <= 0 && + !$state_forced_by_user) { FreshRSS_Context::$state |= FreshRSS_Entry::STATE_READ; } @@ -135,7 +147,10 @@ class FreshRSS_index_Controller extends Minz_ActionController { FreshRSS_Context::$first_id = Minz_Request::param('next', ''); } - private function listByContext() { + /** + * This method returns a list of entries based on the Context object. + */ + private function listEntriesByContext() { $entryDAO = FreshRSS_Factory::createEntryDao(); $get = FreshRSS_Context::currentGet(true); diff --git a/app/Exceptions/ContextException.php b/app/Exceptions/ContextException.php new file mode 100644 index 000000000..357751b7c --- /dev/null +++ b/app/Exceptions/ContextException.php @@ -0,0 +1,10 @@ + 0, ); - public static $state = 0; + public static $get_unread = 0; public static $current_get = array( 'all' => false, 'starred' => false, 'feed' => false, 'category' => false, ); - public static $get_unread = 0; + + public static $state = 0; public static $order = 'DESC'; public static $number = 0; public static $search = ''; @@ -48,8 +49,6 @@ class FreshRSS_Context { $catDAO = new FreshRSS_CategoryDAO(); $entryDAO = FreshRSS_Factory::createEntryDao(); - // Get the current state. - // self::$state = self::$conf->default_view; self::$categories = $catDAO->listCategories(); // Update number of read / unread variables. @@ -97,8 +96,7 @@ class FreshRSS_Context { $feed = $feedDAO->searchById($id); if (!$feed) { - // TODO: raise an exception - return false; + throw new FreshRSS_Context_Exception('Invalid feed: ' . $id); } } @@ -112,8 +110,7 @@ class FreshRSS_Context { $cat = $catDAO->searchById($id); if (!$cat) { - // TODO: raise an exception - return false; + throw new FreshRSS_Context_Exception('Invalid category: ' . $id); } } else { $cat = self::$categories[$id]; @@ -123,8 +120,7 @@ class FreshRSS_Context { self::$get_unread = $cat->nbNotRead(); break; default: - // TODO: raise an exception! - return false; + throw new FreshRSS_Context_Exception('Invalid getter: ' . $get); } } diff --git a/app/layout/layout.phtml b/app/layout/layout.phtml index 2b38df4a1..1827d6c26 100644 --- a/app/layout/layout.phtml +++ b/app/layout/layout.phtml @@ -10,21 +10,22 @@ renderHelper('javascript_vars'); ?> //]]> - + url)) { - $rss_url = $this->url; - $rss_url['params']['output'] = 'rss'; + if (isset($this->rss_title)) { + $url_rss = $url_base; + $url_rss['a'] = 'rss'; ?> - + -- cgit v1.2.3 From eb60b82959d768b199985523e7d4e05ba4055591 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Wed, 22 Oct 2014 18:06:28 +0200 Subject: Move back i18n init in FreshRSS.php --- app/FreshRSS.php | 4 ++++ app/Models/Context.php | 4 ---- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'app/Models') diff --git a/app/FreshRSS.php b/app/FreshRSS.php index b997433bf..6114a5d1a 100644 --- a/app/FreshRSS.php +++ b/app/FreshRSS.php @@ -26,6 +26,10 @@ class FreshRSS extends Minz_FrontController { // Load context and configuration. FreshRSS_Context::init(); + // Init i18n. + Minz_Session::_param('language', FreshRSS_Context::$conf->language); + Minz_Translate::init(); + $this->loadStylesAndScripts(); $this->loadNotifications(); $this->loadExtensions(); diff --git a/app/Models/Context.php b/app/Models/Context.php index 4580a4f52..3b3c8673d 100644 --- a/app/Models/Context.php +++ b/app/Models/Context.php @@ -42,10 +42,6 @@ class FreshRSS_Context { die($e->getMessage()); } - // Init i18n. - Minz_Session::_param('language', self::$conf->language); - Minz_Translate::init(); - $catDAO = new FreshRSS_CategoryDAO(); $entryDAO = FreshRSS_Factory::createEntryDao(); -- cgit v1.2.3 From 9551145200b61717fdeb11007e1da541ddf93f0f Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Wed, 22 Oct 2014 18:21:36 +0200 Subject: Better view mode - Seperate view mode from default state in conf - Load read articles if no unread articles only if view is adaptive See https://github.com/marienfressinaud/FreshRSS/issues/634 --- app/Controllers/configureController.php | 2 +- app/Controllers/indexController.php | 6 +++--- app/Models/Configuration.php | 21 +++++++++++++-------- app/views/configure/reading.phtml | 6 +++--- 4 files changed, 20 insertions(+), 15 deletions(-) (limited to 'app/Models') diff --git a/app/Controllers/configureController.php b/app/Controllers/configureController.php index 8a9dcdc62..9a7870000 100755 --- a/app/Controllers/configureController.php +++ b/app/Controllers/configureController.php @@ -104,7 +104,7 @@ class FreshRSS_configure_Controller extends Minz_ActionController { if (Minz_Request::isPost()) { FreshRSS_Context::$conf->_posts_per_page(Minz_Request::param('posts_per_page', 10)); FreshRSS_Context::$conf->_view_mode(Minz_Request::param('view_mode', 'normal')); - FreshRSS_Context::$conf->_default_view((int)Minz_Request::param('default_view', FreshRSS_Entry::STATE_ALL)); + FreshRSS_Context::$conf->_default_view(Minz_Request::param('default_view', 'adaptive')); FreshRSS_Context::$conf->_auto_load_more(Minz_Request::param('auto_load_more', false)); FreshRSS_Context::$conf->_display_posts(Minz_Request::param('display_posts', false)); FreshRSS_Context::$conf->_display_categories(Minz_Request::param('display_categories', false)); diff --git a/app/Controllers/indexController.php b/app/Controllers/indexController.php index f9af2d0bb..2dd4c3068 100755 --- a/app/Controllers/indexController.php +++ b/app/Controllers/indexController.php @@ -126,13 +126,13 @@ class FreshRSS_index_Controller extends Minz_ActionController { private function updateContext() { FreshRSS_Context::_get(Minz_Request::param('get', 'a')); - // TODO: change default_view by default_state. FreshRSS_Context::$state = Minz_Request::param( - 'state', FreshRSS_Context::$conf->default_view + 'state', FreshRSS_Context::$conf->default_state ); $state_forced_by_user = Minz_Request::param('state', false) !== false; - if (FreshRSS_Context::isStateEnabled(FreshRSS_Entry::STATE_NOT_READ) && + if (FreshRSS_Context::$conf->default_view === 'adaptive' && FreshRSS_Context::$get_unread <= 0 && + !FreshRSS_Context::isStateEnabled(FreshRSS_Entry::STATE_READ) && !$state_forced_by_user) { FreshRSS_Context::$state |= FreshRSS_Entry::STATE_READ; } diff --git a/app/Models/Configuration.php b/app/Models/Configuration.php index 2f208e509..53f136513 100644 --- a/app/Models/Configuration.php +++ b/app/Models/Configuration.php @@ -14,7 +14,8 @@ class FreshRSS_Configuration { 'apiPasswordHash' => '', //CRYPT_BLOWFISH 'posts_per_page' => 20, 'view_mode' => 'normal', - 'default_view' => FreshRSS_Entry::STATE_NOT_READ, + 'default_view' => 'adaptive', + 'default_state' => FreshRSS_Entry::STATE_NOT_READ, 'auto_load_more' => true, 'display_posts' => false, 'display_categories' => false, @@ -153,18 +154,22 @@ class FreshRSS_Configuration { } public function _default_view($value) { switch ($value) { - case FreshRSS_Entry::STATE_ALL: - // left blank on purpose - case FreshRSS_Entry::STATE_NOT_READ: - // left blank on purpose - case FreshRSS_Entry::STATE_STRICT + FreshRSS_Entry::STATE_NOT_READ: + case 'all': $this->data['default_view'] = $value; + $this->data['default_state'] = (FreshRSS_Entry::STATE_READ + + FreshRSS_Entry::STATE_NOT_READ); break; + case 'adaptive': + case 'unread': default: - $this->data['default_view'] = FreshRSS_Entry::STATE_ALL; - break; + $this->data['default_view'] = $value; + $this->data['default_state'] = FreshRSS_Entry::STATE_NOT_READ; } } + public function _default_state($value) { + $this->data['default_state'] = (int)$value; + } + public function _display_posts($value) { $this->data['display_posts'] = ((bool)$value) && $value !== 'no'; } diff --git a/app/views/configure/reading.phtml b/app/views/configure/reading.phtml index ef775b4b1..b8f673466 100644 --- a/app/views/configure/reading.phtml +++ b/app/views/configure/reading.phtml @@ -39,9 +39,9 @@
    -- cgit v1.2.3 From 8a6ad05ebacb6bf6c0f6afd0afe54a29a0a18ee9 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Wed, 22 Oct 2014 18:33:46 +0200 Subject: Remove STATE_STRICT See https://github.com/marienfressinaud/FreshRSS/issues/634 --- app/Controllers/configureController.php | 3 --- app/Models/Entry.php | 3 +-- app/Models/EntryDAO.php | 2 -- 3 files changed, 1 insertion(+), 7 deletions(-) (limited to 'app/Models') diff --git a/app/Controllers/configureController.php b/app/Controllers/configureController.php index 9a7870000..cafd0e8a8 100755 --- a/app/Controllers/configureController.php +++ b/app/Controllers/configureController.php @@ -338,9 +338,6 @@ class FreshRSS_configure_Controller extends Minz_ActionController { unset($query[$key]); } } - if (!empty($query['state']) && $query['state'] & FreshRSS_Entry::STATE_STRICT) { - $query['state'] -= FreshRSS_Entry::STATE_STRICT; - } $queries[] = $query; FreshRSS_Context::$conf->_queries($queries); FreshRSS_Context::$conf->save(); diff --git a/app/Models/Entry.php b/app/Models/Entry.php index ee94d1110..346c98a92 100644 --- a/app/Models/Entry.php +++ b/app/Models/Entry.php @@ -1,12 +1,11 @@ Date: Wed, 22 Oct 2014 19:19:15 +0200 Subject: nextGet and idMax are coming back. See https://github.com/marienfressinaud/FreshRSS/issues/634 --- app/Controllers/entryController.php | 14 ++----- app/Controllers/indexController.php | 15 +++++++- app/Models/Context.php | 73 ++++++++++++++++++++++++++++++++----- app/layout/nav_menu.phtml | 5 +-- 4 files changed, 82 insertions(+), 25 deletions(-) (limited to 'app/Models') diff --git a/app/Controllers/entryController.php b/app/Controllers/entryController.php index 449029648..d11f3a520 100755 --- a/app/Controllers/entryController.php +++ b/app/Controllers/entryController.php @@ -17,14 +17,6 @@ class FreshRSS_entry_Controller extends Minz_ActionController { ); } - // Keep parameter information (output) to do a correct redirection at - // the end. - $this->params = array(); - $output = Minz_Request::param('output', ''); - if ($output != '' && FreshRSS_Context::$conf->view_mode !== $output) { - $this->params['output'] = $output; - } - // If ajax request, we do not print layout $this->ajax = Minz_Request::param('ajax'); if ($this->ajax) { @@ -53,6 +45,7 @@ class FreshRSS_entry_Controller extends Minz_ActionController { $get = Minz_Request::param('get'); $next_get = Minz_Request::param('nextGet', $get); $id_max = Minz_Request::param('idMax', 0); + $params = array(); $entryDAO = FreshRSS_Factory::createEntryDao(); if ($id === false) { @@ -86,7 +79,7 @@ class FreshRSS_entry_Controller extends Minz_ActionController { // Redirect to the correct page (category, feed or starred) // Not "a" because it is the default value if nothing is // given. - $this->params['get'] = $next_get; + $params['get'] = $next_get; } } } else { @@ -98,7 +91,7 @@ class FreshRSS_entry_Controller extends Minz_ActionController { Minz_Request::good(_t('feeds_marked_read'), array( 'c' => 'index', 'a' => 'index', - 'params' => $this->params, + 'params' => $params, ), true); } } @@ -123,7 +116,6 @@ class FreshRSS_entry_Controller extends Minz_ActionController { Minz_Request::forward(array( 'c' => 'index', 'a' => 'index', - 'params' => $this->params, ), true); } } diff --git a/app/Controllers/indexController.php b/app/Controllers/indexController.php index 2dd4c3068..80675b3a6 100755 --- a/app/Controllers/indexController.php +++ b/app/Controllers/indexController.php @@ -34,12 +34,25 @@ class FreshRSS_index_Controller extends Minz_ActionController { try { $entries = $this->listEntriesByContext(); - if (count($entries) > FreshRSS_Context::$number) { + $nb_entries = count($entries); + if ($nb_entries > FreshRSS_Context::$number) { // We have more elements for pagination $last_entry = array_pop($entries); FreshRSS_Context::$next_id = $last_entry->id(); } + $first_entry = $nb_entries > 0 ? $entries[0] : null; + FreshRSS_Context::$id_max = $first_entry === null ? + (time() - 1) . '000000' : + $first_entry->id(); + if (FreshRSS_Context::$order === 'ASC') { + // In this case we do not know but we guess id_max + $id_max = (time() - 1) . '000000'; + if (strcmp($id_max, FreshRSS_Context::$id_max) > 0) { + FreshRSS_Context::$id_max = $id_max; + } + } + $this->view->entries = $entries; } catch (FreshRSS_EntriesGetter_Exception $e) { Minz_Log::notice($e->getMessage()); diff --git a/app/Models/Context.php b/app/Models/Context.php index 3b3c8673d..3d184dcaa 100644 --- a/app/Models/Context.php +++ b/app/Models/Context.php @@ -24,6 +24,7 @@ class FreshRSS_Context { 'feed' => false, 'category' => false, ); + public static $next_get = 'a'; public static $state = 0; public static $order = 'DESC'; @@ -31,6 +32,7 @@ class FreshRSS_Context { public static $search = ''; public static $first_id = ''; public static $next_id = ''; + public static $id_max = ''; public static function init() { // Init configuration. @@ -84,8 +86,6 @@ class FreshRSS_Context { self::$state = self::$state | FreshRSS_Entry::STATE_FAVORITE; break; case 'f': - self::$current_get['feed'] = $id; - $feed = FreshRSS_CategoryDAO::findFeed(self::$categories, $id); if ($feed === null) { $feedDAO = FreshRSS_Factory::createFeedDao(); @@ -96,6 +96,8 @@ class FreshRSS_Context { } } + self::$current_get['feed'] = $id; + self::$current_get['category'] = $feed->category(); self::$name = $feed->name(); self::$get_unread = $feed->nbNotRead(); break; @@ -118,6 +120,8 @@ class FreshRSS_Context { default: throw new FreshRSS_Context_Exception('Invalid getter: ' . $get); } + + self::_nextGet(); } public static function currentGet($array = false) { @@ -150,19 +154,68 @@ class FreshRSS_Context { case 's': return self::$current_get['starred']; case 'f': - return self::$current_get['feed'] === $id; + return self::$current_get['feed'] == $id; case 'c': - return self::$current_get['category'] === $id; + return self::$current_get['category'] == $id; default: return false; } } - public static function nextStep() { - // TODO: fix this method. - return array( - 'get' => 'a', - 'idMax' => (time() - 1) . '000000' - ); + public static function _nextGet() { + $get = self::currentGet(); + self::$next_get = $get; + + if (self::$conf->onread_jump_next && strlen($get) > 2) { + $another_unread_id = ''; + $found_current_get = false; + switch ($get[0]) { + case 'f': + foreach (self::$categories as $cat) { + if ($cat->id() != self::$current_get['category']) { + continue; + } + + foreach ($cat->feeds() as $feed) { + if ($feed->id() == self::$current_get['feed']) { + $found_current_get = true; + continue; + } + + if ($feed->nbNotRead() > 0) { + $another_unread_id = $feed->id(); + if ($found_current_get) { + break; + } + } + } + break; + } + + self::$next_get['get'] = empty($another_unread_id) ? + 'c_' . self::$current_get['category'] : + 'f_' . $another_unread_id; + break; + case 'c': + foreach (self::$categories as $cat) { + if ($cat->id() == self::$current_get['category']) { + $found_current_get = true; + continue; + } + + if ($cat->nbNotRead() > 0) { + $another_unread_id = $cat->id(); + if ($found_current_get) { + break; + } + } + } + + self::$next_get['get'] = empty($another_unread_id) ? + 'a' : + 'c_' . $another_unread_id; + break; + } + } } } diff --git a/app/layout/nav_menu.phtml b/app/layout/nav_menu.phtml index 440e4d0b6..2c9f8724d 100644 --- a/app/layout/nav_menu.phtml +++ b/app/layout/nav_menu.phtml @@ -61,7 +61,6 @@ 'read', 'params' => array( 'get' => $get, - 'nextGet' => $next_step['get'], - 'idMax' => $next_step['idMax'] + 'nextGet' => FreshRSS_Context::$next_get, + 'idMax' => FreshRSS_Context::$id_max, ) ); ?> -- cgit v1.2.3 From db1ad1de233ac7a0e0674c6e64a6a01f3d0e8fbe Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Wed, 22 Oct 2014 19:36:55 +0200 Subject: Fix a bug in nextGet --- app/Models/Context.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'app/Models') diff --git a/app/Models/Context.php b/app/Models/Context.php index 3d184dcaa..d4aeee7ac 100644 --- a/app/Models/Context.php +++ b/app/Models/Context.php @@ -192,9 +192,9 @@ class FreshRSS_Context { break; } - self::$next_get['get'] = empty($another_unread_id) ? - 'c_' . self::$current_get['category'] : - 'f_' . $another_unread_id; + self::$next_get = empty($another_unread_id) ? + 'c_' . self::$current_get['category'] : + 'f_' . $another_unread_id; break; case 'c': foreach (self::$categories as $cat) { @@ -211,9 +211,9 @@ class FreshRSS_Context { } } - self::$next_get['get'] = empty($another_unread_id) ? - 'a' : - 'c_' . $another_unread_id; + self::$next_get = empty($another_unread_id) ? + 'a' : + 'c_' . $another_unread_id; break; } } -- cgit v1.2.3 From 1efbf6fb86dfe4ff549ce1b7884db17dfbf5554f Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Wed, 22 Oct 2014 20:05:00 +0200 Subject: Add comments to Context object. See https://github.com/marienfressinaud/FreshRSS/issues/634 --- app/Controllers/indexController.php | 7 ++ app/Models/Context.php | 135 ++++++++++++++++++++++++------------ 2 files changed, 98 insertions(+), 44 deletions(-) (limited to 'app/Models') diff --git a/app/Controllers/indexController.php b/app/Controllers/indexController.php index 80675b3a6..ed5b58b45 100755 --- a/app/Controllers/indexController.php +++ b/app/Controllers/indexController.php @@ -137,6 +137,13 @@ class FreshRSS_index_Controller extends Minz_ActionController { * - next (default: empty string) */ private function updateContext() { + // Update number of read / unread variables. + $entryDAO = FreshRSS_Factory::createEntryDao(); + FreshRSS_Context::$total_starred = $entryDAO->countUnreadReadFavorites(); + FreshRSS_Context::$total_unread = FreshRSS_CategoryDAO::CountUnreads( + FreshRSS_Context::$categories, 1 + ); + FreshRSS_Context::_get(Minz_Request::param('get', 'a')); FreshRSS_Context::$state = Minz_Request::param( diff --git a/app/Models/Context.php b/app/Models/Context.php index d4aeee7ac..36c4087eb 100644 --- a/app/Models/Context.php +++ b/app/Models/Context.php @@ -34,6 +34,11 @@ class FreshRSS_Context { public static $next_id = ''; public static $id_max = ''; + /** + * Initialize the context. + * + * Set the correct $conf and $categories variables. + */ public static function init() { // Init configuration. $current_user = Minz_Session::param('currentUser'); @@ -45,19 +50,19 @@ class FreshRSS_Context { } $catDAO = new FreshRSS_CategoryDAO(); - $entryDAO = FreshRSS_Factory::createEntryDao(); - self::$categories = $catDAO->listCategories(); - - // Update number of read / unread variables. - self::$total_starred = $entryDAO->countUnreadReadFavorites(); - self::$total_unread = FreshRSS_CategoryDAO::CountUnreads(self::$categories, 1); } + /** + * Returns if the current state includes $state parameter. + */ public static function isStateEnabled($state) { return self::$state & $state; } + /** + * Returns the current state with or without $state parameter. + */ public static function getRevertState($state) { if (self::$state & $state) { return self::$state & ~$state; @@ -66,6 +71,65 @@ class FreshRSS_Context { } } + /** + * Return the current get as a string or an array. + * + * If $array is true, the first item of the returned value is 'f' or 'c' and + * the second is the id. + */ + public static function currentGet($array = false) { + if (self::$current_get['all']) { + return 'a'; + } elseif (self::$current_get['starred']) { + return 's'; + } elseif (self::$current_get['feed']) { + if ($array) { + return array('f', self::$current_get['feed']); + } else { + return 'f_' . self::$current_get['feed']; + } + } elseif (self::$current_get['category']) { + if ($array) { + return array('c', self::$current_get['category']); + } else { + return 'c_' . self::$current_get['category']; + } + } + } + + /** + * Return true if $get parameter correspond to the $current_get attribute. + */ + public static function isCurrentGet($get) { + $type = $get[0]; + $id = substr($get, 2); + + switch($type) { + case 'a': + return self::$current_get['all']; + case 's': + return self::$current_get['starred']; + case 'f': + return self::$current_get['feed'] == $id; + case 'c': + return self::$current_get['category'] == $id; + default: + return false; + } + } + + /** + * Set the current $get attribute. + * + * Valid $get parameter are: + * - a + * - s + * - f_ + * - c_ + * + * $name and $get_unread attributes are also updated as $next_get + * Raise an exception if id or $get is invalid. + */ public static function _get($get) { $type = $get[0]; $id = substr($get, 2); @@ -86,6 +150,7 @@ class FreshRSS_Context { self::$state = self::$state | FreshRSS_Entry::STATE_FAVORITE; break; case 'f': + // We try to find the corresponding feed. $feed = FreshRSS_CategoryDAO::findFeed(self::$categories, $id); if ($feed === null) { $feedDAO = FreshRSS_Factory::createFeedDao(); @@ -102,6 +167,7 @@ class FreshRSS_Context { self::$get_unread = $feed->nbNotRead(); break; case 'c': + // We try to find the corresponding category. self::$current_get['category'] = $id; if (!isset(self::$categories[$id])) { $catDAO = new FreshRSS_CategoryDAO(); @@ -124,46 +190,12 @@ class FreshRSS_Context { self::_nextGet(); } - public static function currentGet($array = false) { - if (self::$current_get['all']) { - return 'a'; - } elseif (self::$current_get['starred']) { - return 's'; - } elseif (self::$current_get['feed']) { - if ($array) { - return array('f', self::$current_get['feed']); - } else { - return 'f_' . self::$current_get['feed']; - } - } elseif (self::$current_get['category']) { - if ($array) { - return array('c', self::$current_get['category']); - } else { - return 'c_' . self::$current_get['category']; - } - } - } - - public static function isCurrentGet($get) { - $type = $get[0]; - $id = substr($get, 2); - - switch($type) { - case 'a': - return self::$current_get['all']; - case 's': - return self::$current_get['starred']; - case 'f': - return self::$current_get['feed'] == $id; - case 'c': - return self::$current_get['category'] == $id; - default: - return false; - } - } - + /** + * Set the value of $next_get attribute. + */ public static function _nextGet() { $get = self::currentGet(); + // By default, $next_get == $get self::$next_get = $get; if (self::$conf->onread_jump_next && strlen($get) > 2) { @@ -171,13 +203,18 @@ class FreshRSS_Context { $found_current_get = false; switch ($get[0]) { case 'f': + // We search the next feed with at least one unread article in + // same category as the currend feed. foreach (self::$categories as $cat) { if ($cat->id() != self::$current_get['category']) { + // We look into the category of the current feed! continue; } foreach ($cat->feeds() as $feed) { if ($feed->id() == self::$current_get['feed']) { + // Here is our current feed! Fine, the next one will + // be a potential candidate. $found_current_get = true; continue; } @@ -185,6 +222,9 @@ class FreshRSS_Context { if ($feed->nbNotRead() > 0) { $another_unread_id = $feed->id(); if ($found_current_get) { + // We have found our current feed and now we + // have an feed with unread articles. Leave the + // loop! break; } } @@ -192,13 +232,17 @@ class FreshRSS_Context { break; } + // If no feed have been found, next_get is the current category. self::$next_get = empty($another_unread_id) ? 'c_' . self::$current_get['category'] : 'f_' . $another_unread_id; break; case 'c': + // We search the next category with at least one unread article. foreach (self::$categories as $cat) { if ($cat->id() == self::$current_get['category']) { + // Here is our current category! Next one could be our + // champion if it has unread articles. $found_current_get = true; continue; } @@ -206,11 +250,14 @@ class FreshRSS_Context { if ($cat->nbNotRead() > 0) { $another_unread_id = $cat->id(); if ($found_current_get) { + // Unread articles and the current category has + // already been found? Leave the loop! break; } } } + // No unread category? The main stream will be our destination! self::$next_get = empty($another_unread_id) ? 'a' : 'c_' . $another_unread_id; -- cgit v1.2.3 From 00127f07c5fc784130d658e3f26519b0279fc6b8 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Tue, 28 Oct 2014 23:52:46 +0100 Subject: SimplePie: cache feeds with errors Before the cache system was not used for feeds with errors, which was problematic especially if several users have this feed. Furthermore, there was no protection against repetitive refresh. Bonus: slightly better performance by avoiding some superfluous file_exists(). Warning: needs a bit of testing https://github.com/marienfressinaud/FreshRSS/issues/681 --- app/Models/Feed.php | 3 ++- lib/SimplePie/SimplePie.php | 24 +++++++++++++++--------- lib/SimplePie/SimplePie/Cache/File.php | 12 ++++++------ 3 files changed, 23 insertions(+), 16 deletions(-) (limited to 'app/Models') diff --git a/app/Models/Feed.php b/app/Models/Feed.php index 03baf3ad2..bd1babeea 100644 --- a/app/Models/Feed.php +++ b/app/Models/Feed.php @@ -217,7 +217,8 @@ class FreshRSS_Feed extends Minz_Model { $mtime = $feed->init(); if ((!$mtime) || $feed->error()) { - throw new FreshRSS_Feed_Exception($feed->error() . ' [' . $url . ']'); + $errorMessage = $feed->error(); + throw new FreshRSS_Feed_Exception(($errorMessage == '' ? 'Feed error' : $errorMessage) . ' [' . $url . ']'); } if ($loadDetails) { diff --git a/lib/SimplePie/SimplePie.php b/lib/SimplePie/SimplePie.php index 06c100f59..84001dd9a 100644 --- a/lib/SimplePie/SimplePie.php +++ b/lib/SimplePie/SimplePie.php @@ -1455,7 +1455,11 @@ class SimplePie { // Load the Cache $this->data = $cache->load(); - if (!empty($this->data)) + if ($cache->mtime() + $this->cache_duration > time()) { //FreshRSS + $this->raw_data = false; + return true; // If the cache is still valid, just return true + } + elseif (!empty($this->data)) { // If the cache is for an outdated build of SimplePie if (!isset($this->data['build']) || $this->data['build'] !== SIMPLEPIE_BUILD) @@ -1487,7 +1491,7 @@ class SimplePie } } // Check if the cache has been updated - elseif ($cache->mtime() + $this->cache_duration < time()) + else //if ($cache->mtime() + $this->cache_duration < time()) //FreshRSS removed { // If we have last-modified and/or etag set //if (isset($this->data['headers']['last-modified']) || isset($this->data['headers']['etag'])) //FreshRSS removed @@ -1516,6 +1520,7 @@ class SimplePie } else { + $cache->touch(); //FreshRSS $this->error = $file->error; //FreshRSS return !empty($this->data); //FreshRSS //unset($file); //FreshRSS removed @@ -1533,17 +1538,18 @@ class SimplePie } } } - // If the cache is still valid, just return true - else - { - $this->raw_data = false; - return true; - } + //// If the cache is still valid, just return true + //else //FreshRSS removed + //{ + // $this->raw_data = false; + // return true; + //} } // If the cache is empty, delete it else { - $cache->unlink(); + //$cache->unlink(); //FreshRSS removed + $cache->touch(); //FreshRSS $this->data = array(); } } diff --git a/lib/SimplePie/SimplePie/Cache/File.php b/lib/SimplePie/SimplePie/Cache/File.php index 3b163545b..cb4b528c4 100644 --- a/lib/SimplePie/SimplePie/Cache/File.php +++ b/lib/SimplePie/SimplePie/Cache/File.php @@ -136,11 +136,11 @@ class SimplePie_Cache_File implements SimplePie_Cache_Base */ public function mtime() { - if (file_exists($this->name)) + //if (file_exists($this->name)) //FreshRSS removed { - return filemtime($this->name); + return @filemtime($this->name); //FreshRSS } - return false; + //return false; //FreshRSS removed } /** @@ -150,11 +150,11 @@ class SimplePie_Cache_File implements SimplePie_Cache_Base */ public function touch() { - if (file_exists($this->name)) + //if (file_exists($this->name)) //FreshRSS removed { - return touch($this->name); + return @touch($this->name); //FreshRSS } - return false; + //return false; //FreshRSS removed } /** -- cgit v1.2.3 From 9f97f7df8822ed2f32a9bc9d46ece92dee93089c Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Wed, 29 Oct 2014 00:45:42 +0100 Subject: Ne pas rafraîchir les flux des utilisateurs non logués depuis x jours MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit https://github.com/marienfressinaud/FreshRSS/issues/681 Warning: needs some testing --- CHANGELOG | 2 +- app/Controllers/userController.php | 3 +-- app/Models/Auth.php | 13 +++++-------- app/Models/UserDAO.php | 10 +++++++++- app/actualize_script.php | 10 ++++++++++ lib/Minz/Configuration.php | 7 +++++++ 6 files changed, 33 insertions(+), 12 deletions(-) (limited to 'app/Models') diff --git a/CHANGELOG b/CHANGELOG index 688a286e3..a556fcc13 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -3,7 +3,7 @@ ## * Configuration - * New options in config.php for cache duration, timeout, max number of feeds and categories per user. + * New options in config.php for cache duration, timeout, max inactivity, max number of feeds and categories per user. ## 2014-09-26 FreshRSS 0.8.0 / 0.9.0 (beta) diff --git a/app/Controllers/userController.php b/app/Controllers/userController.php index 2343520ca..39db1d879 100644 --- a/app/Controllers/userController.php +++ b/app/Controllers/userController.php @@ -95,9 +95,8 @@ class FreshRSS_user_Controller extends Minz_ActionController { Minz_View::prependTitle(_t('gen.title.user_management') . ' · '); // Get the correct current user. - $userDAO = new FreshRSS_UserDAO(); $username = Minz_Request::param('u', Minz_Session::param('currentUser')); - if (!$userDAO->exist($username)) { + if (!FreshRSS_UserDAO::exist($username)) { $username = Minz_Session::param('currentUser'); } $this->view->current_user = $username; diff --git a/app/Models/Auth.php b/app/Models/Auth.php index cc23d7974..2971d65c8 100644 --- a/app/Models/Auth.php +++ b/app/Models/Auth.php @@ -20,10 +20,11 @@ class FreshRSS_Auth { Minz_Session::_param('currentUser', $current_user); } - $access_ok = self::accessControl(); - - if ($access_ok) { + if (self::$login_ok) { self::giveAccess(); + } elseif (self::accessControl()) { + self::giveAccess(); + FreshRSS_UserDAO::touch($current_user); } else { // Be sure all accesses are removed! self::removeAccess(); @@ -38,11 +39,7 @@ class FreshRSS_Auth { * * @return boolean true if user can be connected, false else. */ - public static function accessControl() { - if (self::$login_ok) { - return true; - } - + private static function accessControl() { switch (Minz_Configuration::authType()) { case 'form': $credentials = FreshRSS_FormAuth::getCredentialsFromCookie(); diff --git a/app/Models/UserDAO.php b/app/Models/UserDAO.php index 85b45c4a7..60fca71b1 100644 --- a/app/Models/UserDAO.php +++ b/app/Models/UserDAO.php @@ -54,7 +54,15 @@ class FreshRSS_UserDAO extends Minz_ModelPdo { } } - public function exist($username) { + public static function exist($username) { return file_exists(DATA_PATH . '/' . $username . '_user.php'); } + + public static function touch($username) { + return touch(DATA_PATH . '/' . $username . '_user.php'); + } + + public static function mtime($username) { + return @filemtime(DATA_PATH . '/' . $username . '_user.php'); + } } diff --git a/app/actualize_script.php b/app/actualize_script.php index 9fe499cc9..6ce4178cd 100755 --- a/app/actualize_script.php +++ b/app/actualize_script.php @@ -22,7 +22,17 @@ if (Minz_Configuration::defaultUser() !== ''){ $users = array_unique($users); } +$limits = Minz_Configuration::limits(); +$minLastActivity = time() - $limits['max_inactivity']; + foreach ($users as $myUser) { + if (($myUser !== Minz_Configuration::defaultUser()) && (FreshRSS_UserDAO::mtime($myUser) < $minLastActivity)) { + syslog(LOG_INFO, 'FreshRSS skip inactive user ' . $myUser); + if (defined('STDOUT')) { + fwrite(STDOUT, 'FreshRSS skip inactive user ' . $myUser . "\n"); //Unbuffered + } + continue; + } syslog(LOG_INFO, 'FreshRSS actualize ' . $myUser); if (defined('STDOUT')) { fwrite(STDOUT, 'Actualize ' . $myUser . "...\n"); //Unbuffered diff --git a/lib/Minz/Configuration.php b/lib/Minz/Configuration.php index 9511cb357..6cbc9fc0b 100644 --- a/lib/Minz/Configuration.php +++ b/lib/Minz/Configuration.php @@ -64,6 +64,7 @@ class Minz_Configuration { private static $limits = array( 'cache_duration' => 800, //SimplePie cache duration in seconds 'timeout' => 10, //SimplePie timeout in seconds + 'max_inactivity' => PHP_INT_MAX, //Time in seconds after which a user who has not used the account is considered inactive (no auto-refresh of feeds). 'max_feeds' => Minz_Configuration::MAX_SMALL_INT, 'max_categories' => Minz_Configuration::MAX_SMALL_INT, ); @@ -317,6 +318,12 @@ class Minz_Configuration { self::$limits['timeout'] = $v; } } + if (isset($limits['max_inactivity'])) { + $v = intval($limits['max_inactivity']); + if ($v > 0) { + self::$limits['max_inactivity'] = $v; + } + } if (isset($limits['max_feeds'])) { $v = intval($limits['max_feeds']); if ($v > 0 && $v < Minz_Configuration::MAX_SMALL_INT) { -- cgit v1.2.3 From d20b5a127fe95f91b55f3ae9391365c67f96c4cc Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Wed, 29 Oct 2014 11:47:51 +0100 Subject: Fix limit in import Json files See https://github.com/marienfressinaud/FreshRSS/issues/680 --- app/Controllers/importExportController.php | 28 +++++++++++++++++++++++++--- app/Models/FeedDAO.php | 2 +- 2 files changed, 26 insertions(+), 4 deletions(-) (limited to 'app/Models') diff --git a/app/Controllers/importExportController.php b/app/Controllers/importExportController.php index 514077bbd..8028af8ed 100644 --- a/app/Controllers/importExportController.php +++ b/app/Controllers/importExportController.php @@ -327,12 +327,34 @@ class FreshRSS_importExport_Controller extends Minz_ActionController { $error = false; $article_to_feed = array(); + $nb_feeds = count($this->feedDAO->listFeeds()); + $limits = Minz_Configuration::limits(); + // First, we check feeds of articles are in DB (and add them if needed). foreach ($article_object['items'] as $item) { - $feed = $this->addFeedJson($item['origin'], $google_compliant); + $key = $google_compliant ? 'htmlUrl' : 'feedUrl'; + $feed = new FreshRSS_Feed($item['origin'][$key]); + $feed = $this->feedDAO->searchByUrl($feed->url()); + if (is_null($feed)) { - $error = true; - } else { + // Feed does not exist in DB,we should to try to add it. + if ($nb_feeds >= $limits['max_feeds']) { + // Oops, no more place! + Minz_Log::warning(_t('sub.feeds.over_max', $limits['max_feeds'])); + } else { + $feed = $this->addFeedJson($item['origin'], $google_compliant); + } + + if (is_null($feed)) { + // Still null? It means something went wrong. + $error = true; + } else { + // Nice! Increase the counter. + $nb_feeds += 1; + } + } + + if (!is_null($feed)) { $article_to_feed[$item['id']] = $feed->id(); } } diff --git a/app/Models/FeedDAO.php b/app/Models/FeedDAO.php index 852de6e36..74597c730 100644 --- a/app/Models/FeedDAO.php +++ b/app/Models/FeedDAO.php @@ -191,7 +191,7 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo { $res = $stm->fetchAll(PDO::FETCH_ASSOC); $feed = current(self::daoToFeed($res)); - if (isset($feed)) { + if (isset($feed) && $feed !== false) { return $feed; } else { return null; -- cgit v1.2.3
     
    conf->topline_read ? ' checked="checked"' : ''; ?> /> conf->topline_favorite ? ' checked="checked"' : ''; ?> /> conf->topline_date ? ' checked="checked"' : ''; ?> /> conf->topline_link ? ' checked="checked"' : ''; ?> />
    conf->bottomline_read ? ' checked="checked"' : ''; ?> /> conf->bottomline_favorite ? ' checked="checked"' : ''; ?> /> conf->bottomline_sharing ? ' checked="checked"' : ''; ?> />