From 8a7bab3a55442f85553ab1d897084e89c10f7e05 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Mon, 20 Oct 2014 19:35:22 +0200 Subject: Refactoring of indexController Global view has been moved to a different action (all is not working) See https://github.com/marienfressinaud/FreshRSS/issues/634 and https://github.com/marienfressinaud/FreshRSS/issues/655 --- app/Controllers/errorController.php | 2 +- app/Controllers/indexController.php | 33 +++++++++++++++++++++++++-------- 2 files changed, 26 insertions(+), 9 deletions(-) (limited to 'app/Controllers') diff --git a/app/Controllers/errorController.php b/app/Controllers/errorController.php index 76ab930e0..6c080bea8 100644 --- a/app/Controllers/errorController.php +++ b/app/Controllers/errorController.php @@ -37,7 +37,7 @@ class FreshRSS_error_Controller extends Minz_ActionController { if ($this->view->errorMessage == '') { switch($code_int) { case 403: - $this->view->errorMessage = _t('forbidden_access'); + $this->view->errorMessage = _t('access_denied'); break; case 404: default: diff --git a/app/Controllers/indexController.php b/app/Controllers/indexController.php index f994e257c..e1ce71b28 100755 --- a/app/Controllers/indexController.php +++ b/app/Controllers/indexController.php @@ -1,5 +1,8 @@ array(_t('access_denied'))) - ); + Minz_Error::error(403); return; } elseif ($output !== 'rss') { // "hard" redirection is not required, just ask dispatcher to @@ -201,17 +201,34 @@ class FreshRSS_index_Controller extends Minz_ActionController { return false; } } + + /** + * This action displays the global view of FreshRSS. + */ + public function globalAction() { + if (!FreshRSS_Auth::hasAccess() && !Minz_Configuration::allowAnonymous()) { + Minz_Error::error(403); + } + + 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(); + } + /** + * This action displays the about page of FreshRSS. + */ public function aboutAction() { Minz_View::prependTitle(_t('about') . ' · '); } + /** + * This action displays logs of FreshRSS for the current user. + */ public function logsAction() { if (!FreshRSS_Auth::hasAccess()) { - Minz_Error::error( - 403, - array('error' => array(_t('access_denied'))) - ); + Minz_Error::error(403); } Minz_View::prependTitle(_t('logs') . ' · '); -- 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/Controllers') 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/Controllers') 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 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/Controllers') 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/Controllers') 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/Controllers') 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 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/Controllers') 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 0d6993fe08cf57121eadb2aa0e4208420756165a Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Fri, 24 Oct 2014 12:51:17 +0200 Subject: Reader view comes back! See https://github.com/marienfressinaud/FreshRSS/issues/634 --- app/Controllers/indexController.php | 9 +++++++ app/layout/nav_menu.phtml | 5 ++++ app/views/helpers/view/reader_view.phtml | 44 -------------------------------- app/views/index/reader.phtml | 44 ++++++++++++++++++++++++++++++++ 4 files changed, 58 insertions(+), 44 deletions(-) delete mode 100644 app/views/helpers/view/reader_view.phtml create mode 100644 app/views/index/reader.phtml (limited to 'app/Controllers') diff --git a/app/Controllers/indexController.php b/app/Controllers/indexController.php index ed5b58b45..8bc23fb70 100755 --- a/app/Controllers/indexController.php +++ b/app/Controllers/indexController.php @@ -69,6 +69,15 @@ class FreshRSS_index_Controller extends Minz_ActionController { Minz_View::prependTitle($title . ' · '); } + /** + * This action displays the reader view of FreshRSS. + * + * @todo: change this view into specific CSS rules? + */ + public function readerAction() { + $this->normalAction(); + } + /** * This action displays the global view of FreshRSS. */ diff --git a/app/layout/nav_menu.phtml b/app/layout/nav_menu.phtml index 6f555c3d0..075f84ca6 100644 --- a/app/layout/nav_menu.phtml +++ b/app/layout/nav_menu.phtml @@ -133,6 +133,11 @@ + + + + + diff --git a/app/views/helpers/view/reader_view.phtml b/app/views/helpers/view/reader_view.phtml deleted file mode 100644 index 821a50f7f..000000000 --- a/app/views/helpers/view/reader_view.phtml +++ /dev/null @@ -1,44 +0,0 @@ -partial('nav_menu'); - -if (!empty($this->entries)) { - $lazyload = FreshRSS_Context::$conf->lazyload; - $content_width = FreshRSS_Context::$conf->content_width; -?> - -
- entries as $item) { ?> - -
-
-
- cat_aside, $item->feed()); //We most likely already have the feed object in cache - if (empty($feed)) $feed = $item->feed(true); - ?> - - ✇ name(); ?> - -

title(); ?>

- -
author(); - echo $author != '' ? _t('by_author', $author) . ' — ' : '', - $item->date(); - ?>
- - content(); ?> -
-
-
- - - renderHelper('pagination'); ?> -
- - -
-

-

-
- diff --git a/app/views/index/reader.phtml b/app/views/index/reader.phtml new file mode 100644 index 000000000..f07868488 --- /dev/null +++ b/app/views/index/reader.phtml @@ -0,0 +1,44 @@ +partial('nav_menu'); + +if (!empty($this->entries)) { + $lazyload = FreshRSS_Context::$conf->lazyload; + $content_width = FreshRSS_Context::$conf->content_width; +?> + +
+ entries as $item) { ?> + +
+
+
+ categories, $item->feed()); //We most likely already have the feed object in cache + if (empty($feed)) $feed = $item->feed(true); + ?> + + ✇ name(); ?> + +

title(); ?>

+ +
author(); + echo $author != '' ? _t('by_author', $author) . ' — ' : '', + $item->date(); + ?>
+ + content(); ?> +
+
+
+ + + renderHelper('pagination'); ?> +
+ + +
+

+

+
+ -- cgit v1.2.3 From 83d95ca4b894a84de467a97c7f413c1d04c43631 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Fri, 24 Oct 2014 15:11:02 +0200 Subject: Fix titles for normal and global views See https://github.com/marienfressinaud/FreshRSS/issues/634 --- app/Controllers/indexController.php | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'app/Controllers') diff --git a/app/Controllers/indexController.php b/app/Controllers/indexController.php index 8bc23fb70..1cf618f7f 100755 --- a/app/Controllers/indexController.php +++ b/app/Controllers/indexController.php @@ -64,7 +64,7 @@ class FreshRSS_index_Controller extends Minz_ActionController { $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; + $title = '(' . FreshRSS_Context::$get_unread . ') ' . $title; } Minz_View::prependTitle($title . ' · '); } @@ -98,7 +98,11 @@ class FreshRSS_index_Controller extends Minz_ActionController { $this->view->categories = FreshRSS_Context::$categories; $this->view->rss_title = FreshRSS_Context::$name . ' | ' . Minz_View::title(); - Minz_View::prependTitle(_t('gen.title.global_view') . ' · '); + $title = _t('gen.title.global_view'); + if (FreshRSS_Context::$get_unread > 0) { + $title = '(' . FreshRSS_Context::$get_unread . ') ' . $title; + } + Minz_View::prependTitle($title . ' · '); } /** -- cgit v1.2.3 From 5d6407a0bf0ecee7017f9d6c6c110b7afa98fff0 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Sun, 26 Oct 2014 12:22:13 +0100 Subject: Update i18n - Fix i18n strings - Fix typo profil -> profile See https://github.com/marienfressinaud/FreshRSS/issues/678 --- app/Controllers/authController.php | 6 ++-- app/Controllers/userController.php | 16 +++++------ app/i18n/en.php | 16 +++++++---- app/i18n/fr.php | 16 +++++++---- app/layout/aside_configure.phtml | 6 ++-- app/layout/header.phtml | 4 +-- app/views/user/profil.phtml | 59 -------------------------------------- app/views/user/profile.phtml | 59 ++++++++++++++++++++++++++++++++++++++ 8 files changed, 97 insertions(+), 85 deletions(-) delete mode 100644 app/views/user/profil.phtml create mode 100644 app/views/user/profile.phtml (limited to 'app/Controllers') diff --git a/app/Controllers/authController.php b/app/Controllers/authController.php index 4af39cb71..a08f906e3 100644 --- a/app/Controllers/authController.php +++ b/app/Controllers/authController.php @@ -143,7 +143,7 @@ class FreshRSS_auth_Controller extends Minz_ActionController { } // All is good, go back to the index. - Minz_Request::good(_t('login'), + Minz_Request::good(_t('feedback.login.success'), array('c' => 'index', 'a' => 'index')); } else { Minz_Log::warning('Password mismatch for' . @@ -182,7 +182,7 @@ class FreshRSS_auth_Controller extends Minz_ActionController { Minz_Session::_param('passwordHash', $s); FreshRSS_Auth::giveAccess(); - Minz_Request::good(_t('login'), + Minz_Request::good(_t('feedback.login.success'), array('c' => 'index', 'a' => 'index')); } else { Minz_Log::warning('Unsafe password mismatch for user ' . $username); @@ -274,7 +274,7 @@ class FreshRSS_auth_Controller extends Minz_ActionController { public function logoutAction() { invalidateHttpCache(); FreshRSS_Auth::removeAccess(); - Minz_Request::good(_t('disconnected'), + Minz_Request::good(_t('feedback.logout.success'), array('c' => 'index', 'a' => 'index')); } diff --git a/app/Controllers/userController.php b/app/Controllers/userController.php index 61d33437d..2343520ca 100644 --- a/app/Controllers/userController.php +++ b/app/Controllers/userController.php @@ -23,10 +23,10 @@ class FreshRSS_user_Controller extends Minz_ActionController { } /** - * This action displays the user profil page. + * This action displays the user profile page. */ - public function profilAction() { - Minz_View::prependTitle(_t('users.profil') . ' · '); + public function profileAction() { + Minz_View::prependTitle(_t('gen.title.user_profile') . ' · '); if (Minz_Request::isPost()) { $ok = true; @@ -74,11 +74,11 @@ class FreshRSS_user_Controller extends Minz_ActionController { } if ($ok) { - Minz_Request::good('users.profil.updated', - array('c' => 'user', 'a' => 'profil')); + Minz_Request::good(_t('feedback.user_profile.updated'), + array('c' => 'user', 'a' => 'profile')); } else { - Minz_Request::bad('error_occurred', - array('c' => 'user', 'a' => 'profil')); + Minz_Request::bad(_t('error_occurred'), + array('c' => 'user', 'a' => 'profile')); } } } @@ -92,7 +92,7 @@ class FreshRSS_user_Controller extends Minz_ActionController { array('error' => array(_t('access_denied')))); } - Minz_View::prependTitle(_t('users.manage') . ' · '); + Minz_View::prependTitle(_t('gen.title.user_management') . ' · '); // Get the correct current user. $userDAO = new FreshRSS_UserDAO(); diff --git a/app/i18n/en.php b/app/i18n/en.php index a3593b28c..275471e19 100644 --- a/app/i18n/en.php +++ b/app/i18n/en.php @@ -196,6 +196,10 @@ 'Feb' => '\\F\\e\\b\\r\\u\\a\\r\\y', 'february' => 'Feb', 'feed' => 'Feed', + 'feedback.login.error' => 'Login is invalid', + 'feedback.login.success' => 'You are connected', + 'feedback.logout.success' => 'You are disconnected', + 'feedback.user_profile.updated' => 'Your profile has been modified', 'feeds' => 'Feeds', 'feeds_actualized' => 'RSS feeds have been updated', 'feeds_imported' => 'Your feeds have been imported and will now be updated', @@ -233,10 +237,12 @@ 'gen.menu.admin' => 'Administration', 'gen.menu.authentication' => 'Authentication', 'gen.menu.check_install' => 'Installation checking', - 'gen.menu.manage_users' => 'Manage users', - 'gen.menu.profil' => 'Profil', + 'gen.menu.user_management' => 'Manage users', + 'gen.menu.user_profile' => 'Profile', 'gen.title.check_install' => 'Installation checking', 'gen.title.global_view' => 'Global view', + 'gen.title.user_management' => 'Manage users', + 'gen.title.user_profile' => 'Profile', 'general_configuration' => 'General configuration', 'general_conf_is_ok' => 'General configuration has been saved.', 'github_or_email' => 'on Github or by mail', @@ -262,8 +268,8 @@ 'invalid_login' => 'Login is invalid', 'invalid_url' => 'URL %s is invalid', 'is_admin' => 'is administrator', - 'jan' => 'jan', 'Jan' => '\\J\\a\\n\\u\\a\\r\\y', + 'jan' => 'jan', 'january' => 'Jan', 'javascript_for_shortcuts' => 'JavaScript must be enabled in order to use shortcuts', 'javascript_is_better' => 'FreshRSS is more pleasant with JavaScript enabled', @@ -272,8 +278,8 @@ 'Jul' => '\\J\\u\\l\\y', 'july' => 'Jul', 'jump_next' => 'jump to next unread sibling (feed or category)', - 'jun' => 'jun', 'Jun' => '\\J\\u\\n\\e', + 'jun' => 'jun', 'june' => 'Jun', 'keep_history' => 'Minimum number of articles to keep', 'keep_logged_in' => 'Keep me logged in (1 month)', @@ -329,8 +335,8 @@ 'not_read' => '%d unread', 'not_reads' => '%d unread', 'not_yet_implemented' => 'Not yet implemented', - 'nov' => 'nov', 'Nov' => '\\N\\o\\v\\e\\m\\b\\e\\r', + 'nov' => 'nov', 'november' => 'Nov', 'no_feed_actualized' => 'No RSS feed has been updated', 'no_feed_to_display' => 'There is no article to show.', diff --git a/app/i18n/fr.php b/app/i18n/fr.php index 60b7a4682..e3a49d54c 100644 --- a/app/i18n/fr.php +++ b/app/i18n/fr.php @@ -196,6 +196,10 @@ 'Feb' => '\\f\\é\\v\\r\\i\\e\\r', 'february' => 'février', 'feed' => 'Flux', + 'feedback.login.error' => 'L’identifiant est invalide !', + 'feedback.login.success' => 'Vous êtes désormais connecté', + 'feedback.logout.success' => 'Vous avez été déconnecté', + 'feedback.user_profile.updated' => 'Votre profil a été mis à jour', 'feeds' => 'Flux', 'feeds_actualized' => 'Les flux ont été mis à jour.', 'feeds_imported' => 'Vos flux ont été importés et vont maintenant être actualisés.', @@ -233,10 +237,12 @@ 'gen.menu.admin' => 'Administration', 'gen.menu.authentication' => 'Authentification', 'gen.menu.check_install' => 'Vérification de l\'installation', - 'gen.menu.manage_users' => 'Gestion des utilisateurs', - 'gen.menu.profil' => 'Profil', + 'gen.menu.user_management' => 'Gestion des utilisateurs', + 'gen.menu.user_profile' => 'Profil', 'gen.title.check_install' => 'Vérification de l\'installation', 'gen.title.global_view' => 'Vue globale', + 'gen.title.user_management' => 'Gestion des utilisateurs', + 'gen.title.user_profile' => 'Profil', 'general_configuration' => 'Configuration générale', 'general_conf_is_ok' => 'La configuration générale a été enregistrée.', 'github_or_email' => 'sur Github ou par courriel', @@ -262,8 +268,8 @@ 'invalid_login' => 'L’identifiant est invalide !', 'invalid_url' => 'L’url %s est invalide.', 'is_admin' => 'est administrateur', - 'jan' => 'jan.', 'Jan' => '\\j\\a\\n\\v\\i\\e\\r', + 'jan' => 'jan.', 'january' => 'janvier', 'javascript_for_shortcuts' => 'Le JavaScript doit être activé pour pouvoir profiter des raccourcis.', 'javascript_is_better' => 'FreshRSS est plus agréable à utiliser avec JavaScript activé', @@ -272,8 +278,8 @@ 'Jul' => '\\j\\u\\i\\l\\l\\e\\t', 'july' => 'juillet', 'jump_next' => 'sauter au prochain voisin non lu (flux ou catégorie)', - 'jun' => 'juin', 'Jun' => '\\j\\u\\i\\n', + 'jun' => 'juin', 'june' => 'juin', 'keep_history' => 'Nombre minimum d’articles à conserver', 'keep_logged_in' => 'Rester connecté (1 mois)', @@ -329,8 +335,8 @@ 'not_read' => '%d non lu', 'not_reads' => '%d non lus', 'not_yet_implemented' => 'Pas encore implémenté', - 'nov' => 'nov.', 'Nov' => '\\n\\o\\v\\e\\m\\b\\r\\e', + 'nov' => 'nov.', 'november' => 'novembre', 'no_feed_actualized' => 'Aucun flux n’a pu être mis à jour.', 'no_feed_to_display' => 'Il n’y a aucun article à afficher.', diff --git a/app/layout/aside_configure.phtml b/app/layout/aside_configure.phtml index 32dc19a4e..53c52d3e3 100644 --- a/app/layout/aside_configure.phtml +++ b/app/layout/aside_configure.phtml @@ -19,14 +19,14 @@
  • - + Minz_Request::actionName() === 'profile'? ' active' : ''; ?>"> +
  • - +
  • diff --git a/app/layout/header.phtml b/app/layout/header.phtml index 506cec175..c73d9cdbb 100644 --- a/app/layout/header.phtml +++ b/app/layout/header.phtml @@ -62,11 +62,11 @@ if (Minz_Configuration::canLogIn()) {
  • -
  • +
  • -
  • +
  • diff --git a/app/views/user/profil.phtml b/app/views/user/profil.phtml deleted file mode 100644 index a2af53c96..000000000 --- a/app/views/user/profil.phtml +++ /dev/null @@ -1,59 +0,0 @@ -partial('aside_configure'); ?> - -
    - - -
    - - -
    - -
    - - -
    -
    - -
    - -
    -
    - /> - -
    - -
    -
    - - -
    - -
    -
    - /> - -
    -
    -
    - - -
    - - mail_login; ?> -
    - placeholder="alice@example.net" /> - -
    -
    - -
    -
    - - -
    -
    -
    -
    diff --git a/app/views/user/profile.phtml b/app/views/user/profile.phtml new file mode 100644 index 000000000..60257012c --- /dev/null +++ b/app/views/user/profile.phtml @@ -0,0 +1,59 @@ +partial('aside_configure'); ?> + +
    + + +
    + + +
    + +
    + + +
    +
    + +
    + +
    +
    + /> + +
    + +
    +
    + + +
    + +
    +
    + /> + +
    +
    +
    + + +
    + + mail_login; ?> +
    + placeholder="alice@example.net" /> + +
    +
    + +
    +
    + + +
    +
    +
    +
    -- cgit v1.2.3 From 4dec7bf127fdb71c78d09bb4f64995028a60c439 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Sun, 26 Oct 2014 12:37:38 +0100 Subject: Fix i18n string Order has been changed due to a little bug in sort order function. --- app/Controllers/authController.php | 6 +- app/i18n/en.php | 109 +++++++++++++++++++------------------ app/i18n/fr.php | 109 +++++++++++++++++++------------------ 3 files changed, 114 insertions(+), 110 deletions(-) (limited to 'app/Controllers') diff --git a/app/Controllers/authController.php b/app/Controllers/authController.php index a08f906e3..491be8d8a 100644 --- a/app/Controllers/authController.php +++ b/app/Controllers/authController.php @@ -23,6 +23,8 @@ class FreshRSS_auth_Controller extends Minz_ActionController { array('error' => array(_t('access_denied')))); } + Minz_View::prependTitle(_t('gen.title.authentication') . ' · '); + if (Minz_Request::isPost()) { $ok = true; @@ -55,10 +57,10 @@ class FreshRSS_auth_Controller extends Minz_ActionController { invalidateHttpCache(); if ($ok) { - Minz_Request::good('configuration_updated', + Minz_Request::good(_t('configuration_updated'), array('c' => 'auth', 'a' => 'index')); } else { - Minz_Request::bad('error_occurred', + Minz_Request::bad(_t('error_occurred'), array('c' => 'auth', 'a' => 'index')); } } diff --git a/app/i18n/en.php b/app/i18n/en.php index 275471e19..1e6621c12 100644 --- a/app/i18n/en.php +++ b/app/i18n/en.php @@ -1,5 +1,17 @@ '\\A\\p\\r\\i\\l', + 'Aug' => '\\A\\u\\g\\u\\s\\t', + 'Dec' => '\\D\\e\\c\\e\\m\\b\\e\\r', + 'Feb' => '\\F\\e\\b\\r\\u\\a\\r\\y', + 'Jan' => '\\J\\a\\n\\u\\a\\r\\y', + 'Jul' => '\\J\\u\\l\\y', + 'Jun' => '\\J\\u\\n\\e', + 'Mar' => '\\M\\a\\r\\c\\h', + 'May' => '\\M\\a\\y', + 'Nov' => '\\N\\o\\v\\e\\m\\b\\e\\r', + 'Oct' => '\\O\\c\\t\\o\\b\\e\\r', + 'Sep' => '\\S\\e\\p\\t\\e\\m\\b\\e\\r', 'about' => 'About', 'about_freshrss' => 'About FreshRSS', 'access_denied' => 'You don’t have permission to access this page', @@ -61,42 +73,40 @@ 'advanced' => 'Advanced', 'after_onread' => 'After “mark all as read”,', 'agpl3' => 'AGPL 3', + 'all_feeds' => 'All feeds', 'allow_anonymous' => 'Allow anonymous reading of the articles of the default user (%s)', 'allow_anonymous_refresh' => 'Allow anonymous refresh of the articles', - 'all_feeds' => 'All feeds', 'already_subscribed' => 'You have already subscribed to %s', 'api_enabled' => 'Allow API access (required for mobile apps)', - 'Apr' => '\\A\\p\\r\\i\\l', 'apr' => 'apr', 'april' => 'Apr', 'archiving_configuration' => 'Archiving', 'archiving_configuration_help' => 'More options are available in the individual stream settings', 'article' => 'Article', - 'articles' => 'articles', - 'articles_per_page' => 'Number of articles per page', - 'articles_to_display' => 'Articles to display', 'article_icons' => 'Article icons', 'article_open_on_website' => 'when article is opened on its original website', 'article_published_on' => 'This article originally appeared on %s', 'article_published_on_author' => 'This article originally appeared on %s by %s', 'article_viewed' => 'when article is viewed', + 'articles' => 'articles', + 'articles_per_page' => 'Number of articles per page', + 'articles_to_display' => 'Articles to display', 'ask_empty' => 'Clear?', 'attention' => 'Attention!', - 'Aug' => '\\A\\u\\g\\u\\s\\t', 'aug' => 'aug', 'august' => 'Aug', - 'author' => 'Author', 'auth_form' => 'Web form (traditional, requires JavaScript)', 'auth_form_not_set' => 'A problem occured during authentication system configuration. Please retry later.', 'auth_form_set' => 'Form is now your default authentication system.', + 'auth_no_password_set' => 'Administrator password hasn’t been set. This feature isn’t available.', 'auth_none' => 'None (dangerous)', 'auth_not_persona' => 'Only Persona system can be reset.', - 'auth_no_password_set' => 'Administrator password hasn’t been set. This feature isn’t available.', 'auth_persona' => 'Mozilla Persona (modern, requires JavaScript)', 'auth_reset' => 'Authentication reset', 'auth_token' => 'Authentication token', 'auth_type' => 'Authentication method', 'auth_will_reset' => 'Authentication system will be reset: a form will be used instead of Persona.', + 'author' => 'Author', 'auto_load_more' => 'Load next articles at the page bottom', 'auto_read_when' => 'Mark article as read…', 'auto_share' => 'Share', @@ -105,9 +115,9 @@ 'bad_opml_file' => 'Your OPML file is invalid', 'base_url' => 'Base URL', 'bdd' => 'Database', - 'bdd_configuration' => 'Database configuration', 'bdd_conf_is_ko' => 'Verify your database information.', 'bdd_conf_is_ok' => 'Database configuration has been saved.', + 'bdd_configuration' => 'Database configuration', 'bdd_type' => 'Type of database', 'before_one_day' => 'Before one day', 'before_one_week' => 'Before one week', @@ -123,8 +133,8 @@ 'by_email' => 'By email', 'by_feed' => 'by feed', 'cache_is_ok' => 'Permissions on cache directory are good', - 'cancel' => 'Cancel', 'can_not_be_deleted' => 'Cannot be deleted', + 'cancel' => 'Cancel', 'categories' => 'Categories', 'categories_management' => 'Categories management', 'categories_updated' => 'Categories have been updated', @@ -135,10 +145,10 @@ 'category_emptied' => 'Category has been emptied', 'category_empty' => 'Empty category', 'category_name_exists' => 'Category name already exists.', - 'category_not_delete_default' => 'You cannot delete the default category!', - 'category_not_exist' => 'The category does not exist!', 'category_no_id' => 'You must precise the id of the category.', 'category_no_name' => 'Category name cannot be empty.', + 'category_not_delete_default' => 'You cannot delete the default category!', + 'category_not_exist' => 'The category does not exist!', 'category_number' => 'Category n°%d', 'category_updated' => 'Category has been updated.', 'change_value' => 'You should change this value by any other', @@ -165,7 +175,6 @@ 'current_user' => 'Current user', 'damn' => 'Damn!', 'data_is_ok' => 'Permissions on data directory are good', - 'Dec' => '\\D\\e\\c\\e\\m\\b\\e\\r', 'dec' => 'dec', 'december' => 'Dec', 'default_category' => 'Uncategorized', @@ -178,9 +187,9 @@ 'display_articles_unfolded' => 'Show articles unfolded by default', 'display_categories_unfolded' => 'Show categories folded by default', 'display_configuration' => 'Display', + 'do_not_change_if_doubt' => 'Don’t change if you doubt about it', 'dom_is_nok' => 'You lack a required library to browse the DOM (php-xml package)', 'dom_is_ok' => 'You have the required library to browse the DOM', - 'do_not_change_if_doubt' => 'Don’t change if you doubt about it', 'email' => 'Email', 'error_occurred' => 'An error occurred', 'error_occurred_update' => 'Nothing was changed', @@ -193,19 +202,8 @@ 'favicons_is_ok' => 'Permissions on favicons directory are good', 'favorite_feeds' => 'Favourites (%s)', 'feb' => 'feb', - 'Feb' => '\\F\\e\\b\\r\\u\\a\\r\\y', 'february' => 'Feb', 'feed' => 'Feed', - 'feedback.login.error' => 'Login is invalid', - 'feedback.login.success' => 'You are connected', - 'feedback.logout.success' => 'You are disconnected', - 'feedback.user_profile.updated' => 'Your profile has been modified', - 'feeds' => 'Feeds', - 'feeds_actualized' => 'RSS feeds have been updated', - 'feeds_imported' => 'Your feeds have been imported and will now be updated', - 'feeds_imported_with_errors' => 'Your feeds have been imported but some errors occurred', - 'feeds_marked_read' => 'Feeds have been marked as read', - 'feeds_moved_category_deleted' => 'When you delete a category, their feeds are automatically classified under %s.', 'feed_actualized' => '%s has been updated', 'feed_added' => 'RSS feed %s has been added', 'feed_deleted' => 'Feed has been deleted', @@ -217,6 +215,16 @@ 'feed_updated' => 'Feed has been updated', 'feed_url' => 'Feed URL', 'feed_validator' => 'Check the validity of the feed', + 'feedback.login.error' => 'Login is invalid', + 'feedback.login.success' => 'You are connected', + 'feedback.logout.success' => 'You are disconnected', + 'feedback.user_profile.updated' => 'Your profile has been modified', + 'feeds' => 'Feeds', + 'feeds_actualized' => 'RSS feeds have been updated', + 'feeds_imported' => 'Your feeds have been imported and will now be updated', + 'feeds_imported_with_errors' => 'Your feeds have been imported but some errors occurred', + 'feeds_marked_read' => 'Feeds have been marked as read', + 'feeds_moved_category_deleted' => 'When you delete a category, their feeds are automatically classified under %s.', 'file_cannot_be_uploaded' => 'File cannot be uploaded!', 'file_is_nok' => 'Check permissions on %s directory. HTTP server must have rights to write into', 'file_to_import' => 'File to import
    (OPML, Json or Zip)', @@ -239,12 +247,13 @@ 'gen.menu.check_install' => 'Installation checking', 'gen.menu.user_management' => 'Manage users', 'gen.menu.user_profile' => 'Profile', + 'gen.title.authentication' => 'Authentication', 'gen.title.check_install' => 'Installation checking', 'gen.title.global_view' => 'Global view', 'gen.title.user_management' => 'Manage users', 'gen.title.user_profile' => 'Profile', - 'general_configuration' => 'General configuration', 'general_conf_is_ok' => 'General configuration has been saved.', + 'general_configuration' => 'General configuration', 'github_or_email' => 'on Github or by mail', 'global_view' => 'Global view', 'help' => 'Display documentation', @@ -261,24 +270,21 @@ 'import' => 'Import', 'import_export' => 'Import / export', 'informations' => 'Information', + 'install_not_deleted' => 'Something went wrong; you must delete the file %s manually.', 'installation_is_ok' => 'The installation process was successful.
    The final step will now attempt to delete any file and database backup created during the update process.
    You may choose to skip this step by deleting ./data/do-install.txt manually.', 'installation_step' => 'Installation — step %d · FreshRSS', - 'install_not_deleted' => 'Something went wrong; you must delete the file %s manually.', 'internal_problem_feed' => 'The RSS feed could not be added. Check FressRSS logs for details.', 'invalid_login' => 'Login is invalid', 'invalid_url' => 'URL %s is invalid', 'is_admin' => 'is administrator', - 'Jan' => '\\J\\a\\n\\u\\a\\r\\y', 'jan' => 'jan', 'january' => 'Jan', 'javascript_for_shortcuts' => 'JavaScript must be enabled in order to use shortcuts', 'javascript_is_better' => 'FreshRSS is more pleasant with JavaScript enabled', 'javascript_should_be_activated' => 'JavaScript must be enabled', 'jul' => 'jul', - 'Jul' => '\\J\\u\\l\\y', 'july' => 'Jul', 'jump_next' => 'jump to next unread sibling (feed or category)', - 'Jun' => '\\J\\u\\n\\e', 'jun' => 'jun', 'june' => 'Jun', 'keep_history' => 'Minimum number of articles to keep', @@ -295,6 +301,7 @@ 'lead_developer' => 'Lead developer', 'license' => 'License', 'load_more' => 'Load more articles', + 'log_is_ok' => 'Permissions on logs directory are good', 'login' => 'Login', 'login_configuration' => 'Login', 'login_persona_problem' => 'Connection problem with Persona?', @@ -303,41 +310,30 @@ 'logout' => 'Logout', 'logs' => 'Logs', 'logs_empty' => 'Log file is empty', - 'log_is_ok' => 'Permissions on logs directory are good', 'main_stream' => 'Main stream', 'mar' => 'mar', - 'Mar' => '\\M\\a\\r\\c\\h', 'march' => 'Mar', 'mark_all_read' => 'Mark all as read', 'mark_cat_read' => 'Mark category as read', 'mark_favorite' => 'Mark as favourite', 'mark_feed_read' => 'Mark feed as read', 'mark_read' => 'Mark as read', - 'May' => '\\M\\a\\y', 'may' => 'May', 'minz_is_nok' => 'You lack the Minz framework. You should execute build.sh script or download it on Github and install in %s directory the content of its /lib directory.', 'minz_is_ok' => 'You have the Minz framework', 'mon' => 'Mon', 'month' => 'months', 'more_information' => 'More information', - 'newer_first' => 'Newer first', + 'n_entries_deleted' => '%d articles have been deleted', + 'n_feeds_actualized' => '%d feeds have been updated', 'new_article' => 'There are new available articles, click to refresh the page.', 'new_category' => 'New category', + 'newer_first' => 'Newer first', 'next' => 'Next', 'next_article' => 'Skip to the next article', 'next_page' => 'Skip to the next page', 'next_step' => 'Go to the next step', 'no' => 'No', - 'normal_view' => 'Normal view', - 'nothing_to_load' => 'There are no more articles', - 'notif_body_new_articles' => 'There are \\d new articles to read on FreshRSS.', - 'notif_title_new_articles' => 'FreshRSS: new articles!', - 'not_read' => '%d unread', - 'not_reads' => '%d unread', - 'not_yet_implemented' => 'Not yet implemented', - 'Nov' => '\\N\\o\\v\\e\\m\\b\\e\\r', - 'nov' => 'nov', - 'november' => 'Nov', 'no_feed_actualized' => 'No RSS feed has been updated', 'no_feed_to_display' => 'There is no article to show.', 'no_feed_to_refresh' => 'There is no feed to refresh…', @@ -347,12 +343,18 @@ 'no_selected_feed' => 'No feed selected.', 'no_update' => 'No update to apply', 'no_zip_extension' => 'Zip extension is not present on your server.', + 'normal_view' => 'Normal view', + 'not_read' => '%d unread', + 'not_reads' => '%d unread', + 'not_yet_implemented' => 'Not yet implemented', + 'nothing_to_load' => 'There are no more articles', + 'notif_body_new_articles' => 'There are \\d new articles to read on FreshRSS.', + 'notif_title_new_articles' => 'FreshRSS: new articles!', + 'nov' => 'nov', + 'november' => 'Nov', 'number_articles' => '%d articles', 'number_divided_when_reader' => 'Divided by 2 in the reading view.', 'number_feeds' => '%d feeds', - 'n_entries_deleted' => '%d articles have been deleted', - 'n_feeds_actualized' => '%d feeds have been updated', - 'Oct' => '\\O\\c\\t\\o\\b\\e\\r', 'oct' => 'oct', 'october' => 'Oct', 'ok' => 'Ok!', @@ -419,8 +421,8 @@ 'refresh' => 'Refresh', 'related_tags' => 'Related tags', 'retrieve_truncated_feeds' => 'Retrieves truncated RSS feeds (attention, requires more time!)', - 'rss_feeds_of' => 'RSS feed of %s', 'rss_feed_management' => 'RSS feeds management', + 'rss_feeds_of' => 'RSS feed of %s', 'rss_view' => 'RSS feed', 'sat' => 'Sat', 'save' => 'Save', @@ -431,7 +433,6 @@ 'see_on_website' => 'See on original website', 'see_website' => 'See website', 'sep' => 'sep', - 'Sep' => '\\S\\e\\p\\t\\e\\m\\b\\e\\r', 'september' => 'Sep', 'shaarli' => 'Shaarli', 'share' => 'Share', @@ -492,7 +493,6 @@ 'twitter' => 'Twitter', 'unsafe_autologin' => 'Allow unsafe automatic login using the format: ', 'update' => 'Update', - 'updated' => 'Modifications have been updated', 'update_apply' => 'Apply', 'update_can_apply' => 'An update is available.', 'update_check' => 'Check for new updates', @@ -504,15 +504,16 @@ 'update_server_not_found' => 'Update server cannot be found. [%s]', 'update_start' => 'Start update process', 'update_system' => 'Update system', + 'updated' => 'Modifications have been updated', 'upon_reception' => 'upon reception of the article', - 'username' => 'Username', - 'username_admin' => 'Administrator username', - 'users' => 'Users', - 'users_list' => 'List of users', 'user_created' => 'User %s has been created', 'user_deleted' => 'User %s has been deleted', '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.', + 'username' => 'Username', + 'username_admin' => 'Administrator username', + 'users' => 'Users', + 'users_list' => 'List of users', 'version' => 'Version', 'version_update' => 'Update', 'wallabag' => 'wallabag', diff --git a/app/i18n/fr.php b/app/i18n/fr.php index e3a49d54c..61a84cc04 100644 --- a/app/i18n/fr.php +++ b/app/i18n/fr.php @@ -1,5 +1,17 @@ '\\a\\v\\r\\i\\l', + 'Aug' => '\\a\\o\\û\\t', + 'Dec' => '\\d\\é\\c\\e\\m\\b\\r\\e', + 'Feb' => '\\f\\é\\v\\r\\i\\e\\r', + 'Jan' => '\\j\\a\\n\\v\\i\\e\\r', + 'Jul' => '\\j\\u\\i\\l\\l\\e\\t', + 'Jun' => '\\j\\u\\i\\n', + 'Mar' => '\\m\\a\\r\\s', + 'May' => '\\m\\a\\i', + 'Nov' => '\\n\\o\\v\\e\\m\\b\\r\\e', + 'Oct' => '\\o\\c\\t\\o\\b\\r\\e', + 'Sep' => '\\s\\e\\p\\t\\e\\m\\b\\r\\e', 'about' => 'À propos', 'about_freshrss' => 'À propos de FreshRSS', 'access_denied' => 'Vous n’avez pas le droit d’accéder à cette page !', @@ -61,42 +73,40 @@ 'advanced' => 'Avancé', 'after_onread' => 'Après “marquer tout comme lu”,', 'agpl3' => 'AGPL 3', + 'all_feeds' => 'Tous les flux', 'allow_anonymous' => 'Autoriser la lecture anonyme des articles de l’utilisateur par défaut (%s)', 'allow_anonymous_refresh' => 'Autoriser le rafraîchissement anonyme des flux', - 'all_feeds' => 'Tous les flux', 'already_subscribed' => 'Vous êtes déjà abonné à %s', 'api_enabled' => 'Autoriser l’accès par API (nécessaire pour les applis mobiles)', - 'Apr' => '\\a\\v\\r\\i\\l', 'apr' => 'avr.', 'april' => 'avril', 'archiving_configuration' => 'Archivage', 'archiving_configuration_help' => 'D’autres options sont disponibles dans la configuration individuelle des flux.', 'article' => 'Article', - 'articles' => 'articles', - 'articles_per_page' => 'Nombre d’articles par page', - 'articles_to_display' => 'Articles à afficher', 'article_icons' => 'Icônes d’article', 'article_open_on_website' => 'lorsque l’article est ouvert sur le site d’origine', 'article_published_on' => 'Article publié initialement sur %s', 'article_published_on_author' => 'Article publié initialement sur %s par %s', 'article_viewed' => 'lorsque l’article est affiché', + 'articles' => 'articles', + 'articles_per_page' => 'Nombre d’articles par page', + 'articles_to_display' => 'Articles à afficher', 'ask_empty' => 'Vider ?', 'attention' => 'Attention !', - 'Aug' => '\\a\\o\\û\\t', 'aug' => 'août', 'august' => 'août', - 'author' => 'Auteur', 'auth_form' => 'Formulaire (traditionnel, requiert JavaScript)', 'auth_form_not_set' => 'Un problème est survenu lors de la configuration de votre système d’authentification. Veuillez réessayer plus tard.', 'auth_form_set' => 'Le formulaire est désormais votre système d’authentification.', + 'auth_no_password_set' => 'Aucun mot de passe administrateur n’a été précisé. Cette fonctionnalité n’est pas disponible.', 'auth_none' => 'Aucune (dangereux)', 'auth_not_persona' => 'Seul le système d’authentification Persona peut être réinitialisé.', - 'auth_no_password_set' => 'Aucun mot de passe administrateur n’a été précisé. Cette fonctionnalité n’est pas disponible.', 'auth_persona' => 'Mozilla Persona (moderne, requiert JavaScript)', 'auth_reset' => 'Réinitialisation de l’authentification', 'auth_token' => 'Jeton d’identification', 'auth_type' => 'Méthode d’authentification', 'auth_will_reset' => 'Le système d’authentification va être réinitialisé : un formulaire sera utilisé à la place de Persona.', + 'author' => 'Auteur', 'auto_load_more' => 'Charger les articles suivants en bas de page', 'auto_read_when' => 'Marquer un article comme lu…', 'auto_share' => 'Partager', @@ -105,9 +115,9 @@ 'bad_opml_file' => 'Votre fichier OPML n’est pas valide.', 'base_url' => 'Base de l’URL', 'bdd' => 'Base de données', - 'bdd_configuration' => 'Base de données', 'bdd_conf_is_ko' => 'Vérifiez les informations d’accès à la base de données.', 'bdd_conf_is_ok' => 'La configuration de la base de données a été enregistrée.', + 'bdd_configuration' => 'Base de données', 'bdd_type' => 'Type de base de données', 'before_one_day' => 'Antérieurs à 1 jour', 'before_one_week' => 'Antérieurs à 1 semaine', @@ -123,8 +133,8 @@ 'by_email' => 'Par courriel', 'by_feed' => 'par flux', 'cache_is_ok' => 'Les droits sur le répertoire de cache sont bons', - 'cancel' => 'Annuler', 'can_not_be_deleted' => 'Ne peut pas être supprimée.', + 'cancel' => 'Annuler', 'categories' => 'Catégories', 'categories_management' => 'Gestion des catégories', 'categories_updated' => 'Les catégories ont été mises à jour.', @@ -135,10 +145,10 @@ 'category_emptied' => 'La catégorie a été vidée.', 'category_empty' => 'Catégorie vide', 'category_name_exists' => 'Une catégorie possède déjà ce nom.', - 'category_not_delete_default' => 'Vous ne pouvez pas supprimer la catégorie par défaut !', - 'category_not_exist' => 'Cette catégorie n’existe pas !', 'category_no_id' => 'Vous devez préciser l’id de la catégorie.', 'category_no_name' => 'Vous devez préciser un nom pour la catégorie.', + 'category_not_delete_default' => 'Vous ne pouvez pas supprimer la catégorie par défaut !', + 'category_not_exist' => 'Cette catégorie n’existe pas !', 'category_number' => 'Catégorie n°%d', 'category_updated' => 'La catégorie a été mise à jour.', 'change_value' => 'Vous devriez changer cette valeur par n’importe quelle autre', @@ -165,7 +175,6 @@ 'current_user' => 'Utilisateur actuel', 'damn' => 'Arf !', 'data_is_ok' => 'Les droits sur le répertoire de data sont bons', - 'Dec' => '\\d\\é\\c\\e\\m\\b\\r\\e', 'dec' => 'déc.', 'december' => 'décembre', 'default_category' => 'Sans catégorie', @@ -178,9 +187,9 @@ 'display_articles_unfolded' => 'Afficher les articles dépliés par défaut', 'display_categories_unfolded' => 'Afficher les catégories pliées par défaut', 'display_configuration' => 'Affichage', + 'do_not_change_if_doubt' => 'Laissez tel quel dans le doute', 'dom_is_nok' => 'Il manque une librairie pour parcourir le DOM (paquet php-xml)', 'dom_is_ok' => 'Vous disposez du nécessaire pour parcourir le DOM', - 'do_not_change_if_doubt' => 'Laissez tel quel dans le doute', 'email' => 'Courriel', 'error_occurred' => 'Une erreur est survenue !', 'error_occurred_update' => 'Rien n’a été modifié !', @@ -193,19 +202,8 @@ 'favicons_is_ok' => 'Les droits sur le répertoire des favicons sont bons', 'favorite_feeds' => 'Favoris (%s)', 'feb' => 'fév.', - 'Feb' => '\\f\\é\\v\\r\\i\\e\\r', 'february' => 'février', 'feed' => 'Flux', - 'feedback.login.error' => 'L’identifiant est invalide !', - 'feedback.login.success' => 'Vous êtes désormais connecté', - 'feedback.logout.success' => 'Vous avez été déconnecté', - 'feedback.user_profile.updated' => 'Votre profil a été mis à jour', - 'feeds' => 'Flux', - 'feeds_actualized' => 'Les flux ont été mis à jour.', - 'feeds_imported' => 'Vos flux ont été importés et vont maintenant être actualisés.', - 'feeds_imported_with_errors' => 'Vos flux ont été importés mais des erreurs sont survenues.', - 'feeds_marked_read' => 'Les flux ont été marqués comme lus.', - 'feeds_moved_category_deleted' => 'Lors de la suppression d’une catégorie, ses flux seront automatiquement classés dans %s.', 'feed_actualized' => '%s a été mis à jour.', 'feed_added' => 'Le flux %s a bien été ajouté.', 'feed_deleted' => 'Le flux a été supprimé.', @@ -217,6 +215,16 @@ 'feed_updated' => 'Le flux a été mis à jour.', 'feed_url' => 'URL du flux', 'feed_validator' => 'Vérifier la valididé du flux', + 'feedback.login.error' => 'L’identifiant est invalide !', + 'feedback.login.success' => 'Vous êtes désormais connecté', + 'feedback.logout.success' => 'Vous avez été déconnecté', + 'feedback.user_profile.updated' => 'Votre profil a été mis à jour', + 'feeds' => 'Flux', + 'feeds_actualized' => 'Les flux ont été mis à jour.', + 'feeds_imported' => 'Vos flux ont été importés et vont maintenant être actualisés.', + 'feeds_imported_with_errors' => 'Vos flux ont été importés mais des erreurs sont survenues.', + 'feeds_marked_read' => 'Les flux ont été marqués comme lus.', + 'feeds_moved_category_deleted' => 'Lors de la suppression d’une catégorie, ses flux seront automatiquement classés dans %s.', 'file_cannot_be_uploaded' => 'Le fichier ne peut pas être téléchargé !', 'file_is_nok' => 'Veuillez vérifier les droits sur le répertoire %s. Le serveur HTTP doit être capable d’écrire dedans', 'file_to_import' => 'Fichier à importer
    (OPML, Json ou Zip)', @@ -239,12 +247,13 @@ 'gen.menu.check_install' => 'Vérification de l\'installation', 'gen.menu.user_management' => 'Gestion des utilisateurs', 'gen.menu.user_profile' => 'Profil', + 'gen.title.authentication' => 'Authentification', 'gen.title.check_install' => 'Vérification de l\'installation', 'gen.title.global_view' => 'Vue globale', 'gen.title.user_management' => 'Gestion des utilisateurs', 'gen.title.user_profile' => 'Profil', - 'general_configuration' => 'Configuration générale', 'general_conf_is_ok' => 'La configuration générale a été enregistrée.', + 'general_configuration' => 'Configuration générale', 'github_or_email' => 'sur Github ou par courriel', 'global_view' => 'Vue globale', 'help' => 'Afficher la documentation', @@ -261,24 +270,21 @@ 'import' => 'Importer', 'import_export' => 'Importer / exporter', 'informations' => 'Informations', + 'install_not_deleted' => 'Quelque chose s’est mal passé, vous devez supprimer le fichier %s à la main.', 'installation_is_ok' => 'L’installation s’est bien passée.
    La dernière étape va maintenant tenter de supprimer les fichiers ainsi que d’éventuelles copies de base de données créés durant le processus de mise à jour.
    Vous pouvez choisir de sauter cette étape en supprimant ./data/do-install.txt manuellement.', 'installation_step' => 'Installation — étape %d · FreshRSS', - 'install_not_deleted' => 'Quelque chose s’est mal passé, vous devez supprimer le fichier %s à la main.', 'internal_problem_feed' => 'Le flux ne peut pas être ajouté. Consulter les logs de FreshRSS pour plus de détails.', 'invalid_login' => 'L’identifiant est invalide !', 'invalid_url' => 'L’url %s est invalide.', 'is_admin' => 'est administrateur', - 'Jan' => '\\j\\a\\n\\v\\i\\e\\r', 'jan' => 'jan.', 'january' => 'janvier', 'javascript_for_shortcuts' => 'Le JavaScript doit être activé pour pouvoir profiter des raccourcis.', 'javascript_is_better' => 'FreshRSS est plus agréable à utiliser avec JavaScript activé', 'javascript_should_be_activated' => 'Le JavaScript doit être activé.', 'jul' => 'jui.', - 'Jul' => '\\j\\u\\i\\l\\l\\e\\t', 'july' => 'juillet', 'jump_next' => 'sauter au prochain voisin non lu (flux ou catégorie)', - 'Jun' => '\\j\\u\\i\\n', 'jun' => 'juin', 'june' => 'juin', 'keep_history' => 'Nombre minimum d’articles à conserver', @@ -295,6 +301,7 @@ 'lead_developer' => 'Développeur principal', 'license' => 'Licence', 'load_more' => 'Charger plus d’articles', + 'log_is_ok' => 'Les droits sur le répertoire des logs sont bons', 'login' => 'Connexion', 'login_configuration' => 'Identification', 'login_persona_problem' => 'Problème de connexion à Persona ?', @@ -303,41 +310,30 @@ 'logout' => 'Déconnexion', 'logs' => 'Logs', 'logs_empty' => 'Les logs sont vides.', - 'log_is_ok' => 'Les droits sur le répertoire des logs sont bons', 'main_stream' => 'Flux principal', 'mar' => 'mar.', - 'Mar' => '\\m\\a\\r\\s', 'march' => 'mars', 'mark_all_read' => 'Tout marquer comme lu', 'mark_cat_read' => 'Marquer la catégorie comme lue', 'mark_favorite' => 'Mettre en favori', 'mark_feed_read' => 'Marquer le flux comme lu', 'mark_read' => 'Marquer comme lu', - 'May' => '\\m\\a\\i', 'may' => 'mai.', 'minz_is_nok' => 'Vous ne disposez pas de la librairie Minz. Vous devriez exécuter le script build.sh ou bien la télécharger sur Github et installer dans le répertoire %s le contenu de son répertoire /lib.', 'minz_is_ok' => 'Vous disposez du framework Minz', 'mon' => 'lun.', 'month' => 'mois', 'more_information' => 'Plus d’informations', - 'newer_first' => 'Plus récents en premier', + 'n_entries_deleted' => '%d articles ont été supprimés.', + 'n_feeds_actualized' => '%d flux ont été mis à jour.', 'new_article' => 'Il y a de nouveaux articles disponibles, cliquez pour rafraîchir la page.', 'new_category' => 'Nouvelle catégorie', + 'newer_first' => 'Plus récents en premier', 'next' => 'Suivant', 'next_article' => 'Passer à l’article suivant', 'next_page' => 'Passer à la page suivante', 'next_step' => 'Passer à l’étape suivante', 'no' => 'Non', - 'normal_view' => 'Vue normale', - 'nothing_to_load' => 'Fin des articles', - 'notif_body_new_articles' => 'Il y a \\d nouveaux articles à lire sur FreshRSS.', - 'notif_title_new_articles' => 'FreshRSS : nouveaux articles !', - 'not_read' => '%d non lu', - 'not_reads' => '%d non lus', - 'not_yet_implemented' => 'Pas encore implémenté', - 'Nov' => '\\n\\o\\v\\e\\m\\b\\r\\e', - 'nov' => 'nov.', - 'november' => 'novembre', 'no_feed_actualized' => 'Aucun flux n’a pu être mis à jour.', 'no_feed_to_display' => 'Il n’y a aucun article à afficher.', 'no_feed_to_refresh' => 'Il n’y a aucun flux à actualiser…', @@ -347,12 +343,18 @@ 'no_selected_feed' => 'Aucun flux sélectionné.', 'no_update' => 'Aucune mise à jour à appliquer', 'no_zip_extension' => 'L’extension Zip n’est pas présente sur votre serveur.', + 'normal_view' => 'Vue normale', + 'not_read' => '%d non lu', + 'not_reads' => '%d non lus', + 'not_yet_implemented' => 'Pas encore implémenté', + 'nothing_to_load' => 'Fin des articles', + 'notif_body_new_articles' => 'Il y a \\d nouveaux articles à lire sur FreshRSS.', + 'notif_title_new_articles' => 'FreshRSS : nouveaux articles !', + 'nov' => 'nov.', + 'november' => 'novembre', 'number_articles' => '%d articles', 'number_divided_when_reader' => 'Divisé par 2 dans la vue de lecture.', 'number_feeds' => '%d flux', - 'n_entries_deleted' => '%d articles ont été supprimés.', - 'n_feeds_actualized' => '%d flux ont été mis à jour.', - 'Oct' => '\\o\\c\\t\\o\\b\\r\\e', 'oct' => 'oct.', 'october' => 'octobre', 'ok' => 'Ok !', @@ -419,8 +421,8 @@ 'refresh' => 'Actualisation', 'related_tags' => 'Tags associés', 'retrieve_truncated_feeds' => 'Permet de récupérer les flux tronqués (attention, demande plus de temps !)', - 'rss_feeds_of' => 'Flux RSS de %s', 'rss_feed_management' => 'Gestion des flux RSS', + 'rss_feeds_of' => 'Flux RSS de %s', 'rss_view' => 'Flux RSS', 'sat' => 'sam.', 'save' => 'Enregistrer', @@ -431,7 +433,6 @@ 'see_on_website' => 'Voir sur le site d’origine', 'see_website' => 'Voir le site', 'sep' => 'sep.', - 'Sep' => '\\s\\e\\p\\t\\e\\m\\b\\r\\e', 'september' => 'septembre', 'shaarli' => 'Shaarli', 'share' => 'Partager', @@ -492,7 +493,6 @@ 'twitter' => 'Twitter', 'unsafe_autologin' => 'Autoriser les connexions automatiques non-sûres au format : ', 'update' => 'Mise à jour', - 'updated' => 'Modifications enregistrées.', 'update_apply' => 'Appliquer la mise à jour', 'update_can_apply' => 'Une mise à jour est disponible.', 'update_check' => 'Vérifier les mises à jour', @@ -504,15 +504,16 @@ 'update_server_not_found' => 'Le serveur de mise à jour n’a pas été trouvé. [%s]', 'update_start' => 'Lancer la mise à jour', 'update_system' => 'Système de mise à jour', + 'updated' => 'Modifications enregistrées.', 'upon_reception' => 'dès la réception du nouvel article', - 'username' => 'Nom d’utilisateur', - 'username_admin' => 'Nom d’utilisateur administrateur', - 'users' => 'Utilisateurs', - 'users_list' => 'Liste des utilisateurs', 'user_created' => 'L’utilisateur %s a été créé.', 'user_deleted' => 'L’utilisateur %s a été supprimé.', '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.', + 'username' => 'Nom d’utilisateur', + 'username_admin' => 'Nom d’utilisateur administrateur', + 'users' => 'Utilisateurs', + 'users_list' => 'Liste des utilisateurs', 'version' => 'Version', 'version_update' => 'Mise à jour', 'wallabag' => 'wallabag', -- cgit v1.2.3 From c6f35ef51c2c536efb4f8e73603ae46b8512cc24 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Mon, 27 Oct 2014 21:45:30 +0100 Subject: Global limits for number of feeds and categories New 'limits' sub-array in config.php with 'max_feeds' and 'max_categories'. If the values are < 0, then it is the default value (16384). https://github.com/marienfressinaud/FreshRSS/issues/680 --- app/Controllers/categoryController.php | 7 +++++++ app/Controllers/feedController.php | 7 +++++++ lib/Minz/Configuration.php | 26 ++++++++++++++++++++++++++ 3 files changed, 40 insertions(+) (limited to 'app/Controllers') diff --git a/app/Controllers/categoryController.php b/app/Controllers/categoryController.php index 977ce51be..ef8af7ed6 100644 --- a/app/Controllers/categoryController.php +++ b/app/Controllers/categoryController.php @@ -33,6 +33,13 @@ class FreshRSS_category_Controller extends Minz_ActionController { $catDAO = new FreshRSS_CategoryDAO(); $url_redirect = array('c' => 'subscription', 'a' => 'index'); + $limits = Minz_Configuration::limits(); + $this->view->categories = $catDAO->listCategories(false); + if (count($this->view->categories) >= $limits['max_categories']) { + Minz_Request::bad(_t('over_max_categories', $limits['max_categories']), $url_redirect); + return; + } + if (Minz_Request::isPost()) { invalidateHttpCache(); diff --git a/app/Controllers/feedController.php b/app/Controllers/feedController.php index c2859edf4..39e4b5761 100755 --- a/app/Controllers/feedController.php +++ b/app/Controllers/feedController.php @@ -68,6 +68,13 @@ class FreshRSS_feed_Controller extends Minz_ActionController { 'params' => array(), ); + $limits = Minz_Configuration::limits(); + $this->view->feeds = $feedDAO->listFeeds(); + if (count($this->view->feeds) >= $limits['max_feeds']) { + Minz_Request::bad(_t('over_max_feeds', $limits['max_feeds']), $url_redirect); + return; + } + if (Minz_Request::isPost()) { @set_time_limit(300); diff --git a/lib/Minz/Configuration.php b/lib/Minz/Configuration.php index 554bc8c96..fe9ea6b2e 100644 --- a/lib/Minz/Configuration.php +++ b/lib/Minz/Configuration.php @@ -60,6 +60,12 @@ class Minz_Configuration { 'prefix' => '', ); + const MAX_SMALL_INT = 16384; + private static $limits = array( + 'max_feeds' => Minz_Configuration::MAX_SMALL_INT, + 'max_categories' => Minz_Configuration::MAX_SMALL_INT, + ); + /* * Getteurs */ @@ -97,6 +103,9 @@ class Minz_Configuration { public static function dataBase () { return self::$db; } + public static function limits() { + return self::$limits; + } public static function defaultUser () { return self::$default_user; } @@ -178,6 +187,7 @@ class Minz_Configuration { 'api_enabled' => self::$api_enabled, 'unsafe_autologin_enabled' => self::$unsafe_autologin_enabled, ), + 'limits' => self::$limits, 'db' => self::$db, ); @rename(DATA_PATH . self::CONF_PATH_NAME, DATA_PATH . self::CONF_PATH_NAME . '.bak.php'); @@ -291,6 +301,22 @@ class Minz_Configuration { ); } + if (isset($ini_array['limits'])) { + $limits = $ini_array['limits']; + if (isset($limits['max_feeds'])) { + self::$limits['max_feeds'] = intval($limits['max_feeds']); + if (self::$limits['max_feeds'] < 0 || self::$limits['max_feeds'] > Minz_Configuration::MAX_SMALL_INT) { + self::$limits['max_feeds'] = Minz_Configuration::MAX_SMALL_INT; + } + } + if (isset($limits['max_categories'])) { + self::$limits['max_categories'] = intval($limits['max_categories']); + if (self::$limits['max_categories'] < 0 || self::$limits['max_categories'] > Minz_Configuration::MAX_SMALL_INT) { + self::$limits['max_categories'] = Minz_Configuration::MAX_SMALL_INT; + } + } + } + // Base de données if (isset ($ini_array['db'])) { $db = $ini_array['db']; -- cgit v1.2.3 From 4cbd7e0583709912d790ed04a72b75d79da31b73 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Tue, 28 Oct 2014 23:32:55 +0100 Subject: Bug: unlock was not done for feeds with error --- app/Controllers/feedController.php | 1 + 1 file changed, 1 insertion(+) (limited to 'app/Controllers') diff --git a/app/Controllers/feedController.php b/app/Controllers/feedController.php index 39e4b5761..7ac083d56 100755 --- a/app/Controllers/feedController.php +++ b/app/Controllers/feedController.php @@ -293,6 +293,7 @@ class FreshRSS_feed_Controller extends Minz_ActionController { } catch (FreshRSS_Feed_Exception $e) { Minz_Log::notice($e->getMessage()); $feedDAO->updateLastUpdate($feed->id(), 1); + $feed->unlock(); continue; } -- 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/Controllers') 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 1ea996c4eaa0f07f4fd906e7cade68a9bee3b11d Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Wed, 29 Oct 2014 10:15:22 +0100 Subject: Update i18n for limit of category. --- app/Controllers/categoryController.php | 5 +++-- app/i18n/en.php | 5 +---- app/i18n/fr.php | 5 +---- 3 files changed, 5 insertions(+), 10 deletions(-) (limited to 'app/Controllers') diff --git a/app/Controllers/categoryController.php b/app/Controllers/categoryController.php index ef8af7ed6..609284559 100644 --- a/app/Controllers/categoryController.php +++ b/app/Controllers/categoryController.php @@ -35,9 +35,10 @@ class FreshRSS_category_Controller extends Minz_ActionController { $limits = Minz_Configuration::limits(); $this->view->categories = $catDAO->listCategories(false); + if (count($this->view->categories) >= $limits['max_categories']) { - Minz_Request::bad(_t('over_max_categories', $limits['max_categories']), $url_redirect); - return; + Minz_Request::bad(_t('sub.categories.over_max', $limits['max_categories']), + $url_redirect); } if (Minz_Request::isPost()) { diff --git a/app/i18n/en.php b/app/i18n/en.php index 1e6621c12..2c61d822d 100644 --- a/app/i18n/en.php +++ b/app/i18n/en.php @@ -53,10 +53,6 @@ 'admin.check_install.pcre.ok' => 'You have the required library for regular expressions (PCRE).', 'admin.check_install.pdo.nok' => 'You lack PDO or one of the supported drivers (pdo_mysql, pdo_sqlite).', 'admin.check_install.pdo.ok' => 'You have PDO and at least one of the supported drivers (pdo_mysql, pdo_sqlite).', - 'admin.check_install.pdo_mysql.nok' => 'You lack PDO for MySQL (it\'s ok if PDO is good).', - 'admin.check_install.pdo_mysql.ok' => 'You have PDO for MySQL.', - 'admin.check_install.pdo_sqlite.nok' => 'You lack PDO for SQLite (it\'s ok if PDO is good).', - 'admin.check_install.pdo_sqlite.ok' => 'You have PDO for SQLite.', 'admin.check_install.persona.nok' => 'Check permissions on ./data/persona directory. HTTP server must have rights to write into', 'admin.check_install.persona.ok' => 'Permissions on Mozilla Persona directory are good.', 'admin.check_install.php' => 'PHP installation', @@ -477,6 +473,7 @@ 'status_unread' => 'Unread', 'steps' => 'Steps', 'sticky_post' => 'Stick the article to the top when opened', + 'sub.categories.over_max' => 'You have reached your limit of categories (%d)', 'submit' => 'Submit', 'subscription_management' => 'Subscriptions management', 'sun' => 'Sun', diff --git a/app/i18n/fr.php b/app/i18n/fr.php index 61a84cc04..2420b20c3 100644 --- a/app/i18n/fr.php +++ b/app/i18n/fr.php @@ -53,10 +53,6 @@ 'admin.check_install.pcre.ok' => 'Vous disposez du nécessaire pour les expressions régulières (PCRE).', 'admin.check_install.pdo.nok' => 'Vous ne disposez pas de PDO ou d’un des drivers supportés (pdo_mysql, pdo_sqlite).', 'admin.check_install.pdo.ok' => 'Vous disposez de PDO et d’au moins un des drivers supportés (pdo_mysql, pdo_sqlite).', - 'admin.check_install.pdo_mysql.nok' => 'Vous ne possédez pas PDO pour MySQL (ok si PDO est bon).', - 'admin.check_install.pdo_mysql.ok' => 'Vous possédez PDO pour MySQL.', - 'admin.check_install.pdo_sqlite.nok' => 'Vous ne possédez pas PDO pour SQLite (ok si PDO est bon).', - 'admin.check_install.pdo_sqlite.ok' => 'Vous possédez PDO pour SQLite.', 'admin.check_install.persona.nok' => 'Veuillez vérifier les droits sur le répertoire ./data/persona. Le serveur HTTP doit être capable d’écrire dedans', 'admin.check_install.persona.ok' => 'Les droits sur le répertoire de Mozilla Persona sont bons.', 'admin.check_install.php' => 'Installation de PHP', @@ -477,6 +473,7 @@ 'status_unread' => 'non lus', 'steps' => 'Étapes', 'sticky_post' => 'Aligner l’article en haut quand il est ouvert', + 'sub.categories.over_max' => 'Vous avez atteint votre limite de catégories (%d)', 'submit' => 'Valider', 'subscription_management' => 'Gestion des abonnements', 'sun' => 'dim.', -- cgit v1.2.3 From cf7350af4768809c8b5117ba586f5165a4e2b1a8 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Wed, 29 Oct 2014 10:21:34 +0100 Subject: Update i18n for limit of feeds See https://github.com/marienfressinaud/FreshRSS/issues/680 --- app/Controllers/feedController.php | 4 ++-- app/i18n/en.php | 1 + app/i18n/fr.php | 1 + 3 files changed, 4 insertions(+), 2 deletions(-) (limited to 'app/Controllers') diff --git a/app/Controllers/feedController.php b/app/Controllers/feedController.php index 7ac083d56..8563b1c0f 100755 --- a/app/Controllers/feedController.php +++ b/app/Controllers/feedController.php @@ -71,8 +71,8 @@ class FreshRSS_feed_Controller extends Minz_ActionController { $limits = Minz_Configuration::limits(); $this->view->feeds = $feedDAO->listFeeds(); if (count($this->view->feeds) >= $limits['max_feeds']) { - Minz_Request::bad(_t('over_max_feeds', $limits['max_feeds']), $url_redirect); - return; + Minz_Request::bad(_t('sub.feeds.over_max', $limits['max_feeds']), + $url_redirect); } if (Minz_Request::isPost()) { diff --git a/app/i18n/en.php b/app/i18n/en.php index 2c61d822d..a35a6ccf1 100644 --- a/app/i18n/en.php +++ b/app/i18n/en.php @@ -474,6 +474,7 @@ 'steps' => 'Steps', 'sticky_post' => 'Stick the article to the top when opened', 'sub.categories.over_max' => 'You have reached your limit of categories (%d)', + 'sub.feeds.over_max' => 'You have reached your limit of feeds (%d)', 'submit' => 'Submit', 'subscription_management' => 'Subscriptions management', 'sun' => 'Sun', diff --git a/app/i18n/fr.php b/app/i18n/fr.php index 2420b20c3..c29b6c9ac 100644 --- a/app/i18n/fr.php +++ b/app/i18n/fr.php @@ -474,6 +474,7 @@ 'steps' => 'Étapes', 'sticky_post' => 'Aligner l’article en haut quand il est ouvert', 'sub.categories.over_max' => 'Vous avez atteint votre limite de catégories (%d)', + 'sub.feeds.over_max' => 'Vous avez atteint votre limite de flux (%d)', 'submit' => 'Valider', 'subscription_management' => 'Gestion des abonnements', 'sun' => 'dim.', -- cgit v1.2.3 From fb3cda8ac9f7c8895ed33d7db432a92b063a7198 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Wed, 29 Oct 2014 11:08:31 +0100 Subject: Fix limits in import OPML files See https://github.com/marienfressinaud/FreshRSS/issues/680 --- app/Controllers/importExportController.php | 55 +++++++++++++++++++++++------- 1 file changed, 43 insertions(+), 12 deletions(-) (limited to 'app/Controllers') diff --git a/app/Controllers/importExportController.php b/app/Controllers/importExportController.php index ab277e688..514077bbd 100644 --- a/app/Controllers/importExportController.php +++ b/app/Controllers/importExportController.php @@ -176,19 +176,43 @@ class FreshRSS_importExport_Controller extends Minz_ActionController { */ private function addOpmlElements($opml_elements, $parent_cat = null) { $error = false; + + $nb_feeds = count($this->feedDAO->listFeeds()); + $nb_cats = count($this->catDAO->listCategories(false)); + $limits = Minz_Configuration::limits(); + foreach ($opml_elements as $elt) { - $res = false; + $is_error = false; if (isset($elt['xmlUrl'])) { // If xmlUrl exists, it means it is a feed - $res = $this->addFeedOpml($elt, $parent_cat); + if ($nb_feeds >= $limits['max_feeds']) { + Minz_Log::warning(_t('sub.feeds.over_max', + $limits['max_feeds'])); + $is_error = true; + continue; + } + + $is_error = $this->addFeedOpml($elt, $parent_cat); + if (!$is_error) { + $nb_feeds += 1; + } } else { // No xmlUrl? It should be a category! - $res = $this->addCategoryOpml($elt, $parent_cat); + $limit_reached = ($nb_cats >= $limits['max_categories']); + if ($limit_reached) { + Minz_Log::warning(_t('sub.categories.over_max', + $limits['max_categories'])); + } + + $is_error = $this->addCategoryOpml($elt, $parent_cat, $limit_reached); + if (!$is_error) { + $nb_cats += 1; + } } - if (!$error && $res) { + if (!$error && $is_error) { // oops: there is at least one error! - $error = $res; + $error = $is_error; } } @@ -203,16 +227,18 @@ class FreshRSS_importExport_Controller extends Minz_ActionController { * @return boolean true if an error occured, false else. */ private function addFeedOpml($feed_elt, $parent_cat) { + $default_cat = $this->catDAO->getDefault(); if (is_null($parent_cat)) { // This feed has no parent category so we get the default one - $parent_cat = $this->catDAO->getDefault()->name(); + $parent_cat = $default_cat->name(); } $cat = $this->catDAO->searchByName($parent_cat); - if (!$cat) { + if (is_null($cat)) { // If there is not $cat, it means parent category does not exist in - // database. It should not happened! - return true; + // database. + // If it happens, take the default category. + $cat = $default_cat; } // We get different useful information @@ -253,14 +279,19 @@ class FreshRSS_importExport_Controller extends Minz_ActionController { * * @param array $cat_elt an OPML element (must be a category element). * @param string $parent_cat the name of the parent category. + * @param boolean $cat_limit_reached indicates if category limit has been reached. + * if yes, category is not added (but we try for feeds!) * @return boolean true if an error occured, false else. */ - private function addCategoryOpml($cat_elt, $parent_cat) { + private function addCategoryOpml($cat_elt, $parent_cat, $cat_limit_reached) { // Create a new Category object $cat = new FreshRSS_Category(Minz_Helper::htmlspecialchars_utf8($cat_elt['text'])); - $id = $this->catDAO->addCategoryObject($cat); - $error = ($id === false); + $error = true; + if (!$cat_limit_reached) { + $id = $this->catDAO->addCategoryObject($cat); + $error = ($id === false); + } if (isset($cat_elt['@outlines'])) { // Our cat_elt contains more categories or more feeds, so we -- 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/Controllers') 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 From 9478d2f0116be69e08071dd02c0f945c5f78d7e0 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Thu, 30 Oct 2014 12:43:52 +0100 Subject: Add do_post_update support --- app/Controllers/updateController.php | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) (limited to 'app/Controllers') diff --git a/app/Controllers/updateController.php b/app/Controllers/updateController.php index 4ebb11f51..4ef5357ea 100644 --- a/app/Controllers/updateController.php +++ b/app/Controllers/updateController.php @@ -109,6 +109,19 @@ class FreshRSS_update_Controller extends Minz_ActionController { require(UPDATE_FILENAME); + if (Minz_Request::param('post_conf', false)) { + $res = do_post_update(); + + if ($res === true) { + @unlink(UPDATE_FILENAME); + @file_put_contents(DATA_PATH . '/last_update.txt', time()); + Minz_Request::good(_t('update_finished')); + } else { + Minz_Request::bad(_t('update_problem', $res), + array('c' => 'update', 'a' => 'index')); + } + } + if (Minz_Request::isPost()) { save_info_update(); } @@ -117,10 +130,11 @@ class FreshRSS_update_Controller extends Minz_ActionController { $res = apply_update(); if ($res === true) { - @unlink(UPDATE_FILENAME); - @file_put_contents(DATA_PATH . '/last_update.txt', time()); - - Minz_Request::good(_t('update_finished')); + Minz_Request::forward(array( + 'c' => 'update', + 'a' => 'apply', + 'params' => array('post_conf' => true) + ), true); } else { Minz_Request::bad(_t('update_problem', $res), array('c' => 'update', 'a' => 'index')); -- cgit v1.2.3 From ee5bbe48269a2fd5bc9c175fdb1e5a92a2c04502 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Thu, 30 Oct 2014 19:19:09 +0100 Subject: Fix bug size with SQLite --- app/Controllers/configureController.php | 2 +- lib/Minz/ModelPdo.php | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) (limited to 'app/Controllers') diff --git a/app/Controllers/configureController.php b/app/Controllers/configureController.php index cafd0e8a8..deb8cc849 100755 --- a/app/Controllers/configureController.php +++ b/app/Controllers/configureController.php @@ -225,7 +225,7 @@ class FreshRSS_configure_Controller extends Minz_ActionController { Minz_View::prependTitle(_t('archiving_configuration') . ' · '); - $entryDAO = FreshRSS_Factory::createEntryDao(); + $entryDAO = FreshRSS_Factory::createEntryDao('freshrss'); $this->view->nb_total = $entryDAO->count(); $this->view->size_user = $entryDAO->size(); diff --git a/lib/Minz/ModelPdo.php b/lib/Minz/ModelPdo.php index 827c89c69..6198cd85c 100644 --- a/lib/Minz/ModelPdo.php +++ b/lib/Minz/ModelPdo.php @@ -17,6 +17,7 @@ class Minz_ModelPdo { private static $sharedBd = null; private static $sharedPrefix; private static $has_transaction = false; + private static $sharedCurrentUser; protected static $sharedDbType; /** @@ -39,6 +40,7 @@ class Minz_ModelPdo { if (self::$useSharedBd && self::$sharedBd != null && $currentUser === null) { $this->bd = self::$sharedBd; $this->prefix = self::$sharedPrefix; + $this->current_user = self::$sharedCurrentUser; return; } @@ -48,6 +50,7 @@ class Minz_ModelPdo { $currentUser = Minz_Session::param('currentUser', '_'); } $this->current_user = $currentUser; + self::$sharedCurrentUser = $currentUser; try { $type = $db['type']; -- cgit v1.2.3 From 58deab37cdd97e93ac25aba574a32befe1db2243 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Thu, 30 Oct 2014 19:57:08 +0100 Subject: Fix Minz_Error::error() -> use default values --- app/Controllers/authController.php | 3 +-- app/Controllers/categoryController.php | 5 +---- app/Controllers/configureController.php | 5 +---- app/Controllers/entryController.php | 5 +---- app/Controllers/feedController.php | 10 ++-------- app/Controllers/importExportController.php | 5 +---- app/Controllers/statsController.php | 29 +++++++++++++---------------- app/Controllers/subscriptionController.php | 10 ++-------- app/Controllers/updateController.php | 5 +---- app/Controllers/userController.php | 8 ++------ 10 files changed, 25 insertions(+), 60 deletions(-) (limited to 'app/Controllers') diff --git a/app/Controllers/authController.php b/app/Controllers/authController.php index 491be8d8a..44496cd3e 100644 --- a/app/Controllers/authController.php +++ b/app/Controllers/authController.php @@ -19,8 +19,7 @@ class FreshRSS_auth_Controller extends Minz_ActionController { */ public function indexAction() { if (!FreshRSS_Auth::hasAccess('admin')) { - Minz_Error::error(403, - array('error' => array(_t('access_denied')))); + Minz_Error::error(403); } Minz_View::prependTitle(_t('gen.title.authentication') . ' · '); diff --git a/app/Controllers/categoryController.php b/app/Controllers/categoryController.php index 609284559..50b1d841a 100644 --- a/app/Controllers/categoryController.php +++ b/app/Controllers/categoryController.php @@ -13,10 +13,7 @@ class FreshRSS_category_Controller extends Minz_ActionController { */ public function firstAction() { if (!FreshRSS_Auth::hasAccess()) { - Minz_Error::error( - 403, - array('error' => array(_t('access_denied'))) - ); + Minz_Error::error(403); } $catDAO = new FreshRSS_CategoryDAO(); diff --git a/app/Controllers/configureController.php b/app/Controllers/configureController.php index deb8cc849..1c8ac9111 100755 --- a/app/Controllers/configureController.php +++ b/app/Controllers/configureController.php @@ -11,10 +11,7 @@ class FreshRSS_configure_Controller extends Minz_ActionController { */ public function firstAction() { if (!FreshRSS_Auth::hasAccess()) { - Minz_Error::error( - 403, - array('error' => array(_t('access_denied'))) - ); + Minz_Error::error(403); } } diff --git a/app/Controllers/entryController.php b/app/Controllers/entryController.php index d11f3a520..b4beed619 100755 --- a/app/Controllers/entryController.php +++ b/app/Controllers/entryController.php @@ -11,10 +11,7 @@ class FreshRSS_entry_Controller extends Minz_ActionController { */ public function firstAction() { if (!FreshRSS_Auth::hasAccess()) { - Minz_Error::error( - 403, - array('error' => array(_t('access_denied'))) - ); + Minz_Error::error(403); } // If ajax request, we do not print layout diff --git a/app/Controllers/feedController.php b/app/Controllers/feedController.php index 8563b1c0f..9990a852c 100755 --- a/app/Controllers/feedController.php +++ b/app/Controllers/feedController.php @@ -20,10 +20,7 @@ class FreshRSS_feed_Controller extends Minz_ActionController { $action = Minz_Request::actionName(); if ($action !== 'actualize' || !(Minz_Configuration::allowAnonymousRefresh() || $token_is_ok)) { - Minz_Error::error( - 403, - array('error' => array(_t('access_denied'))) - ); + Minz_Error::error(403); } } } @@ -442,10 +439,7 @@ class FreshRSS_feed_Controller extends Minz_ActionController { } else { Minz_Log::warning('Cannot move feed `' . $feed_id . '` ' . 'in the category `' . $cat_id . '`'); - Minz_Error::error( - 404, - array('error' => array(_t('error_occurred'))) - ); + Minz_Error::error(404); } } diff --git a/app/Controllers/importExportController.php b/app/Controllers/importExportController.php index 8028af8ed..4e2dbd157 100644 --- a/app/Controllers/importExportController.php +++ b/app/Controllers/importExportController.php @@ -11,10 +11,7 @@ class FreshRSS_importExport_Controller extends Minz_ActionController { */ public function firstAction() { if (!FreshRSS_Auth::hasAccess()) { - Minz_Error::error( - 403, - array('error' => array(_t('access_denied'))) - ); + Minz_Error::error(403); } require_once(LIB_PATH . '/lib_opml.php'); diff --git a/app/Controllers/statsController.php b/app/Controllers/statsController.php index 0e3430fcc..18fbca6df 100644 --- a/app/Controllers/statsController.php +++ b/app/Controllers/statsController.php @@ -5,6 +5,19 @@ */ class FreshRSS_stats_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. + */ + public function firstAction() { + if (!FreshRSS_Auth::hasAccess()) { + Minz_Error::error(403); + } + + Minz_View::prependTitle(_t('stats') . ' · '); + } + /** * This action handles the statistic main page. * @@ -111,20 +124,4 @@ class FreshRSS_stats_Controller extends Minz_ActionController { $this->view->repartitionMonth = $statsDAO->calculateEntryRepartitionPerFeedPerMonth($id); $this->view->averageMonth = $statsDAO->calculateEntryAveragePerFeedPerMonth($id); } - - /** - * 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. - */ - public function firstAction() { - if (!FreshRSS_Auth::hasAccess()) { - Minz_Error::error( - 403, array('error' => array(_t('access_denied'))) - ); - } - - Minz_View::prependTitle(_t('stats') . ' · '); - } - } diff --git a/app/Controllers/subscriptionController.php b/app/Controllers/subscriptionController.php index a89168eb3..67b95eba6 100644 --- a/app/Controllers/subscriptionController.php +++ b/app/Controllers/subscriptionController.php @@ -11,10 +11,7 @@ class FreshRSS_subscription_Controller extends Minz_ActionController { */ public function firstAction() { if (!FreshRSS_Auth::hasAccess()) { - Minz_Error::error( - 403, - array('error' => array(_t('access_denied'))) - ); + Minz_Error::error(403); } $catDAO = new FreshRSS_CategoryDAO(); @@ -71,10 +68,7 @@ class FreshRSS_subscription_Controller extends Minz_ActionController { $id = Minz_Request::param('id'); if ($id === false || !isset($this->view->feeds[$id])) { - Minz_Error::error( - 404, - array('error' => array(_t('page_not_found'))) - ); + Minz_Error::error(404); return; } diff --git a/app/Controllers/updateController.php b/app/Controllers/updateController.php index 4ef5357ea..0896b13ac 100644 --- a/app/Controllers/updateController.php +++ b/app/Controllers/updateController.php @@ -4,10 +4,7 @@ class FreshRSS_update_Controller extends Minz_ActionController { public function firstAction() { $current_user = Minz_Session::param('currentUser', ''); if (!FreshRSS_Auth::hasAccess('admin')) { - Minz_Error::error( - 403, - array('error' => array(_t('access_denied'))) - ); + Minz_Error::error(403); } invalidateHttpCache(); diff --git a/app/Controllers/userController.php b/app/Controllers/userController.php index 39db1d879..5050571a9 100644 --- a/app/Controllers/userController.php +++ b/app/Controllers/userController.php @@ -15,10 +15,7 @@ class FreshRSS_user_Controller extends Minz_ActionController { */ public function firstAction() { if (!FreshRSS_Auth::hasAccess()) { - Minz_Error::error( - 403, - array('error' => array(_t('access_denied'))) - ); + Minz_Error::error(403); } } @@ -88,8 +85,7 @@ class FreshRSS_user_Controller extends Minz_ActionController { */ public function manageAction() { if (!FreshRSS_Auth::hasAccess('admin')) { - Minz_Error::error(403, - array('error' => array(_t('access_denied')))); + Minz_Error::error(403); } Minz_View::prependTitle(_t('gen.title.user_management') . ' · '); -- cgit v1.2.3 From 960f86ba20fdf7320c957141a9983d17c7e521fa Mon Sep 17 00:00:00 2001 From: Alexis Degrugillier Date: Sun, 2 Nov 2014 10:05:26 -0500 Subject: Add a feature to hide articles when they are read This is a new reading option to hide articles when they are read. The hidding process occurs when the article is left for an other article. This way, even when the article is marked as read on opening, it is hidden only while navigating to an other article. I'm not really happy with the behavior when the "mark while scrolling" option is enabled. Please review. It is missing the i18n since we're not supposed to push them before it exists on i18n.freshrss.org. Or maybe I misunderstood the process. See #476 --- app/Controllers/configureController.php | 2 ++ app/Models/Configuration.php | 4 ++++ app/Models/Context.php | 22 ++++++++++++++++++++++ app/views/configure/reading.phtml | 10 ++++++++++ app/views/helpers/javascript_vars.phtml | 1 + p/scripts/main.js | 8 ++++++++ 6 files changed, 47 insertions(+) (limited to 'app/Controllers') diff --git a/app/Controllers/configureController.php b/app/Controllers/configureController.php index 1c8ac9111..53536afce 100755 --- a/app/Controllers/configureController.php +++ b/app/Controllers/configureController.php @@ -89,6 +89,7 @@ class FreshRSS_configure_Controller extends Minz_ActionController { * - image lazy loading * - stick open articles to the top * - display a confirmation when reading all articles + * - auto remove article after reading * - article order (default: DESC) * - mark articles as read when: * - displayed @@ -110,6 +111,7 @@ class FreshRSS_configure_Controller extends Minz_ActionController { FreshRSS_Context::$conf->_lazyload(Minz_Request::param('lazyload', false)); FreshRSS_Context::$conf->_sticky_post(Minz_Request::param('sticky_post', false)); FreshRSS_Context::$conf->_reading_confirm(Minz_Request::param('reading_confirm', false)); + FreshRSS_Context::$conf->_auto_remove_article(Minz_Request::param('auto_remove_article', false)); FreshRSS_Context::$conf->_sort_order(Minz_Request::param('sort_order', 'DESC')); FreshRSS_Context::$conf->_mark_when(array( 'article' => Minz_Request::param('mark_open_article', false), diff --git a/app/Models/Configuration.php b/app/Models/Configuration.php index 53f136513..8668470b0 100644 --- a/app/Models/Configuration.php +++ b/app/Models/Configuration.php @@ -24,6 +24,7 @@ class FreshRSS_Configuration { 'lazyload' => true, 'sticky_post' => true, 'reading_confirm' => false, + 'auto_remove_article' => false, 'sort_order' => 'DESC', 'anon_access' => false, 'mark_when' => array( @@ -191,6 +192,9 @@ class FreshRSS_Configuration { public function _reading_confirm($value) { $this->data['reading_confirm'] = ((bool)$value) && $value !== 'no'; } + public function _auto_remove_article($value) { + $this->data['auto_remove_article'] = ((bool)$value) && $value !== 'no'; + } public function _sort_order($value) { $this->data['sort_order'] = $value === 'ASC' ? 'ASC' : 'DESC'; } diff --git a/app/Models/Context.php b/app/Models/Context.php index 36c4087eb..cbd6a5888 100644 --- a/app/Models/Context.php +++ b/app/Models/Context.php @@ -265,4 +265,26 @@ class FreshRSS_Context { } } } + + /** + * Determine if the auto remove is available in the current context. + * This feature is available if: + * - it is activated in the configuration + * - the "read" state is not enable + * - the "unread" state is enable + * + * @return boolean + */ + public static function isAutoRemoveAvailable() { + if (!self::$conf->auto_remove_article) { + return false; + } + if (self::isStateEnabled(FreshRSS_Entry::STATE_READ)) { + return false; + } + if (!self::isStateEnabled(FreshRSS_Entry::STATE_NOT_READ)) { + return false; + } + return true; + } } diff --git a/app/views/configure/reading.phtml b/app/views/configure/reading.phtml index b8f673466..0f7a3347a 100644 --- a/app/views/configure/reading.phtml +++ b/app/views/configure/reading.phtml @@ -115,6 +115,16 @@
    +
    +
    + +
    +
    +
    diff --git a/app/views/helpers/javascript_vars.phtml b/app/views/helpers/javascript_vars.phtml index 8e9141d4e..6424d8d04 100644 --- a/app/views/helpers/javascript_vars.phtml +++ b/app/views/helpers/javascript_vars.phtml @@ -18,6 +18,7 @@ $url_logout = Minz_Url::display(array( ), 'php'); echo 'var context={', + 'auto_remove_article:', FreshRSS_Context::isAutoRemoveAvailable() ? 'true' : 'false', ',', 'hide_posts:', $hide_posts ? 'false' : 'true', ',', 'display_order:"', Minz_Request::param('order', FreshRSS_Context::$conf->sort_order), '",', 'auto_mark_article:', $mark['article'] ? 'true' : 'false', ',', diff --git a/p/scripts/main.js b/p/scripts/main.js index dc5428048..d1d31c801 100644 --- a/p/scripts/main.js +++ b/p/scripts/main.js @@ -231,6 +231,14 @@ function toggleContent(new_active, old_active) { } old_active.removeClass("active current"); new_active.addClass("current"); + if (context['auto_remove_article'] && !old_active.hasClass('not_read')) { + var p = old_active.prev(); + var n = old_active.next(); + if (p.hasClass('day') && n.hasClass('day')) { + p.remove(); + } + old_active.remove(); + } } else { new_active.toggleClass('active'); } -- cgit v1.2.3 From 0b7af8f8719f698b67e31b5a84fa19b0f20c0590 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Fri, 31 Oct 2014 17:21:35 +0100 Subject: Fix bug on archiving page Introduced by https://github.com/FreshRSS/FreshRSS/commit/ee5bbe48269a2fd5bc9c175fdb1e5a92a2c04502 --- app/Controllers/configureController.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'app/Controllers') diff --git a/app/Controllers/configureController.php b/app/Controllers/configureController.php index 1c8ac9111..f8d9b47c3 100755 --- a/app/Controllers/configureController.php +++ b/app/Controllers/configureController.php @@ -222,7 +222,7 @@ class FreshRSS_configure_Controller extends Minz_ActionController { Minz_View::prependTitle(_t('archiving_configuration') . ' · '); - $entryDAO = FreshRSS_Factory::createEntryDao('freshrss'); + $entryDAO = FreshRSS_Factory::createEntryDao(); $this->view->nb_total = $entryDAO->count(); $this->view->size_user = $entryDAO->size(); -- cgit v1.2.3 From 38cf7a109ee80cc03edfd420b641676ecd1dfae6 Mon Sep 17 00:00:00 2001 From: Alexis Degrugillier Date: Sat, 8 Nov 2014 09:26:01 -0500 Subject: Add more info in article repartition page I added the same information than on the main stat page (total, read, unread and favorite) on the repartition page. Some refactoring was needed. --- app/Controllers/statsController.php | 1 + app/Models/StatsDAO.php | 48 ++++++++++++++++++++----------------- app/views/stats/repartition.phtml | 17 +++++++++++++ 3 files changed, 44 insertions(+), 22 deletions(-) (limited to 'app/Controllers') diff --git a/app/Controllers/statsController.php b/app/Controllers/statsController.php index 18fbca6df..578df9434 100644 --- a/app/Controllers/statsController.php +++ b/app/Controllers/statsController.php @@ -117,6 +117,7 @@ class FreshRSS_stats_Controller extends Minz_ActionController { $this->view->feed = $feedDAO->searchById($id); $this->view->days = $statsDAO->getDays(); $this->view->months = $statsDAO->getMonths(); + $this->view->repartition = $statsDAO->calculateEntryRepartitionPerFeed($id); $this->view->repartitionHour = $statsDAO->calculateEntryRepartitionPerFeedPerHour($id); $this->view->averageHour = $statsDAO->calculateEntryAveragePerFeedPerHour($id); $this->view->repartitionDayOfWeek = $statsDAO->calculateEntryRepartitionPerFeedPerDayOfWeek($id); diff --git a/app/Models/StatsDAO.php b/app/Models/StatsDAO.php index 283d5dcb1..0ca251228 100644 --- a/app/Models/StatsDAO.php +++ b/app/Models/StatsDAO.php @@ -6,18 +6,36 @@ class FreshRSS_StatsDAO extends Minz_ModelPdo { /** * Calculates entry repartition for all feeds and for main stream. + * + * @return array + */ + public function calculateEntryRepartition() { + return array( + 'main_stream' => $this->calculateEntryRepartitionPerFeed(null, true), + 'all_feeds' => $this->calculateEntryRepartitionPerFeed(null, false), + ); + } + + /** + * Calculates entry repartition for the selection. * The repartition includes: * - total entries * - read entries * - unread entries * - favorite entries * - * @return type + * @param null|integer $feed feed id + * @param boolean $only_main + * @return array */ - public function calculateEntryRepartition() { - $repartition = array(); - - // Generates the repartition for the main stream of entry + public function calculateEntryRepartitionPerFeed($feed = null, $only_main = false) { + $filter = ''; + if ($only_main) { + $filter .= 'AND f.priority = 10'; + } + if (!is_null($feed)) { + $filter .= "AND e.id_feed = {$feed}"; + } $sql = <<prefix}entry AS e , {$this->prefix}feed AS f WHERE e.id_feed = f.id -AND f.priority = 10 -SQL; - $stm = $this->bd->prepare($sql); - $stm->execute(); - $res = $stm->fetchAll(PDO::FETCH_ASSOC); - $repartition['main_stream'] = $res[0]; - - // Generates the repartition for all entries - $sql = <<prefix}entry AS e +{$filter} SQL; $stm = $this->bd->prepare($sql); $stm->execute(); $res = $stm->fetchAll(PDO::FETCH_ASSOC); - $repartition['all_feeds'] = $res[0]; - return $repartition; + return $res[0]; } /** @@ -179,7 +183,7 @@ SQL; * @return integer */ public function calculateEntryAveragePerFeedPerHour($feed = null) { - return $this->calculateEntryAveragePerFeedPerPeriod(1/24, $feed); + return $this->calculateEntryAveragePerFeedPerPeriod(1 / 24, $feed); } /** diff --git a/app/views/stats/repartition.phtml b/app/views/stats/repartition.phtml index 32268a546..85a750bd0 100644 --- a/app/views/stats/repartition.phtml +++ b/app/views/stats/repartition.phtml @@ -29,6 +29,23 @@ +
    + + + + + + + + + + + + + +
    repartition['total']; ?>repartition['read']; ?>repartition['unread']; ?>repartition['favorite']; ?>
    +
    +

    averageHour); ?>

    -- cgit v1.2.3 From a235f003bd5b78f2c94ccbbe56614f5828918962 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Wed, 12 Nov 2014 22:58:33 +0100 Subject: Better log in case of nonce errors https://github.com/FreshRSS/FreshRSS/issues/676 --- app/Controllers/javascriptController.php | 2 ++ 1 file changed, 2 insertions(+) (limited to 'app/Controllers') diff --git a/app/Controllers/javascriptController.php b/app/Controllers/javascriptController.php index 62f413989..113f58ea9 100755 --- a/app/Controllers/javascriptController.php +++ b/app/Controllers/javascriptController.php @@ -39,6 +39,8 @@ class FreshRSS_javascript_Controller extends Minz_ActionController { } catch (Minz_Exception $me) { Minz_Log::warning('Nonce failure: ' . $me->getMessage()); } + } else { + Minz_Log::notice('Nonce failure due to invalid username!'); } $this->view->nonce = ''; //Failure $this->view->salt1 = ''; -- cgit v1.2.3 From 9fc60317eecba785b66011f04b9a5150296f2df6 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Fri, 5 Dec 2014 14:17:02 +0100 Subject: First draft for listing and manipulate extensions See https://github.com/FreshRSS/FreshRSS/issues/252 --- app/Controllers/extensionController.php | 43 +++++++++++++++++++++++++++++++++ app/layout/aside_configure.phtml | 4 +++ app/layout/header.phtml | 1 + app/views/extension/index.phtml | 35 +++++++++++++++++++++++++++ lib/Minz/Extension.php | 20 +++++++++++++++ lib/Minz/ExtensionManager.php | 17 +++++++++++++ 6 files changed, 120 insertions(+) create mode 100644 app/Controllers/extensionController.php create mode 100644 app/views/extension/index.phtml (limited to 'app/Controllers') diff --git a/app/Controllers/extensionController.php b/app/Controllers/extensionController.php new file mode 100644 index 000000000..504be56d3 --- /dev/null +++ b/app/Controllers/extensionController.php @@ -0,0 +1,43 @@ +view->extension_list = Minz_ExtensionManager::list_extensions(); + } + + public function configureAction() { + if (Minz_Request::param('ajax')) { + $this->view->_useLayout(false); + } + } + + public function enableAction() { + + } + + public function disableAction() { + + } + + public function removeAction() { + + } +} diff --git a/app/layout/aside_configure.phtml b/app/layout/aside_configure.phtml index 53c52d3e3..f7f3617c4 100644 --- a/app/layout/aside_configure.phtml +++ b/app/layout/aside_configure.phtml @@ -22,6 +22,10 @@ Minz_Request::actionName() === 'profile'? ' active' : ''; ?>"> +
  • + +
  • +
  • diff --git a/app/views/extension/index.phtml b/app/views/extension/index.phtml new file mode 100644 index 000000000..c6b7c84a1 --- /dev/null +++ b/app/views/extension/index.phtml @@ -0,0 +1,35 @@ +partial('aside_configure'); ?> + +
    + + +

    + + extension_list)) { ?> + + extension_list as $ext) { ?> +
      +
    • + getName()); ?> +
      + + is_enabled()) { ?> + + + + + + + +
      +
    • +
    • getName(); ?>
    • +
    + + +

    + +
    + + +
    diff --git a/lib/Minz/Extension.php b/lib/Minz/Extension.php index ecf510ea2..a1fdd659b 100644 --- a/lib/Minz/Extension.php +++ b/lib/Minz/Extension.php @@ -17,6 +17,8 @@ class Minz_Extension { 'user', ); + private $is_enabled; + /** * The constructor to assign specific information to the extension. * @@ -41,6 +43,8 @@ class Minz_Extension { $this->description = isset($meta_info['description']) ? $meta_info['description'] : ''; $this->version = isset($meta_info['version']) ? $meta_info['version'] : '0.1'; $this->setType(isset($meta_info['type']) ? $meta_info['type'] : 'user'); + + $this->is_enabled = false; } /** @@ -66,6 +70,22 @@ class Minz_Extension { */ public function init() {} + /** + * Set the current extension to enable. + */ + public function enable() { + $this->is_enabled = true; + } + + /** + * Return if the extension is currently enabled. + * + * @return true if extension is enabled, false else. + */ + public function is_enabled() { + return $this->is_enabled; + } + /** * Getters and setters. */ diff --git a/lib/Minz/ExtensionManager.php b/lib/Minz/ExtensionManager.php index 789557b9e..6c32ccf19 100644 --- a/lib/Minz/ExtensionManager.php +++ b/lib/Minz/ExtensionManager.php @@ -144,6 +144,7 @@ class Minz_ExtensionManager { if (isset(self::$ext_list[$ext_name])) { $ext = self::$ext_list[$ext_name]; self::$ext_list_enabled[$ext_name] = $ext; + $ext->enable(); $ext->init(); } } @@ -158,4 +159,20 @@ class Minz_ExtensionManager { self::enable($ext_name); } } + + + + /** + * Returns a list of extensions. + * + * @param $only_enabled if true returns only the enabled extensions (false by default). + * @return an array of extensions. + */ + public static function list_extensions($only_enabled = false) { + if ($only_enabled) { + return self::$ext_list_enabled; + } else { + return self::$ext_list; + } + } } -- cgit v1.2.3 From 2e4682ebd451f8dd291e11141553add9164cbbef Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Sat, 6 Dec 2014 16:17:11 +0100 Subject: Add enable / disable extension features See https://github.com/FreshRSS/FreshRSS/issues/252 --- app/Controllers/extensionController.php | 72 ++++++++++++++++++++++++++++++++- app/Models/Configuration.php | 12 ++++++ lib/Minz/ExtensionManager.php | 18 +++++++-- 3 files changed, 97 insertions(+), 5 deletions(-) (limited to 'app/Controllers') diff --git a/app/Controllers/extensionController.php b/app/Controllers/extensionController.php index 504be56d3..415f489a6 100644 --- a/app/Controllers/extensionController.php +++ b/app/Controllers/extensionController.php @@ -29,12 +29,80 @@ class FreshRSS_extension_Controller extends Minz_ActionController { } } + /** + * This action enables a disabled extension for the current user. + * + * System extensions can only be enabled by an administrator. + * + * Parameter is: + * - e: the extension name (urlencoded). + */ public function enableAction() { - + $url_redirect = array('c' => 'extension', 'a' => 'index'); + + if (Minz_Request::isPost()) { + $ext_name = urldecode(Minz_Request::param('e')); + $ext = Minz_ExtensionManager::find_extension($ext_name); + + if (is_null($ext)) { + Minz_Request::bad('feedback.extension.not_found', $url_redirect); + } + + if ($ext->is_enabled()) { + Minz_Request::bad('feedback.extension.already_enabled', $url_redirect); + } + + if ($ext->getType() === 'system' && !FreshRSS_Auth::hasAccess('admin')) { + Minz_Request::bad('feedback.extension.no_access', $url_redirect); + } + + $ext->install(); + + FreshRSS_Context::$conf->addExtension($ext_name); + FreshRSS_Context::$conf->save(); + + Minz_Request::good('feedback.extension.enabled', $url_redirect); + } + + Minz_Request::forward($url_redirect, true); } + /** + * This action disables an enabled extension for the current user. + * + * System extensions can only be disabled by an administrator. + * + * Parameter is: + * - e: the extension name (urlencoded). + */ public function disableAction() { - + $url_redirect = array('c' => 'extension', 'a' => 'index'); + + if (Minz_Request::isPost()) { + $ext_name = urldecode(Minz_Request::param('e')); + $ext = Minz_ExtensionManager::find_extension($ext_name); + + if (is_null($ext)) { + Minz_Request::bad('feedback.extension.not_found', $url_redirect); + } + + if (!$ext->is_enabled()) { + Minz_Request::bad('feedback.extension.not_enabled', $url_redirect); + } + + if ($ext->getType() === 'system' && !FreshRSS_Auth::hasAccess('admin')) { + Minz_Request::bad('feedback.extension.no_access', $url_redirect); + } + + $ext->uninstall(); + + FreshRSS_Context::$conf->removeExtension($ext_name); + FreshRSS_Context::$conf->save(); + + Minz_Request::good('feedback.extension.disabled', $url_redirect); + } + + Minz_Request::forward($url_redirect, true); } public function removeAction() { diff --git a/app/Models/Configuration.php b/app/Models/Configuration.php index 13ce43990..83a00d4bb 100644 --- a/app/Models/Configuration.php +++ b/app/Models/Configuration.php @@ -350,4 +350,16 @@ class FreshRSS_Configuration { } $this->data['extensions_enabled'] = $value; } + public function removeExtension($ext_name) { + $this->data['extensions_enabled'] = array_diff( + $this->data['extensions_enabled'], + array($ext_name) + ); + } + public function addExtension($ext_name) { + $found = array_search($ext_name, $this->data['extensions_enabled']) !== false; + if (!$found) { + $this->data['extensions_enabled'][] = $ext_name; + } + } } diff --git a/lib/Minz/ExtensionManager.php b/lib/Minz/ExtensionManager.php index 6c32ccf19..46e421bac 100644 --- a/lib/Minz/ExtensionManager.php +++ b/lib/Minz/ExtensionManager.php @@ -160,10 +160,8 @@ class Minz_ExtensionManager { } } - - /** - * Returns a list of extensions. + * Return a list of extensions. * * @param $only_enabled if true returns only the enabled extensions (false by default). * @return an array of extensions. @@ -175,4 +173,18 @@ class Minz_ExtensionManager { return self::$ext_list; } } + + /** + * Return an extension by its name. + * + * @param $ext_name the name of the extension. + * @return the corresponding extension or null if it doesn't exist. + */ + public static function find_extension($ext_name) { + if (!isset(self::$ext_list[$ext_name])) { + return null; + } + + return self::$ext_list[$ext_name]; + } } -- cgit v1.2.3 From 4c888590e6f0fd89fc1dccebb5e815883eeaa54c Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Sat, 6 Dec 2014 16:39:10 +0100 Subject: Improve system/user types for extensions - system extensions can only be managed by an administrator - system extensions are loaded for all users (even if not logged) - user extensions are loaded for logged users only - system extensions loading is saved in global config.php file See https://github.com/FreshRSS/FreshRSS/issues/252 --- app/Controllers/extensionController.php | 42 ++++++++++++++++++++++----------- app/FreshRSS.php | 8 ++++--- app/views/extension/index.phtml | 4 ++++ lib/Minz/Configuration.php | 19 +++++++++++++-- 4 files changed, 54 insertions(+), 19 deletions(-) (limited to 'app/Controllers') diff --git a/app/Controllers/extensionController.php b/app/Controllers/extensionController.php index 415f489a6..e348d9f31 100644 --- a/app/Controllers/extensionController.php +++ b/app/Controllers/extensionController.php @@ -52,16 +52,23 @@ class FreshRSS_extension_Controller extends Minz_ActionController { Minz_Request::bad('feedback.extension.already_enabled', $url_redirect); } - if ($ext->getType() === 'system' && !FreshRSS_Auth::hasAccess('admin')) { - Minz_Request::bad('feedback.extension.no_access', $url_redirect); - } + if ($ext->getType() === 'system' && FreshRSS_Auth::hasAccess('admin')) { + $ext->install(); + + Minz_Configuration::addExtension($ext_name); + Minz_Configuration::writeFile(); - $ext->install(); + Minz_Request::good('feedback.extension.enabled', $url_redirect); + } elseif ($ext->getType() === 'user') { + $ext->install(); - FreshRSS_Context::$conf->addExtension($ext_name); - FreshRSS_Context::$conf->save(); + FreshRSS_Context::$conf->addExtension($ext_name); + FreshRSS_Context::$conf->save(); - Minz_Request::good('feedback.extension.enabled', $url_redirect); + Minz_Request::good('feedback.extension.enabled', $url_redirect); + } else { + Minz_Request::bad('feedback.extension.no_access', $url_redirect); + } } Minz_Request::forward($url_redirect, true); @@ -90,16 +97,23 @@ class FreshRSS_extension_Controller extends Minz_ActionController { Minz_Request::bad('feedback.extension.not_enabled', $url_redirect); } - if ($ext->getType() === 'system' && !FreshRSS_Auth::hasAccess('admin')) { - Minz_Request::bad('feedback.extension.no_access', $url_redirect); - } + if ($ext->getType() === 'system' && FreshRSS_Auth::hasAccess('admin')) { + $ext->uninstall(); + + Minz_Configuration::removeExtension($ext_name); + Minz_Configuration::writeFile(); - $ext->uninstall(); + Minz_Request::good('feedback.extension.disabled', $url_redirect); + } elseif ($ext->getType() === 'user') { + $ext->uninstall(); - FreshRSS_Context::$conf->removeExtension($ext_name); - FreshRSS_Context::$conf->save(); + FreshRSS_Context::$conf->removeExtension($ext_name); + FreshRSS_Context::$conf->save(); - Minz_Request::good('feedback.extension.disabled', $url_redirect); + Minz_Request::good('feedback.extension.disabled', $url_redirect); + } else { + Minz_Request::bad('feedback.extension.no_access', $url_redirect); + } } Minz_Request::forward($url_redirect, true); diff --git a/app/FreshRSS.php b/app/FreshRSS.php index dc7d0b375..b91dfcc46 100644 --- a/app/FreshRSS.php +++ b/app/FreshRSS.php @@ -29,9 +29,11 @@ class FreshRSS extends Minz_FrontController { // Load context and configuration. FreshRSS_Context::init(); - // Enable extensions for the current user. - $ext_list = FreshRSS_Context::$conf->extensions_enabled; - Minz_ExtensionManager::enable_by_list($ext_list); + // Enable extensions for the current (logged) user. + if (FreshRSS_Auth::hasAccess()) { + $ext_list = FreshRSS_Context::$conf->extensions_enabled; + Minz_ExtensionManager::enable_by_list($ext_list); + } // Init i18n. Minz_Session::_param('language', FreshRSS_Context::$conf->language); diff --git a/app/views/extension/index.phtml b/app/views/extension/index.phtml index c6b7c84a1..0be03d7b5 100644 --- a/app/views/extension/index.phtml +++ b/app/views/extension/index.phtml @@ -10,6 +10,7 @@ extension_list as $ext) { ?>
    • + getType() === 'user' || FreshRSS_Auth::hasAccess('admin')) { ?> getName()); ?>
      @@ -22,6 +23,9 @@
      + + +
    • getName(); ?>
    diff --git a/lib/Minz/Configuration.php b/lib/Minz/Configuration.php index 4d3ab0964..4a3221ef5 100644 --- a/lib/Minz/Configuration.php +++ b/lib/Minz/Configuration.php @@ -165,6 +165,19 @@ class Minz_Configuration { self::$unsafe_autologin_enabled = (bool)$value; } + public function removeExtension($ext_name) { + self::$extensions_enabled = array_diff( + self::$extensions_enabled, + array($ext_name) + ); + } + public function addExtension($ext_name) { + $found = array_search($ext_name, self::$extensions_enabled) !== false; + if (!$found) { + self::$extensions_enabled[] = $ext_name; + } + } + /** * Initialise les variables de configuration * @exception Minz_FileNotExistException si le CONF_PATH_NAME n'existe pas @@ -197,6 +210,7 @@ class Minz_Configuration { ), 'limits' => self::$limits, 'db' => self::$db, + 'extensions_enabled' => self::$extensions_enabled, ); @rename(DATA_PATH . self::CONF_PATH_NAME, DATA_PATH . self::CONF_PATH_NAME . '.bak.php'); $result = file_put_contents(DATA_PATH . self::CONF_PATH_NAME, " Date: Sat, 6 Dec 2014 16:48:13 +0100 Subject: Fix typo (extensions) - change feedback.extension into feedback.extensions - disable button is pushed by default See https://github.com/FreshRSS/FreshRSS/issues/252 --- app/Controllers/extensionController.php | 20 ++++++++++---------- app/views/extension/index.phtml | 2 +- 2 files changed, 11 insertions(+), 11 deletions(-) (limited to 'app/Controllers') diff --git a/app/Controllers/extensionController.php b/app/Controllers/extensionController.php index e348d9f31..543398b05 100644 --- a/app/Controllers/extensionController.php +++ b/app/Controllers/extensionController.php @@ -45,11 +45,11 @@ class FreshRSS_extension_Controller extends Minz_ActionController { $ext = Minz_ExtensionManager::find_extension($ext_name); if (is_null($ext)) { - Minz_Request::bad('feedback.extension.not_found', $url_redirect); + Minz_Request::bad('feedback.extensions.not_found', $url_redirect); } if ($ext->is_enabled()) { - Minz_Request::bad('feedback.extension.already_enabled', $url_redirect); + Minz_Request::bad('feedback.extensions.already_enabled', $url_redirect); } if ($ext->getType() === 'system' && FreshRSS_Auth::hasAccess('admin')) { @@ -58,16 +58,16 @@ class FreshRSS_extension_Controller extends Minz_ActionController { Minz_Configuration::addExtension($ext_name); Minz_Configuration::writeFile(); - Minz_Request::good('feedback.extension.enabled', $url_redirect); + Minz_Request::good('feedback.extensions.enabled', $url_redirect); } elseif ($ext->getType() === 'user') { $ext->install(); FreshRSS_Context::$conf->addExtension($ext_name); FreshRSS_Context::$conf->save(); - Minz_Request::good('feedback.extension.enabled', $url_redirect); + Minz_Request::good('feedback.extensions.enabled', $url_redirect); } else { - Minz_Request::bad('feedback.extension.no_access', $url_redirect); + Minz_Request::bad('feedback.extensions.no_access', $url_redirect); } } @@ -90,11 +90,11 @@ class FreshRSS_extension_Controller extends Minz_ActionController { $ext = Minz_ExtensionManager::find_extension($ext_name); if (is_null($ext)) { - Minz_Request::bad('feedback.extension.not_found', $url_redirect); + Minz_Request::bad('feedback.extensions.not_found', $url_redirect); } if (!$ext->is_enabled()) { - Minz_Request::bad('feedback.extension.not_enabled', $url_redirect); + Minz_Request::bad('feedback.extensions.not_enabled', $url_redirect); } if ($ext->getType() === 'system' && FreshRSS_Auth::hasAccess('admin')) { @@ -103,16 +103,16 @@ class FreshRSS_extension_Controller extends Minz_ActionController { Minz_Configuration::removeExtension($ext_name); Minz_Configuration::writeFile(); - Minz_Request::good('feedback.extension.disabled', $url_redirect); + Minz_Request::good('feedback.extensions.disabled', $url_redirect); } elseif ($ext->getType() === 'user') { $ext->uninstall(); FreshRSS_Context::$conf->removeExtension($ext_name); FreshRSS_Context::$conf->save(); - Minz_Request::good('feedback.extension.disabled', $url_redirect); + Minz_Request::good('feedback.extensions.disabled', $url_redirect); } else { - Minz_Request::bad('feedback.extension.no_access', $url_redirect); + Minz_Request::bad('feedback.extensions.no_access', $url_redirect); } } diff --git a/app/views/extension/index.phtml b/app/views/extension/index.phtml index 0be03d7b5..142ee4bc2 100644 --- a/app/views/extension/index.phtml +++ b/app/views/extension/index.phtml @@ -15,7 +15,7 @@
    is_enabled()) { ?> - + -- cgit v1.2.3 From 2da7c05fa6768b95a5cd0bd1c8f9934bbff05a03 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Sat, 6 Dec 2014 17:15:20 +0100 Subject: Update i18n (extensions) See https://github.com/FreshRSS/FreshRSS/issues/252 --- app/Controllers/extensionController.php | 30 ++++++++++++++++++++---------- app/i18n/en/admin.php | 5 +++++ app/i18n/en/feedback.php | 8 ++++++++ app/i18n/en/gen.php | 7 +++++++ app/i18n/fr/admin.php | 5 +++++ app/i18n/fr/feedback.php | 8 ++++++++ app/i18n/fr/gen.php | 7 +++++++ app/views/extension/index.phtml | 8 ++++---- 8 files changed, 64 insertions(+), 14 deletions(-) (limited to 'app/Controllers') diff --git a/app/Controllers/extensionController.php b/app/Controllers/extensionController.php index 543398b05..35b001094 100644 --- a/app/Controllers/extensionController.php +++ b/app/Controllers/extensionController.php @@ -45,11 +45,13 @@ class FreshRSS_extension_Controller extends Minz_ActionController { $ext = Minz_ExtensionManager::find_extension($ext_name); if (is_null($ext)) { - Minz_Request::bad('feedback.extensions.not_found', $url_redirect); + Minz_Request::bad(_t('feedback.extensions.not_found', $ext_name), + $url_redirect); } if ($ext->is_enabled()) { - Minz_Request::bad('feedback.extensions.already_enabled', $url_redirect); + Minz_Request::bad(_t('feedback.extensions.already_enabled', $ext_name), + $url_redirect); } if ($ext->getType() === 'system' && FreshRSS_Auth::hasAccess('admin')) { @@ -58,16 +60,19 @@ class FreshRSS_extension_Controller extends Minz_ActionController { Minz_Configuration::addExtension($ext_name); Minz_Configuration::writeFile(); - Minz_Request::good('feedback.extensions.enabled', $url_redirect); + Minz_Request::good(_t('feedback.extensions.enabled', $ext_name), + $url_redirect); } elseif ($ext->getType() === 'user') { $ext->install(); FreshRSS_Context::$conf->addExtension($ext_name); FreshRSS_Context::$conf->save(); - Minz_Request::good('feedback.extensions.enabled', $url_redirect); + Minz_Request::good(_t('feedback.extensions.enabled', $ext_name), + $url_redirect); } else { - Minz_Request::bad('feedback.extensions.no_access', $url_redirect); + Minz_Request::bad(_t('feedback.extensions.no_access', $ext_name), + $url_redirect); } } @@ -90,11 +95,13 @@ class FreshRSS_extension_Controller extends Minz_ActionController { $ext = Minz_ExtensionManager::find_extension($ext_name); if (is_null($ext)) { - Minz_Request::bad('feedback.extensions.not_found', $url_redirect); + Minz_Request::bad(_t('feedback.extensions.not_found', $ext_name), + $url_redirect); } if (!$ext->is_enabled()) { - Minz_Request::bad('feedback.extensions.not_enabled', $url_redirect); + Minz_Request::bad(_t('feedback.extensions.not_enabled', $ext_name), + $url_redirect); } if ($ext->getType() === 'system' && FreshRSS_Auth::hasAccess('admin')) { @@ -103,16 +110,19 @@ class FreshRSS_extension_Controller extends Minz_ActionController { Minz_Configuration::removeExtension($ext_name); Minz_Configuration::writeFile(); - Minz_Request::good('feedback.extensions.disabled', $url_redirect); + Minz_Request::good(_t('feedback.extensions.disabled', $ext_name), + $url_redirect); } elseif ($ext->getType() === 'user') { $ext->uninstall(); FreshRSS_Context::$conf->removeExtension($ext_name); FreshRSS_Context::$conf->save(); - Minz_Request::good('feedback.extensions.disabled', $url_redirect); + Minz_Request::good(_t('feedback.extensions.disabled', $ext_name), + $url_redirect); } else { - Minz_Request::bad('feedback.extensions.no_access', $url_redirect); + Minz_Request::bad(_t('feedback.extensions.no_access', $ext_name), + $url_redirect); } } diff --git a/app/i18n/en/admin.php b/app/i18n/en/admin.php index 74f01ae06..d73775d96 100644 --- a/app/i18n/en/admin.php +++ b/app/i18n/en/admin.php @@ -86,6 +86,11 @@ return array( 'ok' => 'You have ZIP extension.', ), ), + 'extensions' => array( + 'empty_list' => 'There is no installed extension', + 'system' => 'System extension (you have no rights on it)', + 'title' => 'Extensions', + ), 'users' => array( 'articles_and_size' => '%s articles (%s)', ), diff --git a/app/i18n/en/feedback.php b/app/i18n/en/feedback.php index b3866f1dc..df1dc5725 100644 --- a/app/i18n/en/feedback.php +++ b/app/i18n/en/feedback.php @@ -1,6 +1,14 @@ array( + 'already_enabled' => '%s is already enabled', + 'disabled' => '%s is now disabled', + 'enabled' => '%s is now enabled', + 'no_access' => 'You have no access on %s', + 'not_enabled' => '%s is not enabled yet', + 'not_found' => '%s does not exist', + ), 'login' => array( 'error' => 'Login is invalid', 'success' => 'You are connected', diff --git a/app/i18n/en/gen.php b/app/i18n/en/gen.php index 9e06357bc..ba5f0c86d 100644 --- a/app/i18n/en/gen.php +++ b/app/i18n/en/gen.php @@ -190,10 +190,17 @@ return array( 'freshrss_installation' => 'Installation · FreshRSS', 'fri' => 'Fri', 'g+' => 'Google+', + 'actions' => array( + 'disable' => 'Disable', + 'enable' => 'Enable', + 'manage' => 'Manage', + 'remove' => 'Remove', + ), 'menu' => array( 'admin' => 'Administration', 'authentication' => 'Authentication', 'check_install' => 'Installation checking', + 'extensions' => 'Extensions', 'user_management' => 'Manage users', 'user_profile' => 'Profile', ), diff --git a/app/i18n/fr/admin.php b/app/i18n/fr/admin.php index ad1fae6c0..e46a5a7b0 100644 --- a/app/i18n/fr/admin.php +++ b/app/i18n/fr/admin.php @@ -86,6 +86,11 @@ return array( 'ok' => 'Vous disposez de l\'extension ZIP.', ), ), + 'extensions' => array( + 'empty_list' => 'Il n’y a aucune extension installée.', + 'system' => 'Extension système (vous n’avez aucun droit dessus)', + 'title' => 'Extensions', + ), 'users' => array( 'articles_and_size' => '%s articles (%s)', ), diff --git a/app/i18n/fr/feedback.php b/app/i18n/fr/feedback.php index f4bb7cccf..7d3ab9db7 100644 --- a/app/i18n/fr/feedback.php +++ b/app/i18n/fr/feedback.php @@ -1,6 +1,14 @@ array( + 'already_enabled' => '%s est déjà activée', + 'disabled' => '%s est désormais désactivée', + 'enabled' => '%s est désormais activée', + 'no_access' => 'Vous n’avez aucun accès sur %s', + 'not_enabled' => '%s n’est pas encore activée', + 'not_found' => '%s n’existe pas', + ), 'login' => array( 'error' => 'L’identifiant est invalide !', 'success' => 'Vous êtes désormais connecté', diff --git a/app/i18n/fr/gen.php b/app/i18n/fr/gen.php index 0b2395bd0..44d8fb837 100644 --- a/app/i18n/fr/gen.php +++ b/app/i18n/fr/gen.php @@ -191,10 +191,17 @@ return array( 'freshrss_installation' => 'Installation · FreshRSS', 'fri' => 'ven.', 'g+' => 'Google+', + 'actions' => array( + 'disable' => 'Désactiver', + 'enable' => 'Activer', + 'manage' => 'Gérer', + 'remove' => 'Supprimer', + ), 'menu' => array( 'admin' => 'Administration', 'authentication' => 'Authentification', 'check_install' => 'Vérification de l’installation', + 'extensions' => 'Extensions', 'user_management' => 'Gestion des utilisateurs', 'user_profile' => 'Profil', ), diff --git a/app/views/extension/index.phtml b/app/views/extension/index.phtml index 142ee4bc2..d34a84452 100644 --- a/app/views/extension/index.phtml +++ b/app/views/extension/index.phtml @@ -13,14 +13,14 @@ getType() === 'user' || FreshRSS_Auth::hasAccess('admin')) { ?> getName()); ?>
    - + is_enabled()) { ?> - + - + - +
    -- cgit v1.2.3 From bc81979a6b25554c4832d5ccb41b427023096463 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Sat, 6 Dec 2014 17:25:01 +0100 Subject: Add default behaviour for configure / remove ext See https://github.com/FreshRSS/FreshRSS/issues/252 --- app/Controllers/extensionController.php | 7 ++++++- app/views/extension/configure.phtml | 12 ++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) create mode 100644 app/views/extension/configure.phtml (limited to 'app/Controllers') diff --git a/app/Controllers/extensionController.php b/app/Controllers/extensionController.php index 35b001094..a1e39af37 100644 --- a/app/Controllers/extensionController.php +++ b/app/Controllers/extensionController.php @@ -130,6 +130,11 @@ class FreshRSS_extension_Controller extends Minz_ActionController { } public function removeAction() { - + if (!FreshRSS_Auth::hasAccess('admin')) { + Minz_Error::error(403); + } + + $url_redirect = array('c' => 'extension', 'a' => 'index'); + Minz_Request::bad('not implemented yet!', $url_redirect); } } diff --git a/app/views/extension/configure.phtml b/app/views/extension/configure.phtml new file mode 100644 index 000000000..a79e9baac --- /dev/null +++ b/app/views/extension/configure.phtml @@ -0,0 +1,12 @@ +partial('aside_configure'); +} + +?> + +
    +

    Extension name

    + Not implemented yet! +
    \ No newline at end of file -- cgit v1.2.3 From 08546af75ff9a25eac3409649ea4660fe070720c Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Sat, 6 Dec 2014 18:48:00 +0100 Subject: Add a first draft for hooks - New Extension->registerHook($hook_name, $hook_function) method to register a new hook - Only one hook works for the moment: entry_before_insert - ExtensionManager::callHook will need to evolve based on future hooks See https://github.com/FreshRSS/FreshRSS/issues/252 --- app/Controllers/feedController.php | 11 ++++++-- lib/Minz/Extension.php | 10 +++++++ lib/Minz/ExtensionManager.php | 55 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 74 insertions(+), 2 deletions(-) (limited to 'app/Controllers') diff --git a/app/Controllers/feedController.php b/app/Controllers/feedController.php index 9990a852c..dce79c57a 100755 --- a/app/Controllers/feedController.php +++ b/app/Controllers/feedController.php @@ -329,9 +329,16 @@ class FreshRSS_feed_Controller extends Minz_ActionController { $id = min(time(), $entry_date) . uSecString(); } + $entry->_id($id); + $entry->_isRead($is_read); + + $entry = Minz_ExtensionManager::callHook('entry_before_insert', $entry); + if (is_null($entry)) { + // An extension has returned a null value, there is nothing to insert. + continue; + } + $values = $entry->toArray(); - $values['id'] = $id; - $values['is_read'] = $is_read; $entryDAO->addEntry($values, $prepared_statement); } } diff --git a/lib/Minz/Extension.php b/lib/Minz/Extension.php index 490a5c5cb..c93ba2520 100644 --- a/lib/Minz/Extension.php +++ b/lib/Minz/Extension.php @@ -153,4 +153,14 @@ class Minz_Extension { public function registerViews() { Minz_View::addBasePathname($this->path); } + + /** + * Register a new hook. + * + * @param $hook_name the hook name (must exist). + * @param $hook_function the function name to call (must be callable). + */ + public function registerHook($hook_name, $hook_function) { + Minz_ExtensionManager::addHook($hook_name, $hook_function, $this); + } } diff --git a/lib/Minz/ExtensionManager.php b/lib/Minz/ExtensionManager.php index 46e421bac..7557e178f 100644 --- a/lib/Minz/ExtensionManager.php +++ b/lib/Minz/ExtensionManager.php @@ -2,6 +2,8 @@ /** * An extension manager to load extensions present in EXTENSIONS_PATH. + * + * @todo see coding style for methods!! */ class Minz_ExtensionManager { private static $ext_metaname = 'metadata.json'; @@ -11,6 +13,11 @@ class Minz_ExtensionManager { private static $ext_auto_enabled = array(); + private static $hook_list = array( + 'entry_before_insert' => array(), // function($entry) + ); + private static $ext_to_hooks = array(); + /** * Initialize the extension manager by loading extensions in EXTENSIONS_PATH. * @@ -131,6 +138,8 @@ class Minz_ExtensionManager { in_array($name, self::$ext_auto_enabled)) { self::enable($ext->getName()); } + + self::$ext_to_hooks[$name] = array(); } /** @@ -187,4 +196,50 @@ class Minz_ExtensionManager { return self::$ext_list[$ext_name]; } + + /** + * Add a hook function to a given hook. + * + * The hook name must be a valid one. For the valid list, see self::$hook_list + * array keys. + * + * @param $hook_name the hook name (must exist). + * @param $hook_function the function name to call (must be callable). + * @param $ext the extension which register the hook. + */ + public static function addHook($hook_name, $hook_function, $ext) { + if (isset(self::$hook_list[$hook_name]) && is_callable($hook_function)) { + self::$hook_list[$hook_name][] = $hook_function; + self::$ext_to_hooks[$ext->getName()][] = $hook_name; + } + } + + /** + * Call functions related to a given hook. + * + * The hook name must be a valid one. For the valid list, see self::$hook_list + * array keys. + * + * @param $hook_name the hook to call. + * @param additionnal parameters (for signature, please see self::$hook_list comments) + * @todo hook functions will have different signatures. So the $res = func($args); + * $args = $res; will not work for all of them in the future. We must + * find a better way to call hooks. + */ + public static function callHook($hook_name) { + $args = func_get_args(); + unset($args[0]); + + $result = $args; + foreach (self::$hook_list[$hook_name] as $function) { + $result = call_user_func_array($function, $args); + + if (is_null($result)) { + break; + } + + $args = $result; + } + return $result; + } } -- cgit v1.2.3 From 7ef4d6c033d6d12a644b6cf39940591901fdcb3b Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Sun, 7 Dec 2014 14:39:02 +0100 Subject: Fix entry_before_insert hook The hook must be called also in: - feedController->addAction() - importExportController->importJson() See https://github.com/FreshRSS/FreshRSS/issues/252 --- app/Controllers/feedController.php | 13 ++++++++++--- app/Controllers/importExportController.php | 6 ++++++ 2 files changed, 16 insertions(+), 3 deletions(-) (limited to 'app/Controllers') diff --git a/app/Controllers/feedController.php b/app/Controllers/feedController.php index dce79c57a..0a7edbee3 100755 --- a/app/Controllers/feedController.php +++ b/app/Controllers/feedController.php @@ -174,10 +174,17 @@ class FreshRSS_feed_Controller extends Minz_ActionController { $feedDAO->beginTransaction(); foreach ($entries as $entry) { // Entries are added without any verification. + $entry->_feed($feed->id()); + $entry->_id(min(time(), $entry->date(true)) . uSecString()); + $entry->_isRead($is_read); + + $entry = Minz_ExtensionManager::callHook('entry_before_insert', $entry); + if (is_null($entry)) { + // An extension has returned a null value, there is nothing to insert. + continue; + } + $values = $entry->toArray(); - $values['id_feed'] = $feed->id(); - $values['id'] = min(time(), $entry->date(true)) . uSecString(); - $values['is_read'] = $is_read; $entryDAO->addEntry($values, $prepared_statement); } $feedDAO->updateLastUpdate($feed->id()); diff --git a/app/Controllers/importExportController.php b/app/Controllers/importExportController.php index 4e2dbd157..c67b30431 100644 --- a/app/Controllers/importExportController.php +++ b/app/Controllers/importExportController.php @@ -385,6 +385,12 @@ class FreshRSS_importExport_Controller extends Minz_ActionController { $entry->_id(min(time(), $entry->date(true)) . uSecString()); $entry->_tags($tags); + $entry = Minz_ExtensionManager::callHook('entry_before_insert', $entry); + if (is_null($entry)) { + // An extension has returned a null value, there is nothing to insert. + continue; + } + $values = $entry->toArray(); $id = $this->entryDAO->addEntry($values, $prepared_statement); -- cgit v1.2.3 From c6dfec3ad351ee3b828c6a2c0a273bad5d9ac0df Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Mon, 8 Dec 2014 12:01:47 +0100 Subject: Add behaviour to configure action (extensions) - Put extension configure view in dir_ext/configure.phtml - Handle POST action in Extension->handleConfigureAction() method See https://github.com/FreshRSS/FreshRSS/issues/252 --- app/Controllers/extensionController.php | 16 ++++++++++++++++ app/views/extension/configure.phtml | 17 ++++++++++++++--- lib/Minz/Extension.php | 21 +++++++++++++++++++++ 3 files changed, 51 insertions(+), 3 deletions(-) (limited to 'app/Controllers') diff --git a/app/Controllers/extensionController.php b/app/Controllers/extensionController.php index a1e39af37..73b8070cb 100644 --- a/app/Controllers/extensionController.php +++ b/app/Controllers/extensionController.php @@ -27,6 +27,22 @@ class FreshRSS_extension_Controller extends Minz_ActionController { if (Minz_Request::param('ajax')) { $this->view->_useLayout(false); } + + $ext_name = urldecode(Minz_Request::param('e')); + $ext = Minz_ExtensionManager::find_extension($ext_name); + + if (is_null($ext)) { + Minz_Error::error(404); + } + if ($ext->getType() === 'system' && !FreshRSS_Auth::hasAccess('admin')) { + Minz_Error::error(403); + } + + $this->view->extension = $ext; + + if (Minz_Request::isPost()) { + $this->view->extension->handleConfigureAction(); + } } /** diff --git a/app/views/extension/configure.phtml b/app/views/extension/configure.phtml index a79e9baac..295080d5e 100644 --- a/app/views/extension/configure.phtml +++ b/app/views/extension/configure.phtml @@ -7,6 +7,17 @@ if (!Minz_Request::param('ajax')) { ?>
    -

    Extension name

    - Not implemented yet! -
    \ No newline at end of file +

    extension->getName(); ?> (extension->getVersion(); ?>) — extension->getType(); ?>

    + +

    extension->getDescription(); ?> — extension->getAuthor(); ?>

    + +

    + extension->getConfigureView(); + if ($configure_view !== false) { + echo $configure_view; + } else { + ?> +

    + +
    diff --git a/lib/Minz/Extension.php b/lib/Minz/Extension.php index c93ba2520..1d706ed80 100644 --- a/lib/Minz/Extension.php +++ b/lib/Minz/Extension.php @@ -86,6 +86,27 @@ class Minz_Extension { return $this->is_enabled; } + /** + * Return the content of the configure view for the current extension. + * + * @return the html content from ext_dir/configure.phtml, false if it does + * not exist. + */ + public function getConfigureView() { + $filename = $this->path . '/configure.phtml'; + if (!file_exists($filename)) { + return false; + } + return @file_get_contents($filename); + } + + /** + * Handle the configure POST action. + * + * It must be redefined by child classes. + */ + public function handleConfigureAction() {} + /** * Getters and setters. */ -- cgit v1.2.3 From 188b517daa174ce494f31dec02ae2cff122488ff Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Mon, 8 Dec 2014 13:05:56 +0100 Subject: Add a feed_before_insert hook See https://github.com/FreshRSS/FreshRSS/issues/252 --- app/Controllers/feedController.php | 6 ++++++ app/Controllers/importExportController.php | 30 ++++++++++++++++++++---------- lib/Minz/ExtensionManager.php | 1 + 3 files changed, 27 insertions(+), 10 deletions(-) (limited to 'app/Controllers') diff --git a/app/Controllers/feedController.php b/app/Controllers/feedController.php index 0a7edbee3..7dda3840e 100755 --- a/app/Controllers/feedController.php +++ b/app/Controllers/feedController.php @@ -138,6 +138,12 @@ class FreshRSS_feed_Controller extends Minz_ActionController { $feed->_category($cat); $feed->_httpAuth($http_auth); + // Call the extension hook + $feed = Minz_ExtensionManager::callHook('feed_before_insert', $feed); + if (is_null($feed)) { + Minz_Request::bad(_t('feed_not_added', $feed->name()), $url_redirect); + } + $values = array( 'url' => $feed->url(), 'category' => $feed->category(), diff --git a/app/Controllers/importExportController.php b/app/Controllers/importExportController.php index c67b30431..52df5bf8b 100644 --- a/app/Controllers/importExportController.php +++ b/app/Controllers/importExportController.php @@ -259,10 +259,16 @@ class FreshRSS_importExport_Controller extends Minz_ActionController { $feed->_website($website); $feed->_description($description); - // addFeedObject checks if feed is already in DB so nothing else to - // check here - $id = $this->feedDAO->addFeedObject($feed); - $error = ($id === false); + // Call the extension hook + $feed = Minz_ExtensionManager::callHook('feed_before_insert', $feed); + if (!is_null($feed)) { + // addFeedObject checks if feed is already in DB so nothing else to + // check here + $id = $this->feedDAO->addFeedObject($feed); + $error = ($id === false); + } else { + $error = true; + } } catch (FreshRSS_Feed_Exception $e) { Minz_Log::warning($e->getMessage()); $error = true; @@ -427,13 +433,17 @@ class FreshRSS_importExport_Controller extends Minz_ActionController { $feed->_name($name); $feed->_website($website); - // addFeedObject checks if feed is already in DB so nothing else to - // check here. - $id = $this->feedDAO->addFeedObject($feed); + // Call the extension hook + $feed = Minz_ExtensionManager::callHook('feed_before_insert', $feed); + if (!is_null($feed)) { + // addFeedObject checks if feed is already in DB so nothing else to + // check here. + $id = $this->feedDAO->addFeedObject($feed); - if ($id !== false) { - $feed->_id($id); - $return = $feed; + if ($id !== false) { + $feed->_id($id); + $return = $feed; + } } } catch (FreshRSS_Feed_Exception $e) { Minz_Log::warning($e->getMessage()); diff --git a/lib/Minz/ExtensionManager.php b/lib/Minz/ExtensionManager.php index 5491c7cf6..9e6a3155a 100644 --- a/lib/Minz/ExtensionManager.php +++ b/lib/Minz/ExtensionManager.php @@ -17,6 +17,7 @@ class Minz_ExtensionManager { private static $hook_list = array( 'entry_before_display' => array(), // function($entry) -> Entry | null 'entry_before_insert' => array(), // function($entry) -> Entry | null + 'feed_before_insert' => array(), // function($feed) -> Feed | null ); private static $ext_to_hooks = array(); -- cgit v1.2.3 From 28c77f22900a10ac43c6d61b2b2d1a146feac42a Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Mon, 8 Dec 2014 13:12:12 +0100 Subject: Fix a bug with feed_before_insert hook $feed->name() was called on a null value. See https://github.com/FreshRSS/FreshRSS/issues/252 --- app/Controllers/feedController.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'app/Controllers') diff --git a/app/Controllers/feedController.php b/app/Controllers/feedController.php index 7dda3840e..379b8d8da 100755 --- a/app/Controllers/feedController.php +++ b/app/Controllers/feedController.php @@ -139,9 +139,10 @@ class FreshRSS_feed_Controller extends Minz_ActionController { $feed->_httpAuth($http_auth); // Call the extension hook + $name = $feed->name(); $feed = Minz_ExtensionManager::callHook('feed_before_insert', $feed); if (is_null($feed)) { - Minz_Request::bad(_t('feed_not_added', $feed->name()), $url_redirect); + Minz_Request::bad(_t('feed_not_added', $name), $url_redirect); } $values = array( -- cgit v1.2.3 From 0543f96a97fa860fdec38d61b117e6b5addf94b6 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Mon, 8 Dec 2014 13:22:11 +0100 Subject: Update comments for ExtensionController See https://github.com/FreshRSS/FreshRSS/issues/252 --- app/Controllers/extensionController.php | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) (limited to 'app/Controllers') diff --git a/app/Controllers/extensionController.php b/app/Controllers/extensionController.php index 73b8070cb..cd56de9eb 100644 --- a/app/Controllers/extensionController.php +++ b/app/Controllers/extensionController.php @@ -23,6 +23,16 @@ class FreshRSS_extension_Controller extends Minz_ActionController { $this->view->extension_list = Minz_ExtensionManager::list_extensions(); } + /** + * This action handles configuration of a given extension. + * + * Only administrator can configure a system extension. + * + * Parameters are: + * - e: the extension name (urlencoded) + * - additional parameters which should be handle by the extension + * handleConfigureAction() method (POST request). + */ public function configureAction() { if (Minz_Request::param('ajax')) { $this->view->_useLayout(false); @@ -49,6 +59,7 @@ class FreshRSS_extension_Controller extends Minz_ActionController { * This action enables a disabled extension for the current user. * * System extensions can only be enabled by an administrator. + * This action must be reached by a POST request. * * Parameter is: * - e: the extension name (urlencoded). @@ -99,6 +110,7 @@ class FreshRSS_extension_Controller extends Minz_ActionController { * This action disables an enabled extension for the current user. * * System extensions can only be disabled by an administrator. + * This action must be reached by a POST request. * * Parameter is: * - e: the extension name (urlencoded). @@ -145,6 +157,15 @@ class FreshRSS_extension_Controller extends Minz_ActionController { Minz_Request::forward($url_redirect, true); } + /** + * This action handles deletion of an extension. + * + * Only administrator can remove an extension. + * This action must be reached by a POST request. + * + * Parameter is: + * -e: extension name (urlencoded) + */ public function removeAction() { if (!FreshRSS_Auth::hasAccess('admin')) { Minz_Error::error(403); -- cgit v1.2.3 From 76358846abe2eba95668d66d3847cbdfe3f8bcdc Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Mon, 8 Dec 2014 13:36:08 +0100 Subject: Implement extension deletion See https://github.com/FreshRSS/FreshRSS/issues/252 --- app/Controllers/extensionController.php | 22 +++++++++++++++++++++- lib/lib_rss.php | 26 ++++++++++++++++++++++++++ 2 files changed, 47 insertions(+), 1 deletion(-) (limited to 'app/Controllers') diff --git a/app/Controllers/extensionController.php b/app/Controllers/extensionController.php index cd56de9eb..adb3e1864 100644 --- a/app/Controllers/extensionController.php +++ b/app/Controllers/extensionController.php @@ -172,6 +172,26 @@ class FreshRSS_extension_Controller extends Minz_ActionController { } $url_redirect = array('c' => 'extension', 'a' => 'index'); - Minz_Request::bad('not implemented yet!', $url_redirect); + + if (Minz_Request::isPost()) { + $ext_name = urldecode(Minz_Request::param('e')); + $ext = Minz_ExtensionManager::find_extension($ext_name); + + if (is_null($ext)) { + Minz_Request::bad(_t('feedback.extensions.not_found', $ext_name), + $url_redirect); + } + + $res = recursive_unlink($ext->getPath()); + if ($res) { + Minz_Request::good(_t('feedback.extensions.removed', $ext_name), + $url_redirect); + } else { + Minz_Request::bad(_t('feedback.extensions.cannot_delete', $ext_name), + $url_redirect); + } + } + + Minz_Request::forward($url_redirect, true); } } diff --git a/lib/lib_rss.php b/lib/lib_rss.php index 8170c7fd9..e466bcb15 100644 --- a/lib/lib_rss.php +++ b/lib/lib_rss.php @@ -319,3 +319,29 @@ function check_install_database() { return $status; } + +/** + * Remove a directory recursively. + * + * From http://php.net/rmdir#110489 + * + * @param $dir the directory to remove + */ +function recursive_unlink($dir) { + if (!is_dir($dir)) { + return true; + } + + $files = array_diff(scandir($dir), array('.', '..')); + foreach ($files as $filename) { + $filename = $dir . '/' . $filename; + if (is_dir($filename)) { + @chmod($filename, 0777); + recursive_unlink($filename); + } else { + unlink($filename); + } + } + + return rmdir($dir); +} -- cgit v1.2.3 From 70c1f0ebb08e2edf1721e2d3f8f98837c5910da4 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Tue, 9 Dec 2014 12:43:33 +0100 Subject: Fix redirection after feed refresh Fix https://github.com/FreshRSS/FreshRSS/issues/716 --- app/Controllers/feedController.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'app/Controllers') diff --git a/app/Controllers/feedController.php b/app/Controllers/feedController.php index 9990a852c..c8727c727 100755 --- a/app/Controllers/feedController.php +++ b/app/Controllers/feedController.php @@ -392,8 +392,9 @@ class FreshRSS_feed_Controller extends Minz_ActionController { // Redirect to the main page with correct notification. if ($updated_feeds === 1) { $feed = reset($feeds); - Minz_Request::good(_t('feed_actualized', $feed->name()), - array('get' => 'f_' . $feed->id())); + Minz_Request::good(_t('feed_actualized', $feed->name()), array( + 'params' => array('get' => 'f_' . $feed->id()) + )); } elseif ($updated_feeds > 1) { Minz_Request::good(_t('n_feeds_actualized', $updated_feeds), array()); } else { -- cgit v1.2.3 From 8a40a726575947c074216ad9084275e0195f9c30 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Wed, 10 Dec 2014 23:16:12 +0100 Subject: Fix i18n for logs, pagination and javascript vars Logs first to avoid annoying message when refreshing log page --- app/Controllers/indexController.php | 2 +- app/i18n/en/gen.php | 26 ++++++++++++++------------ app/i18n/en/index.php | 6 ++++++ app/i18n/fr/gen.php | 26 ++++++++++++++------------ app/i18n/fr/index.php | 6 ++++++ app/views/helpers/javascript_vars.phtml | 8 ++++---- app/views/helpers/logs_pagination.phtml | 8 ++++---- app/views/index/logs.phtml | 8 ++++---- 8 files changed, 53 insertions(+), 37 deletions(-) (limited to 'app/Controllers') diff --git a/app/Controllers/indexController.php b/app/Controllers/indexController.php index 1cf618f7f..eff47ed58 100755 --- a/app/Controllers/indexController.php +++ b/app/Controllers/indexController.php @@ -217,7 +217,7 @@ class FreshRSS_index_Controller extends Minz_ActionController { Minz_Error::error(403); } - Minz_View::prependTitle(_t('logs') . ' · '); + Minz_View::prependTitle(_t('index.logs.title') . ' · '); if (Minz_Request::isPost()) { FreshRSS_LogDAO::truncate(); diff --git a/app/i18n/en/gen.php b/app/i18n/en/gen.php index eadc80360..28659cccb 100644 --- a/app/i18n/en/gen.php +++ b/app/i18n/en/gen.php @@ -2,6 +2,7 @@ return array( 'action' => array( + 'back_to_rss_feeds' => '← Go back to your RSS feeds', 'disable' => 'Disable', 'enable' => 'Enable', 'manage' => 'Manage', @@ -11,6 +12,13 @@ return array( 'login' => 'Login', 'logout' => 'Logout', ), + 'js' => array( + 'category_empty' => 'Empty category', + 'confirm_action' => 'Are you sure you want to perform this action? It cannot be cancelled!', + 'confirm_action_feed_cat' => 'Are you sure you want to perform this action? You will lose related favorites and user queries. It cannot be cancelled!', + 'notif_body_new_articles' => 'There are \\d new articles to read on FreshRSS.', + 'notif_title_new_articles' => 'FreshRSS: new articles!', + ), 'menu' => array( 'about' => 'About', 'admin' => 'Administration', @@ -29,6 +37,12 @@ return array( 'user_management' => 'Manage users', 'user_profile' => 'Profile', ), + 'pagination' => array( + 'first' => 'First', + 'last' => 'Last', + 'next' => 'Next', + 'previous' => 'Previous', + ), 'title' => array( '_' => 'Title', 'authentication' => 'Authentication', @@ -96,7 +110,6 @@ return array( 'auto_remove_article' => 'Hide articles after reading', 'auto_share' => 'Share', 'auto_share_help' => 'If there is only one sharing mode, it is used. Else modes are accessible by their number.', - 'back_to_rss_feeds' => '← Go back to your RSS feeds', 'bad_opml_file' => 'Your OPML file is invalid', 'base_url' => 'Base URL', 'bdd' => 'Database', @@ -125,7 +138,6 @@ return array( 'category_created' => 'Category %s has been created.', 'category_deleted' => 'Category has been deleted.', 'category_emptied' => 'Category has been emptied', - 'category_empty' => 'Empty category', 'category_name_exists' => 'Category name already exists.', 'category_no_id' => 'You must precise the id of the category.', 'category_no_name' => 'Category name cannot be empty.', @@ -136,11 +148,8 @@ return array( 'change_value' => 'You should change this value by any other', 'checks' => 'Checks', 'choose_language' => 'Choose a language for FreshRSS', - 'clear_logs' => 'Clear the logs', 'collapse_article' => 'Collapse', 'configuration_updated' => 'Configuration has been updated', - 'confirm_action' => 'Are you sure you want to perform this action? It cannot be cancelled!', - 'confirm_action_feed_cat' => 'Are you sure you want to perform this action? You will lose related favorites and user queries. It cannot be cancelled!', 'congratulations' => 'Congratulations!', 'content_width' => 'Content width', 'create' => 'Create', @@ -204,7 +213,6 @@ return array( 'file_to_import' => 'File to import
    (OPML, Json or Zip)', 'file_to_import_no_zip' => 'File to import
    (OPML or Json)', 'finish_installation' => 'Complete installation', - 'first' => 'First', 'first_article' => 'Skip to the first article', 'fix_errors_before' => 'Fix errors before skip to the next step.', 'focus_search' => 'Access search box', @@ -252,7 +260,6 @@ return array( 'keep_logged_in' => 'Keep me logged in (1 month)', 'language' => 'Language', 'language_defined' => 'Language has been defined.', - 'last' => 'Last', 'last_3_month' => 'Last three months', 'last_6_month' => 'Last six months', 'last_article' => 'Skip to the last article', @@ -267,7 +274,6 @@ return array( 'login_persona_problem' => 'Connection problem with Persona?', 'login_required' => 'Login required:', 'login_with_persona' => 'Login with Persona', - 'logs_empty' => 'Log file is empty', 'mar' => 'mar', 'march' => 'Mar', 'mark_cat_read' => 'Mark category as read', @@ -283,7 +289,6 @@ return array( 'n_feeds_actualized' => '%d feeds have been updated', 'new_article' => 'There are new available articles, click to refresh the page.', 'new_category' => 'New category', - 'next' => 'Next', 'next_article' => 'Skip to the next article', 'next_page' => 'Skip to the next page', 'next_step' => 'Go to the next step', @@ -301,8 +306,6 @@ return array( 'not_reads' => '%d unread', 'not_yet_implemented' => 'Not yet implemented', 'nothing_to_load' => 'There are no more articles', - 'notif_body_new_articles' => 'There are \\d new articles to read on FreshRSS.', - 'notif_title_new_articles' => 'FreshRSS: new articles!', 'nov' => 'nov', 'november' => 'Nov', 'number_articles' => '%d articles', @@ -329,7 +332,6 @@ return array( 'php_is_nok' => 'Your PHP version is %s but FreshRSS requires at least version %s', 'php_is_ok' => 'Your PHP version is %s, which is compatible with FreshRSS', 'prefix' => 'Table prefix', - 'previous' => 'Previous', 'previous_article' => 'Skip to the previous article', 'previous_page' => 'Skip to the previous page', 'print' => 'Print', diff --git a/app/i18n/en/index.php b/app/i18n/en/index.php index 5e05657d1..97df646c4 100644 --- a/app/i18n/en/index.php +++ b/app/i18n/en/index.php @@ -1,6 +1,12 @@ array( + '_' => 'Logs', + 'clear' => 'Clear the logs', + 'empty' => 'Log file is empty', + 'title' => 'Logs', + ), 'menu' => array( 'about' => 'About FreshRSS', 'actualize' => 'Actualize', diff --git a/app/i18n/fr/gen.php b/app/i18n/fr/gen.php index d22e51f2d..3d3878eb1 100644 --- a/app/i18n/fr/gen.php +++ b/app/i18n/fr/gen.php @@ -2,6 +2,7 @@ return array( 'action' => array( + 'back_to_rss_feeds' => '← Retour à vos flux RSS', 'disable' => 'Désactiver', 'enable' => 'Activer', 'manage' => 'Gérer', @@ -11,6 +12,13 @@ return array( 'login' => 'Connexion', 'logout' => 'Déconnexion', ), + 'js' => array( + 'category_empty' => 'Catégorie vide', + 'confirm_action' => 'Êtes-vous sûr(e) de vouloir continuer ? Cette action ne peut être annulée !', + 'confirm_action_feed_cat' => 'Êtes-vous sûr(e) de vouloir continuer ? Vous perdrez les favoris et les filtres associés. Cette action ne peut être annulée !', + 'notif_body_new_articles' => 'Il y a \\d nouveaux articles à lire sur FreshRSS.', + 'notif_title_new_articles' => 'FreshRSS : nouveaux articles !', + ), 'menu' => array( 'about' => 'À propos', 'admin' => 'Administration', @@ -29,6 +37,12 @@ return array( 'user_management' => 'Gestion des utilisateurs', 'user_profile' => 'Profil', ), + 'pagination' => array( + 'first' => 'Début', + 'last' => 'Fin', + 'next' => 'Suivant', + 'previous' => 'Précédent', + ), 'title' => array( '_' => 'Titre', 'authentication' => 'Authentification', @@ -96,7 +110,6 @@ return array( 'auto_remove_article' => 'Cacher les articles après lecture', 'auto_share' => 'Partager', 'auto_share_help' => 'S’il n’y a qu’un mode de partage, celui-ci est utilisé automatiquement. Sinon ils sont accessibles par leur numéro.', - 'back_to_rss_feeds' => '← Retour à vos flux RSS', 'bad_opml_file' => 'Votre fichier OPML n’est pas valide.', 'base_url' => 'Base de l’URL', 'bdd' => 'Base de données', @@ -125,7 +138,6 @@ return array( 'category_created' => 'La catégorie %s a été créée.', 'category_deleted' => 'La catégorie a été supprimée.', 'category_emptied' => 'La catégorie a été vidée.', - 'category_empty' => 'Catégorie vide', 'category_name_exists' => 'Une catégorie possède déjà ce nom.', 'category_no_id' => 'Vous devez préciser l’id de la catégorie.', 'category_no_name' => 'Vous devez préciser un nom pour la catégorie.', @@ -136,11 +148,8 @@ return array( 'change_value' => 'Vous devriez changer cette valeur par n’importe quelle autre', 'checks' => 'Vérifications', 'choose_language' => 'Choisissez la langue pour FreshRSS', - 'clear_logs' => 'Effacer les logs', 'collapse_article' => 'Refermer', 'configuration_updated' => 'La configuration a été mise à jour.', - 'confirm_action' => 'Êtes-vous sûr(e) de vouloir continuer ? Cette action ne peut être annulée !', - 'confirm_action_feed_cat' => 'Êtes-vous sûr(e) de vouloir continuer ? Vous perdrez les favoris et les filtres associés. Cette action ne peut être annulée !', 'congratulations' => 'Félicitations !', 'content_width' => 'Largeur du contenu', 'create' => 'Créer', @@ -204,7 +213,6 @@ return array( 'file_to_import' => 'Fichier à importer
    (OPML, Json ou Zip)', 'file_to_import_no_zip' => 'Fichier à importer
    (OPML ou Json)', 'finish_installation' => 'Terminer l’installation', - 'first' => 'Début', 'first_article' => 'Passer au premier article', 'fix_errors_before' => 'Veuillez corriger les erreurs avant de passer à l’étape suivante.', 'focus_search' => 'Accéder à la recherche', @@ -252,7 +260,6 @@ return array( 'keep_logged_in' => 'Rester connecté (1 mois)', 'language' => 'Langue', 'language_defined' => 'La langue a bien été définie.', - 'last' => 'Fin', 'last_3_month' => 'Depuis les trois derniers mois', 'last_6_month' => 'Depuis les six derniers mois', 'last_article' => 'Passer au dernier article', @@ -267,7 +274,6 @@ return array( 'login_persona_problem' => 'Problème de connexion à Persona ?', 'login_required' => 'Accès protégé par mot de passe :', 'login_with_persona' => 'Connexion avec Persona', - 'logs_empty' => 'Les logs sont vides.', 'mar' => 'mar.', 'march' => 'mars', 'mark_cat_read' => 'Marquer la catégorie comme lue', @@ -283,7 +289,6 @@ return array( 'n_feeds_actualized' => '%d flux ont été mis à jour.', 'new_article' => 'Il y a de nouveaux articles disponibles, cliquez pour rafraîchir la page.', 'new_category' => 'Nouvelle catégorie', - 'next' => 'Suivant', 'next_article' => 'Passer à l’article suivant', 'next_page' => 'Passer à la page suivante', 'next_step' => 'Passer à l’étape suivante', @@ -301,8 +306,6 @@ return array( 'not_reads' => '%d non lus', 'not_yet_implemented' => 'Pas encore implémenté', 'nothing_to_load' => 'Fin des articles', - 'notif_body_new_articles' => 'Il y a \\d nouveaux articles à lire sur FreshRSS.', - 'notif_title_new_articles' => 'FreshRSS : nouveaux articles !', 'nov' => 'nov.', 'november' => 'novembre', 'number_articles' => '%d articles', @@ -329,7 +332,6 @@ return array( 'php_is_nok' => 'Votre version de PHP est la %s mais FreshRSS requiert au moins la version %s', 'php_is_ok' => 'Votre version de PHP est la %s, qui est compatible avec FreshRSS', 'prefix' => 'Préfixe des tables', - 'previous' => 'Précédent', 'previous_article' => 'Passer à l’article précédent', 'previous_page' => 'Passer à la page précédente', 'print' => 'Imprimer', diff --git a/app/i18n/fr/index.php b/app/i18n/fr/index.php index 3fea1b879..4b8c85033 100644 --- a/app/i18n/fr/index.php +++ b/app/i18n/fr/index.php @@ -1,6 +1,12 @@ array( + '_' => 'Logs', + 'clear' => 'Effacer les logs', + 'empty' => 'Les logs sont vides.', + 'title' => 'Logs', + ), 'menu' => array( 'about' => 'À propos de FreshRSS', 'actualize' => 'Actualiser', diff --git a/app/views/helpers/javascript_vars.phtml b/app/views/helpers/javascript_vars.phtml index 0961ac3fe..6577e0109 100644 --- a/app/views/helpers/javascript_vars.phtml +++ b/app/views/helpers/javascript_vars.phtml @@ -59,10 +59,10 @@ echo 'url={', "},\n"; echo 'i18n={', - 'confirmation_default:"', _t('confirm_action'), '",', - 'notif_title_articles:"', _t('notif_title_new_articles'), '",', - 'notif_body_articles:"', _t('notif_body_new_articles'), '",', - 'category_empty:"', _t('category_empty'), '"', + 'confirmation_default:"', _t('gen.js.confirm_action'), '",', + 'notif_title_articles:"', _t('gen.js.notif_title_new_articles'), '",', + 'notif_body_articles:"', _t('gen.js.notif_body_new_articles'), '",', + 'category_empty:"', _t('gen.js.category_empty'), '"', "},\n"; echo 'icons={', diff --git a/app/views/helpers/logs_pagination.phtml b/app/views/helpers/logs_pagination.phtml index ad46279c7..58b3c68f4 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/index/logs.phtml b/app/views/index/logs.phtml index 101692daf..0262325f5 100644 --- a/app/views/index/logs.phtml +++ b/app/views/index/logs.phtml @@ -1,10 +1,10 @@
    - + -

    +

    - +

    logsPaginator->items(); ?> @@ -20,6 +20,6 @@ logsPaginator->render('logs_pagination.phtml','page'); ?>
    -

    +

    -- cgit v1.2.3 From d455837c6d6e3ad3d64d06f40c947c93fc4e2086 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Thu, 11 Dec 2014 00:00:15 +0100 Subject: Fix i18n for normal view --- app/Controllers/indexController.php | 2 +- app/Models/Context.php | 4 +-- app/i18n/en/gen.php | 62 +++++++++++++++---------------------- app/i18n/en/index.php | 25 ++++++++++++++- app/i18n/fr/gen.php | 62 +++++++++++++++---------------------- app/i18n/fr/index.php | 25 ++++++++++++++- app/layout/header.phtml | 2 +- app/views/helpers/pagination.phtml | 8 ++--- app/views/index/logs.phtml | 6 ++-- app/views/index/normal.phtml | 16 +++++----- lib/lib_rss.php | 8 ++--- 11 files changed, 121 insertions(+), 99 deletions(-) (limited to 'app/Controllers') diff --git a/app/Controllers/indexController.php b/app/Controllers/indexController.php index eff47ed58..2759ab289 100755 --- a/app/Controllers/indexController.php +++ b/app/Controllers/indexController.php @@ -217,7 +217,7 @@ class FreshRSS_index_Controller extends Minz_ActionController { Minz_Error::error(403); } - Minz_View::prependTitle(_t('index.logs.title') . ' · '); + Minz_View::prependTitle(_t('index.log.title') . ' · '); if (Minz_Request::isPost()) { FreshRSS_LogDAO::truncate(); diff --git a/app/Models/Context.php b/app/Models/Context.php index 3dc5349ad..c8a65063a 100644 --- a/app/Models/Context.php +++ b/app/Models/Context.php @@ -138,12 +138,12 @@ class FreshRSS_Context { switch($type) { case 'a': self::$current_get['all'] = true; - self::$name = _t('your_rss_feeds'); + self::$name = _t('index.feed.title'); self::$get_unread = self::$total_unread; break; case 's': self::$current_get['starred'] = true; - self::$name = _t('your_favorites'); + self::$name = _t('index.feed.title_fav'); self::$get_unread = self::$total_starred['unread']; // Update state if favorite is not yet enabled. diff --git a/app/i18n/en/gen.php b/app/i18n/en/gen.php index 28659cccb..a9045c299 100644 --- a/app/i18n/en/gen.php +++ b/app/i18n/en/gen.php @@ -12,10 +12,30 @@ return array( 'login' => 'Login', 'logout' => 'Logout', ), + 'date' => array( + 'Apr' => '\\A\\p\\r\\i\\l', + 'Aug' => '\\A\\u\\g\\u\\s\\t', + 'Dec' => '\\D\\e\\c\\e\\m\\b\\e\\r', + 'Feb' => '\\F\\e\\b\\r\\u\\a\\r\\y', + 'Jan' => '\\J\\a\\n\\u\\a\\r\\y', + 'Jul' => '\\J\\u\\l\\y', + 'Jun' => '\\J\\u\\n\\e', + 'Mar' => '\\M\\a\\r\\c\\h', + 'May' => '\\M\\a\\y', + 'Nov' => '\\N\\o\\v\\e\\m\\b\\e\\r', + 'Oct' => '\\O\\c\\t\\o\\b\\e\\r', + 'Sep' => '\\S\\e\\p\\t\\e\\m\\b\\e\\r', + 'before_yesterday' => 'Before yesterday', + 'format_date' => '%s j\\<\\s\\u\\p\\>S\\<\\/\\s\\u\\p\\> Y', + 'format_date_hour' => '%s j\\<\\s\\u\\p\\>S\\<\\/\\s\\u\\p\\> Y \\a\\t H\\:i', + 'today' => 'Today', + 'yesterday' => 'Yesterday', + ), 'js' => array( 'category_empty' => 'Empty category', 'confirm_action' => 'Are you sure you want to perform this action? It cannot be cancelled!', 'confirm_action_feed_cat' => 'Are you sure you want to perform this action? You will lose related favorites and user queries. It cannot be cancelled!', + 'new_article' => 'There are new available articles, click to refresh the page.', 'notif_body_new_articles' => 'There are \\d new articles to read on FreshRSS.', 'notif_title_new_articles' => 'FreshRSS: new articles!', ), @@ -30,6 +50,7 @@ return array( 'logs' => 'Logs', 'queries' => 'User queries', 'reading' => 'Reading', + 'search' => 'Search words or #tags', 'sharing' => 'Sharing', 'shortcuts' => 'Shortcuts', 'stats' => 'Statistics', @@ -40,7 +61,10 @@ return array( 'pagination' => array( 'first' => 'First', 'last' => 'Last', + 'load_more' => 'Load more articles', + 'mark_all_read' => 'Mark all as read', 'next' => 'Next', + 'nothing_to_load' => 'There are no more articles', 'previous' => 'Previous', ), 'title' => array( @@ -51,18 +75,7 @@ return array( 'user_management' => 'Manage users', 'user_profile' => 'Profile', ), - 'Apr' => '\\A\\p\\r\\i\\l', - 'Aug' => '\\A\\u\\g\\u\\s\\t', - 'Dec' => '\\D\\e\\c\\e\\m\\b\\e\\r', - 'Feb' => '\\F\\e\\b\\r\\u\\a\\r\\y', - 'Jan' => '\\J\\a\\n\\u\\a\\r\\y', - 'Jul' => '\\J\\u\\l\\y', - 'Jun' => '\\J\\u\\n\\e', - 'Mar' => '\\M\\a\\r\\c\\h', - 'May' => '\\M\\a\\y', - 'Nov' => '\\N\\o\\v\\e\\m\\b\\e\\r', - 'Oct' => '\\O\\c\\t\\o\\b\\e\\r', - 'Sep' => '\\S\\e\\p\\t\\e\\m\\b\\e\\r', + 'freshrss' => 'FreshRSS', 'access_denied' => 'You don’t have permission to access this page', 'access_protected_feeds' => 'Connection allows to access HTTP protected RSS feeds', 'activate_sharing' => 'Activate sharing', @@ -117,13 +130,10 @@ return array( 'bdd_conf_is_ok' => 'Database configuration has been saved.', 'bdd_configuration' => 'Database configuration', 'bdd_type' => 'Type of database', - 'before_yesterday' => 'Before yesterday', 'blank_to_disable' => 'Leave blank to disable', - 'blogotext' => 'Blogotext', 'bottom_line' => 'Bottom line', 'bugs_reports' => 'Bugs reports', 'by' => 'by', - 'by_author' => 'By %s', 'by_default' => 'By default', 'by_email' => 'By email', 'by_feed' => 'by feed', @@ -171,14 +181,12 @@ return array( 'default_view' => 'Default view', 'delete' => 'Delete', 'delete_articles_every' => 'Remove articles after', - 'diaspora' => 'Diaspora*', 'display_articles_unfolded' => 'Show articles unfolded by default', 'display_categories_unfolded' => 'Show categories folded by default', 'display_configuration' => 'Display', 'do_not_change_if_doubt' => 'Don’t change if you doubt about it', 'dom_is_nok' => 'You lack a required library to browse the DOM (php-xml package)', 'dom_is_ok' => 'You have the required library to browse the DOM', - 'email' => 'Email', 'error_occurred' => 'An error occurred', 'error_occurred_update' => 'Nothing was changed', 'explain_token' => 'Allows to access RSS output of the default user without authentication.
    %s?output=rss&token=%s', @@ -186,7 +194,6 @@ return array( 'export_no_zip_extension' => 'Zip extension is not present on your server. Please try to export files one by one.', 'export_opml' => 'Export list of feeds (OPML)', 'export_starred' => 'Export your favourites', - 'facebook' => 'Facebook', 'favicons_is_ok' => 'Permissions on favicons directory are good', 'feb' => 'feb', 'february' => 'Feb', @@ -216,13 +223,9 @@ return array( 'first_article' => 'Skip to the first article', 'fix_errors_before' => 'Fix errors before skip to the next step.', 'focus_search' => 'Access search box', - 'format_date' => '%s j\\<\\s\\u\\p\\>S\\<\\/\\s\\u\\p\\> Y', - 'format_date_hour' => '%s j\\<\\s\\u\\p\\>S\\<\\/\\s\\u\\p\\> Y \\a\\t H\\:i', - 'freshrss' => 'FreshRSS', 'freshrss_description' => 'FreshRSS is a RSS feeds aggregator to self-host like Kriss Feed or Leed. It is light and easy to take in hand while being powerful and configurable tool.', 'freshrss_installation' => 'Installation · FreshRSS', 'fri' => 'Fri', - 'g+' => 'Google+', 'general_conf_is_ok' => 'General configuration has been saved.', 'general_configuration' => 'General configuration', 'github_or_email' => 'on Github or by mail', @@ -268,7 +271,6 @@ return array( 'last_year' => 'Last year', 'lead_developer' => 'Lead developer', 'license' => 'License', - 'load_more' => 'Load more articles', 'log_is_ok' => 'Permissions on logs directory are good', 'login_configuration' => 'Login', 'login_persona_problem' => 'Connection problem with Persona?', @@ -287,7 +289,6 @@ return array( 'more_information' => 'More information', 'n_entries_deleted' => '%d articles have been deleted', 'n_feeds_actualized' => '%d feeds have been updated', - 'new_article' => 'There are new available articles, click to refresh the page.', 'new_category' => 'New category', 'next_article' => 'Skip to the next article', 'next_page' => 'Skip to the next page', @@ -305,7 +306,6 @@ return array( 'not_read' => '%d unread', 'not_reads' => '%d unread', 'not_yet_implemented' => 'Not yet implemented', - 'nothing_to_load' => 'There are no more articles', 'nov' => 'nov', 'november' => 'Nov', 'number_articles' => '%d articles', @@ -334,7 +334,6 @@ return array( 'prefix' => 'Table prefix', 'previous_article' => 'Skip to the previous article', 'previous_page' => 'Skip to the previous page', - 'print' => 'Print', 'project_website' => 'Project website', 'public' => 'Public', 'publication_date' => 'Date of publication', @@ -370,21 +369,16 @@ return array( 'random_string' => 'Random string', 'reading_confirm' => 'Display a confirmation dialog on “mark all as read” actions', 'refresh' => 'Refresh', - 'related_tags' => 'Related tags', 'retrieve_truncated_feeds' => 'Retrieves truncated RSS feeds (attention, requires more time!)', 'rss_feed_management' => 'RSS feeds management', 'rss_feeds_of' => 'RSS feed of %s', 'sat' => 'Sat', 'save' => 'Save', 'scroll' => 'while scrolling', - 'search' => 'Search words or #tags', - 'search_short' => 'Search', 'seconds_(0_means_no_timeout)' => 'seconds (0 means no timeout)', 'see_on_website' => 'See on original website', 'sep' => 'sep', 'september' => 'Sep', - 'shaarli' => 'Shaarli', - 'share' => 'Share', 'share_name' => 'Share name to display', 'share_url' => 'Share URL to use', 'sharing_management' => 'Sharing options management', @@ -422,12 +416,10 @@ return array( 'think_to_add' => 'You may add some feeds.', 'this_is_the_end' => 'This is the end', 'thu' => 'Thu', - 'today' => 'Today', 'top_line' => 'Top line', 'truncate' => 'Delete all articles', 'ttl' => 'Do not automatically refresh more often than', 'tue' => 'Tue', - 'twitter' => 'Twitter', 'unsafe_autologin' => 'Allow unsafe automatic login using the format: ', 'update_apply' => 'Apply', 'update_can_apply' => 'An update is available.', @@ -452,7 +444,6 @@ return array( 'users_list' => 'List of users', 'version' => 'Version', 'version_update' => 'Update', - 'wallabag' => 'wallabag', 'website' => 'Website', 'website_url' => 'Website URL', 'wed' => 'Wed', @@ -461,10 +452,7 @@ return array( 'width_no_limit' => 'No limit', 'width_thin' => 'Thin', 'yes' => 'Yes', - 'yesterday' => 'Yesterday', 'your_diaspora_pod' => 'Your Diaspora* pod', - 'your_favorites' => 'Your favourites', - 'your_rss_feeds' => 'Your RSS feeds', 'your_shaarli' => 'Your Shaarli', 'your_wallabag' => 'Your wallabag', 'zip_error' => 'An error occured during Zip import.', diff --git a/app/i18n/en/index.php b/app/i18n/en/index.php index 97df646c4..723feefd7 100644 --- a/app/i18n/en/index.php +++ b/app/i18n/en/index.php @@ -1,7 +1,14 @@ array( + 'entry' => array( + 'by_author' => 'By %s', + ), + 'feed' => array( + 'title' => 'Your RSS feeds', + 'title_fav' => 'Your favourites', + ), + 'log' => array( '_' => 'Logs', 'clear' => 'Clear the logs', 'empty' => 'Log file is empty', @@ -28,10 +35,26 @@ return array( 'read' => 'Show only unread', 'reader_view' => 'Reading view', 'rss_view' => 'RSS feed', + 'search_short' => 'Search', 'see_website' => 'See website', 'starred' => 'Show only favorites', 'stats' => 'Statistics', 'subscription' => 'Subscriptions management', 'unread' => 'Show only read', ), + 'share' => array( + '_' => 'Share', + 'blogotext' => 'Blogotext', + 'diaspora' => 'Diaspora*', + 'email' => 'Email', + 'facebook' => 'Facebook', + 'g+' => 'Google+', + 'print' => 'Print', + 'shaarli' => 'Shaarli', + 'twitter' => 'Twitter', + 'wallabag' => 'wallabag', + ), + 'tag' => array( + 'related' => 'Related tags', + ), ); diff --git a/app/i18n/fr/gen.php b/app/i18n/fr/gen.php index 3d3878eb1..b999b130c 100644 --- a/app/i18n/fr/gen.php +++ b/app/i18n/fr/gen.php @@ -12,10 +12,30 @@ return array( 'login' => 'Connexion', 'logout' => 'Déconnexion', ), + 'date' => array( + 'Apr' => '\\a\\v\\r\\i\\l', + 'Aug' => '\\a\\o\\û\\t', + 'Dec' => '\\d\\é\\c\\e\\m\\b\\r\\e', + 'Feb' => '\\f\\é\\v\\r\\i\\e\\r', + 'Jan' => '\\j\\a\\n\\v\\i\\e\\r', + 'Jul' => '\\j\\u\\i\\l\\l\\e\\t', + 'Jun' => '\\j\\u\\i\\n', + 'Mar' => '\\m\\a\\r\\s', + 'May' => '\\m\\a\\i', + 'Nov' => '\\n\\o\\v\\e\\m\\b\\r\\e', + 'Oct' => '\\o\\c\\t\\o\\b\\r\\e', + 'Sep' => '\\s\\e\\p\\t\\e\\m\\b\\r\\e', + 'before_yesterday' => 'À partir d’avant-hier', + 'format_date' => 'j %s Y', + 'format_date_hour' => 'j %s Y \\à H\\:i', + 'today' => 'Aujourd’hui', + 'yesterday' => 'Hier', + ), 'js' => array( 'category_empty' => 'Catégorie vide', 'confirm_action' => 'Êtes-vous sûr(e) de vouloir continuer ? Cette action ne peut être annulée !', 'confirm_action_feed_cat' => 'Êtes-vous sûr(e) de vouloir continuer ? Vous perdrez les favoris et les filtres associés. Cette action ne peut être annulée !', + 'new_article' => 'Il y a de nouveaux articles disponibles, cliquez pour rafraîchir la page.', 'notif_body_new_articles' => 'Il y a \\d nouveaux articles à lire sur FreshRSS.', 'notif_title_new_articles' => 'FreshRSS : nouveaux articles !', ), @@ -30,6 +50,7 @@ return array( 'logs' => 'Logs', 'queries' => 'Filtres utilisateurs', 'reading' => 'Lecture', + 'search' => 'Rechercher des mots ou des #tags', 'sharing' => 'Partage', 'shortcuts' => 'Raccourcis', 'stats' => 'Statistiques', @@ -40,7 +61,10 @@ return array( 'pagination' => array( 'first' => 'Début', 'last' => 'Fin', + 'load_more' => 'Charger plus d’articles', + 'mark_all_read' => 'Tout marquer comme lu', 'next' => 'Suivant', + 'nothing_to_load' => 'Fin des articles', 'previous' => 'Précédent', ), 'title' => array( @@ -51,18 +75,7 @@ return array( 'user_management' => 'Gestion des utilisateurs', 'user_profile' => 'Profil', ), - 'Apr' => '\\a\\v\\r\\i\\l', - 'Aug' => '\\a\\o\\û\\t', - 'Dec' => '\\d\\é\\c\\e\\m\\b\\r\\e', - 'Feb' => '\\f\\é\\v\\r\\i\\e\\r', - 'Jan' => '\\j\\a\\n\\v\\i\\e\\r', - 'Jul' => '\\j\\u\\i\\l\\l\\e\\t', - 'Jun' => '\\j\\u\\i\\n', - 'Mar' => '\\m\\a\\r\\s', - 'May' => '\\m\\a\\i', - 'Nov' => '\\n\\o\\v\\e\\m\\b\\r\\e', - 'Oct' => '\\o\\c\\t\\o\\b\\r\\e', - 'Sep' => '\\s\\e\\p\\t\\e\\m\\b\\r\\e', + 'freshrss' => 'FreshRSS', 'access_denied' => 'Vous n’avez pas le droit d’accéder à cette page !', 'access_protected_feeds' => 'La connexion permet d’accéder aux flux protégés par une authentification HTTP.', 'activate_sharing' => 'Activer le partage', @@ -117,13 +130,10 @@ return array( 'bdd_conf_is_ok' => 'La configuration de la base de données a été enregistrée.', 'bdd_configuration' => 'Base de données', 'bdd_type' => 'Type de base de données', - 'before_yesterday' => 'À partir d’avant-hier', 'blank_to_disable' => 'Laissez vide pour désactiver', - 'blogotext' => 'Blogotext', 'bottom_line' => 'Ligne du bas', 'bugs_reports' => 'Rapports de bugs', 'by' => 'par', - 'by_author' => 'Par %s', 'by_default' => 'Par défaut', 'by_email' => 'Par courriel', 'by_feed' => 'par flux', @@ -171,14 +181,12 @@ return array( 'default_view' => 'Vue par défaut', 'delete' => 'Supprimer', 'delete_articles_every' => 'Supprimer les articles après', - 'diaspora' => 'Diaspora*', 'display' => 'Affichage', 'display_articles_unfolded' => 'Afficher les articles dépliés par défaut', 'display_categories_unfolded' => 'Afficher les catégories pliées par défaut', 'do_not_change_if_doubt' => 'Laissez tel quel dans le doute', 'dom_is_nok' => 'Il manque une librairie pour parcourir le DOM (paquet php-xml)', 'dom_is_ok' => 'Vous disposez du nécessaire pour parcourir le DOM', - 'email' => 'Courriel', 'error_occurred' => 'Une erreur est survenue !', 'error_occurred_update' => 'Rien n’a été modifié !', 'explain_token' => 'Permet d’accéder à la sortie RSS de l’utilisateur par défaut sans besoin de s’authentifier.
    %s?output=rss&token=%s', @@ -186,7 +194,6 @@ return array( 'export_no_zip_extension' => 'L’extension Zip n’est pas présente sur votre serveur. Veuillez essayer d’exporter les fichiers un par un.', 'export_opml' => 'Exporter la liste des flux (OPML)', 'export_starred' => 'Exporter les favoris', - 'facebook' => 'Facebook', 'favicons_is_ok' => 'Les droits sur le répertoire des favicons sont bons', 'feb' => 'fév.', 'february' => 'février', @@ -216,13 +223,9 @@ return array( 'first_article' => 'Passer au premier article', 'fix_errors_before' => 'Veuillez corriger les erreurs avant de passer à l’étape suivante.', 'focus_search' => 'Accéder à la recherche', - 'format_date' => 'j %s Y', - 'format_date_hour' => 'j %s Y \\à H\\:i', - 'freshrss' => 'FreshRSS', 'freshrss_description' => 'FreshRSS est un agrégateur de flux RSS à auto-héberger à l’image de Kriss Feed ou Leed. Il se veut léger et facile à prendre en main tout en étant un outil puissant et paramétrable.', 'freshrss_installation' => 'Installation · FreshRSS', 'fri' => 'ven.', - 'g+' => 'Google+', 'general_conf_is_ok' => 'La configuration générale a été enregistrée.', 'general_configuration' => 'Configuration générale', 'github_or_email' => 'sur Github ou par courriel', @@ -268,7 +271,6 @@ return array( 'last_year' => 'Depuis l’année dernière', 'lead_developer' => 'Développeur principal', 'license' => 'Licence', - 'load_more' => 'Charger plus d’articles', 'log_is_ok' => 'Les droits sur le répertoire des logs sont bons', 'login_configuration' => 'Identification', 'login_persona_problem' => 'Problème de connexion à Persona ?', @@ -287,7 +289,6 @@ return array( 'more_information' => 'Plus d’informations', 'n_entries_deleted' => '%d articles ont été supprimés.', 'n_feeds_actualized' => '%d flux ont été mis à jour.', - 'new_article' => 'Il y a de nouveaux articles disponibles, cliquez pour rafraîchir la page.', 'new_category' => 'Nouvelle catégorie', 'next_article' => 'Passer à l’article suivant', 'next_page' => 'Passer à la page suivante', @@ -305,7 +306,6 @@ return array( 'not_read' => '%d non lu', 'not_reads' => '%d non lus', 'not_yet_implemented' => 'Pas encore implémenté', - 'nothing_to_load' => 'Fin des articles', 'nov' => 'nov.', 'november' => 'novembre', 'number_articles' => '%d articles', @@ -334,7 +334,6 @@ return array( 'prefix' => 'Préfixe des tables', 'previous_article' => 'Passer à l’article précédent', 'previous_page' => 'Passer à la page précédente', - 'print' => 'Imprimer', 'project_website' => 'Site du projet', 'public' => 'Public', 'publication_date' => 'Date de publication', @@ -370,21 +369,16 @@ return array( 'random_string' => 'Chaîne aléatoire', 'reading_confirm' => 'Afficher une confirmation lors des actions “marquer tout comme lu”', 'refresh' => 'Actualisation', - 'related_tags' => 'Tags associés', 'retrieve_truncated_feeds' => 'Permet de récupérer les flux tronqués (attention, demande plus de temps !)', 'rss_feed_management' => 'Gestion des flux RSS', 'rss_feeds_of' => 'Flux RSS de %s', 'sat' => 'sam.', 'save' => 'Enregistrer', 'scroll' => 'au défilement de la page', - 'search' => 'Rechercher des mots ou des #tags', - 'search_short' => 'Rechercher', 'seconds_(0_means_no_timeout)' => 'secondes (0 signifie aucun timeout ) ', 'see_on_website' => 'Voir sur le site d’origine', 'sep' => 'sep.', 'september' => 'septembre', - 'shaarli' => 'Shaarli', - 'share' => 'Partager', 'share_name' => 'Nom du partage à afficher', 'share_url' => 'URL du partage à utiliser', 'sharing_management' => 'Gestion des options de partage', @@ -422,12 +416,10 @@ return array( 'think_to_add' => 'Vous pouvez ajouter des flux.', 'this_is_the_end' => 'This is the end', 'thu' => 'jeu.', - 'today' => 'Aujourd’hui', 'top_line' => 'Ligne du haut', 'truncate' => 'Supprimer tous les articles', 'ttl' => 'Ne pas automatiquement rafraîchir plus souvent que', 'tue' => 'mar.', - 'twitter' => 'Twitter', 'unsafe_autologin' => 'Autoriser les connexions automatiques non-sûres au format : ', 'update_apply' => 'Appliquer la mise à jour', 'update_can_apply' => 'Une mise à jour est disponible.', @@ -452,7 +444,6 @@ return array( 'users_list' => 'Liste des utilisateurs', 'version' => 'Version', 'version_update' => 'Mise à jour', - 'wallabag' => 'wallabag', 'website' => 'Site Internet', 'website_url' => 'URL du site', 'wed' => 'mer.', @@ -461,10 +452,7 @@ return array( 'width_no_limit' => 'Pas de limite', 'width_thin' => 'Fine', 'yes' => 'Oui', - 'yesterday' => 'Hier', 'your_diaspora_pod' => 'Votre pod Diaspora*', - 'your_favorites' => 'Vos favoris', - 'your_rss_feeds' => 'Vos flux RSS', 'your_shaarli' => 'Votre Shaarli', 'your_wallabag' => 'Votre wallabag', 'zip_error' => 'Une erreur est survenue durant l’import du fichier Zip.', diff --git a/app/i18n/fr/index.php b/app/i18n/fr/index.php index 4b8c85033..e21cc4410 100644 --- a/app/i18n/fr/index.php +++ b/app/i18n/fr/index.php @@ -1,7 +1,14 @@ array( + 'entry' => array( + 'by_author' => 'Par %s', + ), + 'feed' => array( + 'title' => 'Vos flux RSS', + 'title_fav' => 'Vos favoris', + ), + 'log' => array( '_' => 'Logs', 'clear' => 'Effacer les logs', 'empty' => 'Les logs sont vides.', @@ -28,10 +35,26 @@ return array( 'read' => 'Afficher les non lus', 'reader_view' => 'Vue lecture', 'rss_view' => 'Flux RSS', + 'search_short' => 'Rechercher', 'see_website' => 'Voir le site', 'starred' => 'Afficher les favoris', 'stats' => 'Statistiques', 'subscription' => 'Gestion des abonnements', 'unread' => 'Afficher les lus', ), + 'share' => array( + '_' => 'Partager', + 'blogotext' => 'Blogotext', + 'diaspora' => 'Diaspora*', + 'email' => 'Courriel', + 'facebook' => 'Facebook', + 'g+' => 'Google+', + 'print' => 'Imprimer', + 'shaarli' => 'Shaarli', + 'twitter' => 'Twitter', + 'wallabag' => 'wallabag', + ), + 'tag' => array( + 'related' => 'Tags associés', + ), ); diff --git a/app/layout/header.phtml b/app/layout/header.phtml index 429cfc1d2..ba13c2a45 100644 --- a/app/layout/header.phtml +++ b/app/layout/header.phtml @@ -25,7 +25,7 @@ if (Minz_Configuration::canLogIn()) {
    - + diff --git a/app/views/helpers/pagination.phtml b/app/views/helpers/pagination.phtml index 3ea6c3582..8b40e4336 100755 --- a/app/views/helpers/pagination.phtml +++ b/app/views/helpers/pagination.phtml @@ -20,7 +20,7 @@
  • - + -
    +
  • diff --git a/app/views/index/logs.phtml b/app/views/index/logs.phtml index 0262325f5..02256bd98 100644 --- a/app/views/index/logs.phtml +++ b/app/views/index/logs.phtml @@ -1,10 +1,10 @@
    -

    +

    - +

    logsPaginator->items(); ?> @@ -20,6 +20,6 @@ logsPaginator->render('logs_pagination.phtml','page'); ?>
    -

    +

    diff --git a/app/views/index/normal.phtml b/app/views/index/normal.phtml index 02d621bd0..62fb68931 100644 --- a/app/views/index/normal.phtml +++ b/app/views/index/normal.phtml @@ -32,12 +32,12 @@ if (!empty($this->entries)) {
    - +
    entries as $item) { if ($display_today && $item->isDay(FreshRSS_Days::TODAY, $today)) { ?>
    entries)) { } if ($display_yesterday && $item->isDay(FreshRSS_Days::YESTERDAY, $today)) { ?>
    entries)) { } if ($display_others && $item->isDay(FreshRSS_Days::BEFORE_YESTERDAY, $today)) { ?>
    entries)) {

    title(); ?>

    author(); - echo $author != '' ? '
    ' . _t('by_author', $author) . '
    ' : '', + echo $author != '' ? '
    ' . _t('index.entry.by_author', $author) . '
    ' : '', $lazyload && $hidePosts ? lazyimg($item->content()) : $item->content(); ?>
    @@ -135,7 +135,7 @@ if (!empty($this->entries)) { - +
    -- cgit v1.2.3 From 079150eee4eebce3549c3d7db84dd0180bdd11e7 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Fri, 3 Jul 2015 23:47:18 +0200 Subject: Updated log visibility In particular, ensure that ERROR is only used for errors that may affect FreshRSS integrity, and ensure that feed errors are visible also in production, i.e. visibility of WARNING https://github.com/FreshRSS/FreshRSS/issues/885 https://github.com/FreshRSS/FreshRSS/issues/884 --- app/Controllers/authController.php | 2 +- app/Controllers/feedController.php | 2 +- app/Controllers/importExportController.php | 6 +++--- app/Controllers/updateController.php | 2 +- app/Models/CategoryDAO.php | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) (limited to 'app/Controllers') diff --git a/app/Controllers/authController.php b/app/Controllers/authController.php index 937c0759d..b55892475 100644 --- a/app/Controllers/authController.php +++ b/app/Controllers/authController.php @@ -253,7 +253,7 @@ class FreshRSS_auth_Controller extends Minz_ActionController { FreshRSS_Auth::giveAccess(); invalidateHttpCache(); } else { - Minz_Log::error($reason); + Minz_Log::warning($reason); $res = array(); $res['status'] = 'failure'; diff --git a/app/Controllers/feedController.php b/app/Controllers/feedController.php index b91f63b5b..488d066a9 100755 --- a/app/Controllers/feedController.php +++ b/app/Controllers/feedController.php @@ -322,7 +322,7 @@ class FreshRSS_feed_Controller extends Minz_ActionController { $feed->load(false); } } catch (FreshRSS_Feed_Exception $e) { - Minz_Log::notice($e->getMessage()); + Minz_Log::warning($e->getMessage()); $feedDAO->updateLastUpdate($feed->id(), true); $feed->unlock(); continue; diff --git a/app/Controllers/importExportController.php b/app/Controllers/importExportController.php index 26b163e43..60e467255 100644 --- a/app/Controllers/importExportController.php +++ b/app/Controllers/importExportController.php @@ -47,7 +47,7 @@ class FreshRSS_importExport_Controller extends Minz_ActionController { $status_file = $file['error']; if ($status_file !== 0) { - Minz_Log::error('File cannot be uploaded. Error code: ' . $status_file); + Minz_Log::warning('File cannot be uploaded. Error code: ' . $status_file); Minz_Request::bad(_t('feedback.import_export.file_cannot_be_uploaded'), array('c' => 'importExport', 'a' => 'index')); } @@ -69,7 +69,7 @@ class FreshRSS_importExport_Controller extends Minz_ActionController { if (!is_resource($zip)) { // zip_open cannot open file: something is wrong - Minz_Log::error('Zip archive cannot be imported. Error code: ' . $zip); + Minz_Log::warning('Zip archive cannot be imported. Error code: ' . $zip); Minz_Request::bad(_t('feedback.import_export.zip_error'), array('c' => 'importExport', 'a' => 'index')); } @@ -77,7 +77,7 @@ class FreshRSS_importExport_Controller extends Minz_ActionController { while (($zipfile = zip_read($zip)) !== false) { if (!is_resource($zipfile)) { // zip_entry() can also return an error code! - Minz_Log::error('Zip file cannot be imported. Error code: ' . $zipfile); + Minz_Log::warning('Zip file cannot be imported. Error code: ' . $zipfile); } else { $type_zipfile = $this->guessFileType(zip_entry_name($zipfile)); if ($type_file !== 'unknown') { diff --git a/app/Controllers/updateController.php b/app/Controllers/updateController.php index 4797a3486..84a33fe85 100644 --- a/app/Controllers/updateController.php +++ b/app/Controllers/updateController.php @@ -63,7 +63,7 @@ class FreshRSS_update_Controller extends Minz_ActionController { curl_close($c); if ($c_status !== 200) { - Minz_Log::error( + Minz_Log::warning( 'Error during update (HTTP code ' . $c_status . '): ' . $c_error ); diff --git a/app/Models/CategoryDAO.php b/app/Models/CategoryDAO.php index 189a5f0e4..b5abac519 100644 --- a/app/Models/CategoryDAO.php +++ b/app/Models/CategoryDAO.php @@ -13,7 +13,7 @@ class FreshRSS_CategoryDAO extends Minz_ModelPdo implements FreshRSS_Searchable return $this->bd->lastInsertId(); } else { $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo(); - Minz_Log::error('SQL error addCategory: ' . $info[2] ); + Minz_Log::error('SQL error addCategory: ' . $info[2]); return false; } } -- cgit v1.2.3 From ac8bd3d2512dd1bfca43d71ea10202ba9e6a82a6 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Tue, 21 Jul 2015 15:31:23 +0200 Subject: Add a max_registrations limit - Allow user to create accounts (not implemented) - Admin only can set this limit See https://github.com/FreshRSS/FreshRSS/issues/679 --- app/Controllers/userController.php | 24 ++++++++++++++++++++++++ app/Models/ConfigurationSetter.php | 3 +++ app/views/user/manage.phtml | 19 +++++++++++++++++++ data/config.default.php | 4 ++++ 4 files changed, 50 insertions(+) (limited to 'app/Controllers') diff --git a/app/Controllers/userController.php b/app/Controllers/userController.php index ed01b83c5..1c7745753 100644 --- a/app/Controllers/userController.php +++ b/app/Controllers/userController.php @@ -211,4 +211,28 @@ class FreshRSS_user_Controller extends Minz_ActionController { Minz_Request::forward(array('c' => 'user', 'a' => 'manage'), true); } + + /** + * This action updates the max number of registrations. + * + * Request parameter is: + * - max-registrations (int >= 0) + */ + public function setRegistrationAction() { + if (Minz_Request::isPost() && FreshRSS_Auth::hasAccess('admin')) { + $limits = FreshRSS_Context::$system_conf->limits; + $limits['max_registrations'] = Minz_Request::param('max-registrations', 1); + FreshRSS_Context::$system_conf->limits = $limits; + FreshRSS_Context::$system_conf->save(); + + invalidateHttpCache(); + + Minz_Session::_param('notification', array( + 'type' => 'good', + 'content' => _t('feedback.user.set_registration') + )); + } + + Minz_Request::forward(array('c' => 'user', 'a' => 'manage'), true); + } } diff --git a/app/Models/ConfigurationSetter.php b/app/Models/ConfigurationSetter.php index 4bd29ecb0..236bf5b0b 100644 --- a/app/Models/ConfigurationSetter.php +++ b/app/Models/ConfigurationSetter.php @@ -352,6 +352,9 @@ class FreshRSS_ConfigurationSetter { 'min' => 0, 'max' => $max_small_int, ), + 'max_registrations' => array( + 'min' => 0, + ), ); foreach ($values as $key => $value) { diff --git a/app/views/user/manage.phtml b/app/views/user/manage.phtml index fe1b6618b..a7cbf0795 100644 --- a/app/views/user/manage.phtml +++ b/app/views/user/manage.phtml @@ -3,6 +3,25 @@
    + + + +
    + +
    + + +
    +
    + +
    +
    + + +
    +
    + +
    diff --git a/data/config.default.php b/data/config.default.php index 6013b13b8..5db933ff8 100644 --- a/data/config.default.php +++ b/data/config.default.php @@ -77,6 +77,10 @@ return array( # Max number of categories for a user. 'max_categories' => 16384, + # Max number of accounts that anonymous users can create + # 0 for an unlimited number of accounts + # 1 is to not allow user registrations (1 is corresponding to the admin account) + 'max_registrations' => 1, ), # Options used by cURL when making HTTP requests, e.g. when the SimplePie library retrieves feeds. -- cgit v1.2.3 From 37f06799589d9bb92ecfa6368197daf187251ab4 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Tue, 21 Jul 2015 16:03:46 +0200 Subject: First draft for registration form See https://github.com/FreshRSS/FreshRSS/issues/679 --- app/Controllers/authController.php | 6 ++++++ app/views/auth/formLogin.phtml | 2 ++ app/views/auth/register.phtml | 31 +++++++++++++++++++++++++++++++ 3 files changed, 39 insertions(+) create mode 100644 app/views/auth/register.phtml (limited to 'app/Controllers') diff --git a/app/Controllers/authController.php b/app/Controllers/authController.php index b55892475..1c8ad2193 100644 --- a/app/Controllers/authController.php +++ b/app/Controllers/authController.php @@ -346,4 +346,10 @@ class FreshRSS_auth_Controller extends Minz_ActionController { } } } + + /** + * This action gives possibility to a user to create an account. + */ + public function registerAction() { + } } diff --git a/app/views/auth/formLogin.phtml b/app/views/auth/formLogin.phtml index 979e17349..75537ee26 100644 --- a/app/views/auth/formLogin.phtml +++ b/app/views/auth/formLogin.phtml @@ -1,6 +1,8 @@

    + +
    diff --git a/app/views/auth/register.phtml b/app/views/auth/register.phtml new file mode 100644 index 000000000..f67ecc4d9 --- /dev/null +++ b/app/views/auth/register.phtml @@ -0,0 +1,31 @@ +
    +

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

    +
    -- cgit v1.2.3 From 9fca5c70f33291cacc04e7bdfa01a12c6df3f97c Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Wed, 22 Jul 2015 12:20:00 +0200 Subject: Add some comments --- app/Controllers/userController.php | 19 +++++++++++++++++++ app/views/auth/register.phtml | 7 +++++++ 2 files changed, 26 insertions(+) (limited to 'app/Controllers') diff --git a/app/Controllers/userController.php b/app/Controllers/userController.php index 1c7745753..c198d1328 100644 --- a/app/Controllers/userController.php +++ b/app/Controllers/userController.php @@ -103,6 +103,17 @@ class FreshRSS_user_Controller extends Minz_ActionController { $this->view->size_user = $entryDAO->size(); } + /** + * This action creates a new user. + * + * Request parameters are: + * - new_user_language + * - new_user_name + * - new_user_passwordPlain + * - new_user_email + * + * @todo clean up this method. Idea: write a method to init a user with basic information. + */ public function createAction() { if (Minz_Request::isPost() && FreshRSS_Auth::hasAccess('admin')) { $db = FreshRSS_Context::$system_conf->db; @@ -178,6 +189,14 @@ class FreshRSS_user_Controller extends Minz_ActionController { Minz_Request::forward(array('c' => 'user', 'a' => 'manage'), true); } + /** + * This action delete an existing user. + * + * Request parameter is: + * - username + * + * @todo clean up this method. Idea: create a User->clean() method. + */ public function deleteAction() { if (Minz_Request::isPost() && FreshRSS_Auth::hasAccess('admin')) { $db = FreshRSS_Context::$system_conf->db; diff --git a/app/views/auth/register.phtml b/app/views/auth/register.phtml index f67ecc4d9..31ab89d26 100644 --- a/app/views/auth/register.phtml +++ b/app/views/auth/register.phtml @@ -1,3 +1,10 @@ +

    -- cgit v1.2.3 From 02c3546440f961018adc1e2c8e97c16f2aca18fc Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Wed, 22 Jul 2015 13:52:03 +0200 Subject: Registration action is handled and create a user See https://github.com/FreshRSS/FreshRSS/issues/679 --- app/Controllers/userController.php | 20 +++++++++++++++++--- app/views/auth/register.phtml | 7 +++++++ lib/lib_rss.php | 16 ++++++++++++++++ 3 files changed, 40 insertions(+), 3 deletions(-) (limited to 'app/Controllers') diff --git a/app/Controllers/userController.php b/app/Controllers/userController.php index c198d1328..46f4f434d 100644 --- a/app/Controllers/userController.php +++ b/app/Controllers/userController.php @@ -12,9 +12,14 @@ class FreshRSS_user_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 clean up the access condition. */ public function firstAction() { - if (!FreshRSS_Auth::hasAccess()) { + if (!FreshRSS_Auth::hasAccess() && !( + Minz_Request::actionName() === 'create' && + !max_registrations_reached() + )) { Minz_Error::error(403); } } @@ -111,11 +116,16 @@ class FreshRSS_user_Controller extends Minz_ActionController { * - new_user_name * - new_user_passwordPlain * - new_user_email + * - r (i.e. a redirection url, optional) * * @todo clean up this method. Idea: write a method to init a user with basic information. + * @todo handle r redirection in Minz_Request::forward directly? */ public function createAction() { - if (Minz_Request::isPost() && FreshRSS_Auth::hasAccess('admin')) { + if (Minz_Request::isPost() && ( + FreshRSS_Auth::hasAccess('admin') || + !max_registrations_reached() + )) { $db = FreshRSS_Context::$system_conf->db; require_once(APP_PATH . '/SQL/install.sql.' . $db['type'] . '.php'); @@ -186,7 +196,11 @@ class FreshRSS_user_Controller extends Minz_ActionController { Minz_Session::_param('notification', $notif); } - Minz_Request::forward(array('c' => 'user', 'a' => 'manage'), true); + $redirect_url = urldecode(Minz_Request::param('r', false, true)); + if (!$redirect_url) { + $redirect_url = array('c' => 'user', 'a' => 'manage'); + } + Minz_Request::forward($redirect_url, true); } /** diff --git a/app/views/auth/register.phtml b/app/views/auth/register.phtml index 31ab89d26..96c91f411 100644 --- a/app/views/auth/register.phtml +++ b/app/views/auth/register.phtml @@ -29,6 +29,13 @@
    + 'index', 'a' => 'index'), + 'php', true + )); + ?> +
    diff --git a/lib/lib_rss.php b/lib/lib_rss.php index 0118e0f46..c99e2c7e8 100644 --- a/lib/lib_rss.php +++ b/lib/lib_rss.php @@ -266,6 +266,22 @@ function listUsers() { } +/** + * Return if the maximum number of registrations has been reached. + * + * Note a max_regstrations of 0 means there is no limit. + * + * @return true if number of users >= max registrations, false else. + */ +function max_registrations_reached() { + $system_conf = Minz_Configuration::get('system'); + $limit_registrations = $system_conf->limits['max_registrations']; + $number_accounts = count(listUsers()); + + return $limit_registrations > 0 && $number_accounts >= $limit_registrations; +} + + /** * Register and return the configuration for a given user. * -- cgit v1.2.3 From f560c44a003ca69644f8e7262dca2f8f7e6932d5 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Wed, 22 Jul 2015 14:00:08 +0200 Subject: Hide registration form if max registration reached See https://github.com/FreshRSS/FreshRSS/issues/679 --- app/Controllers/authController.php | 3 +++ app/views/auth/formLogin.phtml | 4 +++- app/views/auth/personaLogin.phtml | 4 ++++ 3 files changed, 10 insertions(+), 1 deletion(-) (limited to 'app/Controllers') diff --git a/app/Controllers/authController.php b/app/Controllers/authController.php index 1c8ad2193..223282afb 100644 --- a/app/Controllers/authController.php +++ b/app/Controllers/authController.php @@ -351,5 +351,8 @@ class FreshRSS_auth_Controller extends Minz_ActionController { * This action gives possibility to a user to create an account. */ public function registerAction() { + if (max_registrations_reached()) { + Minz_Error::error(403); + } } } diff --git a/app/views/auth/formLogin.phtml b/app/views/auth/formLogin.phtml index 75537ee26..3a6053065 100644 --- a/app/views/auth/formLogin.phtml +++ b/app/views/auth/formLogin.phtml @@ -1,7 +1,9 @@

    - + + +
    diff --git a/app/views/auth/personaLogin.phtml b/app/views/auth/personaLogin.phtml index 545ed2eac..91349a67e 100644 --- a/app/views/auth/personaLogin.phtml +++ b/app/views/auth/personaLogin.phtml @@ -2,6 +2,10 @@

    + + + +

    + /> +
    @@ -59,21 +59,30 @@ -
    +

    +
    + +
    + +
    + +
    +
    +
    'index', 'a' => 'index'), + array('c' => 'user', 'a' => 'profile'), 'php', true )); ?> - +
    -- cgit v1.2.3 From f0a1b26584787e173c8c9cd1a5fea27bb3044f1c Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Wed, 22 Jul 2015 23:06:46 +0200 Subject: Add title to the account creation page See https://github.com/FreshRSS/FreshRSS/issues/679 --- app/Controllers/authController.php | 2 ++ app/i18n/cz/gen.php | 1 + app/i18n/de/gen.php | 1 + app/i18n/en/gen.php | 1 + app/i18n/fr/gen.php | 1 + 5 files changed, 6 insertions(+) (limited to 'app/Controllers') diff --git a/app/Controllers/authController.php b/app/Controllers/authController.php index 223282afb..aff184263 100644 --- a/app/Controllers/authController.php +++ b/app/Controllers/authController.php @@ -354,5 +354,7 @@ class FreshRSS_auth_Controller extends Minz_ActionController { if (max_registrations_reached()) { Minz_Error::error(403); } + + Minz_View::prependTitle(_t('gen.auth.registration.title') . ' · '); } } diff --git a/app/i18n/cz/gen.php b/app/i18n/cz/gen.php index a89bf6b49..53127998f 100644 --- a/app/i18n/cz/gen.php +++ b/app/i18n/cz/gen.php @@ -34,6 +34,7 @@ return array( 'registration' => array( '_' => 'New account', // TODO: translate 'ask' => 'Create an account?', // TODO: translate + 'title' => 'Account creation', // TODO: translate ), 'reset' => 'Reset přihlášení', 'username' => array( diff --git a/app/i18n/de/gen.php b/app/i18n/de/gen.php index d6fcfe1e4..f8f4823a6 100644 --- a/app/i18n/de/gen.php +++ b/app/i18n/de/gen.php @@ -34,6 +34,7 @@ return array( 'registration' => array( '_' => 'New account', // TODO: translate 'ask' => 'Create an account?', // TODO: translate + 'title' => 'Account creation', // TODO: translate ), 'reset' => 'Zurücksetzen der Authentifizierung', 'username' => array( diff --git a/app/i18n/en/gen.php b/app/i18n/en/gen.php index 063322cbf..1feb8d6ac 100644 --- a/app/i18n/en/gen.php +++ b/app/i18n/en/gen.php @@ -34,6 +34,7 @@ return array( 'registration' => array( '_' => 'New account', 'ask' => 'Create an account?', + 'title' => 'Account creation', ), 'reset' => 'Authentication reset', 'username' => array( diff --git a/app/i18n/fr/gen.php b/app/i18n/fr/gen.php index 5abc7a27b..67d278be4 100644 --- a/app/i18n/fr/gen.php +++ b/app/i18n/fr/gen.php @@ -34,6 +34,7 @@ return array( 'registration' => array( '_' => 'Nouveau compte', 'ask' => 'Créer un compte ?', + 'title' => 'Création de compte', ), 'reset' => 'Réinitialisation de l’authentification', 'username' => array( -- cgit v1.2.3 From f4472fc918c1fa1d1cfb2adae6c38a9a261e8c9b Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Thu, 23 Jul 2015 13:59:40 +0200 Subject: Do not use PubSubHubbub if disabled See https://github.com/FreshRSS/FreshRSS/issues/865 --- app/Controllers/feedController.php | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'app/Controllers') diff --git a/app/Controllers/feedController.php b/app/Controllers/feedController.php index 488d066a9..ec3dce777 100755 --- a/app/Controllers/feedController.php +++ b/app/Controllers/feedController.php @@ -295,14 +295,17 @@ class FreshRSS_feed_Controller extends Minz_ActionController { // Calculate date of oldest entries we accept in DB. $nb_month_old = max(FreshRSS_Context::$user_conf->old_entries, 1); $date_min = time() - (3600 * 24 * 30 * $nb_month_old); - $pshbMinAge = time() - (3600 * 24); //TODO: Make a configuration. + + // PubSubHubbub support + $pubsubhubbubEnabledGeneral = FreshRSS_Context::$system_conf->pubsubhubbub_enabled; + $pshbMinAge = time() - (3600 * 24); //TODO: Make a configuration. $updated_feeds = 0; $is_read = FreshRSS_Context::$user_conf->mark_when['reception'] ? 1 : 0; foreach ($feeds as $feed) { $url = $feed->url(); //For detection of HTTP 301 - $pubSubHubbubEnabled = $feed->pubSubHubbubEnabled(); + $pubSubHubbubEnabled = $pubsubhubbubEnabledGeneral && $feed->pubSubHubbubEnabled(); if ((!$simplePiePush) && (!$id) && $pubSubHubbubEnabled && ($feed->lastUpdate() > $pshbMinAge)) { $text = 'Skip pull of feed using PubSubHubbub: ' . $url; //Minz_Log::debug($text); @@ -442,7 +445,7 @@ class FreshRSS_feed_Controller extends Minz_ActionController { } $feed->faviconPrepare(); - if ($feed->pubSubHubbubPrepare()) { + if ($pubsubhubbubEnabledGeneral && $feed->pubSubHubbubPrepare()) { Minz_Log::notice('PubSubHubbub subscribe ' . $feed->url()); if (!$feed->pubSubHubbubSubscribe(true)) { //Subscribe Minz_Log::warning('Error while PubSubHubbub subscribing to ' . $feed->url()); -- cgit v1.2.3 From 269c6b88c4486a0ae1a92df65578ee6ab6f0bbca Mon Sep 17 00:00:00 2001 From: Alexis Degrugillier Date: Sat, 22 Aug 2015 09:33:58 -0400 Subject: Add a system configuration page It allows to modify system configuration from the interface. At the moment, only limits are modifiable. The user limit was removed from the user page and added here along with categories and feeds limits. --- app/Controllers/configureController.php | 33 +++++++++++++++++++++++ app/Controllers/userController.php | 24 ----------------- app/i18n/cz/admin.php | 14 ++++++---- app/i18n/cz/feedback.php | 1 - app/i18n/cz/gen.php | 1 + app/i18n/de/admin.php | 14 ++++++---- app/i18n/de/feedback.php | 1 - app/i18n/de/gen.php | 1 + app/i18n/en/admin.php | 14 ++++++---- app/i18n/en/feedback.php | 1 - app/i18n/en/gen.php | 1 + app/i18n/fr/admin.php | 14 ++++++---- app/i18n/fr/feedback.php | 1 - app/i18n/fr/gen.php | 1 + app/layout/aside_configure.phtml | 3 +++ app/layout/header.phtml | 1 + app/views/configure/system.phtml | 47 +++++++++++++++++++++++++++++++++ app/views/user/manage.phtml | 28 -------------------- 18 files changed, 124 insertions(+), 76 deletions(-) create mode 100644 app/views/configure/system.phtml (limited to 'app/Controllers') diff --git a/app/Controllers/configureController.php b/app/Controllers/configureController.php index 248a3edcc..7a4d0ecd7 100755 --- a/app/Controllers/configureController.php +++ b/app/Controllers/configureController.php @@ -293,4 +293,37 @@ class FreshRSS_configure_Controller extends Minz_ActionController { Minz_Request::good(_t('feedback.conf.query_created', $query['name']), array('c' => 'configure', 'a' => 'queries')); } + + /** + * This action handles the system configuration page. + * + * It displays the system configuration page. + * If this action is reach through a POST request, it stores all new + * configuration values then sends a notification to the user. + * + * The options available on the page are: + * - user limit (default: 1) + * - user category limit (default: 16384) + * - user feed limit (default: 16384) + */ + public function systemAction() { + if (!FreshRSS_Auth::hasAccess('admin')) { + Minz_Error::error(403); + } + if (Minz_Request::isPost()) { + $limits = FreshRSS_Context::$system_conf->limits; + $limits['max_registrations'] = Minz_Request::param('max-registrations', 1); + $limits['max_feeds'] = Minz_Request::param('max-feeds', 16384); + $limits['max_categories'] = Minz_Request::param('max-categories', 16384); + FreshRSS_Context::$system_conf->limits = $limits; + FreshRSS_Context::$system_conf->save(); + + invalidateHttpCache(); + + Minz_Session::_param('notification', array( + 'type' => 'good', + 'content' => _t('feedback.conf.updated') + )); + } + } } diff --git a/app/Controllers/userController.php b/app/Controllers/userController.php index 428cd145d..1c7d621f1 100644 --- a/app/Controllers/userController.php +++ b/app/Controllers/userController.php @@ -272,28 +272,4 @@ class FreshRSS_user_Controller extends Minz_ActionController { Minz_Request::forward($redirect_url, true); } - - /** - * This action updates the max number of registrations. - * - * Request parameter is: - * - max-registrations (int >= 0) - */ - public function setRegistrationAction() { - if (Minz_Request::isPost() && FreshRSS_Auth::hasAccess('admin')) { - $limits = FreshRSS_Context::$system_conf->limits; - $limits['max_registrations'] = Minz_Request::param('max-registrations', 1); - FreshRSS_Context::$system_conf->limits = $limits; - FreshRSS_Context::$system_conf->save(); - - invalidateHttpCache(); - - Minz_Session::_param('notification', array( - 'type' => 'good', - 'content' => _t('feedback.user.set_registration') - )); - } - - Minz_Request::forward(array('c' => 'user', 'a' => 'manage'), true); - } } diff --git a/app/i18n/cz/admin.php b/app/i18n/cz/admin.php index 4ca56cc37..92c300709 100644 --- a/app/i18n/cz/admin.php +++ b/app/i18n/cz/admin.php @@ -146,6 +146,15 @@ return array( 'title' => 'Statistika', 'top_feed' => 'Top ten kanálů', ), + 'system' => array( + '_' => 'System configuration', + 'max-categories' => 'Categories per user limit', + 'max-feeds' => 'Feeds per user limit', + 'registration' => array( + 'help' => '0 znamená žádná omezení účtu', + 'number' => 'Maximální počet účtů', + ), + ), 'update' => array( '_' => 'Aktualizace systému', 'apply' => 'Použít', @@ -164,11 +173,6 @@ return array( 'numbers' => 'Zatím je vytvořeno %d účtů', 'password_form' => 'Heslo
    (pro přihlášení webovým formulářem)', 'password_format' => 'Alespoň 7 znaků', - 'registration' => array( - 'allow' => 'Povolit vytváření účtů', - 'help' => '0 znamená žádná omezení účtu', - 'number' => 'Maximální počet účtů', - ), 'title' => 'Správa uživatelů', 'user_list' => 'Seznam uživatelů', 'username' => 'Přihlašovací jméno', diff --git a/app/i18n/cz/feedback.php b/app/i18n/cz/feedback.php index 5ba64b938..b75a4a15a 100644 --- a/app/i18n/cz/feedback.php +++ b/app/i18n/cz/feedback.php @@ -102,7 +102,6 @@ return array( '_' => 'Uživatel %s byl smazán', 'error' => 'Uživatele %s nelze smazat', ), - 'set_registration' => 'Maximální počet účtů byl změněn', ), 'profile' => array( 'error' => 'Váš profil nelze změnit', diff --git a/app/i18n/cz/gen.php b/app/i18n/cz/gen.php index 138def772..436e4f0c2 100644 --- a/app/i18n/cz/gen.php +++ b/app/i18n/cz/gen.php @@ -137,6 +137,7 @@ return array( 'sharing' => 'Sdílení', 'shortcuts' => 'Zkratky', 'stats' => 'Statistika', + 'system' => 'System configuration', 'update' => 'Aktualizace', 'user_management' => 'Správa uživatelů', 'user_profile' => 'Profil', diff --git a/app/i18n/de/admin.php b/app/i18n/de/admin.php index 68dcc2ebf..365f065af 100644 --- a/app/i18n/de/admin.php +++ b/app/i18n/de/admin.php @@ -146,6 +146,15 @@ return array( 'title' => 'Statistiken', 'top_feed' => 'Top 10-Feeds', ), + 'system' => array( + '_' => 'System configuration', + 'max-categories' => 'Categories per user limit', + 'max-feeds' => 'Feeds per user limit', + 'registration' => array( + 'help' => '0 meint, dass es kein Account Limit gibt', + 'number' => 'Maximale Anzahl von Accounts', + ), + ), 'update' => array( '_' => 'System aktualisieren', 'apply' => 'Anwenden', @@ -164,11 +173,6 @@ return array( 'numbers' => 'Es wurden bis jetzt %d Accounts erstellt', 'password_form' => 'Passwort
    (für die Anmeldemethode per Webformular)', 'password_format' => 'mindestens 7 Zeichen', - 'registration' => array( - 'allow' => 'Erlaube die Accounterstellung', - 'help' => '0 meint, dass es kein Account Limit gibt', - 'number' => 'Maximale Anzahl von Accounts', - ), 'title' => 'Benutzer verwalten', 'user_list' => 'Liste der Benutzer', 'username' => 'Nutzername', diff --git a/app/i18n/de/feedback.php b/app/i18n/de/feedback.php index e92dacfe9..4c15aadc3 100644 --- a/app/i18n/de/feedback.php +++ b/app/i18n/de/feedback.php @@ -102,7 +102,6 @@ return array( '_' => 'Der Benutzer %s ist gelöscht worden', 'error' => 'Der Benutzer %s kann nicht gelöscht werden', ), - 'set_registration' => 'Die maximale Anzahl von Accounts wurde aktualisiert.', ), 'profile' => array( 'error' => 'Ihr Profil kann nicht geändert werden', diff --git a/app/i18n/de/gen.php b/app/i18n/de/gen.php index de2d846c5..f3450abc0 100644 --- a/app/i18n/de/gen.php +++ b/app/i18n/de/gen.php @@ -137,6 +137,7 @@ return array( 'sharing' => 'Teilen', 'shortcuts' => 'Tastaturkürzel', 'stats' => 'Statistiken', + 'system' => 'System configuration', 'update' => 'Aktualisieren', 'user_management' => 'Benutzer verwalten', 'user_profile' => 'Profil', diff --git a/app/i18n/en/admin.php b/app/i18n/en/admin.php index aeea61631..ad9038203 100644 --- a/app/i18n/en/admin.php +++ b/app/i18n/en/admin.php @@ -146,6 +146,15 @@ return array( 'title' => 'Statistics', 'top_feed' => 'Top ten feeds', ), + 'system' => array( + '_' => 'System configuration', + 'max-categories' => 'Categories per user limit', + 'max-feeds' => 'Feeds per user limit', + 'registration' => array( + 'help' => '0 means that there is no account limit', + 'number' => 'Max number of accounts', + ), + ), 'update' => array( '_' => 'Update system', 'apply' => 'Apply', @@ -164,11 +173,6 @@ return array( 'numbers' => 'There are %d accounts created yet', 'password_form' => 'Password
    (for the Web-form login method)', 'password_format' => 'At least 7 characters', - 'registration' => array( - 'allow' => 'Allow account creation', - 'help' => '0 means that there is no account limit', - 'number' => 'Max number of accounts', - ), 'title' => 'Manage users', 'user_list' => 'List of users', 'username' => 'Username', diff --git a/app/i18n/en/feedback.php b/app/i18n/en/feedback.php index c9f73dc1d..c9189c0d0 100644 --- a/app/i18n/en/feedback.php +++ b/app/i18n/en/feedback.php @@ -102,7 +102,6 @@ return array( '_' => 'User %s has been deleted', 'error' => 'User %s cannot be deleted', ), - 'set_registration' => 'The maximum amount of accounts has been updated.', ), 'profile' => array( 'error' => 'Your profile cannot be modified', diff --git a/app/i18n/en/gen.php b/app/i18n/en/gen.php index 1feb8d6ac..9aef45768 100644 --- a/app/i18n/en/gen.php +++ b/app/i18n/en/gen.php @@ -137,6 +137,7 @@ return array( 'sharing' => 'Sharing', 'shortcuts' => 'Shortcuts', 'stats' => 'Statistics', + 'system' => 'System configuration', 'update' => 'Update', 'user_management' => 'Manage users', 'user_profile' => 'Profile', diff --git a/app/i18n/fr/admin.php b/app/i18n/fr/admin.php index 01e0cb3c7..44e013c2f 100644 --- a/app/i18n/fr/admin.php +++ b/app/i18n/fr/admin.php @@ -146,6 +146,15 @@ return array( 'title' => 'Statistiques', 'top_feed' => 'Les dix plus gros flux', ), + 'system' => array( + '_' => 'Configuration du système', + 'max-categories' => 'Limite de catégories par utilisateur', + 'max-feeds' => 'Limite de flux par utilisateur', + 'registration' => array( + 'help' => 'Un chiffre de 0 signifie que l’on peut créer un nombre infini de comptes', + 'number' => 'Nombre max de comptes', + ), + ), 'update' => array( '_' => 'Système de mise à jour', 'apply' => 'Appliquer la mise à jour', @@ -164,11 +173,6 @@ return array( 'numbers' => '%d comptes ont déjà été créés', 'password_form' => 'Mot de passe
    (pour connexion par formulaire)', 'password_format' => '7 caractères minimum', - 'registration' => array( - 'allow' => 'Autoriser la création de comptes', - 'help' => 'Un chiffre de 0 signifie que l’on peut créer un nombre infini de comptes', - 'number' => 'Nombre max de comptes', - ), 'title' => 'Gestion des utilisateurs', 'user_list' => 'Liste des utilisateurs', 'username' => 'Nom d’utilisateur', diff --git a/app/i18n/fr/feedback.php b/app/i18n/fr/feedback.php index 99c193d28..e2364a251 100644 --- a/app/i18n/fr/feedback.php +++ b/app/i18n/fr/feedback.php @@ -102,7 +102,6 @@ return array( '_' => 'L’utilisateur %s a été supprimé.', 'error' => 'L’utilisateur %s ne peut pas être supprimé.', ), - 'set_registration' => 'Le nombre maximal de comptes a été mis à jour.', ), 'profile' => array( 'error' => 'Votre profil n’a pas pu être mis à jour', diff --git a/app/i18n/fr/gen.php b/app/i18n/fr/gen.php index 67d278be4..9df5b6f05 100644 --- a/app/i18n/fr/gen.php +++ b/app/i18n/fr/gen.php @@ -137,6 +137,7 @@ return array( 'sharing' => 'Partage', 'shortcuts' => 'Raccourcis', 'stats' => 'Statistiques', + 'system' => 'Configuration du système', 'update' => 'Mise à jour', 'user_management' => 'Gestion des utilisateurs', 'user_profile' => 'Profil', diff --git a/app/layout/aside_configure.phtml b/app/layout/aside_configure.phtml index 7567a8206..d956ec21f 100644 --- a/app/layout/aside_configure.phtml +++ b/app/layout/aside_configure.phtml @@ -27,6 +27,9 @@ +
  • + +
  • diff --git a/app/layout/header.phtml b/app/layout/header.phtml index 41a63a565..238c664b0 100644 --- a/app/layout/header.phtml +++ b/app/layout/header.phtml @@ -67,6 +67,7 @@ if (FreshRSS_Auth::accessNeedsAction()) {
  • +
  • diff --git a/app/views/configure/system.phtml b/app/views/configure/system.phtml new file mode 100644 index 000000000..cbedc511b --- /dev/null +++ b/app/views/configure/system.phtml @@ -0,0 +1,47 @@ +partial('aside_configure'); ?> + +
    + + + + + +
    + +
    + + +
    +
    + +
    +
    + 1 ? 'admin.user.numbers' : 'admin.user.number', $number); + ?> +
    +
    + +
    + +
    + +
    +
    + +
    + +
    + +
    +
    + +
    +
    + + +
    +
    + +
    \ No newline at end of file diff --git a/app/views/user/manage.phtml b/app/views/user/manage.phtml index 3d3bc3ddf..fe1b6618b 100644 --- a/app/views/user/manage.phtml +++ b/app/views/user/manage.phtml @@ -3,34 +3,6 @@
    -
    - - -
    - -
    - - -
    -
    - -
    -
    - 1 ? 'admin.user.numbers' : 'admin.user.number', $number); - ?> -
    -
    - -
    -
    - - -
    -
    -
    -
    -- cgit v1.2.3 From d396dd71524694766bde852834be15f477ceaf3e Mon Sep 17 00:00:00 2001 From: Alexis Degrugillier Date: Mon, 24 Aug 2015 18:41:57 -0400 Subject: Add instance name in system configuration page --- app/Controllers/configureController.php | 1 + app/i18n/cz/admin.php | 1 + app/i18n/de/admin.php | 1 + app/i18n/en/admin.php | 1 + app/i18n/fr/admin.php | 1 + app/views/configure/system.phtml | 7 +++++++ 6 files changed, 12 insertions(+) (limited to 'app/Controllers') diff --git a/app/Controllers/configureController.php b/app/Controllers/configureController.php index 7a4d0ecd7..0dc7ceab2 100755 --- a/app/Controllers/configureController.php +++ b/app/Controllers/configureController.php @@ -316,6 +316,7 @@ class FreshRSS_configure_Controller extends Minz_ActionController { $limits['max_feeds'] = Minz_Request::param('max-feeds', 16384); $limits['max_categories'] = Minz_Request::param('max-categories', 16384); FreshRSS_Context::$system_conf->limits = $limits; + FreshRSS_Context::$system_conf->title = Minz_Request::param('instance-name', 'FreshRSS'); FreshRSS_Context::$system_conf->save(); invalidateHttpCache(); diff --git a/app/i18n/cz/admin.php b/app/i18n/cz/admin.php index 6c9156335..e1fa5d141 100644 --- a/app/i18n/cz/admin.php +++ b/app/i18n/cz/admin.php @@ -148,6 +148,7 @@ return array( ), 'system' => array( '_' => 'System configuration', // @todo translate + 'instance-name' => 'Instance name', // @todo translate 'max-categories' => 'Categories per user limit', // @todo translate 'max-feeds' => 'Feeds per user limit', // @todo translate 'registration' => array( diff --git a/app/i18n/de/admin.php b/app/i18n/de/admin.php index 26d0bcd36..395b51acf 100644 --- a/app/i18n/de/admin.php +++ b/app/i18n/de/admin.php @@ -148,6 +148,7 @@ return array( ), 'system' => array( '_' => 'System configuration', // @todo translate + 'instance-name' => 'Instance name', // @todo translate 'max-categories' => 'Categories per user limit', // @todo translate 'max-feeds' => 'Feeds per user limit', // @todo translate 'registration' => array( diff --git a/app/i18n/en/admin.php b/app/i18n/en/admin.php index ad9038203..6edb38cf0 100644 --- a/app/i18n/en/admin.php +++ b/app/i18n/en/admin.php @@ -148,6 +148,7 @@ return array( ), 'system' => array( '_' => 'System configuration', + 'instance-name' => 'Instance name', 'max-categories' => 'Categories per user limit', 'max-feeds' => 'Feeds per user limit', 'registration' => array( diff --git a/app/i18n/fr/admin.php b/app/i18n/fr/admin.php index 44e013c2f..e73622577 100644 --- a/app/i18n/fr/admin.php +++ b/app/i18n/fr/admin.php @@ -148,6 +148,7 @@ return array( ), 'system' => array( '_' => 'Configuration du système', + 'instance-name' => 'Nom de l’instance', 'max-categories' => 'Limite de catégories par utilisateur', 'max-feeds' => 'Limite de flux par utilisateur', 'registration' => array( diff --git a/app/views/configure/system.phtml b/app/views/configure/system.phtml index 9c9813729..9406c34d6 100644 --- a/app/views/configure/system.phtml +++ b/app/views/configure/system.phtml @@ -6,6 +6,13 @@ +
    + +
    + +
    +
    +
    -- cgit v1.2.3 From 481c2a671913cdd6099a1b6ee4d5491dff16c0bf Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sat, 24 Oct 2015 22:25:48 +0200 Subject: Clean logs Reduced login of API and PubSubHubbub (both are quite stable now). When clearing logs as admin, also clear API and PubSubHubbub logs. https://github.com/FreshRSS/FreshRSS/issues/988 --- app/Controllers/feedController.php | 4 ++-- app/Models/LogDAO.php | 5 +++++ p/api/greader.php | 38 +++++++++++++++++++------------------- 3 files changed, 26 insertions(+), 21 deletions(-) (limited to 'app/Controllers') diff --git a/app/Controllers/feedController.php b/app/Controllers/feedController.php index ec3dce777..4ec661115 100755 --- a/app/Controllers/feedController.php +++ b/app/Controllers/feedController.php @@ -307,9 +307,9 @@ class FreshRSS_feed_Controller extends Minz_ActionController { $pubSubHubbubEnabled = $pubsubhubbubEnabledGeneral && $feed->pubSubHubbubEnabled(); if ((!$simplePiePush) && (!$id) && $pubSubHubbubEnabled && ($feed->lastUpdate() > $pshbMinAge)) { - $text = 'Skip pull of feed using PubSubHubbub: ' . $url; + //$text = 'Skip pull of feed using PubSubHubbub: ' . $url; //Minz_Log::debug($text); - file_put_contents(USERS_PATH . '/_/log_pshb.txt', date('c') . "\t" . $text . "\n", FILE_APPEND); + //file_put_contents(USERS_PATH . '/_/log_pshb.txt', date('c') . "\t" . $text . "\n", FILE_APPEND); continue; //When PubSubHubbub is used, do not pull refresh so often } diff --git a/app/Models/LogDAO.php b/app/Models/LogDAO.php index 4c56e3150..ab258cd58 100644 --- a/app/Models/LogDAO.php +++ b/app/Models/LogDAO.php @@ -21,5 +21,10 @@ class FreshRSS_LogDAO { public static function truncate() { file_put_contents(join_path(DATA_PATH, 'users', Minz_Session::param('currentUser', '_'), 'log.txt'), ''); + if (FreshRSS_Auth::hasAccess('admin')) { + file_put_contents(join_path(DATA_PATH, 'users', '_', 'log.txt'), ''); + file_put_contents(join_path(DATA_PATH, 'users', '_', 'log_api.txt'), ''); + file_put_contents(join_path(DATA_PATH, 'users', '_', 'log_pshb.txt'), ''); + } } } diff --git a/p/api/greader.php b/p/api/greader.php index 5a23af006..b9942f0bc 100644 --- a/p/api/greader.php +++ b/p/api/greader.php @@ -77,7 +77,7 @@ class MyPDO extends Minz_ModelPdo { } function logMe($text) { - file_put_contents(join_path(USERS_PATH, '_', 'log_api.txt'), $text, FILE_APPEND); + file_put_contents(join_path(USERS_PATH, '_', 'log_api.txt'), date('c') . "\t" . $text . "\n", FILE_APPEND); } function debugInfo() { @@ -96,7 +96,7 @@ function debugInfo() { } function badRequest() { - logMe("badRequest()\n"); + logMe("badRequest()"); logMe(debugInfo()); header('HTTP/1.1 400 Bad Request'); header('Content-Type: text/plain; charset=UTF-8'); @@ -104,7 +104,7 @@ function badRequest() { } function unauthorized() { - logMe("unauthorized()\n"); + logMe("unauthorized()"); logMe(debugInfo()); header('HTTP/1.1 401 Unauthorized'); header('Content-Type: text/plain; charset=UTF-8'); @@ -113,7 +113,7 @@ function unauthorized() { } function notImplemented() { - logMe("notImplemented()\n"); + logMe("notImplemented()"); logMe(debugInfo()); header('HTTP/1.1 501 Not Implemented'); header('Content-Type: text/plain; charset=UTF-8'); @@ -121,14 +121,14 @@ function notImplemented() { } function serviceUnavailable() { - logMe("serviceUnavailable()\n"); + logMe("serviceUnavailable()"); header('HTTP/1.1 503 Service Unavailable'); header('Content-Type: text/plain; charset=UTF-8'); die('Service Unavailable!'); } function checkCompatibility() { - logMe("checkCompatibility()\n"); + logMe("checkCompatibility()"); header('Content-Type: text/plain; charset=UTF-8'); if (PHP_INT_SIZE < 8 && !function_exists('gmp_init')) { die('FAIL 64-bit or GMP extension!'); @@ -159,7 +159,7 @@ function authorizationToUser() { if ($headerAuthX[1] === sha1($system_conf->salt . $user . $conf->apiPasswordHash)) { return $user; } else { - logMe('Invalid API authorisation for user ' . $user . ': ' . $headerAuthX[1] . "\n"); + logMe('Invalid API authorisation for user ' . $user . ': ' . $headerAuthX[1]); Minz_Log::warning('Invalid API authorisation for user ' . $user . ': ' . $headerAuthX[1]); unauthorized(); } @@ -172,7 +172,7 @@ function authorizationToUser() { } function clientLogin($email, $pass) { //http://web.archive.org/web/20130604091042/http://undoc.in/clientLogin.html - logMe('clientLogin(' . $email . ")\n"); + //logMe('clientLogin(' . $email . ")"); if (ctype_alnum($email)) { if (!function_exists('password_verify')) { include_once(LIB_PATH . '/password_compat.php'); @@ -205,7 +205,7 @@ function token($conf) { //http://blog.martindoms.com/2009/08/15/using-the-google-reader-api-part-1/ //https://github.com/ericmann/gReader-Library/blob/master/greader.class.php $user = Minz_Session::param('currentUser', '_'); - logMe('token('. $user . ")\n"); //TODO: Implement real token that expires + //logMe('token('. $user . ")"); //TODO: Implement real token that expires $system_conf = Minz_Configuration::get('system'); $token = str_pad(sha1($system_conf->salt . $user . $conf->apiPasswordHash), 57, 'Z'); //Must have 57 characters echo $token, "\n"; @@ -215,7 +215,7 @@ function token($conf) { function checkToken($conf, $token) { //http://code.google.com/p/google-reader-api/wiki/ActionToken $user = Minz_Session::param('currentUser', '_'); - logMe('checkToken(' . $token . ")\n"); + //logMe('checkToken(' . $token . ")"); $system_conf = Minz_Configuration::get('system'); if ($token === str_pad(sha1($system_conf->salt . $user . $conf->apiPasswordHash), 57, 'Z')) { return true; @@ -224,7 +224,7 @@ function checkToken($conf, $token) { } function tagList() { - logMe("tagList()\n"); + //logMe("tagList()"); header('Content-Type: application/json; charset=UTF-8'); $pdo = new MyPDO(); @@ -249,7 +249,7 @@ function tagList() { } function subscriptionList() { - logMe("subscriptionList()\n"); + //logMe("subscriptionList()"); header('Content-Type: application/json; charset=UTF-8'); $pdo = new MyPDO(); @@ -283,7 +283,7 @@ function subscriptionList() { } function unreadCount() { //http://blog.martindoms.com/2009/10/16/using-the-google-reader-api-part-2/#unread-count - logMe("unreadCount()\n"); + //logMe("unreadCount()"); header('Content-Type: application/json; charset=UTF-8'); $totalUnreads = 0; @@ -330,7 +330,7 @@ function unreadCount() { //http://blog.martindoms.com/2009/10/16/using-the-googl function streamContents($path, $include_target, $start_time, $count, $order, $exclude_target, $continuation) { //http://code.google.com/p/pyrfeed/wiki/GoogleReaderAPI //http://blog.martindoms.com/2009/10/16/using-the-google-reader-api-part-2/#feed - logMe("streamContents($path, $include_target, $start_time, $count, $order, $exclude_target, $continuation)\n"); + //logMe("streamContents($path, $include_target, $start_time, $count, $order, $exclude_target, $continuation)"); header('Content-Type: application/json; charset=UTF-8'); $feedDAO = FreshRSS_Factory::createFeedDao(); @@ -436,7 +436,7 @@ function streamContentsItemsIds($streamId, $start_time, $count, $order, $exclude //http://code.google.com/p/google-reader-api/wiki/ApiStreamItemsIds //http://code.google.com/p/pyrfeed/wiki/GoogleReaderAPI //http://blog.martindoms.com/2009/10/16/using-the-google-reader-api-part-2/#feed - logMe("streamContentsItemsIds($streamId, $start_time, $count, $order, $exclude_target)\n"); + //logMe("streamContentsItemsIds($streamId, $start_time, $count, $order, $exclude_target)"); $type = 'A'; $id = ''; @@ -484,7 +484,7 @@ function streamContentsItemsIds($streamId, $start_time, $count, $order, $exclude } function editTag($e_ids, $a, $r) { - logMe("editTag()\n"); + //logMe("editTag()"); foreach ($e_ids as $i => $e_id) { $e_ids[$i] = hex2dec(basename($e_id)); //Strip prefix 'tag:google.com,2005:reader/item/' @@ -520,7 +520,7 @@ function editTag($e_ids, $a, $r) { } function markAllAsRead($streamId, $olderThanId) { - logMe("markAllAsRead($streamId, $olderThanId)\n"); + //logMe("markAllAsRead($streamId, $olderThanId)"); $entryDAO = FreshRSS_Factory::createEntryDao(); if (strpos($streamId, 'feed/') === 0) { $f_id = basename($streamId); @@ -538,7 +538,7 @@ function markAllAsRead($streamId, $olderThanId) { exit(); } -logMe('----------------------------------------------------------------'."\n"); +//logMe('----------------------------------------------------------------'); //logMe(debugInfo()); $pathInfo = empty($_SERVER['PATH_INFO']) ? '/Error' : urldecode($_SERVER['PATH_INFO']); @@ -560,7 +560,7 @@ if ($user !== '') { $conf = get_user_configuration($user); } -logMe('User => ' . $user . "\n"); +//logMe('User => ' . $user); Minz_Session::_param('currentUser', $user); -- cgit v1.2.3 From 7bb28c3f2b77b109451e2514e83fa99789fee35e Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sun, 25 Oct 2015 13:24:48 +0100 Subject: HTTP 403 for invalid login https://github.com/FreshRSS/FreshRSS/issues/1015 And does not leak if user exists or not --- app/Controllers/authController.php | 9 +++------ app/Controllers/javascriptController.php | 8 ++++++-- 2 files changed, 9 insertions(+), 8 deletions(-) (limited to 'app/Controllers') diff --git a/app/Controllers/authController.php b/app/Controllers/authController.php index aff184263..bccce5a59 100644 --- a/app/Controllers/authController.php +++ b/app/Controllers/authController.php @@ -123,8 +123,7 @@ class FreshRSS_auth_Controller extends Minz_ActionController { $conf = get_user_configuration($username); if (is_null($conf)) { - Minz_Request::bad(_t('feedback.auth.login.invalid'), - array('c' => 'auth', 'a' => 'login')); + Minz_Error::error(403, array(_t('feedback.auth.login.invalid')), false); } $ok = FreshRSS_FormAuth::checkCredentials( @@ -151,8 +150,7 @@ class FreshRSS_auth_Controller extends Minz_ActionController { ' user=' . $username . ', nonce=' . $nonce . ', c=' . $challenge); - Minz_Request::bad(_t('feedback.auth.login.invalid'), - array('c' => 'auth', 'a' => 'login')); + Minz_Error::error(403, array(_t('feedback.auth.login.invalid')), false); } } elseif (FreshRSS_Context::$system_conf->unsafe_autologin_enabled) { $username = Minz_Request::param('u', ''); @@ -184,8 +182,7 @@ class FreshRSS_auth_Controller extends Minz_ActionController { array('c' => 'index', 'a' => 'index')); } else { Minz_Log::warning('Unsafe password mismatch for user ' . $username); - Minz_Request::bad(_t('feedback.auth.login.invalid'), - array('c' => 'auth', 'a' => 'login')); + Minz_Error::error(403, array(_t('feedback.auth.login.invalid')), false); } } } diff --git a/app/Controllers/javascriptController.php b/app/Controllers/javascriptController.php index 421cf6f72..f8746240c 100755 --- a/app/Controllers/javascriptController.php +++ b/app/Controllers/javascriptController.php @@ -43,7 +43,11 @@ class FreshRSS_javascript_Controller extends Minz_ActionController { } else { Minz_Log::notice('Nonce failure due to invalid username!'); } - $this->view->nonce = ''; //Failure - $this->view->salt1 = ''; + //Failure: Return random data. + $this->view->salt1 = sprintf('$2a$%02d$', FreshRSS_user_Controller::BCRYPT_COST); + for ($i = 22; $i > 0; $i--) { + $this->view->salt1 .= './ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'[rand(0, 63)]; + } + $this->view->nonce = sha1(rand()); } } -- cgit v1.2.3 From ad1f0cb96b3eefdeac5031e59c8810fc9427b6e2 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sun, 25 Oct 2015 19:31:41 +0100 Subject: Return after 403 https://github.com/FreshRSS/FreshRSS/pull/1016 https://github.com/FreshRSS/FreshRSS/issues/1015 --- app/Controllers/authController.php | 1 + 1 file changed, 1 insertion(+) (limited to 'app/Controllers') diff --git a/app/Controllers/authController.php b/app/Controllers/authController.php index bccce5a59..f58b008de 100644 --- a/app/Controllers/authController.php +++ b/app/Controllers/authController.php @@ -124,6 +124,7 @@ class FreshRSS_auth_Controller extends Minz_ActionController { $conf = get_user_configuration($username); if (is_null($conf)) { Minz_Error::error(403, array(_t('feedback.auth.login.invalid')), false); + return; } $ok = FreshRSS_FormAuth::checkCredentials( -- cgit v1.2.3 From c992b683a8467de60136e4d4b1860f06a746c6b1 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Mon, 26 Oct 2015 17:38:32 +0100 Subject: PHP 5.2 compatibility https://github.com/FreshRSS/FreshRSS/pull/1016 https://github.com/FreshRSS/FreshRSS/issues/1015 It is first PHP 5.5 that added support for accessing characters within string literals using []... --- app/Controllers/javascriptController.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'app/Controllers') diff --git a/app/Controllers/javascriptController.php b/app/Controllers/javascriptController.php index f8746240c..e3ae3669e 100755 --- a/app/Controllers/javascriptController.php +++ b/app/Controllers/javascriptController.php @@ -45,8 +45,9 @@ class FreshRSS_javascript_Controller extends Minz_ActionController { } //Failure: Return random data. $this->view->salt1 = sprintf('$2a$%02d$', FreshRSS_user_Controller::BCRYPT_COST); + $alphabet = './ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; for ($i = 22; $i > 0; $i--) { - $this->view->salt1 .= './ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'[rand(0, 63)]; + $this->view->salt1 .= $alphabet[rand(0, 63)]; } $this->view->nonce = sha1(rand()); } -- cgit v1.2.3 From bb0556543d3d5d54832ea6d81372587b88062a5b Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Mon, 2 Nov 2015 20:20:40 +0100 Subject: Move auto-update server URL in configuration Fix https://github.com/FreshRSS/FreshRSS/issues/1019 --- app/Controllers/updateController.php | 5 +++-- constants.php | 1 - data/config.default.php | 3 +++ 3 files changed, 6 insertions(+), 3 deletions(-) (limited to 'app/Controllers') diff --git a/app/Controllers/updateController.php b/app/Controllers/updateController.php index 84a33fe85..64c984b04 100644 --- a/app/Controllers/updateController.php +++ b/app/Controllers/updateController.php @@ -53,7 +53,8 @@ class FreshRSS_update_Controller extends Minz_ActionController { return; } - $c = curl_init(FRESHRSS_UPDATE_WEBSITE); + $auto_update_url = FreshRSS_Context::$system_conf->auto_update_url . '?v=' . FRESHRSS_VERSION; + $c = curl_init($auto_update_url); curl_setopt($c, CURLOPT_RETURNTRANSFER, true); curl_setopt($c, CURLOPT_SSL_VERIFYPEER, true); curl_setopt($c, CURLOPT_SSL_VERIFYHOST, 2); @@ -70,7 +71,7 @@ class FreshRSS_update_Controller extends Minz_ActionController { $this->view->message = array( 'status' => 'bad', 'title' => _t('gen.short.damn'), - 'body' => _t('feedback.update.server_not_found', FRESHRSS_UPDATE_WEBSITE) + 'body' => _t('feedback.update.server_not_found', $auto_update_url) ); return; } diff --git a/constants.php b/constants.php index 0035c259b..1c50d4a83 100644 --- a/constants.php +++ b/constants.php @@ -1,7 +1,6 @@ '', + # Specify address of the FreshRSS auto-update server. + 'auto_update_url' => 'https://update.freshrss.org', + # Natural language of the user interface, e.g. `en`, `fr`. 'language' => 'en', -- cgit v1.2.3 From 697817eebf754c2a05c7b4c88df1f13dbd0179da Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Mon, 2 Nov 2015 21:11:31 +0100 Subject: Make auto-update server URL alterable See https://github.com/FreshRSS/FreshRSS/issues/1019 --- CHANGELOG.md | 2 ++ app/Controllers/configureController.php | 1 + app/Models/ConfigurationSetter.php | 8 ++++++++ app/i18n/cz/admin.php | 1 + app/i18n/de/admin.php | 1 + app/i18n/en/admin.php | 1 + app/i18n/fr/admin.php | 1 + app/i18n/it/admin.php | 1 + app/i18n/nl/admin.php | 11 +++++++++++ app/i18n/nl/gen.php | 1 + app/views/configure/system.phtml | 9 ++++++++- 11 files changed, 36 insertions(+), 1 deletion(-) (limited to 'app/Controllers') diff --git a/CHANGELOG.md b/CHANGELOG.md index 14b6a18ce..828884546 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,8 @@ * Visual alert on categories containing feeds in error [#984](https://github.com/FreshRSS/FreshRSS/pull/984) * I18n * Italian [#1003](https://github.com/FreshRSS/FreshRSS/issues/1003) +* Misc. + * Make auto-update server URL alterable [#1019](https://github.com/FreshRSS/FreshRSS/issues/1019) ## 2015-09-12 FreshRSS 1.1.3-beta diff --git a/app/Controllers/configureController.php b/app/Controllers/configureController.php index 0dc7ceab2..d0f0bd68b 100755 --- a/app/Controllers/configureController.php +++ b/app/Controllers/configureController.php @@ -317,6 +317,7 @@ class FreshRSS_configure_Controller extends Minz_ActionController { $limits['max_categories'] = Minz_Request::param('max-categories', 16384); FreshRSS_Context::$system_conf->limits = $limits; FreshRSS_Context::$system_conf->title = Minz_Request::param('instance-name', 'FreshRSS'); + FreshRSS_Context::$system_conf->auto_update_url = Minz_Request::param('auto-update-url', false); FreshRSS_Context::$system_conf->save(); invalidateHttpCache(); diff --git a/app/Models/ConfigurationSetter.php b/app/Models/ConfigurationSetter.php index 5c8a1ce29..250c14c39 100644 --- a/app/Models/ConfigurationSetter.php +++ b/app/Models/ConfigurationSetter.php @@ -378,4 +378,12 @@ class FreshRSS_ConfigurationSetter { private function _unsafe_autologin_enabled(&$data, $value) { $data['unsafe_autologin_enabled'] = $this->handleBool($value); } + + private function _auto_update_url(&$data, $value) { + if (!$value) { + return; + } + + $data['auto_update_url'] = $value; + } } diff --git a/app/i18n/cz/admin.php b/app/i18n/cz/admin.php index e1fa5d141..342ac7ccd 100644 --- a/app/i18n/cz/admin.php +++ b/app/i18n/cz/admin.php @@ -148,6 +148,7 @@ return array( ), 'system' => array( '_' => 'System configuration', // @todo translate + 'auto-update-url' => 'Auto-update server URL', // @todo translate 'instance-name' => 'Instance name', // @todo translate 'max-categories' => 'Categories per user limit', // @todo translate 'max-feeds' => 'Feeds per user limit', // @todo translate diff --git a/app/i18n/de/admin.php b/app/i18n/de/admin.php index 395b51acf..6e6cc0956 100644 --- a/app/i18n/de/admin.php +++ b/app/i18n/de/admin.php @@ -148,6 +148,7 @@ return array( ), 'system' => array( '_' => 'System configuration', // @todo translate + 'auto-update-url' => 'Auto-update server URL', // @todo translate 'instance-name' => 'Instance name', // @todo translate 'max-categories' => 'Categories per user limit', // @todo translate 'max-feeds' => 'Feeds per user limit', // @todo translate diff --git a/app/i18n/en/admin.php b/app/i18n/en/admin.php index 6edb38cf0..a58771edf 100644 --- a/app/i18n/en/admin.php +++ b/app/i18n/en/admin.php @@ -148,6 +148,7 @@ return array( ), 'system' => array( '_' => 'System configuration', + 'auto-update-url' => 'Auto-update server URL', 'instance-name' => 'Instance name', 'max-categories' => 'Categories per user limit', 'max-feeds' => 'Feeds per user limit', diff --git a/app/i18n/fr/admin.php b/app/i18n/fr/admin.php index e73622577..f4f267306 100644 --- a/app/i18n/fr/admin.php +++ b/app/i18n/fr/admin.php @@ -148,6 +148,7 @@ return array( ), 'system' => array( '_' => 'Configuration du système', + 'auto-update-url' => 'URL du service de mise à jour', 'instance-name' => 'Nom de l’instance', 'max-categories' => 'Limite de catégories par utilisateur', 'max-feeds' => 'Limite de flux par utilisateur', diff --git a/app/i18n/it/admin.php b/app/i18n/it/admin.php index cb9a55c0b..94b2d6762 100644 --- a/app/i18n/it/admin.php +++ b/app/i18n/it/admin.php @@ -148,6 +148,7 @@ return array( ), 'system' => array( '_' => 'Configurazione di sistema', + 'auto-update-url' => 'Auto-update server URL', // @todo translate 'instance-name' => 'Nome istanza', 'max-categories' => 'Limite categorie per utente', 'max-feeds' => 'Limite feeds per utente', diff --git a/app/i18n/nl/admin.php b/app/i18n/nl/admin.php index 5c6a14fda..c3a3062b9 100644 --- a/app/i18n/nl/admin.php +++ b/app/i18n/nl/admin.php @@ -146,6 +146,17 @@ return array( 'title' => 'Statistieken', 'top_feed' => 'Top tien feeds', ), + 'system' => array( + '_' => 'System configuration', // @todo translate + 'auto-update-url' => 'Auto-update server URL', // @todo translate + 'instance-name' => 'Instance name', // @todo translate + 'max-categories' => 'Categories per user limit', // @todo translate + 'max-feeds' => 'Feeds per user limit', // @todo translate + 'registration' => array( + 'help' => '0 means that there is no account limit', // @todo translate + 'number' => 'Max number of accounts', // @todo translate + ), + ), 'update' => array( '_' => 'Versie controle', 'apply' => 'Toepassen', diff --git a/app/i18n/nl/gen.php b/app/i18n/nl/gen.php index b8467f92f..574f0386b 100644 --- a/app/i18n/nl/gen.php +++ b/app/i18n/nl/gen.php @@ -139,6 +139,7 @@ return array( 'sharing' => 'Delen', 'shortcuts' => 'Snelle toegang', 'stats' => 'Statistieken', + 'system' => 'System configuration', // @todo translate 'update' => 'Versie controle', 'user_management' => 'Beheer gebruikers', 'user_profile' => 'Profiel', diff --git a/app/views/configure/system.phtml b/app/views/configure/system.phtml index 9406c34d6..4af669eb0 100644 --- a/app/views/configure/system.phtml +++ b/app/views/configure/system.phtml @@ -9,7 +9,14 @@
    - + +
    +
    + +
    + +
    +
    -- cgit v1.2.3 From 05ba5bc569060edf88c7b2e284736dcca68249aa Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Mon, 22 Feb 2016 21:10:35 +0100 Subject: Do not log article updates It seems to work well, and there are too many such updates. BTW, we should have a verbose/insane log level. --- app/Controllers/feedController.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'app/Controllers') diff --git a/app/Controllers/feedController.php b/app/Controllers/feedController.php index 4ec661115..7294fe8f4 100755 --- a/app/Controllers/feedController.php +++ b/app/Controllers/feedController.php @@ -359,8 +359,8 @@ class FreshRSS_feed_Controller extends Minz_ActionController { //This entry already exists and is unchanged. TODO: Remove the test with the zero'ed hash in FreshRSS v1.3 $oldGuids[] = $entry->guid(); } else { //This entry already exists but has been updated - Minz_Log::debug('Entry with GUID `' . $entry->guid() . '` updated in feed ' . $feed->id() . - ', old hash ' . $existingHash . ', new hash ' . $entry->hash()); + //Minz_Log::debug('Entry with GUID `' . $entry->guid() . '` updated in feed ' . $feed->id() . + //', old hash ' . $existingHash . ', new hash ' . $entry->hash()); //TODO: Make an updated/is_read policy by feed, in addition to the global one. $entry->_isRead(FreshRSS_Context::$user_conf->mark_updated_article_unread ? false : null); //Change is_read according to policy. if (!$entryDAO->hasTransaction()) { -- cgit v1.2.3 From c9d3d78340e062b9e2fe19c8c55b8bdc75392e63 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sat, 27 Feb 2016 17:51:13 +0100 Subject: CSP manually refreshing feeds https://github.com/FreshRSS/FreshRSS/issues/1075 --- app/Controllers/javascriptController.php | 2 +- app/views/javascript/actualize.phtml | 69 ++++++-------------------------- p/scripts/main.js | 44 +++++++++++++++++--- 3 files changed, 53 insertions(+), 62 deletions(-) (limited to 'app/Controllers') diff --git a/app/Controllers/javascriptController.php b/app/Controllers/javascriptController.php index e3ae3669e..00a7b5c38 100755 --- a/app/Controllers/javascriptController.php +++ b/app/Controllers/javascriptController.php @@ -6,7 +6,7 @@ class FreshRSS_javascript_Controller extends Minz_ActionController { } public function actualizeAction() { - header('Content-Type: text/javascript; charset=UTF-8'); + header('Content-Type: application/json; charset=UTF-8'); $feedDAO = FreshRSS_Factory::createFeedDao(); $this->view->feeds = $feedDAO->listFeedsOrderUpdate(FreshRSS_Context::$user_conf->ttl_default); } diff --git a/app/views/javascript/actualize.phtml b/app/views/javascript/actualize.phtml index 454228909..3baabf748 100644 --- a/app/views/javascript/actualize.phtml +++ b/app/views/javascript/actualize.phtml @@ -1,56 +1,13 @@ -"use strict"; -var feeds = [feeds as $feed) { ?>{url: " 'feed', 'a' => 'actualize', 'params' => array('id' => $feed->id(), 'ajax' => '1')), 'php'); ?>",title: "name(); ?>"},], - feed_processed = 0, - feed_count = feeds.length; - -function initProgressBar(init) { - if (init) { - $("body").after("\
    \ -
    /
    \ - 0 / " + feed_count + "\ -
    "); - } else { - window.location.reload(); - } -} -function updateProgressBar(i, title_feed) { - $("#actualizeProgress .progress").html(i + " / " + feed_count); - $("#actualizeProgress .title").html(title_feed); -} - -function updateFeeds() { - if (feed_count === 0) { - openNotification("", "good"); - ajax_loading = false; - return; - } - initProgressBar(true); - - for (var i = 0; i < 10; i++) { - updateFeed(); - } -} - -function updateFeed() { - var feed = feeds.pop(); - if (feed == undefined) { - return; - } - - $.ajax({ - type: 'POST', - url: feed['url'], - }).complete(function (data) { - feed_processed++; - updateProgressBar(feed_processed, feed['title']); - - if (feed_processed === feed_count) { - initProgressBar(false); - } else { - updateFeed(); - } - }); -} +feeds as $feed) { + $feeds[] = array( + 'url' => Minz_Url::display(array('c' => 'feed', 'a' => 'actualize', 'params' => array('id' => $feed->id(), 'ajax' => '1')), 'php'), + 'title' => $feed->name(), + ); +} +echo json_encode(array( + 'feeds' => $feeds, + 'feedback_no_refresh' => _t('feedback.sub.feed.no_refresh'), + 'feedback_actualize' => _t('feedback.sub.actualize'), +)); diff --git a/p/scripts/main.js b/p/scripts/main.js index d62a6aff8..51c8f4cbf 100644 --- a/p/scripts/main.js +++ b/p/scripts/main.js @@ -767,6 +767,31 @@ function init_nav_entries() { }); } +// +var feed_processed = 0; + +function updateFeed(feeds, feeds_count) { + var feed = feeds.pop(); + if (feed == undefined) { + return; + } + + $.ajax({ + type: 'POST', + url: feed['url'], + }).complete(function (data) { + feed_processed++; + $("#actualizeProgress .progress").html(feed_processed + " / " + feeds_count); + $("#actualizeProgress .title").html(feed['title']); + + if (feed_processed === feeds_count) { + window.location.reload(); + } else { + updateFeed(feeds, feeds_count); + } + }); +} + function init_actualize() { var auto = false; @@ -777,14 +802,23 @@ function init_actualize() { ajax_loading = true; - $.getScript('./?c=javascript&a=actualize').done(function () { - if (auto && feed_count < 1) { + $.getJSON('./?c=javascript&a=actualize').done(function (data) { + if (auto && data.feeds.length < 1) { auto = false; ajax_loading = false; return false; } - - updateFeeds(); + if (data.feeds.length === 0) { + openNotification(data.feedback_no_refresh, "good"); + ajax_loading = false; + return; + } + //Progress bar + var feeds_count = data.feeds.length; + $('body').after('
    ' + data.feedback_actualize + '
    /
    0 / ' + feeds_count + '
    '); + for (var i = 10; i > 0; i--) { + updateFeed(data.feeds, feeds_count); + } }); return false; @@ -795,7 +829,7 @@ function init_actualize() { $("#actualize").click(); } } - +//
    // var notification = null, -- cgit v1.2.3 From 7f91dbf16dca9f824b7bbbd42ef34f39ac7c22a9 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sun, 6 Mar 2016 15:32:58 +0100 Subject: SQLite: Articles from old FreshRSS are marked as unread on update Bug fixed https://github.com/FreshRSS/FreshRSS/issues/1049 --- app/Controllers/feedController.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'app/Controllers') diff --git a/app/Controllers/feedController.php b/app/Controllers/feedController.php index 7294fe8f4..b559d3c22 100755 --- a/app/Controllers/feedController.php +++ b/app/Controllers/feedController.php @@ -355,7 +355,7 @@ class FreshRSS_feed_Controller extends Minz_ActionController { $entry_date = $entry->date(true); if (isset($existingHashForGuids[$entry->guid()])) { $existingHash = $existingHashForGuids[$entry->guid()]; - if (strcasecmp($existingHash, $entry->hash()) === 0 || $existingHash === '00000000000000000000000000000000') { + if (strcasecmp($existingHash, $entry->hash()) === 0 || trim($existingHash, '0') == '') { //This entry already exists and is unchanged. TODO: Remove the test with the zero'ed hash in FreshRSS v1.3 $oldGuids[] = $entry->guid(); } else { //This entry already exists but has been updated -- cgit v1.2.3 From b042d3a7728037db90a9306c61091be0a8ac42c4 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sat, 23 Apr 2016 19:10:32 +0200 Subject: HTTP2 optimization Fast flush HTTP headers, push promise CSS. Requires PHP 5.3+ due to anonymous function. Do not load syles, scripts, and notifications for Ajax requests. https://github.com/FreshRSS/FreshRSS/issues/1089 --- README.fr.md | 2 +- README.md | 2 +- app/Controllers/indexController.php | 64 +++++++++++++++++++------------------ app/FreshRSS.php | 37 ++++++++++----------- app/Models/Themes.php | 4 --- app/layout/layout.phtml | 40 ++++++++++++----------- lib/Minz/Request.php | 5 ++- lib/Minz/Url.php | 12 ++++--- lib/lib_rss.php | 4 +++ 9 files changed, 89 insertions(+), 81 deletions(-) (limited to 'app/Controllers') diff --git a/README.fr.md b/README.fr.md index 794b1a9e1..a173f0a75 100644 --- a/README.fr.md +++ b/README.fr.md @@ -33,7 +33,7 @@ Nous sommes une communauté amicale. * Serveur modeste, par exemple sous Linux ou Windows * Fonctionne même sur un Raspberry Pi 1 avec des temps de réponse < 1s (testé sur 150 flux, 22k articles) * Serveur Web Apache2 (recommandé), ou nginx, lighttpd (non testé sur les autres) -* PHP 5.2.1+ (PHP 5.3.7+ recommandé, et PHP 5.5+ pour les performances) (support bêta de PHP 7 avec encore meilleures performances) +* PHP 5.3+ (PHP 5.3.7+ recommandé, et PHP 5.5+ pour les performances, et PHP 7+ pour d’encore meilleures performances) * Requis : [PDO_MySQL](http://php.net/pdo-mysql) ou [PDO_SQLite](http://php.net/pdo-sqlite), [cURL](http://php.net/curl), [GMP](http://php.net/gmp) (pour accès API sur plateformes < 64 bits), [IDN](http://php.net/intl.idn) (pour les noms de domaines internationalisés) * Recommandés : [iconv](http://php.net/iconv), [JSON](http://php.net/json), [mbstring](http://php.net/mbstring), [Zip](http://php.net/zip), [zlib](http://php.net/zlib) * Inclus par défaut : [DOM](http://php.net/dom), [XML](http://php.net/xml)… diff --git a/README.md b/README.md index 728204a38..4d3bb5c4c 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,7 @@ We are a friendly community. * Light server running Linux or Windows * It even works on Raspberry Pi 1 with response time under a second (tested with 150 feeds, 22k articles) * A web server: Apache2 (recommended), nginx, lighttpd (not tested on others) -* PHP 5.2.1+ (PHP 5.3.7+ recommended, and PHP 5.5+ for performance) (beta support for PHP 7 with even higher performance) +* PHP 5.3+ (PHP 5.3.7+ recommended, and PHP 5.5+ for performance, and PHP 7 for even higher performance) * Required extensions: [PDO_MySQL](http://php.net/pdo-mysql) or [PDO_SQLite](http://php.net/pdo-sqlite), [cURL](http://php.net/curl), [GMP](http://php.net/gmp) (for API access on platforms < 64 bits), [IDN](http://php.net/intl.idn) (for Internationalized Domain Names) * Recommended extensions: [iconv](http://php.net/iconv), [JSON](http://php.net/json), [mbstring](http://php.net/mbstring), [Zip](http://php.net/zip), [zlib](http://php.net/zlib) * Enabled by default: [DOM](http://php.net/dom), [XML](http://php.net/xml)… diff --git a/app/Controllers/indexController.php b/app/Controllers/indexController.php index baaf99065..7e626720e 100755 --- a/app/Controllers/indexController.php +++ b/app/Controllers/indexController.php @@ -32,42 +32,44 @@ class FreshRSS_index_Controller extends Minz_ActionController { Minz_Error::error(404); } - try { - $entries = $this->listEntriesByContext(); - - $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(); - } + $this->view->callbackBeforeContent = function() { + try { + $entries = $this->listEntriesByContext(); + + $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; + $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()); - Minz_Error::error(404); - } + $this->view->entries = $entries; + } catch (FreshRSS_EntriesGetter_Exception $e) { + Minz_Log::notice($e->getMessage()); + Minz_Error::error(404); + } - $this->view->categories = FreshRSS_Context::$categories; + $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; - } - Minz_View::prependTitle($title . ' · '); + $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; + } + Minz_View::prependTitle($title . ' · '); + }; } /** diff --git a/app/FreshRSS.php b/app/FreshRSS.php index bafa970da..562d8e2cd 100644 --- a/app/FreshRSS.php +++ b/app/FreshRSS.php @@ -34,7 +34,7 @@ class FreshRSS extends Minz_FrontController { // Auth has to be initialized before using currentUser session parameter // because it's this part which create this parameter. - $this->initAuth(); + self::initAuth(); // Then, register the user configuration and use the configuration setter // created above. @@ -46,10 +46,7 @@ class FreshRSS extends Minz_FrontController { // Finish to initialize the other FreshRSS / Minz components. FreshRSS_Context::init(); - $this->initI18n(); - FreshRSS_Share::load(join_path(DATA_PATH, 'shares.php')); - $this->loadStylesAndScripts(); - $this->loadNotifications(); + self::initI18n(); // Enable extensions for the current (logged) user. if (FreshRSS_Auth::hasAccess()) { $ext_list = FreshRSS_Context::$user_conf->extensions_enabled; @@ -57,7 +54,7 @@ class FreshRSS extends Minz_FrontController { } } - private function initAuth() { + private static function initAuth() { FreshRSS_Auth::init(); if (Minz_Request::isPost() && !is_referer_from_same_domain()) { // Basic protection against XSRF attacks @@ -74,12 +71,12 @@ class FreshRSS extends Minz_FrontController { } } - private function initI18n() { + private static function initI18n() { Minz_Session::_param('language', FreshRSS_Context::$user_conf->language); Minz_Translate::init(FreshRSS_Context::$user_conf->language); } - private function loadStylesAndScripts() { + private static function loadStylesAndScripts() { $theme = FreshRSS_Themes::load(FreshRSS_Context::$user_conf->theme); if ($theme) { foreach($theme['files'] as $file) { @@ -91,9 +88,9 @@ class FreshRSS extends Minz_FrontController { $filename = $file; } $filetime = @filemtime(PUBLIC_PATH . '/themes/' . $theme_id . '/' . $filename); - Minz_View::appendStyle(Minz_Url::display( - '/themes/' . $theme_id . '/' . $filename . '?' . $filetime - )); + $url = '/themes/' . $theme_id . '/' . $filename . '?' . $filetime; + header('Link: <' . Minz_Url::display($url, '', 'root') . '>;rel=preload', false); //HTTP2 + Minz_View::appendStyle(Minz_Url::display($url)); } } @@ -110,6 +107,14 @@ class FreshRSS extends Minz_FrontController { } } + private static function loadNotifications() { + $notif = Minz_Session::param('notification'); + if ($notif) { + Minz_View::_param('notification', $notif); + Minz_Session::_param('notification'); + } + } + public static function preLayout() { switch (Minz_Request::controllerName()) { case 'index': @@ -123,13 +128,9 @@ class FreshRSS extends Minz_FrontController { break; } header("X-Content-Type-Options: nosniff"); - } - private function loadNotifications() { - $notif = Minz_Session::param('notification'); - if ($notif) { - Minz_View::_param('notification', $notif); - Minz_Session::_param('notification'); - } + FreshRSS_Share::load(join_path(DATA_PATH, 'shares.php')); + self::loadStylesAndScripts(); + self::loadNotifications(); } } diff --git a/app/Models/Themes.php b/app/Models/Themes.php index e3b260261..5a6ec0a05 100644 --- a/app/Models/Themes.php +++ b/app/Models/Themes.php @@ -116,7 +116,3 @@ class FreshRSS_Themes extends Minz_Model { '' . $alts[$name] . ''; } } - -function _i($icon, $url_only = false) { - return FreshRSS_Themes::icon($icon, $url_only); -} diff --git a/app/layout/layout.phtml b/app/layout/layout.phtml index 99a3717bc..6906fa05f 100644 --- a/app/layout/layout.phtml +++ b/app/layout/layout.phtml @@ -1,17 +1,32 @@ - + - + + + + + + + + + + + +callbackBeforeContent)) { + call_user_func($this->callbackBeforeContent); + } +?> + - - - rss_title)) { + } if (isset($this->rss_title)) { $url_rss = $url_base; $url_rss['a'] = 'rss'; ?> - - - - - - - - - - -allow_robots) { ?> +allow_robots) { ?> diff --git a/lib/Minz/Request.php b/lib/Minz/Request.php index 81457df9e..f80b707d6 100644 --- a/lib/Minz/Request.php +++ b/lib/Minz/Request.php @@ -137,12 +137,11 @@ class Minz_Request { /** * Return the base_url from configuration and add a suffix if given. * - * @param $base_url_suffix a string to add at base_url (default: empty string) * @return the base_url with a suffix. */ - public static function getBaseUrl($base_url_suffix = '') { + public static function getBaseUrl() { $conf = Minz_Configuration::get('system'); - $url = rtrim($conf->base_url, '/\\') . $base_url_suffix; + $url = rtrim($conf->base_url, '/\\'); return filter_var($url, FILTER_SANITIZE_URL); } diff --git a/lib/Minz/Url.php b/lib/Minz/Url.php index 382437e9a..c7c67123e 100644 --- a/lib/Minz/Url.php +++ b/lib/Minz/Url.php @@ -24,11 +24,15 @@ class Minz_Url { $url_string = ''; if ($absolute) { - $url_string = Minz_Request::getBaseUrl(PUBLIC_TO_INDEX_PATH); - if ($url_string === PUBLIC_TO_INDEX_PATH) { + $url_string = Minz_Request::getBaseUrl(); + if ($url_string == '') { $url_string = Minz_Request::guessBaseUrl(); - } else { - $url_string .= '/'; + } + if ($isArray) { + $url_string .= PUBLIC_TO_INDEX_PATH; + } + if ($absolute === 'root') { + $url_string = parse_url($url_string, PHP_URL_PATH); } } else { $url_string = $isArray ? '.' : PUBLIC_RELATIVE; diff --git a/lib/lib_rss.php b/lib/lib_rss.php index 135115ea5..f89baf9b1 100644 --- a/lib/lib_rss.php +++ b/lib/lib_rss.php @@ -548,3 +548,7 @@ function base64url_encode($data) { function base64url_decode($data) { return base64_decode(strtr($data, '-_', '+/')); } + +function _i($icon, $url_only = false) { + return FreshRSS_Themes::icon($icon, $url_only); +} -- cgit v1.2.3 From 6b787c7408ecad4271c19e7c92edbad3f8df4330 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sat, 23 Apr 2016 23:07:12 +0200 Subject: Error message when accessing entry by GET --- app/Controllers/entryController.php | 1 + 1 file changed, 1 insertion(+) (limited to 'app/Controllers') diff --git a/app/Controllers/entryController.php b/app/Controllers/entryController.php index 1d9989f40..bff1073ef 100755 --- a/app/Controllers/entryController.php +++ b/app/Controllers/entryController.php @@ -46,6 +46,7 @@ class FreshRSS_entry_Controller extends Minz_ActionController { if ($id === false) { // id is false? It MUST be a POST request! if (!Minz_Request::isPost()) { + Minz_Request::bad(_t('feedback.access.not_found'), array('c' => 'index', 'a' => 'index')); return; } -- cgit v1.2.3 From 91593cecd218413960c4f05f814aaa38d4a0c4ce Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sun, 24 Apr 2016 14:50:31 +0200 Subject: But when adding feeds with passwords https://github.com/FreshRSS/FreshRSS/issues/1131 --- app/Controllers/feedController.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'app/Controllers') diff --git a/app/Controllers/feedController.php b/app/Controllers/feedController.php index b559d3c22..6a8aa01cf 100755 --- a/app/Controllers/feedController.php +++ b/app/Controllers/feedController.php @@ -114,6 +114,8 @@ class FreshRSS_feed_Controller extends Minz_ActionController { Minz_Request::bad(_t('feedback.sub.feed.invalid_url', $url), $url_redirect); } + $feed->_httpAuth($http_auth); + try { $feed->load(true); } catch (FreshRSS_Feed_Exception $e) { @@ -140,7 +142,6 @@ class FreshRSS_feed_Controller extends Minz_ActionController { } $feed->_category($cat); - $feed->_httpAuth($http_auth); // Call the extension hook $name = $feed->name(); -- cgit v1.2.3 From fe18d12551f626c56257f825caf8f97a4a5461ce Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sat, 30 Jul 2016 18:45:34 +0200 Subject: Update MySQL to utf8mb4 (full unicode) 🔥 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Requires MySQL 5.5.3+ (drop support for MySQL 5.0) * Requires PHP 5.3.3+ (drop support for PHP 5.3.0) https://github.com/FreshRSS/FreshRSS/issues/789#issuecomment-73878076 --- README.fr.md | 4 +-- README.md | 4 +-- app/Controllers/feedController.php | 14 +++++---- app/Models/EntryDAO.php | 60 +++++++++++++++++++++++++++++++------ app/SQL/install.sql.mysql.php | 31 +++++++++++++++---- app/install.php | 10 +++---- app/views/update/checkInstall.phtml | 2 +- lib/Minz/ModelPdo.php | 12 +++----- 8 files changed, 99 insertions(+), 38 deletions(-) (limited to 'app/Controllers') diff --git a/README.fr.md b/README.fr.md index fd01a507b..9da60408f 100644 --- a/README.fr.md +++ b/README.fr.md @@ -32,11 +32,11 @@ Nous sommes une communauté amicale. * Serveur modeste, par exemple sous Linux ou Windows * Fonctionne même sur un Raspberry Pi 1 avec des temps de réponse < 1s (testé sur 150 flux, 22k articles) * Serveur Web Apache2 (recommandé), ou nginx, lighttpd (non testé sur les autres) -* PHP 5.3+ (PHP 5.3.7+ recommandé, et PHP 5.5+ pour les performances, et PHP 7+ pour d’encore meilleures performances) +* PHP 5.3.3+ (PHP 5.3.7+ recommandé, et PHP 5.5+ pour les performances, et PHP 7+ pour d’encore meilleures performances) * Requis : [PDO_MySQL](http://php.net/pdo-mysql) ou [PDO_SQLite](http://php.net/pdo-sqlite), [cURL](http://php.net/curl), [GMP](http://php.net/gmp) (pour accès API sur plateformes < 64 bits), [IDN](http://php.net/intl.idn) (pour les noms de domaines internationalisés) * Recommandés : [iconv](http://php.net/iconv), [JSON](http://php.net/json), [mbstring](http://php.net/mbstring), [Zip](http://php.net/zip), [zlib](http://php.net/zlib) * Inclus par défaut : [DOM](http://php.net/dom), [XML](http://php.net/xml)… -* MySQL 5.0.3+ (recommandé) ou SQLite 3.7.4+ +* MySQL 5.5.3+ (recommandé) ou SQLite 3.7.4+ * Un navigateur Web récent tel Firefox, Chrome, Opera, Safari. [Internet Explorer ne fonctionne plus, mais ce sera corrigé](https://github.com/FreshRSS/FreshRSS/issues/772). * Fonctionne aussi sur mobile * L’entête HTTP `Referer` ne doit pas être désactivé pour pouvoir utiliser le formulaire de connexion diff --git a/README.md b/README.md index a0d22a75c..db5e8c02d 100644 --- a/README.md +++ b/README.md @@ -32,11 +32,11 @@ We are a friendly community. * Light server running Linux or Windows * It even works on Raspberry Pi 1 with response time under a second (tested with 150 feeds, 22k articles) * A web server: Apache2 (recommended), nginx, lighttpd (not tested on others) -* PHP 5.3+ (PHP 5.3.7+ recommended, and PHP 5.5+ for performance, and PHP 7 for even higher performance) +* PHP 5.3.3+ (PHP 5.3.7+ recommended, and PHP 5.5+ for performance, and PHP 7 for even higher performance) * Required extensions: [PDO_MySQL](http://php.net/pdo-mysql) or [PDO_SQLite](http://php.net/pdo-sqlite), [cURL](http://php.net/curl), [GMP](http://php.net/gmp) (for API access on platforms < 64 bits), [IDN](http://php.net/intl.idn) (for Internationalized Domain Names) * Recommended extensions: [iconv](http://php.net/iconv), [JSON](http://php.net/json), [mbstring](http://php.net/mbstring), [Zip](http://php.net/zip), [zlib](http://php.net/zlib) * Enabled by default: [DOM](http://php.net/dom), [XML](http://php.net/xml)… -* MySQL 5.0.3+ (recommended) or SQLite 3.7.4+ +* MySQL 5.5.3+ (recommended) or SQLite 3.7.4+ * A recent browser like Firefox, Chrome, Opera, Safari. [Internet Explorer currently not supported, but support will come back](https://github.com/FreshRSS/FreshRSS/issues/772). * Works on mobile * The browser HTTP `Referer` header must not be disabled when using the form login method diff --git a/app/Controllers/feedController.php b/app/Controllers/feedController.php index 6a8aa01cf..ffda1450d 100755 --- a/app/Controllers/feedController.php +++ b/app/Controllers/feedController.php @@ -200,7 +200,9 @@ class FreshRSS_feed_Controller extends Minz_ActionController { $entryDAO->addEntry($values); } $feedDAO->updateLastUpdate($feed->id()); - $feedDAO->commit(); + if ($feedDAO->inTransaction()) { + $feedDAO->commit(); + } // Entries are in DB, we redirect to feed configuration page. $url_redirect['params']['id'] = $feed->id(); @@ -364,7 +366,7 @@ class FreshRSS_feed_Controller extends Minz_ActionController { //', old hash ' . $existingHash . ', new hash ' . $entry->hash()); //TODO: Make an updated/is_read policy by feed, in addition to the global one. $entry->_isRead(FreshRSS_Context::$user_conf->mark_updated_article_unread ? false : null); //Change is_read according to policy. - if (!$entryDAO->hasTransaction()) { + if (!$entryDAO->inTransaction()) { $entryDAO->beginTransaction(); } $entryDAO->updateEntry($entry->toArray()); @@ -396,7 +398,7 @@ class FreshRSS_feed_Controller extends Minz_ActionController { $feed->pubSubHubbubError(true); } - if (!$entryDAO->hasTransaction()) { + if (!$entryDAO->inTransaction()) { $entryDAO->beginTransaction(); } $entryDAO->addEntry($entry->toArray()); @@ -408,7 +410,7 @@ class FreshRSS_feed_Controller extends Minz_ActionController { if ($feed_history >= 0 && rand(0, 30) === 1) { // TODO: move this function in web cron when available (see entry::purge) // Remove old entries once in 30. - if (!$entryDAO->hasTransaction()) { + if (!$entryDAO->inTransaction()) { $entryDAO->beginTransaction(); } @@ -421,8 +423,8 @@ class FreshRSS_feed_Controller extends Minz_ActionController { } } - $feedDAO->updateLastUpdate($feed->id(), 0, $entryDAO->hasTransaction()); - if ($entryDAO->hasTransaction()) { + $feedDAO->updateLastUpdate($feed->id(), 0, $entryDAO->inTransaction()); + if ($entryDAO->inTransaction()) { $entryDAO->commit(); } diff --git a/app/Models/EntryDAO.php b/app/Models/EntryDAO.php index f74055835..fa5d87b55 100644 --- a/app/Models/EntryDAO.php +++ b/app/Models/EntryDAO.php @@ -11,7 +11,7 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable { } protected function addColumn($name) { - Minz_Log::debug('FreshRSS_EntryDAO::autoAddColumn: ' . $name); + Minz_Log::warning('FreshRSS_EntryDAO::addColumn: ' . $name); $hasTransaction = false; try { $stm = null; @@ -38,7 +38,7 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable { return $stm && $stm->execute(); } } catch (Exception $e) { - Minz_Log::debug('FreshRSS_EntryDAO::autoAddColumn error: ' . $e->getMessage()); + Minz_Log::error('FreshRSS_EntryDAO::addColumn error: ' . $e->getMessage()); if ($hasTransaction) { $this->bd->rollBack(); } @@ -46,9 +46,44 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable { return false; } - protected function autoAddColumn($errorInfo) { + private $triedUpdateToUtf8mb4 = false; + + protected function updateToUtf8mb4() { + if ($this->triedUpdateToUtf8mb4) { + return false; + } + $this->triedUpdateToUtf8mb4 = true; + Minz_Log::warning('Updating MySQL to UTF8MB4...'); + $db = FreshRSS_Context::$system_conf->db; + if ($db['type'] === 'mysql') { + include_once(APP_PATH . '/SQL/install.sql.mysql.php'); + if (defined('SQL_UPDATE_UTF8MB4')) { + $hadTransaction = $this->bd->inTransaction(); + if ($hadTransaction) { + $this->bd->commit(); + } + $ok = false; + try { + $sql = sprintf(SQL_UPDATE_UTF8MB4, $this->prefix, $db['base']); + $stm = $this->bd->prepare($sql); + $ok = $stm->execute(); + } catch (Exception $e) { + Minz_Log::error('FreshRSS_EntryDAO::updateToUtf8mb4 error: ' . $e->getMessage()); + } + if ($hadTransaction) { + $this->bd->beginTransaction(); + //NB: Transaction not starting. Why? (tested on PHP 7.0.8-0ubuntu and MySQL 5.7.13-0ubuntu) + } + return $ok; + } + } + return false; + } + + protected function autoUpdateDb($errorInfo) { if (isset($errorInfo[0])) { - if ($errorInfo[0] == '42S22') { //ER_BAD_FIELD_ERROR + if ($errorInfo[0] === '42S22') { //ER_BAD_FIELD_ERROR + //autoAddColumn foreach (array('lastSeen', 'hash') as $column) { if (stripos($errorInfo[2], $column) !== false) { return $this->addColumn($column); @@ -56,6 +91,11 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable { } } } + if (isset($errorInfo[1])) { + if ($errorInfo[1] == '1366') { //ER_TRUNCATED_WRONG_VALUE_FOR_FIELD + return $this->updateToUtf8mb4(); + } + } return false; } @@ -94,7 +134,7 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable { return $this->bd->lastInsertId(); } else { $info = $this->addEntryPrepared == null ? array(0 => '', 1 => '', 2 => 'syntax error') : $this->addEntryPrepared->errorInfo(); - if ($this->autoAddColumn($info)) { + if ($this->autoUpdateDb($info)) { return $this->addEntry($valuesTmp); } elseif ((int)($info[0] / 1000) !== 23) { //Filter out "SQLSTATE Class code 23: Constraint Violation" because of expected duplicate entries Minz_Log::error('SQL error addEntry: ' . $info[0] . ': ' . $info[1] . ' ' . $info[2] @@ -145,7 +185,7 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable { return $this->bd->lastInsertId(); } else { $info = $this->updateEntryPrepared == null ? array(0 => '', 1 => '', 2 => 'syntax error') : $this->updateEntryPrepared->errorInfo(); - if ($this->autoAddColumn($info)) { + if ($this->autoUpdateDb($info)) { return $this->updateEntry($valuesTmp); } Minz_Log::error('SQL error updateEntry: ' . $info[0] . ': ' . $info[1] . ' ' . $info[2] @@ -615,7 +655,7 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable { return $result; } else { $info = $stm == null ? array(0 => '', 1 => '', 2 => 'syntax error') : $stm->errorInfo(); - if ($this->autoAddColumn($info)) { + if ($this->autoUpdateDb($info)) { return $this->listHashForFeedGuids($id_feed, $guids); } Minz_Log::error('SQL error listHashForFeedGuids: ' . $info[0] . ': ' . $info[1] . ' ' . $info[2] @@ -636,7 +676,7 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable { return $stm->rowCount(); } else { $info = $stm == null ? array(0 => '', 1 => '', 2 => 'syntax error') : $stm->errorInfo(); - if ($this->autoAddColumn($info)) { + if ($this->autoUpdateDb($info)) { return $this->updateLastSeen($id_feed, $guids); } Minz_Log::error('SQL error updateLastSeen: ' . $info[0] . ': ' . $info[1] . ' ' . $info[2] @@ -692,7 +732,9 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable { public function optimizeTable() { $sql = 'OPTIMIZE TABLE `' . $this->prefix . 'entry`'; //MySQL $stm = $this->bd->prepare($sql); - $stm->execute(); + if ($stm) { + return $stm->execute(); + } } public function size($all = false) { diff --git a/app/SQL/install.sql.mysql.php b/app/SQL/install.sql.mysql.php index 0f4e04620..c8755c1ad 100644 --- a/app/SQL/install.sql.mysql.php +++ b/app/SQL/install.sql.mysql.php @@ -2,17 +2,17 @@ define('SQL_CREATE_TABLES', ' CREATE TABLE IF NOT EXISTS `%1$scategory` ( `id` SMALLINT NOT NULL AUTO_INCREMENT, -- v0.7 - `name` varchar(255) NOT NULL, + `name` varchar(191) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY (`name`) -- v0.7 -) DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci +) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci ENGINE = INNODB; CREATE TABLE IF NOT EXISTS `%1$sfeed` ( `id` SMALLINT NOT NULL AUTO_INCREMENT, -- v0.7 `url` varchar(511) CHARACTER SET latin1 NOT NULL, `category` SMALLINT DEFAULT 0, -- v0.7 - `name` varchar(255) NOT NULL, + `name` varchar(191) NOT NULL, `website` varchar(255) CHARACTER SET latin1, `description` text, `lastUpdate` int(11) DEFAULT 0, -- Until year 2038 @@ -30,7 +30,7 @@ CREATE TABLE IF NOT EXISTS `%1$sfeed` ( INDEX (`name`), -- v0.7 INDEX (`priority`), -- v0.7 INDEX (`keep_history`) -- v0.7 -) DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci +) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci ENGINE = INNODB; CREATE TABLE IF NOT EXISTS `%1$sentry` ( @@ -53,7 +53,7 @@ CREATE TABLE IF NOT EXISTS `%1$sentry` ( INDEX (`is_favorite`), -- v0.7 INDEX (`is_read`), -- v0.7 INDEX `entry_lastSeen_index` (`lastSeen`) -- v1.1.1 -) DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci +) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci ENGINE = INNODB; INSERT IGNORE INTO `%1$scategory` (id, name) VALUES(1, "%2$s"); @@ -62,3 +62,24 @@ INSERT IGNORE INTO `%1$sfeed` (url, category, name, website, description, ttl) V '); define('SQL_DROP_TABLES', 'DROP TABLES %1$sentry, %1$sfeed, %1$scategory'); + +define('SQL_UPDATE_UTF8MB4', ' +ALTER DATABASE `%2$s` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; + +ALTER TABLE `%1$scategory` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; +UPDATE `%1$scategory` SET name=SUBSTRING(name,1,190) where LENGTH(name) > 191; +ALTER TABLE `%1$scategory` MODIFY `name` VARCHAR(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL; +OPTIMIZE TABLE `%1$scategory`; + +ALTER TABLE `%1$sfeed` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; +UPDATE `%1$sfeed` SET name=SUBSTRING(name,1,190) where LENGTH(name) > 191; +ALTER TABLE `%1$sfeed` MODIFY `name` VARCHAR(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL; +ALTER TABLE `%1$sfeed` MODIFY `description` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; +OPTIMIZE TABLE `%1$sfeed`; + +ALTER TABLE `%1$sentry` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; +ALTER TABLE `%1$sentry` MODIFY `title` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL; +ALTER TABLE `%1$sentry` MODIFY `author` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; +ALTER TABLE `%1$sentry` MODIFY `tags` VARCHAR(1023) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; +OPTIMIZE TABLE `%1$sentry`; +'); diff --git a/app/install.php b/app/install.php index 062f66814..df6e1aeec 100644 --- a/app/install.php +++ b/app/install.php @@ -19,7 +19,7 @@ if (isset($_GET['step'])) { define('STEP', 0); } -define('SQL_CREATE_DB', 'CREATE DATABASE IF NOT EXISTS %1$s DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci;'); +define('SQL_CREATE_DB', 'CREATE DATABASE IF NOT EXISTS %1$s DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;'); if (STEP === 3 && isset($_POST['type'])) { $_SESSION['bd_type'] = $_POST['type']; @@ -253,7 +253,7 @@ function newPdo() { case 'mysql': $str = 'mysql:host=' . $_SESSION['bd_host'] . ';dbname=' . $_SESSION['bd_base']; $driver_options = array( - PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8', + PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8mb4', ); break; case 'sqlite': @@ -309,7 +309,7 @@ function checkStep0() { } function checkStep1() { - $php = version_compare(PHP_VERSION, '5.3.0') >= 0; + $php = version_compare(PHP_VERSION, '5.3.3') >= 0; $minz = file_exists(join_path(LIB_PATH, 'Minz')); $curl = extension_loaded('curl'); $pdo_mysql = extension_loaded('pdo_mysql'); @@ -437,7 +437,7 @@ function checkBD() { switch ($_SESSION['bd_type']) { case 'mysql': $driver_options = array( - PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8' + PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8mb4' ); try { // on ouvre une connexion juste pour créer la base si elle n'existe pas @@ -536,7 +536,7 @@ function printStep1() {

    -

    +

    diff --git a/app/views/update/checkInstall.phtml b/app/views/update/checkInstall.phtml index ed3858b56..543ab43de 100644 --- a/app/views/update/checkInstall.phtml +++ b/app/views/update/checkInstall.phtml @@ -9,7 +9,7 @@

    prefix = $db['prefix'] . $currentUser . '_'; } elseif ($type === 'sqlite') { $string = 'sqlite:' . join_path(DATA_PATH, 'users', $currentUser, 'db.sqlite'); @@ -96,18 +95,15 @@ class Minz_ModelPdo { public function beginTransaction() { $this->bd->beginTransaction(); - self::$has_transaction = true; } - public function hasTransaction() { - return self::$has_transaction; + public function inTransaction() { + return $this->bd->inTransaction(); //requires PHP >= 5.3.3 } public function commit() { $this->bd->commit(); - self::$has_transaction = false; } public function rollBack() { $this->bd->rollBack(); - self::$has_transaction = false; } public static function clean() { -- cgit v1.2.3 From c1548e732d7472c40473b3d99858059333a05eae Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sun, 31 Jul 2016 14:58:19 +0200 Subject: Remove Mozilla Persona login https://github.com/FreshRSS/FreshRSS/issues/1052 --- README.fr.md | 3 +- README.md | 3 +- app/Controllers/authController.php | 152 +------------------------------- app/Controllers/userController.php | 25 ------ app/FreshRSS.php | 8 -- app/Models/Auth.php | 18 +--- app/Models/ConfigurationSetter.php | 7 +- app/i18n/cz/admin.php | 6 -- app/i18n/cz/conf.php | 1 - app/i18n/cz/feedback.php | 1 - app/i18n/cz/gen.php | 3 - app/i18n/cz/install.php | 6 -- app/i18n/de/admin.php | 6 -- app/i18n/de/conf.php | 1 - app/i18n/de/feedback.php | 1 - app/i18n/de/gen.php | 3 - app/i18n/de/install.php | 6 -- app/i18n/en/admin.php | 6 -- app/i18n/en/conf.php | 1 - app/i18n/en/feedback.php | 1 - app/i18n/en/gen.php | 3 - app/i18n/en/install.php | 6 -- app/i18n/fr/admin.php | 6 -- app/i18n/fr/conf.php | 1 - app/i18n/fr/feedback.php | 1 - app/i18n/fr/gen.php | 3 - app/i18n/fr/install.php | 6 -- app/i18n/it/admin.php | 6 -- app/i18n/it/conf.php | 1 - app/i18n/it/feedback.php | 1 - app/i18n/it/gen.php | 3 - app/i18n/it/install.php | 6 -- app/i18n/nl/admin.php | 6 -- app/i18n/nl/conf.php | 1 - app/i18n/nl/feedback.php | 1 - app/i18n/nl/gen.php | 3 - app/i18n/nl/install.php | 6 -- app/i18n/ru/admin.php | 6 -- app/i18n/ru/conf.php | 1 - app/i18n/ru/feedback.php | 1 - app/i18n/ru/gen.php | 3 - app/i18n/ru/install.php | 6 -- app/i18n/tr/admin.php | 6 -- app/i18n/tr/conf.php | 1 - app/i18n/tr/feedback.php | 1 - app/i18n/tr/gen.php | 3 - app/i18n/tr/install.php | 6 -- app/install.php | 45 +--------- app/views/auth/index.phtml | 3 +- app/views/auth/personaLogin.phtml | 28 ------ app/views/auth/register.phtml | 5 -- app/views/auth/reset.phtml | 33 ------- app/views/helpers/javascript_vars.phtml | 2 - app/views/user/manage.phtml | 8 -- app/views/user/profile.phtml | 9 -- data/config.default.php | 1 - data/users/_/config.default.php | 1 - lib/lib_rss.php | 1 - p/scripts/install.js | 8 +- p/scripts/persona.js | 76 ---------------- 60 files changed, 11 insertions(+), 561 deletions(-) delete mode 100644 app/views/auth/personaLogin.phtml delete mode 100644 app/views/auth/reset.phtml delete mode 100644 p/scripts/persona.js (limited to 'app/Controllers') diff --git a/README.fr.md b/README.fr.md index fd01a507b..067d6d1a1 100644 --- a/README.fr.md +++ b/README.fr.md @@ -89,7 +89,6 @@ sudo chmod -R g+w ./data/ # Contrôle d’accès Il est requis pour le mode multi-utilisateur, et recommandé dans tous les cas, de limiter l’accès à votre FreshRSS. Au choix : * En utilisant l’identification par formulaire (requiert JavaScript, et PHP 5.3.7+ recommandé – fonctionne avec certaines versions de PHP 5.3.3+) -* En utilisant l’identification par [Mozilla Persona](https://login.persona.org/about) incluse dans FreshRSS * En utilisant un contrôle d’accès HTTP défini par votre serveur Web * Voir par exemple la [documentation d’Apache sur l’authentification](http://httpd.apache.org/docs/trunk/howto/auth.html) * Créer dans ce cas un fichier `./p/i/.htaccess` avec un fichier `.htpasswd` correspondant. @@ -111,7 +110,7 @@ Par exemple, pour exécuter le script toutes les heures : * En cas de problème, les logs peuvent être utile à lire, soit depuis l’interface de FreshRSS, soit manuellement depuis `./data/log/*.log`. # Sauvegarde -* Il faut conserver vos fichiers `./data/config.php` ainsi que `./data/*_user.php` et éventuellement `./data/persona/` +* Il faut conserver vos fichiers `./data/config.php` ainsi que `./data/*_user.php` * Vous pouvez exporter votre liste de flux depuis FreshRSS au format OPML * Pour sauvegarder les articles eux-mêmes, vous pouvez utiliser [phpMyAdmin](http://www.phpmyadmin.net) ou les outils de MySQL : diff --git a/README.md b/README.md index a0d22a75c..76975adbd 100644 --- a/README.md +++ b/README.md @@ -89,7 +89,6 @@ sudo chmod -R g+w ./data/ # Access control It is needed for the multi-user mode to limit access to FreshRSS. You can: * use form authentication (need JavaScript and PHP 5.3.7+, works with some PHP 5.3.3+) -* use [Mozilla Persona](https://login.persona.org/about) authentication included in FreshRSS * use HTTP authentication supported by your web server * See [Apache documentation](http://httpd.apache.org/docs/trunk/howto/auth.html) * In that case, create a `./p/i/.htaccess` file with a matching `.htpasswd` file. @@ -111,7 +110,7 @@ For example, if you want to run the script every hour: * If you encounter any problem, logs are accessible from the interface or manually in `./data/log/*.log` files. # Backup -* You need to keep `./data/config.php`, `./data/*_user.php` and `./data/persona/` files +* You need to keep `./data/config.php`, and `./data/*_user.php` files * You can export your feed list in OPML format from FreshRSS * To save articles, you can use [phpMyAdmin](http://www.phpmyadmin.net) or MySQL tools: diff --git a/app/Controllers/authController.php b/app/Controllers/authController.php index f58b008de..9decba431 100644 --- a/app/Controllers/authController.php +++ b/app/Controllers/authController.php @@ -70,7 +70,7 @@ class FreshRSS_auth_Controller extends Minz_ActionController { /** * This action handles the login page. * - * It forwards to the correct login page (form or Persona) or main page if + * It forwards to the correct login page (form) or main page if * the user is already connected. */ public function loginAction() { @@ -83,9 +83,6 @@ class FreshRSS_auth_Controller extends Minz_ActionController { 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! @@ -188,81 +185,6 @@ class FreshRSS_auth_Controller extends Minz_ActionController { } } - /** - * 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); - $conf = get_user_configuration($current_user); - if (!is_null($conf)) { - $login_ok = strcasecmp($email, $conf->mail_login) === 0; - } else { - $reason = 'Invalid configuration for user ' . - '[' . $current_user . ']'; - } - } - } 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::warning($reason); - - $res = array(); - $res['status'] = 'failure'; - $res['reason'] = _t('feedback.auth.login.invalid'); - } - - header('Content-Type: application/json; charset=UTF-8'); - $this->view->res = $res; - } - } - /** * This action removes all accesses of the current user. */ @@ -273,78 +195,6 @@ class FreshRSS_auth_Controller extends Minz_ActionController { array('c' => 'index', 'a' => 'index')); } - /** - * This action resets the authentication system. - * - * After reseting, form auth is set by default. - */ - public function resetAction() { - Minz_View::prependTitle(_t('admin.auth.title_reset') . ' · '); - - Minz_View::appendScript(Minz_Url::display( - '/scripts/bcrypt.min.js?' . @filemtime(PUBLIC_PATH . '/scripts/bcrypt.min.js') - )); - - $this->view->no_form = false; - // Enable changement of auth only if Persona! - if (FreshRSS_Context::$system_conf->auth_type != 'persona') { - $this->view->message = array( - 'status' => 'bad', - 'title' => _t('gen.short.damn'), - 'body' => _t('feedback.auth.not_persona') - ); - $this->view->no_form = true; - return; - } - - $conf = get_user_configuration(FreshRSS_Context::$system_conf->default_user); - if (is_null($conf)) { - return; - } - - // Admin user must have set its master password. - if (!$conf->passwordHash) { - $this->view->message = array( - 'status' => 'bad', - 'title' => _t('gen.short.damn'), - 'body' => _t('feedback.auth.no_password_set') - ); - $this->view->no_form = true; - return; - } - - invalidateHttpCache(); - - if (Minz_Request::isPost()) { - $nonce = Minz_Session::param('nonce'); - $username = Minz_Request::param('username', ''); - $challenge = Minz_Request::param('challenge', ''); - - $ok = FreshRSS_FormAuth::checkCredentials( - $username, $conf->passwordHash, $nonce, $challenge - ); - - if ($ok) { - FreshRSS_Context::$system_conf->auth_type = 'form'; - $ok = FreshRSS_Context::$system_conf->save(); - - if ($ok) { - Minz_Request::good(_t('feedback.auth.form.set')); - } else { - Minz_Request::bad(_t('feedback.auth.form.not_set'), - array('c' => 'auth', 'a' => 'reset')); - } - } else { - Minz_Log::warning('Password mismatch for' . - ' user=' . $username . - ', nonce=' . $nonce . - ', c=' . $challenge); - Minz_Request::bad(_t('feedback.auth.login.invalid'), - array('c' => 'auth', 'a' => 'reset')); - } - } - } - /** * This action gives possibility to a user to create an account. */ diff --git a/app/Controllers/userController.php b/app/Controllers/userController.php index 1c7d621f1..0521bc008 100644 --- a/app/Controllers/userController.php +++ b/app/Controllers/userController.php @@ -64,21 +64,8 @@ class FreshRSS_user_Controller extends Minz_ActionController { FreshRSS_Context::$user_conf->apiPasswordHash = $passwordHash; } - // TODO: why do we need of hasAccess here? - if (FreshRSS_Auth::hasAccess('admin')) { - FreshRSS_Context::$user_conf->mail_login = Minz_Request::param('mail_login', '', true); - } - $email = FreshRSS_Context::$user_conf->mail_login; - Minz_Session::_param('mail', $email); - $ok &= FreshRSS_Context::$user_conf->save(); - if ($email != '') { - $personaFile = DATA_PATH . '/persona/' . $email . '.txt'; - @unlink($personaFile); - $ok &= (file_put_contents($personaFile, Minz_Session::param('currentUser', '_')) !== false); - } - if ($ok) { Minz_Request::good(_t('feedback.profile.updated'), array('c' => 'user', 'a' => 'profile')); @@ -119,7 +106,6 @@ class FreshRSS_user_Controller extends Minz_ActionController { * - new_user_language * - new_user_name * - new_user_passwordPlain - * - new_user_email * - r (i.e. a redirection url, optional) * * @todo clean up this method. Idea: write a method to init a user with basic information. @@ -168,22 +154,12 @@ class FreshRSS_user_Controller extends Minz_ActionController { if (empty($passwordHash)) { $passwordHash = ''; } - - $new_user_email = filter_var($_POST['new_user_email'], FILTER_VALIDATE_EMAIL); - if (empty($new_user_email)) { - $new_user_email = ''; - } else { - $personaFile = join_path(DATA_PATH, 'persona', $new_user_email . '.txt'); - @unlink($personaFile); - $ok &= (file_put_contents($personaFile, $new_user_name) !== false); - } } if ($ok) { mkdir(join_path(DATA_PATH, 'users', $new_user_name)); $config_array = array( 'language' => $new_user_language, 'passwordHash' => $passwordHash, - 'mail_login' => $new_user_email, ); $ok &= (file_put_contents($configPath, "deleteUser($username); $ok &= recursive_unlink($user_data); - //TODO: delete Persona file } if ($ok && $self_deletion) { FreshRSS_Auth::removeAccess(); diff --git a/app/FreshRSS.php b/app/FreshRSS.php index 4933892bc..20640266e 100644 --- a/app/FreshRSS.php +++ b/app/FreshRSS.php @@ -98,14 +98,6 @@ 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 (FreshRSS_Context::$system_conf->auth_type === '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 static function loadNotifications() { diff --git a/app/Models/Auth.php b/app/Models/Auth.php index 4e7a71947..d689f7cdb 100644 --- a/app/Models/Auth.php +++ b/app/Models/Auth.php @@ -60,16 +60,6 @@ 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: @@ -93,9 +83,6 @@ 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'), $user_conf->mail_login) === 0; - break; case 'none': self::$login_ok = true; break; @@ -143,9 +130,6 @@ 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... @@ -170,7 +154,7 @@ class FreshRSS_Auth { public static function accessNeedsAction() { $conf = Minz_Configuration::get('system'); $auth_type = $conf->auth_type; - return $auth_type === 'form' || $auth_type === 'persona'; + return $auth_type === 'form'; } } diff --git a/app/Models/ConfigurationSetter.php b/app/Models/ConfigurationSetter.php index 250c14c39..e472b1e7f 100644 --- a/app/Models/ConfigurationSetter.php +++ b/app/Models/ConfigurationSetter.php @@ -95,11 +95,6 @@ class FreshRSS_ConfigurationSetter { $data['language'] = $value; } - private function _mail_login(&$data, $value) { - $value = filter_var($value, FILTER_VALIDATE_EMAIL); - $data['mail_login'] = $value ? $value : ''; - } - private function _old_entries(&$data, $value) { $value = intval($value); $data['old_entries'] = $value > 0 ? $value : 3; @@ -278,7 +273,7 @@ class FreshRSS_ConfigurationSetter { private function _auth_type(&$data, $value) { $value = strtolower($value); - if (!in_array($value, array('form', 'http_auth', 'persona', 'none'))) { + if (!in_array($value, array('form', 'http_auth', 'none'))) { $value = 'none'; } $data['auth_type'] = $value; diff --git a/app/i18n/cz/admin.php b/app/i18n/cz/admin.php index 342ac7ccd..881c02fc6 100644 --- a/app/i18n/cz/admin.php +++ b/app/i18n/cz/admin.php @@ -8,7 +8,6 @@ return array( 'form' => 'Webový formulář (tradiční, vyžaduje JavaScript)', 'http' => 'HTTP (pro pokročilé uživatele s HTTPS)', 'none' => 'Žádný (nebezpečné)', - 'persona' => 'Mozilla Persona (moderní, vyžaduje JavaScript)', 'title' => 'Přihlášení', 'title_reset' => 'Reset přihlášení', 'token' => 'Authentizační token', @@ -75,10 +74,6 @@ return array( 'nok' => 'Nemáte PDO nebo některý z podporovaných ovladačů (pdo_mysql, pdo_sqlite).', 'ok' => 'Máte PDO a alespoň jeden z podporovaných ovladačů (pdo_mysql, pdo_sqlite).', ), - 'persona' => array( - 'nok' => 'Zkontrolujte oprávnění adresáře ./data/persona. HTTP server musí mít do tohoto adresáře práva zápisu', - 'ok' => 'Oprávnění adresáře Mozilla Persona jsou v pořádku.', - ), 'php' => array( '_' => 'PHP instalace', 'nok' => 'Vaše verze PHP je %s, ale FreshRSS vyžaduje alespoň verzi %s.', @@ -169,7 +164,6 @@ return array( 'user' => array( 'articles_and_size' => '%s článků (%s)', 'create' => 'Vytvořit nového uživatele', - 'email_persona' => 'Email pro přihlášení
    (pro Mozilla Persona)', 'language' => 'Jazyk', 'number' => 'Zatím je vytvořen %d účet', 'numbers' => 'Zatím je vytvořeno %d účtů', diff --git a/app/i18n/cz/conf.php b/app/i18n/cz/conf.php index 823ab1ea3..ec25f988c 100644 --- a/app/i18n/cz/conf.php +++ b/app/i18n/cz/conf.php @@ -76,7 +76,6 @@ return array( '_' => 'Smazání účtu', 'warn' => 'Váš účet bude smazán spolu se všemi souvisejícími daty', ), - 'email_persona' => 'Email pro přihlášení
    (pro Mozilla Persona)', 'password_api' => 'Password API
    (tzn. pro mobilní aplikace)', 'password_form' => 'Heslo
    (pro přihlášení webovým formulářem)', 'password_format' => 'Alespoň 7 znaků', diff --git a/app/i18n/cz/feedback.php b/app/i18n/cz/feedback.php index b75a4a15a..81302afca 100644 --- a/app/i18n/cz/feedback.php +++ b/app/i18n/cz/feedback.php @@ -21,7 +21,6 @@ return array( 'success' => 'Jste odhlášen', ), 'no_password_set' => 'Heslo administrátora nebylo nastaveno. Tato funkce není k dispozici.', - 'not_persona' => 'Resetovat lze pouze systém Persona.', ), 'conf' => array( 'error' => 'Během ukládání nastavení došlo k chybě', diff --git a/app/i18n/cz/gen.php b/app/i18n/cz/gen.php index 5e15ae6f9..e73325c55 100644 --- a/app/i18n/cz/gen.php +++ b/app/i18n/cz/gen.php @@ -24,8 +24,6 @@ return array( 'email' => 'Email', 'keep_logged_in' => 'Zapamatovat přihlášení (1 měsíc)', 'login' => 'Login', - 'login_persona' => 'Přihlášení pomocí Persona', - 'login_persona_problem' => 'Problém s připojením k Persona?', 'logout' => 'Odhlášení', 'password' => array( '_' => 'Heslo', @@ -42,7 +40,6 @@ return array( 'admin' => 'Název administrátorského účtu', 'format' => 'maximálně 16 alfanumerických znaků', ), - 'will_reset' => 'Přihlašovací systém bude vyresetován: místo sytému Persona bude použito přihlášení formulářem.', ), 'date' => array( 'Apr' => '\\D\\u\\b\\e\\n', diff --git a/app/i18n/cz/install.php b/app/i18n/cz/install.php index bc3e01992..6b94c0d4b 100644 --- a/app/i18n/cz/install.php +++ b/app/i18n/cz/install.php @@ -9,13 +9,11 @@ return array( 'reinstall' => 'Reinstalovat FreshRSS', ), 'auth' => array( - 'email_persona' => 'Email pro přihlášení
    (pro Mozilla Persona)', 'form' => 'Webový formulář (tradiční, vyžaduje JavaScript)', 'http' => 'HTTP (pro pokročilé uživatele s HTTPS)', 'none' => 'Žádný (nebezpečné)', 'password_form' => 'Heslo
    (pro přihlášení webovým formulářem)', 'password_format' => 'Alespoň 7 znaků', - 'persona' => 'Mozilla Persona (moderní, vyžaduje JavaScript)', 'type' => 'Způsob přihlášení', ), 'bdd' => array( @@ -78,10 +76,6 @@ return array( 'nok' => 'Nemáte PDO nebo některý z podporovaných ovladačů (pdo_mysql, pdo_sqlite).', 'ok' => 'Máte PDO a alespoň jeden z podporovaných ovladačů (pdo_mysql, pdo_sqlite).', ), - 'persona' => array( - 'nok' => 'Zkontrolujte oprávnění adresáře ./data/persona. HTTP server musí mít do tohoto adresáře práva zápisu', - 'ok' => 'Oprávnění adresáře Mozilla Persona jsou v pořádku.', - ), 'php' => array( 'nok' => 'Vaše verze PHP je %s, ale FreshRSS vyžaduje alespoň verzi %s.', 'ok' => 'Vaše verze PHP je %s a je kompatibilní s FreshRSS.', diff --git a/app/i18n/de/admin.php b/app/i18n/de/admin.php index 6e6cc0956..7b75fe5f4 100644 --- a/app/i18n/de/admin.php +++ b/app/i18n/de/admin.php @@ -8,7 +8,6 @@ return array( 'form' => 'Webformular (traditionell, benötigt JavaScript)', 'http' => 'HTTP (HTTPS für erfahrene Benutzer)', 'none' => 'Keine (gefährlich)', - 'persona' => 'Mozilla Persona (modern, benötigt JavaScript)', 'title' => 'Authentifizierung', 'title_reset' => 'Zurücksetzen der Authentifizierung', 'token' => 'Authentifizierungs-Token', @@ -75,10 +74,6 @@ return array( 'nok' => 'Ihnen fehlt PDO oder einer der unterstützten Treiber (pdo_mysql, pdo_sqlite).', 'ok' => 'Sie haben PDO und mindestens einen der unterstützten Treiber (pdo_mysql, pdo_sqlite).', ), - 'persona' => array( - 'nok' => 'Überprüfen Sie die Berechtigungen des Verzeichnisses ./data/persona. Der HTTP-Server muss Schreibrechte besitzen.', - 'ok' => 'Die Berechtigungen des Verzeichnisses ./data/persona sind in Ordnung.', - ), 'php' => array( '_' => 'PHP-Installation', 'nok' => 'Ihre PHP-Version ist %s aber FreshRSS benötigt mindestens Version %s.', @@ -169,7 +164,6 @@ return array( 'user' => array( 'articles_and_size' => '%s Artikel (%s)', 'create' => 'Neuen Benutzer erstellen', - 'email_persona' => 'Anmelde-E-Mail-Adresse
    (für Mozilla Persona)', 'language' => 'Sprache', 'number' => 'Es wurde bis jetzt %d Account erstellt', 'numbers' => 'Es wurden bis jetzt %d Accounts erstellt', diff --git a/app/i18n/de/conf.php b/app/i18n/de/conf.php index c1a762f12..7c57d5655 100644 --- a/app/i18n/de/conf.php +++ b/app/i18n/de/conf.php @@ -76,7 +76,6 @@ return array( '_' => 'Accountlöschung', 'warn' => 'Dein Account und alle damit bezogenen Daten werden gelöscht.', ), - 'email_persona' => 'Anmelde-E-Mail-Adresse
    (für Mozilla Persona)', 'password_api' => 'Passwort-API
    (z. B. für mobile Anwendungen)', 'password_form' => 'Passwort
    (für die Anmeldemethode per Webformular)', 'password_format' => 'mindestens 7 Zeichen', diff --git a/app/i18n/de/feedback.php b/app/i18n/de/feedback.php index 4c15aadc3..f93992982 100644 --- a/app/i18n/de/feedback.php +++ b/app/i18n/de/feedback.php @@ -21,7 +21,6 @@ return array( 'success' => 'Sie sind abgemeldet', ), 'no_password_set' => 'Administrator-Passwort ist nicht gesetzt worden. Dieses Feature ist nicht verfügbar.', - 'not_persona' => 'Nur das Persona-System kann zurückgesetzt werden.', ), 'conf' => array( 'error' => 'Während der Speicherung der Konfiguration trat ein Fehler auf', diff --git a/app/i18n/de/gen.php b/app/i18n/de/gen.php index 4b85c722a..c6e7f1ef3 100644 --- a/app/i18n/de/gen.php +++ b/app/i18n/de/gen.php @@ -24,8 +24,6 @@ return array( 'email' => 'E-Mail-Adresse', 'keep_logged_in' => 'Eingeloggt bleiben (1 Monat)', 'login' => 'Anmelden', - 'login_persona' => 'Anmelden mit Persona', - 'login_persona_problem' => 'Verbindungsproblem mit Persona?', 'logout' => 'Abmelden', 'password' => array( '_' => 'Passwort', @@ -42,7 +40,6 @@ return array( 'admin' => 'Administrator-Nutzername', 'format' => 'maximal 16 alphanumerische Zeichen', ), - 'will_reset' => 'Authentifikationssystem wird zurückgesetzt: ein Formular wird anstelle von Persona benutzt.', ), 'date' => array( 'Apr' => '\\A\\p\\r\\i\\l', diff --git a/app/i18n/de/install.php b/app/i18n/de/install.php index d16496818..a77822e7b 100644 --- a/app/i18n/de/install.php +++ b/app/i18n/de/install.php @@ -9,13 +9,11 @@ return array( 'reinstall' => 'Neuinstallation von FreshRSS', ), 'auth' => array( - 'email_persona' => 'Anmelde-E-Mail-Adresse
    (für Mozilla Persona)', 'form' => 'Webformular (traditionell, benötigt JavaScript)', 'http' => 'HTTP (HTTPS für erfahrene Benutzer)', 'none' => 'Keine (gefährlich)', 'password_form' => 'Passwort
    (für die Anmeldemethode per Webformular)', 'password_format' => 'mindestens 7 Zeichen', - 'persona' => 'Mozilla Persona (modern, benötigt JavaScript)', 'type' => 'Authentifizierungsmethode', ), 'bdd' => array( @@ -78,10 +76,6 @@ return array( 'nok' => 'Ihnen fehlt PDO oder einer der unterstützten Treiber (pdo_mysql, pdo_sqlite).', 'ok' => 'Sie haben PDO und mindestens einen der unterstützten Treiber (pdo_mysql, pdo_sqlite).', ), - 'persona' => array( - 'nok' => 'Überprüfen Sie die Berechtigungen des Verzeichnisses ./data/persona. Der HTTP-Server muss Schreibrechte besitzen.', - 'ok' => 'Die Berechtigungen des Verzeichnisses ./data/persona sind in Ordnung.', - ), 'php' => array( 'nok' => 'Ihre PHP-Version ist %s aber FreshRSS benötigt mindestens Version %s.', 'ok' => 'Ihre PHP-Version ist %s, welche kompatibel mit FreshRSS ist.', diff --git a/app/i18n/en/admin.php b/app/i18n/en/admin.php index a58771edf..a88552087 100644 --- a/app/i18n/en/admin.php +++ b/app/i18n/en/admin.php @@ -8,7 +8,6 @@ return array( 'form' => 'Web form (traditional, requires JavaScript)', 'http' => 'HTTP (for advanced users with HTTPS)', 'none' => 'None (dangerous)', - 'persona' => 'Mozilla Persona (modern, requires JavaScript)', 'title' => 'Authentication', 'title_reset' => 'Authentication reset', 'token' => 'Authentication token', @@ -75,10 +74,6 @@ return array( 'nok' => 'You lack PDO or one of the supported drivers (pdo_mysql, pdo_sqlite).', 'ok' => 'You have PDO and at least one of the supported drivers (pdo_mysql, pdo_sqlite).', ), - 'persona' => array( - 'nok' => 'Check permissions on ./data/persona directory. HTTP server must have rights to write into', - 'ok' => 'Permissions on Mozilla Persona directory are good.', - ), 'php' => array( '_' => 'PHP installation', 'nok' => 'Your PHP version is %s but FreshRSS requires at least version %s.', @@ -169,7 +164,6 @@ return array( 'user' => array( 'articles_and_size' => '%s articles (%s)', 'create' => 'Create new user', - 'email_persona' => 'Login mail address
    (for Mozilla Persona)', 'language' => 'Language', 'number' => 'There is %d account created yet', 'numbers' => 'There are %d accounts created yet', diff --git a/app/i18n/en/conf.php b/app/i18n/en/conf.php index 38e9197e9..b5ab73510 100644 --- a/app/i18n/en/conf.php +++ b/app/i18n/en/conf.php @@ -76,7 +76,6 @@ return array( '_' => 'Account deletion', 'warn' => 'Your account and all the related data will be deleted.', ), - 'email_persona' => 'Login email address
    (for Mozilla Persona)', 'password_api' => 'API password
    (e.g., for mobile apps)', 'password_form' => 'Password
    (for the Web-form login method)', 'password_format' => 'At least 7 characters', diff --git a/app/i18n/en/feedback.php b/app/i18n/en/feedback.php index c9189c0d0..7ce2ae9cf 100644 --- a/app/i18n/en/feedback.php +++ b/app/i18n/en/feedback.php @@ -21,7 +21,6 @@ return array( 'success' => 'You are disconnected', ), 'no_password_set' => 'Administrator password hasn’t been set. This feature isn’t available.', - 'not_persona' => 'Only Persona system can be reset.', ), 'conf' => array( 'error' => 'An error occurred during configuration saving', diff --git a/app/i18n/en/gen.php b/app/i18n/en/gen.php index ba4e2f86c..17b47ba2f 100644 --- a/app/i18n/en/gen.php +++ b/app/i18n/en/gen.php @@ -24,8 +24,6 @@ return array( 'email' => 'Email address', 'keep_logged_in' => 'Keep me logged in (1 month)', 'login' => 'Login', - 'login_persona' => 'Login with Persona', - 'login_persona_problem' => 'Connection problem with Persona?', 'logout' => 'Logout', 'password' => array( '_' => 'Password', @@ -42,7 +40,6 @@ return array( 'admin' => 'Administrator username', 'format' => 'maximum 16 alphanumeric characters', ), - 'will_reset' => 'Authentication system will be reset: a form will be used instead of Persona.', ), 'date' => array( 'Apr' => '\\A\\p\\r\\i\\l', diff --git a/app/i18n/en/install.php b/app/i18n/en/install.php index 4b5bbc62e..d1c5f37c8 100644 --- a/app/i18n/en/install.php +++ b/app/i18n/en/install.php @@ -9,13 +9,11 @@ return array( 'reinstall' => 'Reinstall FreshRSS', ), 'auth' => array( - 'email_persona' => 'Login email address
    (for Mozilla Persona)', 'form' => 'Web form (traditional, requires JavaScript)', 'http' => 'HTTP (for advanced users with HTTPS)', 'none' => 'None (dangerous)', 'password_form' => 'Password
    (for the Web-form login method)', 'password_format' => 'At least 7 characters', - 'persona' => 'Mozilla Persona (modern, requires JavaScript)', 'type' => 'Authentication method', ), 'bdd' => array( @@ -78,10 +76,6 @@ return array( 'nok' => 'You lack PDO or one of the supported drivers (pdo_mysql, pdo_sqlite).', 'ok' => 'You have PDO and at least one of the supported drivers (pdo_mysql, pdo_sqlite).', ), - 'persona' => array( - 'nok' => 'Check permissions on ./data/persona directory. HTTP server must have rights to write into', - 'ok' => 'Permissions on Mozilla Persona directory are good.', - ), 'php' => array( 'nok' => 'Your PHP version is %s but FreshRSS requires at least version %s.', 'ok' => 'Your PHP version is %s, which is compatible with FreshRSS.', diff --git a/app/i18n/fr/admin.php b/app/i18n/fr/admin.php index f4f267306..c359e9d24 100644 --- a/app/i18n/fr/admin.php +++ b/app/i18n/fr/admin.php @@ -8,7 +8,6 @@ return array( 'form' => 'Formulaire (traditionnel, requiert JavaScript)', 'http' => 'HTTP (pour utilisateurs avancés avec HTTPS)', 'none' => 'Aucune (dangereux)', - 'persona' => 'Mozilla Persona (moderne, requiert JavaScript)', 'title' => 'Authentification', 'title_reset' => 'Réinitialisation de l’authentification', 'token' => 'Jeton d’identification', @@ -75,10 +74,6 @@ return array( 'nok' => 'Vous ne disposez pas de PDO ou d’un des drivers supportés (pdo_mysql, pdo_sqlite).', 'ok' => 'Vous disposez de PDO et d’au moins un des drivers supportés (pdo_mysql, pdo_sqlite).', ), - 'persona' => array( - 'nok' => 'Veuillez vérifier les droits sur le répertoire ./data/persona. Le serveur HTTP doit être capable d’écrire dedans', - 'ok' => 'Les droits sur le répertoire de Mozilla Persona sont bons.', - ), 'php' => array( '_' => 'Installation de PHP', 'nok' => 'Votre version de PHP est la %s mais FreshRSS requiert au moins la version %s.', @@ -169,7 +164,6 @@ return array( 'user' => array( 'articles_and_size' => '%s articles (%s)', 'create' => 'Créer un nouvel utilisateur', - 'email_persona' => 'Adresse courriel de connexion
    (pour Mozilla Persona)', 'language' => 'Langue', 'number' => '%d compte a déjà été créé', 'numbers' => '%d comptes ont déjà été créés', diff --git a/app/i18n/fr/conf.php b/app/i18n/fr/conf.php index 6193b7a01..7a6d12e17 100644 --- a/app/i18n/fr/conf.php +++ b/app/i18n/fr/conf.php @@ -76,7 +76,6 @@ return array( '_' => 'Suppression du compte', 'warn' => 'Le compte et toutes les données associées vont être supprimées.', ), - 'email_persona' => 'Adresse courriel de connexion
    (pour Mozilla Persona)', 'password_api' => 'Mot de passe API
    (ex. : pour applis mobiles)', 'password_form' => 'Mot de passe
    (pour connexion par formulaire)', 'password_format' => '7 caractères minimum', diff --git a/app/i18n/fr/feedback.php b/app/i18n/fr/feedback.php index e2364a251..15f3ab859 100644 --- a/app/i18n/fr/feedback.php +++ b/app/i18n/fr/feedback.php @@ -21,7 +21,6 @@ return array( 'success' => 'Vous avez été déconnecté', ), 'no_password_set' => 'Aucun mot de passe administrateur n’a été précisé. Cette fonctionnalité n’est pas disponible.', - 'not_persona' => 'Seul le système d’authentification Persona peut être réinitialisé.', ), 'conf' => array( 'error' => 'Une erreur est survenue durant la sauvegarde de la configuration', diff --git a/app/i18n/fr/gen.php b/app/i18n/fr/gen.php index 031098aa2..d61a716a7 100644 --- a/app/i18n/fr/gen.php +++ b/app/i18n/fr/gen.php @@ -24,8 +24,6 @@ return array( 'email' => 'Adresse courriel', 'keep_logged_in' => 'Rester connecté (1 mois)', 'login' => 'Connexion', - 'login_persona' => 'Connexion avec Persona', - 'login_persona_problem' => 'Problème de connexion à Persona ?', 'logout' => 'Déconnexion', 'password' => array( '_' => 'Mot de passe', @@ -42,7 +40,6 @@ return array( 'admin' => 'Nom d’utilisateur administrateur', 'format' => '16 caractères alphanumériques maximum', ), - 'will_reset' => 'Le système d’authentification va être réinitialisé : un formulaire sera utilisé à la place de Persona.', ), 'date' => array( 'Apr' => '\\a\\v\\r\\i\\l', diff --git a/app/i18n/fr/install.php b/app/i18n/fr/install.php index 91dfbbb09..946a210ee 100644 --- a/app/i18n/fr/install.php +++ b/app/i18n/fr/install.php @@ -9,13 +9,11 @@ return array( 'reinstall' => 'Réinstaller FreshRSS', ), 'auth' => array( - 'email_persona' => 'Adresse courriel de connexion
    (pour Mozilla Persona)', 'form' => 'Formulaire (traditionnel, requiert JavaScript)', 'http' => 'HTTP (pour utilisateurs avancés avec HTTPS)', 'none' => 'Aucune (dangereux)', 'password_form' => 'Mot de passe
    (pour connexion par formulaire)', 'password_format' => '7 caractères minimum', - 'persona' => 'Mozilla Persona (moderne, requiert JavaScript)', 'type' => 'Méthode d’authentification', ), 'bdd' => array( @@ -78,10 +76,6 @@ return array( 'nok' => 'Vous ne disposez pas de PDO ou d’un des drivers supportés (pdo_mysql, pdo_sqlite).', 'ok' => 'Vous disposez de PDO et d’au moins un des drivers supportés (pdo_mysql, pdo_sqlite).', ), - 'persona' => array( - 'nok' => 'Veuillez vérifier les droits sur le répertoire ./data/persona. Le serveur HTTP doit être capable d’écrire dedans', - 'ok' => 'Les droits sur le répertoire de Mozilla Persona sont bons.', - ), 'php' => array( 'nok' => 'Votre version de PHP est la %s mais FreshRSS requiert au moins la version %s.', 'ok' => 'Votre version de PHP est la %s, qui est compatible avec FreshRSS.', diff --git a/app/i18n/it/admin.php b/app/i18n/it/admin.php index 94b2d6762..4eea158f6 100644 --- a/app/i18n/it/admin.php +++ b/app/i18n/it/admin.php @@ -8,7 +8,6 @@ return array( 'form' => 'Web form (tradizionale, richiede JavaScript)', 'http' => 'HTTP (per gli utenti avanzati con HTTPS)', 'none' => 'Nessuno (pericoloso)', - 'persona' => 'Mozilla Persona (moderno, richiede JavaScript)', 'title' => 'Autenticazione', 'title_reset' => 'Reset autenticazione', 'token' => 'Token di autenticazione', @@ -75,10 +74,6 @@ return array( 'nok' => 'Manca PDO o uno degli altri driver supportati (pdo_mysql, pdo_sqlite).', 'ok' => 'PDO e altri driver supportati (pdo_mysql, pdo_sqlite).', ), - 'persona' => array( - 'nok' => 'Verifica i permessi sulla cartella ./data/persona. Il server HTTP deve avere i permessi per scriverci dentro', - 'ok' => 'I permessi sulla cartella Mozilla Persona sono corretti.', - ), 'php' => array( '_' => 'Installazione PHP', 'nok' => 'Versione PHP %s FreshRSS richiede almeno la versione %s.', @@ -169,7 +164,6 @@ return array( 'user' => array( 'articles_and_size' => '%s articoli (%s)', 'create' => 'Crea nuovo utente', - 'email_persona' => 'Indirizzo mail
    (Login Mozilla Persona)', 'language' => 'Lingua', 'number' => ' %d profilo utente creato', 'numbers' => 'Sono presenti %d profili utente', diff --git a/app/i18n/it/conf.php b/app/i18n/it/conf.php index b757b3210..19b62c9a7 100644 --- a/app/i18n/it/conf.php +++ b/app/i18n/it/conf.php @@ -76,7 +76,6 @@ return array( '_' => 'Cancellazione account', 'warn' => 'Il tuo account e tutti i dati associati saranno cancellati.', ), - 'email_persona' => 'Indirizzo email
    (Login Mozilla Persona)', 'password_api' => 'Password API
    (e.g., per applicazioni mobili)', 'password_form' => 'Password
    (per il login classico)', 'password_format' => 'Almeno 7 caratteri', diff --git a/app/i18n/it/feedback.php b/app/i18n/it/feedback.php index caf1cd2b4..f217586b0 100644 --- a/app/i18n/it/feedback.php +++ b/app/i18n/it/feedback.php @@ -21,7 +21,6 @@ return array( 'success' => 'Disconnessione effettuata', ), 'no_password_set' => 'Password di amministrazione non impostata. Opzione non disponibile.', - 'not_persona' => 'Solo il sistema Mozilla Persona può essere resettato.', ), 'conf' => array( 'error' => 'Si è verificato un errore durante il salvataggio della configurazione', diff --git a/app/i18n/it/gen.php b/app/i18n/it/gen.php index d24377593..c02ddd13a 100644 --- a/app/i18n/it/gen.php +++ b/app/i18n/it/gen.php @@ -24,8 +24,6 @@ return array( 'email' => 'Indirizzo email', 'keep_logged_in' => 'Ricorda i dati (1 mese)', 'login' => 'Accedi', - 'login_persona' => 'Accedi con Mozilla Persona', - 'login_persona_problem' => 'Problemi di connessione con Mozilla Persona?', 'logout' => 'Esci', 'password' => array( '_' => 'Password', @@ -42,7 +40,6 @@ return array( 'admin' => 'Username amministratore', 'format' => 'massimo 16 caratteri alfanumerici', ), - 'will_reset' => 'Il sistema di autenticazione verrà resettato: un form verrà usato per Mozilla Persona.', ), 'date' => array( 'Apr' => '\\A\\p\\r\\i\\l\\e', diff --git a/app/i18n/it/install.php b/app/i18n/it/install.php index 8f5300bd5..a60dd4523 100644 --- a/app/i18n/it/install.php +++ b/app/i18n/it/install.php @@ -9,13 +9,11 @@ return array( 'reinstall' => 'Reinstalla FreshRSS', ), 'auth' => array( - 'email_persona' => 'Indirizzo mail
    (per Mozilla Persona)', 'form' => 'Web form (tradizionale, richiede JavaScript)', 'http' => 'HTTP (per gli utenti avanzati con HTTPS)', 'none' => 'Nessuno (pericoloso)', 'password_form' => 'Password
    (per il login tramite Web-form tradizionale)', 'password_format' => 'Almeno 7 caratteri', - 'persona' => 'Mozilla Persona (moderno, richiede JavaScript)', 'type' => 'Metodo di autenticazione', ), 'bdd' => array( @@ -78,10 +76,6 @@ return array( 'nok' => 'Manca PDO o uno degli altri driver supportati (pdo_mysql, pdo_sqlite).', 'ok' => 'PDO e altri driver supportati (pdo_mysql, pdo_sqlite).', ), - 'persona' => array( - 'nok' => 'Verifica i permessi sulla cartella ./data/persona. Il server HTTP deve avere i permessi per scriverci dentro', - 'ok' => 'I permessi sulla cartella Mozilla Persona sono corretti.', - ), 'php' => array( '_' => 'Installazione PHP', 'nok' => 'Versione di PHP %s FreshRSS richiede almeno la versione %s.', diff --git a/app/i18n/nl/admin.php b/app/i18n/nl/admin.php index bd7d63b6a..9f05d69b1 100644 --- a/app/i18n/nl/admin.php +++ b/app/i18n/nl/admin.php @@ -8,7 +8,6 @@ return array( 'form' => 'Web formulier (traditioneel, benodigd JavaScript)', 'http' => 'HTTP (voor geavanceerde gebruikers met HTTPS)', 'none' => 'Geen (gevaarlijk)', - 'persona' => 'Mozilla Persona (modern, benodigd JavaScript)', 'title' => 'Authenticatie', 'title_reset' => 'Authenticatie terugzetten', 'token' => 'Authenticatie teken', @@ -75,10 +74,6 @@ return array( 'nok' => 'U mist PDO of een van de ondersteunde drivers (pdo_mysql, pdo_sqlite).', 'ok' => 'U hebt PDO en ten minste één van de ondersteunde drivers (pdo_mysql, pdo_sqlite).', ), - 'persona' => array( - 'nok' => 'Controleer de permissies op de ./data/persona map. HTTP server moet rechten hebben om hierin te schrijven', - 'ok' => 'Permissies op de Mozilla Persona map zijn goed.', - ), 'php' => array( '_' => 'PHP installatie', 'nok' => 'Uw PHP versie is %s maar FreshRSS benodigd tenminste versie %s.', @@ -169,7 +164,6 @@ return array( 'user' => array( 'articles_and_size' => '%s artikelen (%s)', 'create' => 'Creëer nieuwe gebruiker', - 'email_persona' => 'Log in mail adres
    (voor Mozilla Persona)', 'language' => 'Taal', 'number' => 'Er is %d accounts gemaakt', 'numbers' => 'Er zijn %d accounts gemaakt', diff --git a/app/i18n/nl/conf.php b/app/i18n/nl/conf.php index 9b0aff793..573dabf45 100644 --- a/app/i18n/nl/conf.php +++ b/app/i18n/nl/conf.php @@ -76,7 +76,6 @@ return array( '_' => 'Account verwijderen', 'warn' => 'Uw account en alle gerelateerde gegvens worden verwijderd.', ), - 'email_persona' => 'Log in mail adres
    (voor Mozilla Persona)', 'password_api' => 'Wachtwoord API
    (e.g., voor mobiele apps)', 'password_form' => 'Wachtwoord
    (voor de Web-formulier log in methode)', 'password_format' => 'Ten minste 7 tekens', diff --git a/app/i18n/nl/feedback.php b/app/i18n/nl/feedback.php index 54d84f7d6..b703c43cf 100644 --- a/app/i18n/nl/feedback.php +++ b/app/i18n/nl/feedback.php @@ -21,7 +21,6 @@ return array( 'success' => 'U bent uitgelogd', ), 'no_password_set' => 'Administrateur wachtwoord is niet ingesteld. Deze mogelijkheid is niet beschikbaar.', - 'not_persona' => 'Alleen Persona systeem kan worden gereset.', ), 'conf' => array( 'error' => 'Er is een fout opgetreden tijdens het opslaan van de configuratie', diff --git a/app/i18n/nl/gen.php b/app/i18n/nl/gen.php index 24cba574e..7e03229c9 100644 --- a/app/i18n/nl/gen.php +++ b/app/i18n/nl/gen.php @@ -24,8 +24,6 @@ return array( 'email' => 'Email adres', 'keep_logged_in' => 'Ingelogd blijven voor (1 maand)', 'login' => 'Log in', - 'login_persona' => 'Login met Persona', - 'login_persona_problem' => 'Connectiviteits problemen met Persona', 'logout' => 'Log uit', 'password' => array( '_' => 'Wachtwoord', @@ -42,7 +40,6 @@ return array( 'admin' => 'Administrator gebruikersnaam', 'format' => 'maximaal 16 alphanumerieke tekens', ), - 'will_reset' => 'Het authenticatie system zal worden gereset: een formulier zal worden gebruikt in plaats van Persona.', ), 'date' => array( 'Apr' => '\\A\\p\\r\\i\\l', diff --git a/app/i18n/nl/install.php b/app/i18n/nl/install.php index d16dda4ca..77783cd48 100644 --- a/app/i18n/nl/install.php +++ b/app/i18n/nl/install.php @@ -9,13 +9,11 @@ return array( 'reinstall' => 'Installeer FreshRSS opnieuw', ), 'auth' => array( - 'email_persona' => 'Log in mail adres
    (voor Mozilla Persona)', 'form' => 'Web formulier (traditioneel, benodigd JavaScript)', 'http' => 'HTTP (voor geavanceerde gebruikers met HTTPS)', 'none' => 'Geen (gevaarlijk)', 'password_form' => 'Wachtwoord
    (voor de Web-formulier log in methode)', 'password_format' => 'Tenminste 7 tekens', - 'persona' => 'Mozilla Persona (modern, benodigd JavaScript)', 'type' => 'Authenticatie methode', ), 'bdd' => array( @@ -78,10 +76,6 @@ return array( 'nok' => 'U mist PDO of één van de ondersteunde (pdo_mysql, pdo_sqlite).', 'ok' => 'U hebt PDO en ten minste één van de ondersteunde drivers (pdo_mysql, pdo_sqlite).', ), - 'persona' => array( - 'nok' => 'Controleer permissies van de ./data/persona map. HTTP server moet rechten hebben om er in te kunnen schrijven', - 'ok' => 'Permissies van de Mozilla Persona map zijn goed.', - ), 'php' => array( 'nok' => 'Uw PHP versie is %s maar FreshRSS benodigd tenminste versie %s.', 'ok' => 'Uw PHP versie is %s, welke compatibel is met FreshRSS.', diff --git a/app/i18n/ru/admin.php b/app/i18n/ru/admin.php index dfea5b3cb..caea627f3 100644 --- a/app/i18n/ru/admin.php +++ b/app/i18n/ru/admin.php @@ -8,7 +8,6 @@ return array( 'form' => 'На основе веб-формы (традиционный, необходим JavaScript)', 'http' => 'HTTP (для продвинутых пользователей - по HTTPS)', 'none' => 'Без аутентификации (небезопасный)', - 'persona' => 'Mozilla Persona (новый, необходим JavaScript)', 'title' => 'Аутентификации', 'title_reset' => 'Сброс аутентицикации', 'token' => 'Токен аутентификации', @@ -75,10 +74,6 @@ return array( 'nok' => 'У вас не установлен PDO или один из необходимых драйверов (pdo_mysql, pdo_sqlite).', 'ok' => 'У вас установлен PDO и как минимум один из поддерживаемых драйверов (pdo_mysql, pdo_sqlite).', ), - 'persona' => array( - 'nok' => 'Проверьте права доступа к папке ./data/persona . Сервер HTTP должен иметь права на запись в эту папку.', - 'ok' => 'Права на папку Mozilla Persona в порядке.', - ), 'php' => array( '_' => 'PHP installation', 'nok' => 'У вас установлен PHP версии %s, но FreshRSS необходима версия не ниже %s.', @@ -169,7 +164,6 @@ return array( 'user' => array( 'articles_and_size' => '%s статей (%s)', 'create' => 'Создать нового пользователя', - 'email_persona' => 'Адрес электронной почты для входа
    (for Mozilla Persona)', 'language' => 'Язык', 'number' => 'На данный момент создан %d аккаунт', 'numbers' => 'На данный момент аккаунтов создано: %d', diff --git a/app/i18n/ru/conf.php b/app/i18n/ru/conf.php index e502e9a43..557fbe369 100644 --- a/app/i18n/ru/conf.php +++ b/app/i18n/ru/conf.php @@ -76,7 +76,6 @@ return array( '_' => 'Account deletion', 'warn' => 'Your account and all the related data will be deleted.', ), - 'email_persona' => 'Login email address
    (for Mozilla Persona)', 'password_api' => 'Password API
    (e.g., for mobile apps)', 'password_form' => 'Password
    (for the Web-form login method)', 'password_format' => 'At least 7 characters', diff --git a/app/i18n/ru/feedback.php b/app/i18n/ru/feedback.php index c9189c0d0..7ce2ae9cf 100644 --- a/app/i18n/ru/feedback.php +++ b/app/i18n/ru/feedback.php @@ -21,7 +21,6 @@ return array( 'success' => 'You are disconnected', ), 'no_password_set' => 'Administrator password hasn’t been set. This feature isn’t available.', - 'not_persona' => 'Only Persona system can be reset.', ), 'conf' => array( 'error' => 'An error occurred during configuration saving', diff --git a/app/i18n/ru/gen.php b/app/i18n/ru/gen.php index b8e8511d9..eecd72749 100644 --- a/app/i18n/ru/gen.php +++ b/app/i18n/ru/gen.php @@ -24,8 +24,6 @@ return array( 'email' => 'Email address', 'keep_logged_in' => 'Keep me logged in (1 month)', 'login' => 'Login', - 'login_persona' => 'Login with Persona', - 'login_persona_problem' => 'Connection problem with Persona?', 'logout' => 'Logout', 'password' => array( '_' => 'Password', @@ -42,7 +40,6 @@ return array( 'admin' => 'Administrator username', 'format' => 'maximum 16 alphanumeric characters', ), - 'will_reset' => 'Authentication system will be reset: a form will be used instead of Persona.', ), 'date' => array( 'Apr' => '\\A\\p\\r\\i\\l', diff --git a/app/i18n/ru/install.php b/app/i18n/ru/install.php index c838b2eba..a52e2959b 100644 --- a/app/i18n/ru/install.php +++ b/app/i18n/ru/install.php @@ -9,13 +9,11 @@ return array( 'reinstall' => 'Переустановить FreshRSS', ), 'auth' => array( - 'email_persona' => 'Почта (логин) для
    (for Mozilla Persona)', 'form' => 'Вэб-форма (традиционный, необходим JavaScript)', 'http' => 'HTTP (для продвинутых пользователей с HTTPS)', 'none' => 'Никакого (опасно)', 'password_form' => 'Пароль
    (для метода аутентификации на Вэб-формах)', 'password_format' => 'Как минимум 7 букв', - 'persona' => 'Mozilla Persona (современный, необходим JavaScript)', 'type' => 'Метод аутентификации', ), 'bdd' => array( @@ -74,10 +72,6 @@ return array( 'nok' => 'У вас не установлен PDO или один из необходимых драйверов (pdo_mysql, pdo_sqlite).', 'ok' => 'У вас установлен PDO и как минимум один из поддерживаемых драйверов (pdo_mysql, pdo_sqlite).', ), - 'persona' => array( - 'nok' => 'Проверьте права доступа к папке ./data/persona . Сервер HTTP должен иметь права на запись в эту папку.', - 'ok' => 'Права на папку Mozilla Persona в порядке.', - ), 'php' => array( 'nok' => 'У вас установлен PHP версии %s, но FreshRSS необходима версия не ниже %s.', 'ok' => 'У вас установлен PHP версии %s, который совместим с FreshRSS.', diff --git a/app/i18n/tr/admin.php b/app/i18n/tr/admin.php index 3a6f8118e..43f8e23c5 100644 --- a/app/i18n/tr/admin.php +++ b/app/i18n/tr/admin.php @@ -8,7 +8,6 @@ return array( 'form' => 'Web formu (geleneksel, JavaScript gerektirir)', 'http' => 'HTTP (ileri kullanıcılar için, HTTPS)', 'none' => 'Hiçbiri (tehlikeli)', - 'persona' => 'Mozilla Persona (modern, JavaScript gerektirir)', 'title' => 'Kimlik doğrulama', 'title_reset' => 'Kimlik doğrulama sıfırla', 'token' => 'Kimlik doğrulama işareti', @@ -75,10 +74,6 @@ return array( 'nok' => 'PDO veya PDO destekli bir sürücü eksik (pdo_mysql, pdo_sqlite).', 'ok' => 'PDO sorunsuz (pdo_mysql, pdo_sqlite).', ), - 'persona' => array( - 'nok' => './data/persona klasör yetkisini kontrol edin. HTTP yazma yetkisi olmalı', - 'ok' => 'Mozilla Persona klasörü yetkileri sorunsuz.', - ), 'php' => array( '_' => 'PHP kurulumu', 'nok' => 'PHP versiyonunuz %s fakat FreshRSS için gerekli olan en düşük sürüm %s.', @@ -169,7 +164,6 @@ return array( 'user' => array( 'articles_and_size' => '%s makale (%s)', 'create' => 'Yeni kullanıcı oluştur', - 'email_persona' => 'Giriş email adresi
    (Mozilla Persona için)', 'language' => 'Dil', 'number' => 'Oluşturulmuş %d hesap var', 'numbers' => 'Oluşturulmuş %d hesap var', diff --git a/app/i18n/tr/conf.php b/app/i18n/tr/conf.php index d9e275b21..2fdc248e4 100644 --- a/app/i18n/tr/conf.php +++ b/app/i18n/tr/conf.php @@ -76,7 +76,6 @@ return array( '_' => 'Hesap silme', 'warn' => 'Hesabınız ve tüm verileriniz silinecek.', ), - 'email_persona' => 'Giriş email adresi
    (Mozilla Persona için)', 'password_api' => 'API Şifresi
    (ör. mobil uygulamalar için)', 'password_form' => 'Şifre
    (Tarayıcı girişi için)', 'password_format' => 'En az 7 karakter', diff --git a/app/i18n/tr/feedback.php b/app/i18n/tr/feedback.php index 0572c6da1..a53316206 100644 --- a/app/i18n/tr/feedback.php +++ b/app/i18n/tr/feedback.php @@ -21,7 +21,6 @@ return array( 'success' => 'Bağlantı koptu', ), 'no_password_set' => 'Yönetici şifresi ayarlanmadı. Bu özellik kullanıma uygun değil.', - 'not_persona' => 'Sadece Persona sistem sıfırlanabilir.', ), 'conf' => array( 'error' => 'Yapılandırma ayarları kaydedilirken hata oluştu', diff --git a/app/i18n/tr/gen.php b/app/i18n/tr/gen.php index 492e2cb9b..865dbd4e2 100644 --- a/app/i18n/tr/gen.php +++ b/app/i18n/tr/gen.php @@ -24,8 +24,6 @@ return array( 'email' => 'Email adresleri', 'keep_logged_in' => '(1 ay) oturumu açık tut', 'login' => 'Giriş', - 'login_persona' => 'Persona ile giriş yap', - 'login_persona_problem' => 'Persona ile bağlantı sorununuz mu var ?', 'logout' => 'Çıkış', 'password' => array( '_' => 'Şifre', @@ -42,7 +40,6 @@ return array( 'admin' => 'Yönetici kullanıcı adı', 'format' => 'en fazla 16 alfanümerik karakter', ), - 'will_reset' => 'Kimlik doğrulama sistemi sıfırlanacak: Persone yerine bir form kullanılacak.', ), 'date' => array( 'Apr' => '\\N\\i\\s\\a\\n', diff --git a/app/i18n/tr/install.php b/app/i18n/tr/install.php index 85134845b..951a7c5fd 100644 --- a/app/i18n/tr/install.php +++ b/app/i18n/tr/install.php @@ -9,13 +9,11 @@ return array( 'reinstall' => 'FreshRSS i yeniden yükle', ), 'auth' => array( - 'email_persona' => 'Giriş email adresi
    (Mozilla Persona için)', 'form' => 'Web formu (geleneksel, JavaScript gerektirir)', 'http' => 'HTTP (ileri kullanıcılar için, HTTPS)', 'none' => 'Hiçbiri (tehlikeli)', 'password_form' => 'Şifre
    (Tarayıcı girişi için)', 'password_format' => 'En az 7 karakter', - 'persona' => 'Mozilla Persona (modern, JavaScript gerektirir)', 'type' => 'Kimlik doğrulama yöntemi', ), 'bdd' => array( @@ -78,10 +76,6 @@ return array( 'nok' => 'PDO veya PDO destekli bir sürücü eksik (pdo_mysql, pdo_sqlite).', 'ok' => 'PDO sorunsuz (pdo_mysql, pdo_sqlite).', ), - 'persona' => array( - 'nok' => './data/persona klasör yetkisini kontrol edin. HTTP yazma yetkisi olmalı', - 'ok' => 'Mozilla Persona klasörü yetkileri sorunsuz.', - ), 'php' => array( 'nok' => 'PHP versiyonunuz %s fakat FreshRSS için gerekli olan en düşük sürüm %s.', 'ok' => 'PHP versiyonunuz %s, FreshRSS ile tam uyumlu.', diff --git a/app/install.php b/app/install.php index 062f66814..e73bc9972 100644 --- a/app/install.php +++ b/app/install.php @@ -103,7 +103,6 @@ function saveStep1() { $_SESSION['title'] = $system_conf->title; $_SESSION['auth_type'] = $system_conf->auth_type; $_SESSION['old_entries'] = $user_conf->old_entries; - $_SESSION['mail_login'] = $user_conf->mail_login; $_SESSION['default_user'] = $current_user; $_SESSION['passwordHash'] = $user_conf->passwordHash; @@ -128,7 +127,6 @@ function saveStep2() { $_SESSION['old_entries'] = param('old_entries', $user_default_config->old_entries); $_SESSION['auth_type'] = param('auth_type', 'form'); $_SESSION['default_user'] = substr(preg_replace('/[^a-zA-Z0-9]/', '', param('default_user', '')), 0, 16); - $_SESSION['mail_login'] = filter_var(param('mail_login', ''), FILTER_VALIDATE_EMAIL); $password_plain = param('passwordPlain', false); if ($password_plain !== false && cryptAvailable()) { @@ -146,8 +144,7 @@ function saveStep2() { return false; } - if (($_SESSION['auth_type'] === 'form' && empty($_SESSION['passwordHash'])) || - ($_SESSION['auth_type'] === 'persona' && empty($_SESSION['mail_login']))) { + if ($_SESSION['auth_type'] === 'form' && empty($_SESSION['passwordHash'])) { return false; } @@ -157,15 +154,11 @@ function saveStep2() { } $token = ''; - if ($_SESSION['mail_login']) { - $token = sha1($_SESSION['salt'] . $_SESSION['mail_login']); - } $config_array = array( 'language' => $_SESSION['language'], 'theme' => $user_default_config->theme, 'old_entries' => $_SESSION['old_entries'], - 'mail_login' => $_SESSION['mail_login'], 'passwordHash' => $_SESSION['passwordHash'], 'token' => $token, ); @@ -179,12 +172,6 @@ function saveStep2() { mkdir($user_dir); file_put_contents($user_config_path, " $cache ? 'ok' : 'ko', 'users' => $users ? 'ok' : 'ko', 'favicons' => $favicons ? 'ok' : 'ko', - 'persona' => $persona ? 'ok' : 'ko', 'http_referer' => $http_referer ? 'ok' : 'ko', 'all' => $php && $minz && $curl && $pdo && $pcre && $ctype && $dom && $xml && - $data && $cache && $users && $favicons && $persona && $http_referer ? + $data && $cache && $users && $favicons && $http_referer ? 'ok' : 'ko' ); } @@ -380,7 +365,6 @@ function freshrss_already_installed() { function checkStep2() { $conf = !empty($_SESSION['old_entries']) && - isset($_SESSION['mail_login']) && !empty($_SESSION['default_user']); $form = ( @@ -388,11 +372,6 @@ function checkStep2() { ($_SESSION['auth_type'] != 'form' || !empty($_SESSION['passwordHash'])) ); - $persona = ( - isset($_SESSION['auth_type']) && - ($_SESSION['auth_type'] != 'persona' || !empty($_SESSION['mail_login'])) - ); - $defaultUser = empty($_POST['default_user']) ? null : $_POST['default_user']; if ($defaultUser === null) { $defaultUser = empty($_SESSION['default_user']) ? '' : $_SESSION['default_user']; @@ -402,9 +381,8 @@ function checkStep2() { return array( 'conf' => $conf ? 'ok' : 'ko', 'form' => $form ? 'ok' : 'ko', - 'persona' => $persona ? 'ok' : 'ko', 'data' => $data ? 'ok' : 'ko', - 'all' => $conf && $form && $persona && $data ? 'ok' : 'ko' + 'all' => $conf && $form && $data ? 'ok' : 'ko' ); } @@ -612,12 +590,6 @@ function printStep1() {

    - -

    - -

    - -

    @@ -673,12 +645,11 @@ function printStep2() { @@ -697,14 +668,6 @@ function printStep2() {
    -
    - -
    - tabindex="6"/> - -
    -
    -
    diff --git a/app/views/auth/index.phtml b/app/views/auth/index.phtml index 8e4df8c2c..8f81ac856 100644 --- a/app/views/auth/index.phtml +++ b/app/views/auth/index.phtml @@ -10,11 +10,10 @@
    diff --git a/app/views/auth/personaLogin.phtml b/app/views/auth/personaLogin.phtml deleted file mode 100644 index c6d738bf6..000000000 --- a/app/views/auth/personaLogin.phtml +++ /dev/null @@ -1,28 +0,0 @@ -res === false) { ?> -
    -

    - - - - - -

    - - -

    - - - - - -

    - -

    -
    -res); -} -?> diff --git a/app/views/auth/register.phtml b/app/views/auth/register.phtml index 306679601..0c261319a 100644 --- a/app/views/auth/register.phtml +++ b/app/views/auth/register.phtml @@ -16,11 +16,6 @@
    -
    - - -
    -
    -

    - - message)) { ?> -

    - message['title']; ?>
    - message['body']; ?> -

    - - - no_form) { ?> - -

    -
    - -

    - -
    - - -
    -
    - - -
    - -
    -
    - -
    - - -
    diff --git a/app/views/helpers/javascript_vars.phtml b/app/views/helpers/javascript_vars.phtml index 6178cacf2..1aa43a207 100644 --- a/app/views/helpers/javascript_vars.phtml +++ b/app/views/helpers/javascript_vars.phtml @@ -1,6 +1,5 @@ mark_when; -$mail = Minz_Session::param('mail', false); $s = FreshRSS_Context::$user_conf->shortcuts; echo htmlspecialchars(json_encode(array( 'context' => array( @@ -16,7 +15,6 @@ echo htmlspecialchars(json_encode(array( 'sticky_post' => !!FreshRSS_Context::isStickyPostEnabled(), 'html5_notif_timeout' => FreshRSS_Context::$user_conf->html5_notif_timeout, 'auth_type' => FreshRSS_Context::$system_conf->auth_type, - 'current_user_mail' => $mail ? ('"' . $mail . '"') : null, 'current_view' => Minz_Request::actionName(), ), 'shortcuts' => array( diff --git a/app/views/user/manage.phtml b/app/views/user/manage.phtml index fe1b6618b..e48841d9b 100644 --- a/app/views/user/manage.phtml +++ b/app/views/user/manage.phtml @@ -37,14 +37,6 @@
    -
    - - mail_login; ?> -
    - -
    -
    -
    diff --git a/app/views/user/profile.phtml b/app/views/user/profile.phtml index 7ae2c7ede..e96b5aa32 100644 --- a/app/views/user/profile.phtml +++ b/app/views/user/profile.phtml @@ -41,15 +41,6 @@
    -
    - - mail_login; ?> -
    - placeholder="alice@example.net" /> - -
    -
    -
    diff --git a/data/config.default.php b/data/config.default.php index cae15330f..be3fa8ae2 100644 --- a/data/config.default.php +++ b/data/config.default.php @@ -40,7 +40,6 @@ return array( # Login method: # `none` is without password and shows only the default user; # `form` is a conventional Web login form; - # `persona` is the email-based login by Mozilla; # `http_auth` is an access controled by the HTTP Web server (e.g. `/FreshRSS/p/i/.htaccess` for Apache) # if you use `http_auth`, remember to protect only `/FreshRSS/p/i/`, # and in particular not protect `/FreshRSS/p/api/` if you would like to use the API (different login system). diff --git a/data/users/_/config.default.php b/data/users/_/config.default.php index 8f8ff528c..4a3403453 100644 --- a/data/users/_/config.default.php +++ b/data/users/_/config.default.php @@ -5,7 +5,6 @@ return array ( 'old_entries' => 3, 'keep_history_default' => 0, 'ttl_default' => 3600, - 'mail_login' => '', 'token' => '', 'passwordHash' => '', 'apiPasswordHash' => '', diff --git a/lib/lib_rss.php b/lib/lib_rss.php index f89baf9b1..8196f7847 100644 --- a/lib/lib_rss.php +++ b/lib/lib_rss.php @@ -440,7 +440,6 @@ function check_install_files() { 'cache' => CACHE_PATH && is_writable(CACHE_PATH), 'users' => USERS_PATH && is_writable(USERS_PATH), 'favicons' => is_writable(DATA_PATH . '/favicons'), - 'persona' => is_writable(DATA_PATH . '/persona'), 'tokens' => is_writable(DATA_PATH . '/tokens'), ); } diff --git a/p/scripts/install.js b/p/scripts/install.js index 9a49e6031..57fc2450a 100644 --- a/p/scripts/install.js +++ b/p/scripts/install.js @@ -24,18 +24,12 @@ function auth_type_change() { var auth_type = document.getElementById('auth_type'); if (auth_type) { var auth_value = auth_type.value, - password_input = document.getElementById('passwordPlain'), - mail_input = document.getElementById('mail_login'); + password_input = document.getElementById('passwordPlain'); if (auth_value === 'form') { password_input.required = true; - mail_input.required = false; - } else if (auth_value === 'persona') { - password_input.required = false; - mail_input.required = true; } else { password_input.required = false; - mail_input.required = false; } } } diff --git a/p/scripts/persona.js b/p/scripts/persona.js deleted file mode 100644 index 63ab43795..000000000 --- a/p/scripts/persona.js +++ /dev/null @@ -1,76 +0,0 @@ -"use strict"; - -function init_persona() { - if (!(navigator.id && window.$ && window.url)) { - 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 a6071a0d9824908ea48099a66435d70d74b9b1b8 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Fri, 12 Aug 2016 22:56:02 +0200 Subject: PHP 5.3 compatibility for callback https://github.com/FreshRSS/FreshRSS/issues/1208 --- app/Controllers/indexController.php | 10 +++++----- app/layout/layout.phtml | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) (limited to 'app/Controllers') diff --git a/app/Controllers/indexController.php b/app/Controllers/indexController.php index 7e626720e..2333ff69d 100755 --- a/app/Controllers/indexController.php +++ b/app/Controllers/indexController.php @@ -32,9 +32,9 @@ class FreshRSS_index_Controller extends Minz_ActionController { Minz_Error::error(404); } - $this->view->callbackBeforeContent = function() { + $this->view->callbackBeforeContent = function($view) { try { - $entries = $this->listEntriesByContext(); + $entries = FreshRSS_index_Controller::listEntriesByContext(); $nb_entries = count($entries); if ($nb_entries > FreshRSS_Context::$number) { @@ -55,7 +55,7 @@ class FreshRSS_index_Controller extends Minz_ActionController { } } - $this->view->entries = $entries; + $view->entries = $entries; } catch (FreshRSS_EntriesGetter_Exception $e) { Minz_Log::notice($e->getMessage()); Minz_Error::error(404); @@ -132,7 +132,7 @@ class FreshRSS_index_Controller extends Minz_ActionController { } try { - $this->view->entries = $this->listEntriesByContext(); + $this->view->entries = FreshRSS_index_Controller::listEntriesByContext(); } catch (FreshRSS_EntriesGetter_Exception $e) { Minz_Log::notice($e->getMessage()); Minz_Error::error(404); @@ -189,7 +189,7 @@ class FreshRSS_index_Controller extends Minz_ActionController { /** * This method returns a list of entries based on the Context object. */ - private function listEntriesByContext() { + private static function listEntriesByContext() { $entryDAO = FreshRSS_Factory::createEntryDao(); $get = FreshRSS_Context::currentGet(true); diff --git a/app/layout/layout.phtml b/app/layout/layout.phtml index 7fdc01241..2aeba40a9 100644 --- a/app/layout/layout.phtml +++ b/app/layout/layout.phtml @@ -23,7 +23,7 @@ callbackBeforeContent)) { - call_user_func($this->callbackBeforeContent); + call_user_func($this->callbackBeforeContent, $this); } ?> -- cgit v1.2.3 From af31f1b20fa7675a208c7a73933231ac2fb8928a Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sat, 13 Aug 2016 10:35:45 +0200 Subject: PHP 5.3 scope compatibility https://github.com/FreshRSS/FreshRSS/issues/1208 --- app/Controllers/indexController.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'app/Controllers') diff --git a/app/Controllers/indexController.php b/app/Controllers/indexController.php index 2333ff69d..5d7925eed 100755 --- a/app/Controllers/indexController.php +++ b/app/Controllers/indexController.php @@ -189,7 +189,7 @@ class FreshRSS_index_Controller extends Minz_ActionController { /** * This method returns a list of entries based on the Context object. */ - private static function listEntriesByContext() { + public static function listEntriesByContext() { $entryDAO = FreshRSS_Factory::createEntryDao(); $get = FreshRSS_Context::currentGet(true); -- cgit v1.2.3 From 02d1d66235d9ca5dd71929c76a1ecec94cf14f3d Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sat, 13 Aug 2016 15:35:52 +0200 Subject: PHP 5.3 more compatibility https://github.com/FreshRSS/FreshRSS/pull/1209#issuecomment-239617504 https://github.com/FreshRSS/FreshRSS/issues/1208 --- app/Controllers/indexController.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'app/Controllers') diff --git a/app/Controllers/indexController.php b/app/Controllers/indexController.php index 5d7925eed..2332d225d 100755 --- a/app/Controllers/indexController.php +++ b/app/Controllers/indexController.php @@ -61,9 +61,9 @@ class FreshRSS_index_Controller extends Minz_ActionController { Minz_Error::error(404); } - $this->view->categories = FreshRSS_Context::$categories; + $view->categories = FreshRSS_Context::$categories; - $this->view->rss_title = FreshRSS_Context::$name . ' | ' . Minz_View::title(); + $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; -- cgit v1.2.3 From 56ffc115d15bf136bfced74707ccc1f41c7b5e44 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sat, 13 Aug 2016 19:10:32 +0200 Subject: Do not mix POST and GET params Avoid returning CSRF POST token for a GET --- app/Controllers/configureController.php | 4 ++-- app/Models/Auth.php | 2 +- app/views/entry/bookmark.phtml | 19 +++++++++---------- app/views/entry/read.phtml | 19 +++++++++---------- app/views/helpers/logs_pagination.phtml | 2 +- app/views/index/global.phtml | 2 +- 6 files changed, 23 insertions(+), 25 deletions(-) (limited to 'app/Controllers') diff --git a/app/Controllers/configureController.php b/app/Controllers/configureController.php index d0f0bd68b..147a2fe06 100755 --- a/app/Controllers/configureController.php +++ b/app/Controllers/configureController.php @@ -139,7 +139,7 @@ class FreshRSS_configure_Controller extends Minz_ActionController { */ public function sharingAction() { if (Minz_Request::isPost()) { - $params = Minz_Request::params(); + $params = Minz_Request::fetchGET(); FreshRSS_Context::$user_conf->sharing = $params['share']; FreshRSS_Context::$user_conf->save(); invalidateHttpCache(); @@ -282,7 +282,7 @@ class FreshRSS_configure_Controller extends Minz_ActionController { foreach (FreshRSS_Context::$user_conf->queries as $key => $query) { $queries[$key] = new FreshRSS_UserQuery($query, $feed_dao, $category_dao); } - $params = Minz_Request::params(); + $params = Minz_Request::fetchGET(); $params['url'] = Minz_Url::display(array('params' => $params)); $params['name'] = _t('conf.query.number', count($queries) + 1); $queries[] = new FreshRSS_UserQuery($params, $feed_dao, $category_dao); diff --git a/app/Models/Auth.php b/app/Models/Auth.php index f0e8db5a2..b93942e19 100644 --- a/app/Models/Auth.php +++ b/app/Models/Auth.php @@ -173,7 +173,7 @@ class FreshRSS_Auth { return true; //Not logged in yet } if ($token === null) { - $token = Minz_Request::param('_csrf'); + $token = Minz_Request::fetchPOST('_csrf'); } return $token === $csrf; } diff --git a/app/views/entry/bookmark.phtml b/app/views/entry/bookmark.phtml index 6b5a4ed03..d85706669 100755 --- a/app/views/entry/bookmark.phtml +++ b/app/views/entry/bookmark.phtml @@ -1,17 +1,16 @@ Minz_Request::controllerName(), 'a' => Minz_Request::actionName(), - 'params' => Minz_Request::params(), -)); + 'params' => Minz_Request::fetchGET(), +); + +$url['params']['is_favorite'] = Minz_Request::param('is_favorite', true) ? '0' : '1'; FreshRSS::loadStylesAndScripts(); -echo json_encode(array('url' => str_ireplace('&', '&', $url), 'icon' => _i(Minz_Request::param('is_favorite') ? 'non-starred' : 'starred'))); +echo json_encode(array( + 'url' => str_ireplace('&', '&', Minz_Url::display($url)), + 'icon' => _i($url['params']['is_favorite'] === '1' ? 'non-starred' : 'starred') + )); diff --git a/app/views/entry/read.phtml b/app/views/entry/read.phtml index 7d0e3de82..73977d94b 100755 --- a/app/views/entry/read.phtml +++ b/app/views/entry/read.phtml @@ -1,17 +1,16 @@ Minz_Request::controllerName(), 'a' => Minz_Request::actionName(), - 'params' => Minz_Request::params(), -)); + 'params' => Minz_Request::fetchGET(), +); + +$url['params']['is_read'] = Minz_Request::param('is_read', true) ? '0' : '1'; FreshRSS::loadStylesAndScripts(); -echo json_encode(array('url' => str_ireplace('&', '&', $url), 'icon' => _i(Minz_Request::param('is_read') ? 'unread' : 'read'))); +echo json_encode(array( + 'url' => str_ireplace('&', '&', Minz_Url::display($url)), + 'icon' => _i($url['params']['is_read'] === '1' ? 'unread' : 'read') + )); diff --git a/app/views/helpers/logs_pagination.phtml b/app/views/helpers/logs_pagination.phtml index 58b3c68f4..bf9d91f04 100755 --- a/app/views/helpers/logs_pagination.phtml +++ b/app/views/helpers/logs_pagination.phtml @@ -1,7 +1,7 @@ nbPage > 1) { ?> diff --git a/app/views/index/global.phtml b/app/views/index/global.phtml index 0ffa3bc54..1e53e4f8c 100644 --- a/app/views/index/global.phtml +++ b/app/views/index/global.phtml @@ -14,7 +14,7 @@ $url_base = array( 'c' => 'index', 'a' => 'normal', - 'params' => Minz_Request::params() + 'params' => Minz_Request::fetchGET(), ); foreach ($this->categories as $cat) { -- cgit v1.2.3 From 32c734ef622f4ed83d212d3eb1d15d83d406bd86 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Thu, 18 Aug 2016 00:00:08 +0200 Subject: SQL mark search as read https://github.com/FreshRSS/FreshRSS/issues/608 --- app/Controllers/entryController.php | 19 ++++- app/Models/EntryDAO.php | 150 ++++++++++++++++++++---------------- app/layout/nav_menu.phtml | 2 + app/views/helpers/pagination.phtml | 2 + 4 files changed, 102 insertions(+), 71 deletions(-) (limited to 'app/Controllers') diff --git a/app/Controllers/entryController.php b/app/Controllers/entryController.php index bff1073ef..c40588105 100755 --- a/app/Controllers/entryController.php +++ b/app/Controllers/entryController.php @@ -40,6 +40,17 @@ 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); + FreshRSS_Context::$search = new FreshRSS_Search(Minz_Request::param('search', '')); + + FreshRSS_Context::$state = Minz_Request::param('state', 0); + if (FreshRSS_Context::isStateEnabled(FreshRSS_Entry::STATE_FAVORITE)) { + FreshRSS_Context::$state = FreshRSS_Entry::STATE_FAVORITE; + } elseif (FreshRSS_Context::isStateEnabled(FreshRSS_Entry::STATE_NOT_FAVORITE)) { + FreshRSS_Context::$state = FreshRSS_Entry::STATE_NOT_FAVORITE; + } else { + FreshRSS_Context::$state = 0; + } + $params = array(); $entryDAO = FreshRSS_Factory::createEntryDao(); @@ -58,16 +69,16 @@ class FreshRSS_entry_Controller extends Minz_ActionController { $get = substr($get, 2); switch($type_get) { case 'c': - $entryDAO->markReadCat($get, $id_max); + $entryDAO->markReadCat($get, $id_max, FreshRSS_Context::$search, FreshRSS_Context::$state); break; case 'f': - $entryDAO->markReadFeed($get, $id_max); + $entryDAO->markReadFeed($get, $id_max, FreshRSS_Context::$search, FreshRSS_Context::$state); break; case 's': - $entryDAO->markReadEntries($id_max, true); + $entryDAO->markReadEntries($id_max, true, 0, FreshRSS_Context::$search); break; case 'a': - $entryDAO->markReadEntries($id_max); + $entryDAO->markReadEntries($id_max, false, 0, FreshRSS_Context::$search, FreshRSS_Context::$state); break; } diff --git a/app/Models/EntryDAO.php b/app/Models/EntryDAO.php index c9e6f9742..3bb8a720c 100644 --- a/app/Models/EntryDAO.php +++ b/app/Models/EntryDAO.php @@ -344,7 +344,7 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable { * @param integer $priorityMin * @return integer affected rows */ - public function markReadEntries($idMax = 0, $onlyFavorites = false, $priorityMin = 0) { + public function markReadEntries($idMax = 0, $onlyFavorites = false, $priorityMin = 0, $filter = null, $state = 0) { if ($idMax == 0) { $idMax = time() . '000000'; Minz_Log::debug('Calling markReadEntries(0) is deprecated!'); @@ -359,8 +359,11 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable { $sql .= ' AND f.priority > ' . intval($priorityMin); } $values = array($idMax); - $stm = $this->bd->prepare($sql); - if (!($stm && $stm->execute($values))) { + + list($searchValues, $search) = $this->sqlListEntriesWhere($filter, $state); + + $stm = $this->bd->prepare($sql . $search); + if (!($stm && $stm->execute(array_merge($values, $searchValues)))) { $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo(); Minz_Log::error('SQL error markReadEntries: ' . $info[2]); return false; @@ -383,7 +386,7 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable { * @param integer $idMax fail safe article ID * @return integer affected rows */ - public function markReadCat($id, $idMax = 0) { + public function markReadCat($id, $idMax = 0, $filter = null, $state = 0) { if ($idMax == 0) { $idMax = time() . '000000'; Minz_Log::debug('Calling markReadCat(0) is deprecated!'); @@ -393,8 +396,11 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable { . 'SET e.is_read=1 ' . 'WHERE f.category=? AND e.is_read=0 AND e.id <= ?'; $values = array($id, $idMax); - $stm = $this->bd->prepare($sql); - if (!($stm && $stm->execute($values))) { + + list($searchValues, $search) = $this->sqlListEntriesWhere($filter, $state); + + $stm = $this->bd->prepare($sql . $search); + if (!($stm && $stm->execute(array_merge($values, $searchValues)))) { $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo(); Minz_Log::error('SQL error markReadCat: ' . $info[2]); return false; @@ -417,19 +423,22 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable { * @param integer $idMax fail safe article ID * @return integer affected rows */ - public function markReadFeed($id_feed, $idMax = 0) { + public function markReadFeed($id_feed, $idMax = 0, $filter = null, $state = 0) { if ($idMax == 0) { $idMax = time() . '000000'; Minz_Log::debug('Calling markReadFeed(0) is deprecated!'); } $this->bd->beginTransaction(); - $sql = 'UPDATE `' . $this->prefix . 'entry` ' - . 'SET is_read=1 ' - . 'WHERE id_feed=? AND is_read=0 AND id <= ?'; + $sql = 'UPDATE `' . $this->prefix . 'entry` e ' + . 'SET e.is_read=1 ' + . 'WHERE e.id_feed=? AND e.is_read=0 AND e.id <= ?'; $values = array($id_feed, $idMax); - $stm = $this->bd->prepare($sql); - if (!($stm && $stm->execute($values))) { + + list($searchValues, $search) = $this->sqlListEntriesWhere($filter, $state); + + $stm = $this->bd->prepare($sql . $search); + if (!($stm && $stm->execute(array_merge($values, $searchValues)))) { $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo(); Minz_Log::error('SQL error markReadFeed: ' . $info[2]); $this->bd->rollBack(); @@ -493,52 +502,24 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable { 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) { - if (!$state) { - $state = FreshRSS_Entry::STATE_ALL; - } - $where = ''; - $joinFeed = false; + private function sqlListEntriesWhere($filter = null, $state = FreshRSS_Entry::STATE_ALL, $order = 'DESC', $firstId = '', $date_min = 0) { + $search = ' '; $values = array(); - switch ($type) { - case 'a': - $where .= 'f.priority > 0 '; - $joinFeed = true; - break; - case 's': //Deprecated: use $state instead - $where .= 'e1.is_favorite=1 '; - break; - case 'c': - $where .= 'f.category=? '; - $values[] = intval($id); - $joinFeed = true; - break; - case 'f': - $where .= 'e1.id_feed=? '; - $values[] = intval($id); - break; - case 'A': - $where .= '1 '; - break; - default: - throw new FreshRSS_EntriesGetter_Exception('Bad type in Entry->listByType: [' . $type . ']!'); - } - if ($state & FreshRSS_Entry::STATE_NOT_READ) { if (!($state & FreshRSS_Entry::STATE_READ)) { - $where .= 'AND e1.is_read=0 '; + $search .= 'AND e.is_read=0 '; } } elseif ($state & FreshRSS_Entry::STATE_READ) { - $where .= 'AND e1.is_read=1 '; + $search .= 'AND e.is_read=1 '; } if ($state & FreshRSS_Entry::STATE_FAVORITE) { if (!($state & FreshRSS_Entry::STATE_NOT_FAVORITE)) { - $where .= 'AND e1.is_favorite=1 '; + $search .= 'AND e.is_favorite=1 '; } } elseif ($state & FreshRSS_Entry::STATE_NOT_FAVORITE) { - $where .= 'AND e1.is_favorite=0 '; + $search .= 'AND e.is_favorite=0 '; } switch ($order) { @@ -552,76 +533,111 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable { $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 . ' '; + $search .= 'AND e.id ' . ($order === 'DESC' ? '<=' : '>=') . $firstId . ' '; } if ($date_min > 0) { - $where .= 'AND e1.id >= ' . $date_min . '000000 '; + $search .= 'AND e.id >= ' . $date_min . '000000 '; } - $search = ''; if ($filter) { if ($filter->getIntitle()) { - $search .= 'AND e1.title LIKE ? '; + $search .= 'AND e.title LIKE ? '; $values[] = "%{$filter->getIntitle()}%"; } if ($filter->getInurl()) { - $search .= 'AND CONCAT(e1.link, e1.guid) LIKE ? '; + $search .= 'AND CONCAT(e.link, e.guid) LIKE ? '; $values[] = "%{$filter->getInurl()}%"; } if ($filter->getAuthor()) { - $search .= 'AND e1.author LIKE ? '; + $search .= 'AND e.author LIKE ? '; $values[] = "%{$filter->getAuthor()}%"; } if ($filter->getMinDate()) { - $search .= 'AND e1.id >= ? '; + $search .= 'AND e.id >= ? '; $values[] = "{$filter->getMinDate()}000000"; } if ($filter->getMaxDate()) { - $search .= 'AND e1.id <= ? '; + $search .= 'AND e.id <= ? '; $values[] = "{$filter->getMaxDate()}000000"; } if ($filter->getMinPubdate()) { - $search .= 'AND e1.date >= ? '; + $search .= 'AND e.date >= ? '; $values[] = $filter->getMinPubdate(); } if ($filter->getMaxPubdate()) { - $search .= 'AND e1.date <= ? '; + $search .= 'AND e.date <= ? '; $values[] = $filter->getMaxPubdate(); } if ($filter->getTags()) { $tags = $filter->getTags(); foreach ($tags as $tag) { - $search .= 'AND e1.tags LIKE ? '; + $search .= 'AND e.tags LIKE ? '; $values[] = "%{$tag}%"; } } if ($filter->getSearch()) { $search_values = $filter->getSearch(); foreach ($search_values as $search_value) { - $search .= 'AND ' . $this->sqlconcat('e1.title', $this->isCompressed() ? 'UNCOMPRESS(content_bin)' : 'content') . ' LIKE ? '; + $search .= 'AND ' . $this->sqlconcat('e.title', $this->isCompressed() ? 'UNCOMPRESS(content_bin)' : 'content') . ' LIKE ? '; $values[] = "%{$search_value}%"; } } } - return array($values, - 'SELECT e1.id FROM `' . $this->prefix . 'entry` e1 ' - . ($joinFeed ? 'INNER JOIN `' . $this->prefix . 'feed` f ON e1.id_feed=f.id ' : '') + return array($values, $search); + } + + 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; + } + $where = ''; + $joinFeed = false; + $values = array(); + switch ($type) { + case 'a': + $where .= 'f.priority > 0 '; + $joinFeed = true; + break; + case 's': //Deprecated: use $state instead + $where .= 'e.is_favorite=1 '; + break; + case 'c': + $where .= 'f.category=? '; + $values[] = intval($id); + $joinFeed = true; + break; + case 'f': + $where .= 'e.id_feed=? '; + $values[] = intval($id); + break; + case 'A': + $where .= '1 '; + break; + default: + throw new FreshRSS_EntriesGetter_Exception('Bad type in Entry->listByType: [' . $type . ']!'); + } + + list($searchValues, $search) = $this->sqlListEntriesWhere($filter, $state, $order, $firstId, $date_min); + + return array(array_merge($values, $searchValues), + 'SELECT e.id FROM `' . $this->prefix . 'entry` e ' + . ($joinFeed ? 'INNER JOIN `' . $this->prefix . 'feed` f ON e.id_feed=f.id ' : '') . 'WHERE ' . $where . $search - . 'ORDER BY e1.id ' . $order + . 'ORDER BY e.id ' . $order . ($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) { list($values, $sql) = $this->sqlListWhere($type, $id, $state, $order, $limit, $firstId, $filter, $date_min); - $sql = 'SELECT e.id, e.guid, e.title, e.author, ' + $sql = 'SELECT e0.id, e0.guid, e0.title, e0.author, ' . ($this->isCompressed() ? 'UNCOMPRESS(content_bin) AS content' : 'content') - . ', e.link, e.date, e.is_read, e.is_favorite, e.id_feed, e.tags ' - . 'FROM `' . $this->prefix . 'entry` e ' + . ', e0.link, e0.date, e0.is_read, e0.is_favorite, e0.id_feed, e0.tags ' + . 'FROM `' . $this->prefix . 'entry` e0 ' . 'INNER JOIN (' . $sql - . ') e2 ON e2.id=e.id ' - . 'ORDER BY e.id ' . $order; + . ') e2 ON e2.id=e0.id ' + . 'ORDER BY e0.id ' . $order; $stm = $this->bd->prepare($sql); $stm->execute($values); diff --git a/app/layout/nav_menu.phtml b/app/layout/nav_menu.phtml index 488c6fdef..23255f04f 100644 --- a/app/layout/nav_menu.phtml +++ b/app/layout/nav_menu.phtml @@ -75,6 +75,8 @@ 'get' => $get, 'nextGet' => FreshRSS_Context::$next_get, 'idMax' => FreshRSS_Context::$id_max, + 'search' => FreshRSS_Context::$search, + 'state' => FreshRSS_Context::$state, ) ); ?> diff --git a/app/views/helpers/pagination.phtml b/app/views/helpers/pagination.phtml index 23c45114d..20957fc67 100755 --- a/app/views/helpers/pagination.phtml +++ b/app/views/helpers/pagination.phtml @@ -10,6 +10,8 @@ 'get' => FreshRSS_Context::currentGet(), 'nextGet' => FreshRSS_Context::$next_get, 'idMax' => FreshRSS_Context::$id_max, + 'search' => FreshRSS_Context::$search, + 'state' => FreshRSS_Context::$state, ) ); ?> -- cgit v1.2.3 From ccb56bcbf3ef69228ae4147a76cf3059f519bbf3 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sun, 11 Sep 2016 11:24:32 +0200 Subject: Simplify SQL in statistics Reduce the use of product-specific date functions. Improve performances. Remove redundant functions. --- app/Controllers/statsController.php | 36 +++++++++++++++++----- app/Models/StatsDAO.php | 61 ++++++------------------------------- app/Models/StatsDAOSQLite.php | 55 --------------------------------- 3 files changed, 39 insertions(+), 113 deletions(-) (limited to 'app/Controllers') diff --git a/app/Controllers/statsController.php b/app/Controllers/statsController.php index 4a597ae7d..5d1dee72c 100644 --- a/app/Controllers/statsController.php +++ b/app/Controllers/statsController.php @@ -18,6 +18,27 @@ class FreshRSS_stats_Controller extends Minz_ActionController { Minz_View::prependTitle(_t('admin.stats.title') . ' · '); } + private function convertToSerie($data) { + $serie = array(); + + foreach ($data as $key => $value) { + $serie[] = array($key, $value); + } + + return $serie; + } + + private function convertToPieSerie($data) { + $serie = array(); + + foreach ($data as $value) { + $value['data'] = array(array(0, (int) $value['data'])); + $serie[] = $value; + } + + return $serie; + } + /** * This action handles the statistic main page. * @@ -33,10 +54,11 @@ class FreshRSS_stats_Controller extends Minz_ActionController { $statsDAO = FreshRSS_Factory::createStatsDAO(); Minz_View::appendScript(Minz_Url::display('/scripts/flotr2.min.js?' . @filemtime(PUBLIC_PATH . '/scripts/flotr2.min.js'))); $this->view->repartition = $statsDAO->calculateEntryRepartition(); - $this->view->count = $statsDAO->calculateEntryCount(); - $this->view->average = $statsDAO->calculateEntryAverage(); - $this->view->feedByCategory = $statsDAO->calculateFeedByCategory(); - $this->view->entryByCategory = $statsDAO->calculateEntryByCategory(); + $entryCount = $statsDAO->calculateEntryCount(); + $this->view->count = $this->convertToSerie($entryCount); + $this->view->average = round(array_sum(array_values($entryCount)) / count($entryCount), 2); + $this->view->feedByCategory = $this->convertToPieSerie($statsDAO->calculateFeedByCategory()); + $this->view->entryByCategory = $this->convertToPieSerie($statsDAO->calculateEntryByCategory()); $this->view->topFeed = $statsDAO->calculateTopFeed(); } @@ -118,11 +140,11 @@ class FreshRSS_stats_Controller extends Minz_ActionController { $this->view->days = $statsDAO->getDays(); $this->view->months = $statsDAO->getMonths(); $this->view->repartition = $statsDAO->calculateEntryRepartitionPerFeed($id); - $this->view->repartitionHour = $statsDAO->calculateEntryRepartitionPerFeedPerHour($id); + $this->view->repartitionHour = $this->convertToSerie($statsDAO->calculateEntryRepartitionPerFeedPerHour($id)); $this->view->averageHour = $statsDAO->calculateEntryAveragePerFeedPerHour($id); - $this->view->repartitionDayOfWeek = $statsDAO->calculateEntryRepartitionPerFeedPerDayOfWeek($id); + $this->view->repartitionDayOfWeek = $this->convertToSerie($statsDAO->calculateEntryRepartitionPerFeedPerDayOfWeek($id)); $this->view->averageDayOfWeek = $statsDAO->calculateEntryAveragePerFeedPerDayOfWeek($id); - $this->view->repartitionMonth = $statsDAO->calculateEntryRepartitionPerFeedPerMonth($id); + $this->view->repartitionMonth = $this->convertToSerie($statsDAO->calculateEntryRepartitionPerFeedPerMonth($id)); $this->view->averageMonth = $statsDAO->calculateEntryAveragePerFeedPerMonth($id); } } diff --git a/app/Models/StatsDAO.php b/app/Models/StatsDAO.php index 4f83ff577..28882baab 100644 --- a/app/Models/StatsDAO.php +++ b/app/Models/StatsDAO.php @@ -61,14 +61,15 @@ SQL; */ public function calculateEntryCount() { $count = $this->initEntryCountArray(); - $period = self::ENTRY_COUNT_PERIOD; + $midnight = mktime(0, 0, 0); + $oldest = $midnight - (self::ENTRY_COUNT_PERIOD * 86400); // 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') +SELECT FLOOR((date - {$midnight}) / 86400) AS day, +COUNT(*) as count +FROM {$this->prefix}entry +WHERE date >= {$oldest} AND date < {$midnight} GROUP BY day ORDER BY day ASC SQL; @@ -80,28 +81,7 @@ SQL; $count[$value['day']] = (int) $value['count']; } - 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); + return $count; } /** @@ -173,7 +153,7 @@ SQL; $repartition[(int) $value['period']] = (int) $value['count']; } - return $this->convertToSerie($repartition); + return $repartition; } /** @@ -276,7 +256,7 @@ SQL; $stm->execute(); $res = $stm->fetchAll(PDO::FETCH_ASSOC); - return $this->convertToPieSerie($res); + return $res; } /** @@ -301,7 +281,7 @@ SQL; $stm->execute(); $res = $stm->fetchAll(PDO::FETCH_ASSOC); - return $this->convertToPieSerie($res); + return $res; } /** @@ -351,27 +331,6 @@ SQL; return $stm->fetchAll(PDO::FETCH_ASSOC); } - protected function convertToSerie($data) { - $serie = array(); - - foreach ($data as $key => $value) { - $serie[] = array($key, $value); - } - - return $serie; - } - - protected function convertToPieSerie($data) { - $serie = array(); - - foreach ($data as $value) { - $value['data'] = array(array(0, (int) $value['data'])); - $serie[] = $value; - } - - return $serie; - } - /** * Gets days ready for graphs * diff --git a/app/Models/StatsDAOSQLite.php b/app/Models/StatsDAOSQLite.php index 9bfe8b20a..e09d18c77 100644 --- a/app/Models/StatsDAOSQLite.php +++ b/app/Models/StatsDAOSQLite.php @@ -2,61 +2,6 @@ class FreshRSS_StatsDAOSQLite extends FreshRSS_StatsDAO { - /** - * Calculates entry count per day on a 30 days period. - * Returns the result as a JSON object. - * - * @return JSON object - */ - public function calculateEntryCount() { - $count = $this->initEntryCountArray(); - $period = parent::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') -GROUP BY day -ORDER BY day ASC -SQL; - $stm = $this->bd->prepare($sql); - $stm->execute(); - $res = $stm->fetchAll(PDO::FETCH_ASSOC); - - foreach ($res as $value) { - $count[(int) $value['day']] = (int) $value['count']; - } - - 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 2a5aa34ad2796df00fa09de41361c20764ccdfa8 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sun, 11 Sep 2016 15:06:33 +0200 Subject: Better control of number of entries per page or RSS feed https://github.com/FreshRSS/FreshRSS/issues/1249 * Since X hours: `https://freshrss.example/i/?a=rss&hours=3` * Explicit number: `https://freshrss.example/i/?a=rss&nb=10` * Limited by `min_posts_per_rss` and `max_posts_per_rss` in user config --- CHANGELOG.md | 4 ++++ app/Controllers/indexController.php | 39 +++++++++++++++++++++++++++++++------ app/Models/Context.php | 1 + app/layout/layout.phtml | 3 +++ app/layout/nav_menu.phtml | 3 +++ app/views/auth/index.phtml | 2 +- data/users/_/config.default.php | 3 +++ 7 files changed, 48 insertions(+), 7 deletions(-) (limited to 'app/Controllers') diff --git a/CHANGELOG.md b/CHANGELOG.md index b3c46bdb6..f82f68fff 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,10 @@ ## 2016-XX-XX FreshRSS 1.6.0-dev * Features + * Better control of number of entries per page or RSS feed [#1249](https://github.com/FreshRSS/FreshRSS/issues/1249) + * Since X hours: `https://freshrss.example/i/?a=rss&hours=3` + * Explicit number: `https://freshrss.example/i/?a=rss&nb=10` + * Limited by `min_posts_per_rss` and `max_posts_per_rss` in user config * Support custom ports `localhost:3306` for database servers [#1241](https://github.com/FreshRSS/FreshRSS/issues/1241) * Security * Prevent `` attacks with `window.opener` [#1245](https://github.com/FreshRSS/FreshRSS/issues/1245) diff --git a/app/Controllers/indexController.php b/app/Controllers/indexController.php index 2332d225d..4e2717920 100755 --- a/app/Controllers/indexController.php +++ b/app/Controllers/indexController.php @@ -34,7 +34,9 @@ class FreshRSS_index_Controller extends Minz_ActionController { $this->view->callbackBeforeContent = function($view) { try { + FreshRSS_Context::$number++; //+1 for pagination $entries = FreshRSS_index_Controller::listEntriesByContext(); + FreshRSS_Context::$number--; $nb_entries = count($entries); if ($nb_entries > FreshRSS_Context::$number) { @@ -154,6 +156,7 @@ class FreshRSS_index_Controller extends Minz_ActionController { * - order (default: conf->sort_order) * - nb (default: conf->posts_per_page) * - next (default: empty string) + * - hours (default: 0) */ private function updateContext() { // Update number of read / unread variables. @@ -180,10 +183,14 @@ class FreshRSS_index_Controller extends Minz_ActionController { FreshRSS_Context::$order = Minz_Request::param( 'order', FreshRSS_Context::$user_conf->sort_order ); - FreshRSS_Context::$number = Minz_Request::param( - 'nb', FreshRSS_Context::$user_conf->posts_per_page - ); + FreshRSS_Context::$number = intval(Minz_Request::param('nb', FreshRSS_Context::$user_conf->posts_per_page)); + if (FreshRSS_Context::$number > FreshRSS_Context::$user_conf->max_posts_per_rss) { + FreshRSS_Context::$number = max( + FreshRSS_Context::$user_conf->max_posts_per_rss, + FreshRSS_Context::$user_conf->posts_per_page); + } FreshRSS_Context::$first_id = Minz_Request::param('next', ''); + FreshRSS_Context::$sinceHours = intval(Minz_Request::param('hours', 0)); } /** @@ -201,11 +208,31 @@ class FreshRSS_index_Controller extends Minz_ActionController { $id = ''; } - return $entryDAO->listWhere( + $limit = FreshRSS_Context::$number; + + $date_min = 0; + if (FreshRSS_Context::$sinceHours) { + $date_min = time() - (FreshRSS_Context::$sinceHours * 3600); + $limit = FreshRSS_Context::$user_conf->max_posts_per_rss; + } + + $entries = $entryDAO->listWhere( $type, $id, FreshRSS_Context::$state, FreshRSS_Context::$order, - FreshRSS_Context::$number + 1, FreshRSS_Context::$first_id, - FreshRSS_Context::$search + $limit, FreshRSS_Context::$first_id, + FreshRSS_Context::$search, $date_min ); + + if (FreshRSS_Context::$sinceHours && (count($entries) < FreshRSS_Context::$user_conf->min_posts_per_rss)) { + $date_min = 0; + $limit = FreshRSS_Context::$user_conf->min_posts_per_rss; + $entries = $entryDAO->listWhere( + $type, $id, FreshRSS_Context::$state, FreshRSS_Context::$order, + $limit, FreshRSS_Context::$first_id, + FreshRSS_Context::$search, $date_min + ); + } + + return $entries; } /** diff --git a/app/Models/Context.php b/app/Models/Context.php index 2a58bd4ba..33e65a619 100644 --- a/app/Models/Context.php +++ b/app/Models/Context.php @@ -35,6 +35,7 @@ class FreshRSS_Context { public static $first_id = ''; public static $next_id = ''; public static $id_max = ''; + public static $sinceHours = 0; /** * Initialize the context. diff --git a/app/layout/layout.phtml b/app/layout/layout.phtml index 4d9ad5458..1f11e0af1 100644 --- a/app/layout/layout.phtml +++ b/app/layout/layout.phtml @@ -42,6 +42,9 @@ } if (isset($this->rss_title)) { $url_rss = $url_base; $url_rss['a'] = 'rss'; + if (FreshRSS_Context::$user_conf->since_hours_posts_per_rss) { + $url_rss['params']['hours'] = FreshRSS_Context::$user_conf->since_hours_posts_per_rss; + } ?> allow_robots) { ?> diff --git a/app/layout/nav_menu.phtml b/app/layout/nav_menu.phtml index d77c1abf9..c02232242 100644 --- a/app/layout/nav_menu.phtml +++ b/app/layout/nav_menu.phtml @@ -151,6 +151,9 @@ if (FreshRSS_Context::$user_conf->token) { $url_output['params']['token'] = FreshRSS_Context::$user_conf->token; } + if (FreshRSS_Context::$user_conf->since_hours_posts_per_rss) { + $url_output['params']['hours'] = FreshRSS_Context::$user_conf->since_hours_posts_per_rss; + } ?> diff --git a/app/views/auth/index.phtml b/app/views/auth/index.phtml index 74e692ec5..7195bab5d 100644 --- a/app/views/auth/index.phtml +++ b/app/views/auth/index.phtml @@ -60,7 +60,7 @@ data-leave-validation=""/> - array('output' => 'rss', 'token' => $token)), 'html', true); ?> + array('output' => 'rss', 'token' => $token, 'hours' => FreshRSS_Context::$user_conf->since_hours_posts_per_rss)), 'html', true); ?>
    diff --git a/data/users/_/config.default.php b/data/users/_/config.default.php index 4a3403453..2c56d5f45 100644 --- a/data/users/_/config.default.php +++ b/data/users/_/config.default.php @@ -9,6 +9,9 @@ return array ( 'passwordHash' => '', 'apiPasswordHash' => '', 'posts_per_page' => 20, + 'since_hours_posts_per_rss' => 168, + 'min_posts_per_rss' => 2, + 'max_posts_per_rss' => 400, 'view_mode' => 'normal', 'default_view' => 'adaptive', 'default_state' => FreshRSS_Entry::STATE_NOT_READ, -- cgit v1.2.3 From 44f22ab8b4c46befab98440f69a05725928bed75 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sat, 24 Sep 2016 17:36:33 +0200 Subject: API move feed to another category https://github.com/jangernert/FeedReader/issues/59 https://github.com/FreshRSS/FreshRSS/issues/443 --- app/Controllers/feedController.php | 14 +------------- app/Models/FeedDAO.php | 13 +++++++++++++ p/api/greader.php | 7 +++++-- 3 files changed, 19 insertions(+), 15 deletions(-) (limited to 'app/Controllers') diff --git a/app/Controllers/feedController.php b/app/Controllers/feedController.php index ffda1450d..c64b67a80 100755 --- a/app/Controllers/feedController.php +++ b/app/Controllers/feedController.php @@ -511,21 +511,9 @@ class FreshRSS_feed_Controller extends Minz_ActionController { $feed_id = Minz_Request::param('f_id'); $cat_id = Minz_Request::param('c_id'); - - if ($cat_id === false) { - // If category was not given get the default one. - $catDAO = new FreshRSS_CategoryDAO(); - $catDAO->checkDefault(); - $def_cat = $catDAO->getDefault(); - $cat_id = $def_cat->id(); - } - $feedDAO = FreshRSS_Factory::createFeedDao(); - $values = array('category' => $cat_id); - $feed = $feedDAO->searchById($feed_id); - if ($feed && ($feed->category() == $cat_id || - $feedDAO->updateFeed($feed_id, $values))) { + if ($feedDAO->moveFeed($feed_id, $cat_id)) { // TODO: return something useful } else { Minz_Log::warning('Cannot move feed `' . $feed_id . '` ' . diff --git a/app/Models/FeedDAO.php b/app/Models/FeedDAO.php index 475d39286..2fd2c6194 100644 --- a/app/Models/FeedDAO.php +++ b/app/Models/FeedDAO.php @@ -136,6 +136,19 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo implements FreshRSS_Searchable { } } + public function moveFeed($feed_id, $cat_id) { + if ($cat_id <= 0) { + // If category was not given get the default one. + $catDAO = new FreshRSS_CategoryDAO(); + $catDAO->checkDefault(); + $def_cat = $catDAO->getDefault(); + $cat_id = $def_cat->id(); + } + $feed = $this->searchById($feed_id); + return $feed && ($feed->category() == $cat_id || + $this->updateFeed($feed_id, array('category' => $cat_id))); + } + public function deleteFeed($id) { $sql = 'DELETE FROM `' . $this->prefix . 'feed` WHERE id=?'; $stm = $this->bd->prepare($sql); diff --git a/p/api/greader.php b/p/api/greader.php index 3da1156c2..426f3fe44 100644 --- a/p/api/greader.php +++ b/p/api/greader.php @@ -337,14 +337,17 @@ function subscriptionEdit($streamNames, $titles, $action, $add = '', $remove = ' break; case 'edit': if ($feedId > 0) { - //TODO + if ($feedDAO->moveFeed($feed_id, $cat_id)) { + exit('OK'); + } else { + badRequest(); + } } break; } } } notImplemented(); - exit('OK'); } function unreadCount() { //http://blog.martindoms.com/2009/10/16/using-the-google-reader-api-part-2/#unread-count -- cgit v1.2.3 From d6b4186040011aad16a173a1ceaa5a5084025470 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sat, 24 Sep 2016 19:26:40 +0200 Subject: API implement delete feed + refactor move feed --- app/Controllers/feedController.php | 45 ++++++++++++++++++++++++++++--------- app/Models/FeedDAO.php | 13 ----------- p/api/greader.php | 46 +++++++++++++++++--------------------- 3 files changed, 54 insertions(+), 50 deletions(-) (limited to 'app/Controllers') diff --git a/app/Controllers/feedController.php b/app/Controllers/feedController.php index c64b67a80..0ff27e0da 100755 --- a/app/Controllers/feedController.php +++ b/app/Controllers/feedController.php @@ -492,6 +492,23 @@ class FreshRSS_feed_Controller extends Minz_ActionController { return $updated_feeds; } + public static function moveFeed($feed_id, $cat_id) { + if ($feed_id <= 0) { + return false; + } + if ($cat_id <= 0) { + // If category was not given get the default one. + $catDAO = new FreshRSS_CategoryDAO(); + $catDAO->checkDefault(); + $def_cat = $catDAO->getDefault(); + $cat_id = $def_cat->id(); + } + $feedDAO = FreshRSS_Factory::createFeedDao(); + $feed = $feedDAO->searchById($feed_id); + return $feed && ($feed->category() == $cat_id || + $feedDAO->updateFeed($feed_id, array('category' => $cat_id))); + } + /** * This action changes the category of a feed. * @@ -511,9 +528,8 @@ class FreshRSS_feed_Controller extends Minz_ActionController { $feed_id = Minz_Request::param('f_id'); $cat_id = Minz_Request::param('c_id'); - $feedDAO = FreshRSS_Factory::createFeedDao(); - if ($feedDAO->moveFeed($feed_id, $cat_id)) { + if (self::moveFeed($feed_id, $cat_id)) { // TODO: return something useful } else { Minz_Log::warning('Cannot move feed `' . $feed_id . '` ' . @@ -522,6 +538,21 @@ class FreshRSS_feed_Controller extends Minz_ActionController { } } + public static function deleteFeed($feed_id) { + $feedDAO = FreshRSS_Factory::createFeedDao(); + if ($feedDAO->deleteFeed($feed_id)) { + // TODO: Delete old favicon + + // Remove related queries + FreshRSS_Context::$user_conf->queries = remove_query_by_get( + 'f_' . $feed_id, FreshRSS_Context::$user_conf->queries); + FreshRSS_Context::$user_conf->save(); + + return true; + } + return false; + } + /** * This action deletes a feed. * @@ -540,21 +571,13 @@ class FreshRSS_feed_Controller extends Minz_ActionController { if (!$redirect_url) { $redirect_url = array('c' => 'subscription', 'a' => 'index'); } - if (!Minz_Request::isPost()) { Minz_Request::forward($redirect_url, true); } $id = Minz_Request::param('id'); - $feedDAO = FreshRSS_Factory::createFeedDao(); - if ($feedDAO->deleteFeed($id)) { - // TODO: Delete old favicon - - // Remove related queries - FreshRSS_Context::$user_conf->queries = remove_query_by_get( - 'f_' . $id, FreshRSS_Context::$user_conf->queries); - FreshRSS_Context::$user_conf->save(); + if (self::deleteFeed($id)) { Minz_Request::good(_t('feedback.sub.feed.deleted'), $redirect_url); } else { Minz_Request::bad(_t('feedback.sub.feed.error'), $redirect_url); diff --git a/app/Models/FeedDAO.php b/app/Models/FeedDAO.php index 2fd2c6194..475d39286 100644 --- a/app/Models/FeedDAO.php +++ b/app/Models/FeedDAO.php @@ -136,19 +136,6 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo implements FreshRSS_Searchable { } } - public function moveFeed($feed_id, $cat_id) { - if ($cat_id <= 0) { - // If category was not given get the default one. - $catDAO = new FreshRSS_CategoryDAO(); - $catDAO->checkDefault(); - $def_cat = $catDAO->getDefault(); - $cat_id = $def_cat->id(); - } - $feed = $this->searchById($feed_id); - return $feed && ($feed->category() == $cat_id || - $this->updateFeed($feed_id, array('category' => $cat_id))); - } - public function deleteFeed($id) { $sql = 'DELETE FROM `' . $this->prefix . 'feed` WHERE id=?'; $stm = $this->bd->prepare($sql); diff --git a/p/api/greader.php b/p/api/greader.php index 7094fb381..9b07e0729 100644 --- a/p/api/greader.php +++ b/p/api/greader.php @@ -153,13 +153,12 @@ function authorizationToUser() { if (count($headerAuthX) === 2) { $user = $headerAuthX[0]; if (ctype_alnum($user)) { - $conf = get_user_configuration($user); - if (is_null($conf)) { + FreshRSS_Context::$user_conf = get_user_configuration($user); + if (FreshRSS_Context::$user_conf == null) { Minz_Log::warning('Invalid API user ' . $user . ': configuration cannot be found.'); unauthorized(); } - global $system_conf; - if ($headerAuthX[1] === sha1($system_conf->salt . $user . $conf->apiPasswordHash)) { + if ($headerAuthX[1] === sha1(FreshRSS_Context::$system_conf->salt . $user . FreshRSS_Context::$user_conf->apiPasswordHash)) { return $user; } else { logMe('Invalid API authorisation for user ' . $user . ': ' . $headerAuthX[1]); @@ -181,16 +180,15 @@ function clientLogin($email, $pass) { //http://web.archive.org/web/2013060409104 include_once(LIB_PATH . '/password_compat.php'); } - $conf = get_user_configuration($email); - if (is_null($conf)) { + FreshRSS_Context::$user_conf = get_user_configuration($email); + if (FreshRSS_Context::$user_conf == null) { Minz_Log::warning('Invalid API user ' . $email . ': configuration cannot be found.'); unauthorized(); } - if ($conf->apiPasswordHash != '' && password_verify($pass, $conf->apiPasswordHash)) { + if (FreshRSS_Context::$user_conf->apiPasswordHash != '' && password_verify($pass, FreshRSS_Context::$user_conf->apiPasswordHash)) { header('Content-Type: text/plain; charset=UTF-8'); - global $system_conf; - $auth = $email . '/' . sha1($system_conf->salt . $email . $conf->apiPasswordHash); + $auth = $email . '/' . sha1(FreshRSS_Context::$system_conf->salt . $email . FreshRSS_Context::$user_conf->apiPasswordHash); echo 'SID=', $auth, "\n", 'Auth=', $auth, "\n"; exit(); @@ -209,8 +207,7 @@ function token($conf) { //https://github.com/ericmann/gReader-Library/blob/master/greader.class.php $user = Minz_Session::param('currentUser', '_'); //logMe('token('. $user . ")"); //TODO: Implement real token that expires - global $system_conf; - $token = str_pad(sha1($system_conf->salt . $user . $conf->apiPasswordHash), 57, 'Z'); //Must have 57 characters + $token = str_pad(sha1(FreshRSS_Context::$system_conf->salt . $user . $conf->apiPasswordHash), 57, 'Z'); //Must have 57 characters echo $token, "\n"; exit(); } @@ -219,8 +216,7 @@ function checkToken($conf, $token) { //http://code.google.com/p/google-reader-api/wiki/ActionToken $user = Minz_Session::param('currentUser', '_'); //logMe('checkToken(' . $token . ")"); - global $system_conf; - if ($token === str_pad(sha1($system_conf->salt . $user . $conf->apiPasswordHash), 57, 'Z')) { + if ($token === str_pad(sha1(FreshRSS_Context::$system_conf->salt . $user . $conf->apiPasswordHash), 57, 'Z')) { return true; } unauthorized(); @@ -261,8 +257,7 @@ function subscriptionList() { $stm->execute(); $res = $stm->fetchAll(PDO::FETCH_ASSOC); - global $system_conf; - $salt = $system_conf->salt; + $salt = FreshRSS_Context::$system_conf->salt; $subscriptions = array(); foreach ($res as $line) { @@ -296,7 +291,6 @@ function subscriptionEdit($streamNames, $titles, $action, $add = '', $remove = ' case 'edit': break; default: - logMe("Bad action: $action"); badRequest(); } $addCatId = 0; @@ -336,14 +330,14 @@ function subscriptionEdit($streamNames, $titles, $action, $add = '', $remove = ' } break; case 'unsubscribe': - if ($feedId > 0) { - //TODO + if ($feedId > 0 && FreshRSS_feed_Controller::deleteFeed($feedId)) { + exit('OK'); } else { badRequest(); } break; case 'edit': - if ($feedId > 0 && $feedDAO->moveFeed($feedId, $addCatId)) { + if ($feedId > 0 && FreshRSS_feed_Controller::moveFeed($feedId, $addCatId)) { exit('OK'); } badRequest(); @@ -620,17 +614,17 @@ $pathInfos = explode('/', $pathInfo); Minz_Configuration::register('system', DATA_PATH . '/config.php', DATA_PATH . '/config.default.php'); -$system_conf = Minz_Configuration::get('system'); -if (!$system_conf->api_enabled) { +FreshRSS_Context::$system_conf = Minz_Configuration::get('system'); +if (!FreshRSS_Context::$system_conf->api_enabled) { serviceUnavailable(); } Minz_Session::init('FreshRSS'); $user = authorizationToUser(); -$conf = null; +FreshRSS_Context::$user_conf = null; if ($user !== '') { - $conf = get_user_configuration($user); + FreshRSS_Context::$user_conf = get_user_configuration($user); } //logMe('User => ' . $user); @@ -722,7 +716,7 @@ elseif ($pathInfos[1] === 'reader' && $pathInfos[2] === 'api' && isset($pathInfo break; case 'edit-tag': //http://blog.martindoms.com/2010/01/20/using-the-google-reader-api-part-3/ $token = isset($_POST['T']) ? trim($_POST['T']) : ''; - checkToken($conf, $token); + checkToken(FreshRSS_Context::$user_conf, $token); $a = isset($_POST['a']) ? $_POST['a'] : ''; //Add: user/-/state/com.google/read user/-/state/com.google/starred $r = isset($_POST['r']) ? $_POST['r'] : ''; //Remove: user/-/state/com.google/read user/-/state/com.google/starred $e_ids = multiplePosts('i'); //item IDs @@ -730,7 +724,7 @@ elseif ($pathInfos[1] === 'reader' && $pathInfos[2] === 'api' && isset($pathInfo break; case 'mark-all-as-read': $token = isset($_POST['T']) ? trim($_POST['T']) : ''; - checkToken($conf, $token); + checkToken(FreshRSS_Context::$user_conf, $token); $streamId = $_POST['s']; //StreamId $ts = isset($_POST['ts']) ? $_POST['ts'] : '0'; //Older than timestamp in nanoseconds if (!ctype_digit($ts)) { @@ -739,7 +733,7 @@ elseif ($pathInfos[1] === 'reader' && $pathInfos[2] === 'api' && isset($pathInfo markAllAsRead($streamId, $ts); break; case 'token': - token($conf); + token(FreshRSS_Context::$user_conf); break; } } elseif ($pathInfos[1] === 'check' && $pathInfos[2] === 'compatibility') { -- cgit v1.2.3 From 6a812b0d31df275d9b8b211a90628400ee097644 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sat, 24 Sep 2016 19:54:46 +0200 Subject: API rename feed --- app/Controllers/feedController.php | 12 +++++++++--- p/api/greader.php | 19 ++++++++++++------- 2 files changed, 21 insertions(+), 10 deletions(-) (limited to 'app/Controllers') diff --git a/app/Controllers/feedController.php b/app/Controllers/feedController.php index 0ff27e0da..0364424f5 100755 --- a/app/Controllers/feedController.php +++ b/app/Controllers/feedController.php @@ -492,6 +492,14 @@ class FreshRSS_feed_Controller extends Minz_ActionController { return $updated_feeds; } + public static function renameFeed($feed_id, $feed_name) { + if ($feed_id <= 0 || $feed_name == '') { + return false; + } + $feedDAO = FreshRSS_Factory::createFeedDao(); + return $feedDAO->updateFeed($feed_id, array('name' => $feed_name)); + } + public static function moveFeed($feed_id, $cat_id) { if ($feed_id <= 0) { return false; @@ -504,9 +512,7 @@ class FreshRSS_feed_Controller extends Minz_ActionController { $cat_id = $def_cat->id(); } $feedDAO = FreshRSS_Factory::createFeedDao(); - $feed = $feedDAO->searchById($feed_id); - return $feed && ($feed->category() == $cat_id || - $feedDAO->updateFeed($feed_id, array('category' => $cat_id))); + return $feedDAO->updateFeed($feed_id, array('category' => $cat_id)); } /** diff --git a/p/api/greader.php b/p/api/greader.php index 9b07e0729..131eb65c5 100644 --- a/p/api/greader.php +++ b/p/api/greader.php @@ -325,27 +325,32 @@ function subscriptionEdit($streamNames, $titles, $action, $add = '', $remove = ' case 'subscribe': if ($feedId <= 0) { //TODO + notImplemented(); } else { badRequest(); } break; case 'unsubscribe': - if ($feedId > 0 && FreshRSS_feed_Controller::deleteFeed($feedId)) { - exit('OK'); - } else { + if (!($feedId > 0 && FreshRSS_feed_Controller::deleteFeed($feedId))) { badRequest(); } break; case 'edit': - if ($feedId > 0 && FreshRSS_feed_Controller::moveFeed($feedId, $addCatId)) { - exit('OK'); + if ($feedId > 0) { + if ($addCatId > 0) { + FreshRSS_feed_Controller::moveFeed($feedId, $addCatId); + } + if ($title != '') { + FreshRSS_feed_Controller::renameFeed($feedId, $title); + } + } else { + badRequest(); } - badRequest(); break; } } } - notImplemented(); + exit('OK'); } function unreadCount() { //http://blog.martindoms.com/2009/10/16/using-the-google-reader-api-part-2/#unread-count -- cgit v1.2.3 From 0a79d4085b18c5607438f8ebd56543508e7db3a8 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sat, 24 Sep 2016 20:43:52 +0200 Subject: Refactor controller for actualize feed --- app/Controllers/feedController.php | 46 +++++++++++++++++++++----------------- lib/lib_rss.php | 2 +- p/api/pshb.php | 7 ++---- 3 files changed, 28 insertions(+), 27 deletions(-) (limited to 'app/Controllers') diff --git a/app/Controllers/feedController.php b/app/Controllers/feedController.php index 0364424f5..25d504480 100755 --- a/app/Controllers/feedController.php +++ b/app/Controllers/feedController.php @@ -261,33 +261,18 @@ class FreshRSS_feed_Controller extends Minz_ActionController { } } - /** - * This action actualizes entries from one or several feeds. - * - * Parameters are: - * - id (default: false): Feed ID - * - url (default: false): Feed URL - * - force (default: false) - * If id and url are not specified, all the feeds are actualized. But if force is - * false, process stops at 10 feeds to avoid time execution problem. - */ - public function actualizeAction($simplePiePush = null) { + public static function actualizeFeed($feed_id, $feed_url, $force, $simplePiePush = null) { @set_time_limit(300); $feedDAO = FreshRSS_Factory::createFeedDao(); $entryDAO = FreshRSS_Factory::createEntryDao(); - Minz_Session::_param('actualize_feeds', false); - $id = Minz_Request::param('id'); - $url = Minz_Request::param('url'); - $force = Minz_Request::param('force'); - // Create a list of feeds to actualize. - // If id is set and valid, corresponding feed is added to the list but + // If feed_id is set and valid, corresponding feed is added to the list but // alone in order to automatize further process. $feeds = array(); - if ($id || $url) { - $feed = $id ? $feedDAO->searchById($id) : $feedDAO->searchByUrl($url); + if ($feed_id > 0 || $feed_url) { + $feed = $feed_id > 0 ? $feedDAO->searchById($feed_id) : $feedDAO->searchByUrl($feed_url); if ($feed) { $feeds[] = $feed; } @@ -309,7 +294,7 @@ class FreshRSS_feed_Controller extends Minz_ActionController { $url = $feed->url(); //For detection of HTTP 301 $pubSubHubbubEnabled = $pubsubhubbubEnabledGeneral && $feed->pubSubHubbubEnabled(); - if ((!$simplePiePush) && (!$id) && $pubSubHubbubEnabled && ($feed->lastUpdate() > $pshbMinAge)) { + if ((!$simplePiePush) && (!$feed_id) && $pubSubHubbubEnabled && ($feed->lastUpdate() > $pshbMinAge)) { //$text = 'Skip pull of feed using PubSubHubbub: ' . $url; //Minz_Log::debug($text); //file_put_contents(USERS_PATH . '/_/log_pshb.txt', date('c') . "\t" . $text . "\n", FILE_APPEND); @@ -464,6 +449,26 @@ class FreshRSS_feed_Controller extends Minz_ActionController { break; } } + return array($updated_feeds, reset($feeds)); + } + + /** + * This action actualizes entries from one or several feeds. + * + * Parameters are: + * - id (default: false): Feed ID + * - url (default: false): Feed URL + * - force (default: false) + * If id and url are not specified, all the feeds are actualized. But if force is + * false, process stops at 10 feeds to avoid time execution problem. + */ + public function actualizeAction() { + Minz_Session::_param('actualize_feeds', false); + $id = Minz_Request::param('id'); + $url = Minz_Request::param('url'); + $force = Minz_Request::param('force'); + + list($updated_feeds, $feed) = self::actualizeFeed($id, $url, $force); if (Minz_Request::param('ajax')) { // Most of the time, ajax request is for only one feed. But since @@ -479,7 +484,6 @@ class FreshRSS_feed_Controller extends Minz_ActionController { } else { // Redirect to the main page with correct notification. if ($updated_feeds === 1) { - $feed = reset($feeds); Minz_Request::good(_t('feedback.sub.feed.actualized', $feed->name()), array( 'params' => array('get' => 'f_' . $feed->id()) )); diff --git a/lib/lib_rss.php b/lib/lib_rss.php index 82ddced2c..a4cd8e782 100644 --- a/lib/lib_rss.php +++ b/lib/lib_rss.php @@ -165,7 +165,7 @@ function customSimplePie() { $system_conf = Minz_Configuration::get('system'); $limits = $system_conf->limits; $simplePie = new SimplePie(); - $simplePie->set_useragent(_t('gen.freshrss') . '/' . FRESHRSS_VERSION . ' (' . PHP_OS . '; ' . FRESHRSS_WEBSITE . ') ' . SIMPLEPIE_NAME . '/' . SIMPLEPIE_VERSION); + $simplePie->set_useragent('FreshRSS/' . FRESHRSS_VERSION . ' (' . PHP_OS . '; ' . FRESHRSS_WEBSITE . ') ' . SIMPLEPIE_NAME . '/' . SIMPLEPIE_VERSION); $simplePie->set_syslog($system_conf->simplepie_syslog_enabled); $simplePie->set_cache_location(CACHE_PATH); $simplePie->set_cache_duration($limits['cache_duration']); diff --git a/p/api/pshb.php b/p/api/pshb.php index 650767114..94a0068ed 100644 --- a/p/api/pshb.php +++ b/p/api/pshb.php @@ -88,9 +88,6 @@ if ($ORIGINAL_INPUT == '') { Minz_Configuration::register('system', DATA_PATH . '/config.php', DATA_PATH . '/config.default.php'); $system_conf = Minz_Configuration::get('system'); $system_conf->auth_type = 'none'; // avoid necessity to be logged in (not saved!) -Minz_Translate::init('en'); -Minz_Request::_param('ajax', true); -$feedController = new FreshRSS_feed_Controller(); $simplePie = customSimplePie(); $simplePie->set_raw_data($ORIGINAL_INPUT); @@ -106,7 +103,6 @@ if ($self !== base64url_decode($canonical64)) { //die('Self URL does not match registered canonical URL!'); $self = base64url_decode($canonical64); } -Minz_Request::_param('url', $self); $nb = 0; foreach ($users as $userFilename) { @@ -121,7 +117,8 @@ foreach ($users as $userFilename) { join_path(USERS_PATH, $username, 'config.php'), join_path(USERS_PATH, '_', 'config.default.php')); FreshRSS_Context::init(); - if ($feedController->actualizeAction($simplePie) > 0) { + list($updated_feeds, $feed) = FreshRSS_feed_Controller::actualizeFeed(0, $self, false, $simplePie); + if ($updated_feeds > 0) { $nb++; } } catch (Exception $e) { -- cgit v1.2.3 From 324c83348ca44f3c13f4e0efeea25bbc96ed3b05 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sat, 24 Sep 2016 23:29:49 +0200 Subject: Refactor controller add feed --- app/Controllers/feedController.php | 181 +++++++++++--------------- app/Exceptions/AlreadySubscribedException.php | 14 ++ app/Exceptions/FeedNotAddedException.php | 14 ++ app/Models/Feed.php | 4 +- 4 files changed, 105 insertions(+), 108 deletions(-) create mode 100644 app/Exceptions/AlreadySubscribedException.php create mode 100644 app/Exceptions/FeedNotAddedException.php (limited to 'app/Controllers') diff --git a/app/Controllers/feedController.php b/app/Controllers/feedController.php index 25d504480..c6adc64cb 100755 --- a/app/Controllers/feedController.php +++ b/app/Controllers/feedController.php @@ -26,6 +26,63 @@ class FreshRSS_feed_Controller extends Minz_ActionController { } } + public static function addFeed($url, $cat_id = 0, $new_cat_name = '', $http_auth = '') { + @set_time_limit(300); + + $catDAO = new FreshRSS_CategoryDAO(); + + $cat = null; + if ($cat_id > 0) { + $cat = $catDAO->searchById($cat_id); + } + if ($cat == null && $new_cat_name != '') { + $cat = $catDAO->addCategory(array('name' => $new_cat_name)); + } + if ($cat == null) { + $catDAO->checkDefault(); + $def_cat = $catDAO->getDefault(); + $cat = $def_cat->id(); + } + + $feed = new FreshRSS_Feed($url); //Throws FreshRSS_BadUrl_Exception + $feed->_httpAuth($http_auth); + $feed->load(true); //Throws FreshRSS_Feed_Exception, Minz_FileNotExistException + $feed->_category($cat_id); + + $feedDAO = FreshRSS_Factory::createFeedDao(); + if ($feedDAO->searchByUrl($feed->url())) { + throw new FreshRSS_AlreadySubscribed_Exception($url, $feed->name()); + } + + // Call the extension hook + $feed = Minz_ExtensionManager::callHook('feed_before_insert', $feed); + if ($feed === null) { + throw new FreshRSS_FeedNotAdded_Exception($url, $feed->name()); + } + + $values = array( + 'url' => $feed->url(), + 'category' => $feed->category(), + 'name' => $feed->name(), + 'website' => $feed->website(), + 'description' => $feed->description(), + 'lastUpdate' => time(), + 'httpAuth' => $feed->httpAuth(), + ); + + $id = $feedDAO->addFeed($values); + if (!$id) { + // There was an error in database... we cannot say what here. + throw new FreshRSS_FeedNotAdded_Exception($url, $feed->name()); + } + $feed->_id($id); + + // Ok, feed has been added in database. Now we have to refresh entries. + self::actualizeFeed($id, $url, false, null, true); + + return $feed; + } + /** * This action subscribes to a feed. * @@ -59,7 +116,6 @@ class FreshRSS_feed_Controller extends Minz_ActionController { } $feedDAO = FreshRSS_Factory::createFeedDao(); - $this->catDAO = new FreshRSS_CategoryDAO(); $url_redirect = array( 'c' => 'subscription', 'a' => 'index', @@ -74,26 +130,13 @@ class FreshRSS_feed_Controller extends Minz_ActionController { } if (Minz_Request::isPost()) { - @set_time_limit(300); - $cat = Minz_Request::param('category'); + $new_cat_name = ''; if ($cat === 'nc') { // User want to create a new category, new_category parameter // must exist $new_cat = Minz_Request::param('new_category'); - if (empty($new_cat['name'])) { - $cat = false; - } else { - $cat = $this->catDAO->addCategory($new_cat); - } - } - - if ($cat === false) { - // If category was not given or if creating new category failed, - // get the default category - $this->catDAO->checkDefault(); - $def_cat = $this->catDAO->getDefault(); - $cat = $def_cat->id(); + $new_cat_name = isset($new_cat['name']) ? $new_cat['name'] : ''; } // HTTP information are useful if feed is protected behind a @@ -105,103 +148,24 @@ class FreshRSS_feed_Controller extends Minz_ActionController { $http_auth = $user . ':' . $pass; } - $transaction_started = false; try { - $feed = new FreshRSS_Feed($url); + $feed = self::addFeed($url, $cat, $new_cat_name, $http_auth); } catch (FreshRSS_BadUrl_Exception $e) { // Given url was not a valid url! Minz_Log::warning($e->getMessage()); Minz_Request::bad(_t('feedback.sub.feed.invalid_url', $url), $url_redirect); - } - - $feed->_httpAuth($http_auth); - - try { - $feed->load(true); } catch (FreshRSS_Feed_Exception $e) { // Something went bad (timeout, server not found, etc.) Minz_Log::warning($e->getMessage()); - Minz_Request::bad( - _t('feedback.sub.feed.internal_problem', _url('index', 'logs')), - $url_redirect - ); + Minz_Request::bad(_t('feedback.sub.feed.internal_problem', _url('index', 'logs')), $url_redirect); } catch (Minz_FileNotExistException $e) { // Cache directory doesn't exist! Minz_Log::error($e->getMessage()); - Minz_Request::bad( - _t('feedback.sub.feed.internal_problem', _url('index', 'logs')), - $url_redirect - ); - } - - if ($feedDAO->searchByUrl($feed->url())) { - Minz_Request::bad( - _t('feedback.sub.feed.already_subscribed', $feed->name()), - $url_redirect - ); - } - - $feed->_category($cat); - - // Call the extension hook - $name = $feed->name(); - $feed = Minz_ExtensionManager::callHook('feed_before_insert', $feed); - if ($feed === null) { - Minz_Request::bad(_t('feedback.sub.feed.not_added', $name), $url_redirect); - } - - $values = array( - 'url' => $feed->url(), - 'category' => $feed->category(), - 'name' => $feed->name(), - 'website' => $feed->website(), - 'description' => $feed->description(), - 'lastUpdate' => time(), - 'httpAuth' => $feed->httpAuth(), - ); - - $id = $feedDAO->addFeed($values); - if (!$id) { - // There was an error in database... we cannot say what here. - Minz_Request::bad(_t('feedback.sub.feed.not_added', $feed->name()), $url_redirect); - } - - // Ok, feed has been added in database. Now we have to refresh entries. - $feed->_id($id); - $feed->faviconPrepare(); - //$feed->pubSubHubbubPrepare(); //TODO: prepare PubSubHubbub already when adding the feed - - $is_read = FreshRSS_Context::$user_conf->mark_when['reception'] ? 1 : 0; - - $entryDAO = FreshRSS_Factory::createEntryDao(); - // We want chronological order and SimplePie uses reverse order. - $entries = array_reverse($feed->entries()); - - // Calculate date of oldest entries we accept in DB. - $nb_month_old = FreshRSS_Context::$user_conf->old_entries; - $date_min = time() - (3600 * 24 * 30 * $nb_month_old); - - // Use a shared statement and a transaction to improve a LOT the - // performances. - $feedDAO->beginTransaction(); - foreach ($entries as $entry) { - // Entries are added without any verification. - $entry->_feed($feed->id()); - $entry->_id(min(time(), $entry->date(true)) . uSecString()); - $entry->_isRead($is_read); - - $entry = Minz_ExtensionManager::callHook('entry_before_insert', $entry); - if ($entry === null) { - // An extension has returned a null value, there is nothing to insert. - continue; - } - - $values = $entry->toArray(); - $entryDAO->addEntry($values); - } - $feedDAO->updateLastUpdate($feed->id()); - if ($feedDAO->inTransaction()) { - $feedDAO->commit(); + Minz_Request::bad(_t('feedback.sub.feed.internal_problem', _url('index', 'logs')), $url_redirect); + } catch (FreshRSS_AlreadySubscribed_Exception $e) { + Minz_Request::bad(_t('feedback.sub.feed.already_subscribed', $e->feedName()), $url_redirect); + } catch (FreshRSS_FeedNotAdded_Exception $e) { + Minz_Request::bad(_t('feedback.sub.feed.not_added', $e->feedName()), $url_redirect); } // Entries are in DB, we redirect to feed configuration page. @@ -211,6 +175,7 @@ class FreshRSS_feed_Controller extends Minz_ActionController { // GET request: we must ask confirmation to user before adding feed. Minz_View::prependTitle(_t('sub.feed.title_add') . ' · '); + $this->catDAO = new FreshRSS_CategoryDAO(); $this->view->categories = $this->catDAO->listCategories(false); $this->view->feed = new FreshRSS_Feed($url); try { @@ -261,7 +226,7 @@ class FreshRSS_feed_Controller extends Minz_ActionController { } } - public static function actualizeFeed($feed_id, $feed_url, $force, $simplePiePush = null) { + public static function actualizeFeed($feed_id, $feed_url, $force, $simplePiePush = null, $isNewFeed = false) { @set_time_limit(300); $feedDAO = FreshRSS_Factory::createFeedDao(); @@ -310,7 +275,7 @@ class FreshRSS_feed_Controller extends Minz_ActionController { if ($simplePiePush) { $feed->loadEntries($simplePiePush); //Used by PubSubHubbub } else { - $feed->load(false); + $feed->load(false, $isNewFeed); } } catch (FreshRSS_Feed_Exception $e) { Minz_Log::warning($e->getMessage()); @@ -320,7 +285,9 @@ class FreshRSS_feed_Controller extends Minz_ActionController { } $feed_history = $feed->keepHistory(); - if ($feed_history == -2) { + if ($isNewFeed) { + $feed_history = -1; //∞ + } elseif ($feed_history == -2) { // TODO: -2 must be a constant! // -2 means we take the default value from configuration $feed_history = FreshRSS_Context::$user_conf->keep_history_default; @@ -360,7 +327,9 @@ class FreshRSS_feed_Controller extends Minz_ActionController { // This entry should not be added considering configuration and date. $oldGuids[] = $entry->guid(); } else { - if ($entry_date < $date_min) { + if ($isNewFeed) { + $id = min(time(), $entry_date) . uSecString(); + } elseif ($entry_date < $date_min) { $id = min(time(), $entry_date) . uSecString(); $entry->_isRead(true); //Old article that was not in database. Probably an error, so mark as read } else { diff --git a/app/Exceptions/AlreadySubscribedException.php b/app/Exceptions/AlreadySubscribedException.php new file mode 100644 index 000000000..f85d51300 --- /dev/null +++ b/app/Exceptions/AlreadySubscribedException.php @@ -0,0 +1,14 @@ +$feedName = $feedName; + } + + public function feedName() { + return $this->feedName(); + } +} diff --git a/app/Exceptions/FeedNotAddedException.php b/app/Exceptions/FeedNotAddedException.php new file mode 100644 index 000000000..02a8bc6be --- /dev/null +++ b/app/Exceptions/FeedNotAddedException.php @@ -0,0 +1,14 @@ +$feedName = $feedName; + } + + public function feedName() { + return $this->feedName(); + } +} diff --git a/app/Models/Feed.php b/app/Models/Feed.php index 4403a23c4..658b9ccca 100644 --- a/app/Models/Feed.php +++ b/app/Models/Feed.php @@ -216,7 +216,7 @@ class FreshRSS_Feed extends Minz_Model { $this->nbEntries = intval($value); } - public function load($loadDetails = false) { + public function load($loadDetails = false, $noCache = false) { if ($this->url !== null) { if (CACHE_PATH === false) { throw new Minz_FileNotExistException( @@ -268,7 +268,7 @@ class FreshRSS_Feed extends Minz_Model { $this->_url($clean_url); } - if (($mtime === true) || ($mtime > $this->lastUpdate)) { + if (($mtime === true) || ($mtime > $this->lastUpdate) || $noCache) { //Minz_Log::debug('FreshRSS no cache ' . $mtime . ' > ' . $this->lastUpdate . ' for ' . $clean_url); $this->loadEntries($feed); // et on charge les articles du flux } else { -- cgit v1.2.3 From 71b98a0ffc41ea869e8c49c2889cda5b3e113030 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sun, 25 Sep 2016 00:14:36 +0200 Subject: API add feed --- app/Controllers/feedController.php | 10 +++++----- p/api/greader.php | 20 ++++++++++++++------ 2 files changed, 19 insertions(+), 11 deletions(-) (limited to 'app/Controllers') diff --git a/app/Controllers/feedController.php b/app/Controllers/feedController.php index c6adc64cb..faf670e6e 100755 --- a/app/Controllers/feedController.php +++ b/app/Controllers/feedController.php @@ -26,7 +26,7 @@ class FreshRSS_feed_Controller extends Minz_ActionController { } } - public static function addFeed($url, $cat_id = 0, $new_cat_name = '', $http_auth = '') { + public static function addFeed($url, $title = '', $cat_id = 0, $new_cat_name = '', $http_auth = '') { @set_time_limit(300); $catDAO = new FreshRSS_CategoryDAO(); @@ -40,9 +40,9 @@ class FreshRSS_feed_Controller extends Minz_ActionController { } if ($cat == null) { $catDAO->checkDefault(); - $def_cat = $catDAO->getDefault(); - $cat = $def_cat->id(); + $cat = $catDAO->getDefault(); } + $cat_id = $cat->id(); $feed = new FreshRSS_Feed($url); //Throws FreshRSS_BadUrl_Exception $feed->_httpAuth($http_auth); @@ -63,7 +63,7 @@ class FreshRSS_feed_Controller extends Minz_ActionController { $values = array( 'url' => $feed->url(), 'category' => $feed->category(), - 'name' => $feed->name(), + 'name' => $title != '' ? $title : $feed->name(), 'website' => $feed->website(), 'description' => $feed->description(), 'lastUpdate' => time(), @@ -149,7 +149,7 @@ class FreshRSS_feed_Controller extends Minz_ActionController { } try { - $feed = self::addFeed($url, $cat, $new_cat_name, $http_auth); + $feed = self::addFeed($url, '', $cat, $new_cat_name, $http_auth); } catch (FreshRSS_BadUrl_Exception $e) { // Given url was not a valid url! Minz_Log::warning($e->getMessage()); diff --git a/p/api/greader.php b/p/api/greader.php index 131eb65c5..dc8dd92bc 100644 --- a/p/api/greader.php +++ b/p/api/greader.php @@ -298,18 +298,22 @@ function subscriptionEdit($streamNames, $titles, $action, $add = '', $remove = ' if ($add != '' || $remove != '') { $categoryDAO = new FreshRSS_CategoryDAO(); } + $c_name = ''; if ($add != '' && strpos($add, 'user/-/label/') === 0) { //user/-/label/Example - $c_name = basename($add); + $c_name = substr($add, 13); $cat = $categoryDAO->searchByName($c_name); $addCatId = $cat == null ? -1 : $cat->id(); } else if ($remove != '' && strpos($remove, 'user/-/label/')) { $addCatId = 1; //Default category } + if ($addCatId <= 0 && $c_name = '') { + $addCatId = 1; //Default category + } $feedDAO = FreshRSS_Factory::createFeedDao(); for ($i = count($streamNames) - 1; $i >= 0; $i--) { $streamName = $streamNames[$i]; //feed/http://example.net/sample.xml ; feed/338 if (strpos($streamName, 'feed/') === 0) { - $streamName = basename($streamName); + $streamName = substr($streamName, 5); $feedId = 0; if (ctype_digit($streamName)) { if ($action === 'subscribe') { @@ -324,11 +328,15 @@ function subscriptionEdit($streamNames, $titles, $action, $add = '', $remove = ' switch ($action) { case 'subscribe': if ($feedId <= 0) { - //TODO - notImplemented(); - } else { - badRequest(); + $http_auth = ''; //TODO + try { + $feed = FreshRSS_feed_Controller::addFeed($streamName, $title, $addCatId, $c_name, $http_auth); + continue; + } catch (Exception $e) { + logMe("subscriptionEdit error subscribe: " . $e->getMessage()); + } } + badRequest(); break; case 'unsubscribe': if (!($feedId > 0 && FreshRSS_feed_Controller::deleteFeed($feedId))) { -- cgit v1.2.3 From 9291748c4745ff8f4be2beaa2998869fd26e907e Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Mon, 26 Sep 2016 10:44:44 +0200 Subject: API implement user-info and fix edits https://github.com/FreshRSS/FreshRSS/issues/1254 https://github.com/jangernert/FeedReader/issues/59#issuecomment-249491580 --- app/Controllers/feedController.php | 20 +++++++++++----- app/Models/CategoryDAO.php | 3 +++ data/users/_/config.default.php | 1 + p/api/greader.php | 47 ++++++++++++++++++++++++++++++-------- 4 files changed, 55 insertions(+), 16 deletions(-) (limited to 'app/Controllers') diff --git a/app/Controllers/feedController.php b/app/Controllers/feedController.php index faf670e6e..ca7a818c6 100755 --- a/app/Controllers/feedController.php +++ b/app/Controllers/feedController.php @@ -473,17 +473,25 @@ class FreshRSS_feed_Controller extends Minz_ActionController { return $feedDAO->updateFeed($feed_id, array('name' => $feed_name)); } - public static function moveFeed($feed_id, $cat_id) { + public static function moveFeed($feed_id, $cat_id, $new_cat_name = '') { if ($feed_id <= 0) { return false; } - if ($cat_id <= 0) { - // If category was not given get the default one. - $catDAO = new FreshRSS_CategoryDAO(); + + $catDAO = new FreshRSS_CategoryDAO(); + if ($cat_id > 0) { + $cat = $catDAO->searchById($cat_id); + $cat_id = $cat == null ? 0 : $cat->id(); + } + if ($cat_id <= 1 && $new_cat_name != '') { + $cat_id = $catDAO->addCategory(array('name' => $new_cat_name)); + } + if ($cat_id <= 1) { $catDAO->checkDefault(); - $def_cat = $catDAO->getDefault(); - $cat_id = $def_cat->id(); + $cat = $catDAO->getDefault(); + $cat_id = $cat->id(); } + $feedDAO = FreshRSS_Factory::createFeedDao(); return $feedDAO->updateFeed($feed_id, array('category' => $cat_id)); } diff --git a/app/Models/CategoryDAO.php b/app/Models/CategoryDAO.php index fc431553e..c103163a1 100644 --- a/app/Models/CategoryDAO.php +++ b/app/Models/CategoryDAO.php @@ -50,6 +50,9 @@ class FreshRSS_CategoryDAO extends Minz_ModelPdo implements FreshRSS_Searchable } public function deleteCategory($id) { + if ($id <= 1) { + return false; + } $sql = 'DELETE FROM `' . $this->prefix . 'category` WHERE id=?'; $stm = $this->bd->prepare($sql); diff --git a/data/users/_/config.default.php b/data/users/_/config.default.php index 2c56d5f45..6e1d497bc 100644 --- a/data/users/_/config.default.php +++ b/data/users/_/config.default.php @@ -5,6 +5,7 @@ return array ( 'old_entries' => 3, 'keep_history_default' => 0, 'ttl_default' => 3600, + 'mail_login' => '', 'token' => '', 'passwordHash' => '', 'apiPasswordHash' => '', diff --git a/p/api/greader.php b/p/api/greader.php index e2d7dc039..8b1e0ffb1 100644 --- a/p/api/greader.php +++ b/p/api/greader.php @@ -222,6 +222,17 @@ function checkToken($conf, $token) { unauthorized(); } +function userInfo() { //https://github.com/theoldreader/api#user-info + //logMe("userInfo()"); + $user = Minz_Session::param('currentUser', '_'); + exit(json_encode(array( + 'userId' => $user, + 'userName' => $user, + 'userProfileId' => $user, + 'userEmail' => FreshRSS_Context::$user_conf->mail_login, + ))); +} + function tagList() { //logMe("tagList()"); header('Content-Type: application/json; charset=UTF-8'); @@ -299,14 +310,24 @@ function subscriptionEdit($streamNames, $titles, $action, $add = '', $remove = ' $categoryDAO = new FreshRSS_CategoryDAO(); } $c_name = ''; - if ($add != '' && strpos($add, 'user/-/label/') === 0) { //user/-/label/Example - $c_name = substr($add, 13); + if ($add != '' && strpos($add, 'user/') === 0) { //user/-/label/Example ; user/username/label/Example + if (strpos($add, 'user/-/label/') === 0) { + $c_name = substr($add, 13); + } else { + $user = Minz_Session::param('currentUser', '_'); + $prefix = 'user/' . $user . '/label/'; + if (strpos($add, $prefix) === 0) { + $c_name = substr($add, strlen($prefix)); + } else { + $c_name = ''; + } + } $cat = $categoryDAO->searchByName($c_name); $addCatId = $cat == null ? -1 : $cat->id(); } else if ($remove != '' && strpos($remove, 'user/-/label/')) { $addCatId = 1; //Default category } - if ($addCatId <= 0 && $c_name = '') { + if ($addCatId <= 0 && $c_name == '') { $addCatId = 1; //Default category } $feedDAO = FreshRSS_Factory::createFeedDao(); @@ -345,9 +366,7 @@ function subscriptionEdit($streamNames, $titles, $action, $add = '', $remove = ' break; case 'edit': if ($feedId > 0) { - if ($addCatId > 0) { - FreshRSS_feed_Controller::moveFeed($feedId, $addCatId); - } + FreshRSS_feed_Controller::moveFeed($feedId, $addCatId, $c_name); if ($title != '') { FreshRSS_feed_Controller::renameFeed($feedId, $title); } @@ -633,8 +652,8 @@ function renameTag($s, $dest) { badRequest(); } -function disableTag($s, $dest) { - //logMe("renameTag()"); +function disableTag($s) { + //logMe("disableTag($s)"); if ($s != '' && strpos($s, 'user/-/label/') === 0) { $s = substr($s, 13); $categoryDAO = new FreshRSS_CategoryDAO(); @@ -642,6 +661,9 @@ function disableTag($s, $dest) { if ($cat != null) { $feedDAO = FreshRSS_Factory::createFeedDao(); $feedDAO->changeCategory($cat->id(), 0); + if ($cat->id() > 1) { + $categoryDAO->deleteCategory($cat->id()); + } exit('OK'); } } @@ -798,8 +820,10 @@ elseif ($pathInfos[1] === 'reader' && $pathInfos[2] === 'api' && isset($pathInfo case 'disable-tag': //https://github.com/theoldreader/api $token = isset($_POST['T']) ? trim($_POST['T']) : ''; checkToken(FreshRSS_Context::$user_conf, $token); - $s = isset($_POST['s']) ? $_POST['s'] : ''; //user/-/label/Folder - disableTag($s); + $s_s = multiplePosts('s'); + foreach ($s_s as $s) { + disableTag($s); //user/-/label/Folder + } break; case 'mark-all-as-read': $token = isset($_POST['T']) ? trim($_POST['T']) : ''; @@ -814,6 +838,9 @@ elseif ($pathInfos[1] === 'reader' && $pathInfos[2] === 'api' && isset($pathInfo case 'token': token(FreshRSS_Context::$user_conf); break; + case 'user-info': + userInfo(); + break; } } elseif ($pathInfos[1] === 'check' && $pathInfos[2] === 'compatibility') { checkCompatibility(); -- cgit v1.2.3 From d5ca360ca967d327a184429a2e37aed196add7a0 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Mon, 26 Sep 2016 15:20:02 +0200 Subject: API fix feed rename https://github.com/FreshRSS/FreshRSS/issues/1254 https://github.com/jangernert/FeedReader/issues/59#issuecomment-249558202 --- app/Controllers/feedController.php | 2 +- p/api/greader.php | 9 ++++----- 2 files changed, 5 insertions(+), 6 deletions(-) (limited to 'app/Controllers') diff --git a/app/Controllers/feedController.php b/app/Controllers/feedController.php index ca7a818c6..c2a22aeb3 100755 --- a/app/Controllers/feedController.php +++ b/app/Controllers/feedController.php @@ -474,7 +474,7 @@ class FreshRSS_feed_Controller extends Minz_ActionController { } public static function moveFeed($feed_id, $cat_id, $new_cat_name = '') { - if ($feed_id <= 0) { + if ($feed_id <= 0 || ($cat_id <= 0 && $new_cat_name == '')) { return false; } diff --git a/p/api/greader.php b/p/api/greader.php index 8b1e0ffb1..4965ffd3b 100644 --- a/p/api/greader.php +++ b/p/api/greader.php @@ -323,13 +323,10 @@ function subscriptionEdit($streamNames, $titles, $action, $add = '', $remove = ' } } $cat = $categoryDAO->searchByName($c_name); - $addCatId = $cat == null ? -1 : $cat->id(); + $addCatId = $cat == null ? 0 : $cat->id(); } else if ($remove != '' && strpos($remove, 'user/-/label/')) { $addCatId = 1; //Default category } - if ($addCatId <= 0 && $c_name == '') { - $addCatId = 1; //Default category - } $feedDAO = FreshRSS_Factory::createFeedDao(); for ($i = count($streamNames) - 1; $i >= 0; $i--) { $streamName = $streamNames[$i]; //feed/http://example.net/sample.xml ; feed/338 @@ -366,7 +363,9 @@ function subscriptionEdit($streamNames, $titles, $action, $add = '', $remove = ' break; case 'edit': if ($feedId > 0) { - FreshRSS_feed_Controller::moveFeed($feedId, $addCatId, $c_name); + if ($addCatId > 0 || $c_name != '') { + FreshRSS_feed_Controller::moveFeed($feedId, $addCatId, $c_name); + } if ($title != '') { FreshRSS_feed_Controller::renameFeed($feedId, $title); } -- cgit v1.2.3 From c4b43316c756c4e8f5b35128e6ab40bc4f724337 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sat, 1 Oct 2016 20:22:34 +0200 Subject: Export files with date --- app/Controllers/importExportController.php | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'app/Controllers') diff --git a/app/Controllers/importExportController.php b/app/Controllers/importExportController.php index 60e467255..9dfc479f0 100644 --- a/app/Controllers/importExportController.php +++ b/app/Controllers/importExportController.php @@ -469,20 +469,21 @@ class FreshRSS_importExport_Controller extends Minz_ActionController { $export_opml = Minz_Request::param('export_opml', false); $export_starred = Minz_Request::param('export_starred', false); $export_feeds = Minz_Request::param('export_feeds', array()); + $day = date('Y-m-d'); $export_files = array(); if ($export_opml) { - $export_files['feeds.opml'] = $this->generateOpml(); + $export_files["feeds_${day}.opml.xml"] = $this->generateOpml(); } if ($export_starred) { - $export_files['starred.json'] = $this->generateEntries('starred'); + $export_files["starred_${day}.json"] = $this->generateEntries('starred'); } foreach ($export_feeds as $feed_id) { $feed = $this->feedDAO->searchById($feed_id); if ($feed) { - $filename = 'feed_' . $feed->category() . '_' + $filename = "feed_${day}_" . $feed->category() . '_' . $feed->id() . '.json'; $export_files[$filename] = $this->generateEntries('feed', $feed); } @@ -579,7 +580,8 @@ class FreshRSS_importExport_Controller extends Minz_ActionController { $zip->close(); header('Content-Type: application/zip'); header('Content-Length: ' . filesize($zip_file)); - header('Content-Disposition: attachment; filename="freshrss_export.zip"'); + $day = date('Y-m-d'); + header('Content-Disposition: attachment; filename="freshrss_' . $day . '_export.zip"'); readfile($zip_file); unlink($zip_file); } @@ -599,9 +601,9 @@ class FreshRSS_importExport_Controller extends Minz_ActionController { $content_type = ''; if ($type === 'opml') { - $content_type = "text/opml"; + $content_type = 'application/xml'; } elseif ($type === 'json_feed' || $type === 'json_starred') { - $content_type = "text/json"; + $content_type = 'application/json'; } header('Content-Type: ' . $content_type . '; charset=utf-8'); -- cgit v1.2.3 From f81c441920d2de087099c85f0119e823d15225c4 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Tue, 4 Oct 2016 21:06:37 +0200 Subject: Fix bug language option for new user https://github.com/FreshRSS/FreshRSS/issues/1273 --- app/Controllers/userController.php | 4 ++-- app/Models/UserDAO.php | 41 +++++++++++++++++++++++--------------- app/views/user/manage.phtml | 4 ++-- 3 files changed, 29 insertions(+), 20 deletions(-) (limited to 'app/Controllers') diff --git a/app/Controllers/userController.php b/app/Controllers/userController.php index 0521bc008..c259ffde9 100644 --- a/app/Controllers/userController.php +++ b/app/Controllers/userController.php @@ -121,7 +121,7 @@ class FreshRSS_user_Controller extends Minz_ActionController { $new_user_language = Minz_Request::param('new_user_language', FreshRSS_Context::$user_conf->language); $languages = Minz_Translate::availableLanguages(); - if (!isset($languages[$new_user_language])) { + if (!in_array($new_user_language, $languages)) { $new_user_language = FreshRSS_Context::$user_conf->language; } @@ -165,7 +165,7 @@ class FreshRSS_user_Controller extends Minz_ActionController { } if ($ok) { $userDAO = new FreshRSS_UserDAO(); - $ok &= $userDAO->createUser($new_user_name); + $ok &= $userDAO->createUser($new_user_name, $new_user_language); } invalidateHttpCache(); diff --git a/app/Models/UserDAO.php b/app/Models/UserDAO.php index e35be848c..597182693 100644 --- a/app/Models/UserDAO.php +++ b/app/Models/UserDAO.php @@ -1,35 +1,44 @@ db; require_once(APP_PATH . '/SQL/install.sql.' . $db['type'] . '.php'); $userPDO = new Minz_ModelPdo($username); - $ok = false; - $bd_prefix_user = $db['prefix'] . $username . '_'; - if (defined('SQL_CREATE_TABLES')) { //E.g. MySQL - $sql = sprintf(SQL_CREATE_TABLES, $bd_prefix_user, _t('gen.short.default_category')); - $stm = $userPDO->bd->prepare($sql); - $ok = $stm && $stm->execute(); - } else { //E.g. SQLite - global $SQL_CREATE_TABLES; - if (is_array($SQL_CREATE_TABLES)) { - $ok = true; - foreach ($SQL_CREATE_TABLES as $instruction) { - $sql = sprintf($instruction, $bd_prefix_user, _t('gen.short.default_category')); - $stm = $userPDO->bd->prepare($sql); - $ok &= ($stm && $stm->execute()); + $currentLanguage = Minz_Translate::language(); + + try { + Minz_Translate::reset($new_user_language); + $ok = false; + $bd_prefix_user = $db['prefix'] . $username . '_'; + if (defined('SQL_CREATE_TABLES')) { //E.g. MySQL + $sql = sprintf(SQL_CREATE_TABLES, $bd_prefix_user, _t('gen.short.default_category')); + $stm = $userPDO->bd->prepare($sql); + $ok = $stm && $stm->execute(); + } else { //E.g. SQLite + global $SQL_CREATE_TABLES; + if (is_array($SQL_CREATE_TABLES)) { + $ok = true; + foreach ($SQL_CREATE_TABLES as $instruction) { + $sql = sprintf($instruction, $bd_prefix_user, _t('gen.short.default_category')); + $stm = $userPDO->bd->prepare($sql); + $ok &= ($stm && $stm->execute()); + } } } + } catch (Exception $e) { + Minz_Log::error('Error while creating user: ' . $e->getMessage()); } + Minz_Translate::reset($currentLanguage); + if ($ok) { return true; } else { $info = empty($stm) ? array(2 => 'syntax error') : $stm->errorInfo(); - Minz_Log::error('SQL error : ' . $info[2]); + Minz_Log::error('SQL error: ' . $info[2]); return false; } } diff --git a/app/views/user/manage.phtml b/app/views/user/manage.phtml index aab3aa4c4..a32247d14 100644 --- a/app/views/user/manage.phtml +++ b/app/views/user/manage.phtml @@ -3,7 +3,7 @@
    -
    + @@ -30,7 +30,7 @@
    - +
    -- cgit v1.2.3 From 05cabe99ae48a187a77e0246dfffc60f2434b5e5 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Wed, 5 Oct 2016 00:39:54 +0200 Subject: Take better advantage of other users refresh --- app/Controllers/feedController.php | 18 ++++++++++++++++-- app/Models/EntryDAO.php | 7 +++++-- app/Models/Feed.php | 4 ++++ app/Models/FeedDAO.php | 8 ++++---- 4 files changed, 29 insertions(+), 8 deletions(-) (limited to 'app/Controllers') diff --git a/app/Controllers/feedController.php b/app/Controllers/feedController.php index c2a22aeb3..15f373833 100755 --- a/app/Controllers/feedController.php +++ b/app/Controllers/feedController.php @@ -242,7 +242,7 @@ class FreshRSS_feed_Controller extends Minz_ActionController { $feeds[] = $feed; } } else { - $feeds = $feedDAO->listFeedsOrderUpdate(FreshRSS_Context::$user_conf->ttl_default); + $feeds = $feedDAO->listFeedsOrderUpdate(-1); } // Calculate date of oldest entries we accept in DB. @@ -266,6 +266,20 @@ class FreshRSS_feed_Controller extends Minz_ActionController { continue; //When PubSubHubbub is used, do not pull refresh so often } + $mtime = 0; + $ttl = $feed->ttl(); + if ($ttl == -1) { + continue; //Feed refresh is disabled + } + if (feed->lastUpdate() < time() - ($ttl == -2 ? FreshRSS_Context::$user_conf->ttl_default : $ttl)) { + //Too early to refresh from source, but check if the feed was already updated by another user + $mtime = feed->cacheModifiedTime(); + if (feed->lastUpdate() >= $mtime + 10) { + continue; //Nothing newer from other users + } + Minz_Log::debug($feed->url() . ' was recently updated by another user'); + } + if (!$feed->lock()) { Minz_Log::notice('Feed already being actualized: ' . $feed->url()); continue; @@ -358,7 +372,7 @@ class FreshRSS_feed_Controller extends Minz_ActionController { $entryDAO->addEntry($entry->toArray()); } } - $entryDAO->updateLastSeen($feed->id(), $oldGuids); + $entryDAO->updateLastSeen($feed->id(), $oldGuids, $mtime); } if ($feed_history >= 0 && rand(0, 30) === 1) { diff --git a/app/Models/EntryDAO.php b/app/Models/EntryDAO.php index 63565e73a..43ac21f9e 100644 --- a/app/Models/EntryDAO.php +++ b/app/Models/EntryDAO.php @@ -707,13 +707,16 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable { } } - public function updateLastSeen($id_feed, $guids) { + public function updateLastSeen($id_feed, $guids, $mtime = 0) { if (count($guids) < 1) { return 0; } $sql = 'UPDATE `' . $this->prefix . 'entry` SET `lastSeen`=? WHERE id_feed=? AND guid IN (' . str_repeat('?,', count($guids) - 1). '?)'; $stm = $this->bd->prepare($sql); - $values = array(time(), $id_feed); + if ($mtime <= 0) { + $mtime = time(); + } + $values = array($mtime, $id_feed); $values = array_merge($values, $guids); if ($stm && $stm->execute($values)) { return $stm->rowCount(); diff --git a/app/Models/Feed.php b/app/Models/Feed.php index f2f345662..f435620c8 100644 --- a/app/Models/Feed.php +++ b/app/Models/Feed.php @@ -340,6 +340,10 @@ class FreshRSS_Feed extends Minz_Model { $this->entries = $entries; } + function cacheModifiedTime() { + return @filemtime(CACHE_PATH . '/' . md5($this->url) . '.spc'); + } + function lock() { $this->lockPath = TMP_PATH . '/' . $this->hash() . '.freshrss.lock'; if (file_exists($this->lockPath) && ((time() - @filemtime($this->lockPath)) > 3600)) { diff --git a/app/Models/FeedDAO.php b/app/Models/FeedDAO.php index 6e6d8857b..ad3cb0c2e 100644 --- a/app/Models/FeedDAO.php +++ b/app/Models/FeedDAO.php @@ -222,13 +222,13 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo implements FreshRSS_Searchable { return $feedCategoryNames; } + /** + * Use $defaultCacheDuration == -1 to return all feeds, without filtering them by TTL. + */ public function listFeedsOrderUpdate($defaultCacheDuration = 3600) { - if ($defaultCacheDuration < 0) { - $defaultCacheDuration = 2147483647; - } $sql = 'SELECT id, url, name, website, `lastUpdate`, `pathEntries`, `httpAuth`, keep_history, ttl ' . 'FROM `' . $this->prefix . 'feed` ' - . 'WHERE ttl <> -1 AND `lastUpdate` < (' . (time() + 60) . '-(CASE WHEN ttl=-2 THEN ' . intval($defaultCacheDuration) . ' ELSE ttl END)) ' + . ($defaultCacheDuration < 0 ? '' : 'WHERE ttl <> -1 AND `lastUpdate` < (' . (time() + 60) . '-(CASE WHEN ttl=-2 THEN ' . intval($defaultCacheDuration) . ' ELSE ttl END)) ') . 'ORDER BY `lastUpdate`'; $stm = $this->bd->prepare($sql); if (!($stm && $stm->execute())) { -- cgit v1.2.3 From 9e34d7275eb936e1a08b872aca7adbce5a5674c5 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Wed, 5 Oct 2016 00:44:14 +0200 Subject: Typo --- app/Controllers/feedController.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'app/Controllers') diff --git a/app/Controllers/feedController.php b/app/Controllers/feedController.php index 15f373833..d85a53446 100755 --- a/app/Controllers/feedController.php +++ b/app/Controllers/feedController.php @@ -271,10 +271,10 @@ class FreshRSS_feed_Controller extends Minz_ActionController { if ($ttl == -1) { continue; //Feed refresh is disabled } - if (feed->lastUpdate() < time() - ($ttl == -2 ? FreshRSS_Context::$user_conf->ttl_default : $ttl)) { - //Too early to refresh from source, but check if the feed was already updated by another user - $mtime = feed->cacheModifiedTime(); - if (feed->lastUpdate() >= $mtime + 10) { + if ($feed->lastUpdate() < time() + 60 - ($ttl == -2 ? FreshRSS_Context::$user_conf->ttl_default : $ttl)) { + //Too early to refresh from source, but check whether the feed was updated by another user + $mtime = $feed->cacheModifiedTime(); + if ($feed->lastUpdate() >= $mtime + 10) { continue; //Nothing newer from other users } Minz_Log::debug($feed->url() . ' was recently updated by another user'); -- cgit v1.2.3 From fe65eec5bbdaee37177e3673e31e241b1f1b938d Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Wed, 5 Oct 2016 17:48:24 +0200 Subject: Better multiuser update --- app/Controllers/feedController.php | 9 +++++---- app/Models/FeedDAO.php | 10 +++++++--- 2 files changed, 12 insertions(+), 7 deletions(-) (limited to 'app/Controllers') diff --git a/app/Controllers/feedController.php b/app/Controllers/feedController.php index d85a53446..dadc8aa83 100755 --- a/app/Controllers/feedController.php +++ b/app/Controllers/feedController.php @@ -271,13 +271,14 @@ class FreshRSS_feed_Controller extends Minz_ActionController { if ($ttl == -1) { continue; //Feed refresh is disabled } - if ($feed->lastUpdate() < time() + 60 - ($ttl == -2 ? FreshRSS_Context::$user_conf->ttl_default : $ttl)) { + if ($feed->lastUpdate() + 10 >= time() - ($ttl == -2 ? FreshRSS_Context::$user_conf->ttl_default : $ttl)) { //Too early to refresh from source, but check whether the feed was updated by another user $mtime = $feed->cacheModifiedTime(); - if ($feed->lastUpdate() >= $mtime + 10) { + if ($feed->lastUpdate() + 10 >= $mtime) { continue; //Nothing newer from other users } - Minz_Log::debug($feed->url() . ' was recently updated by another user'); + //Minz_Log::debug($feed->url() . ' was updated at ' . date('c', $mtime) . ' by another user'); + //Will take advantage of the newer cache } if (!$feed->lock()) { @@ -391,7 +392,7 @@ class FreshRSS_feed_Controller extends Minz_ActionController { } } - $feedDAO->updateLastUpdate($feed->id(), 0, $entryDAO->inTransaction()); + $feedDAO->updateLastUpdate($feed->id(), false, $entryDAO->inTransaction(), $mtime); if ($entryDAO->inTransaction()) { $entryDAO->commit(); } diff --git a/app/Models/FeedDAO.php b/app/Models/FeedDAO.php index ad3cb0c2e..c680d270c 100644 --- a/app/Models/FeedDAO.php +++ b/app/Models/FeedDAO.php @@ -82,7 +82,7 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo implements FreshRSS_Searchable { } } - public function updateLastUpdate($id, $inError = 0, $updateCache = true) { + public function updateLastUpdate($id, $inError = false, $updateCache = true, $mtime = 0) { if ($updateCache) { $sql = 'UPDATE `' . $this->prefix . 'feed` ' //2 sub-requests with FOREIGN KEY(e.id_feed), INDEX(e.is_read) faster than 1 request with GROUP BY or CASE . 'SET `cache_nbEntries`=(SELECT COUNT(e1.id) FROM `' . $this->prefix . 'entry` e1 WHERE e1.id_feed=`' . $this->prefix . 'feed`.id),' @@ -95,9 +95,13 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo implements FreshRSS_Searchable { . 'WHERE id=?'; } + if ($mtime <= 0) { + $mtime = time(); + } + $values = array( - time(), - $inError, + $mtime, + $inError ? 1 : 0, $id, ); -- cgit v1.2.3 From ca4dcca5b20c3e2e6da1293746cd46674d97c710 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Fri, 7 Oct 2016 21:46:48 +0200 Subject: PSHB bugs Introduced by https://github.com/FreshRSS/FreshRSS/pull/1280 --- app/Controllers/feedController.php | 3 ++- p/api/pshb.php | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) (limited to 'app/Controllers') diff --git a/app/Controllers/feedController.php b/app/Controllers/feedController.php index dadc8aa83..8751d2fff 100755 --- a/app/Controllers/feedController.php +++ b/app/Controllers/feedController.php @@ -271,7 +271,8 @@ class FreshRSS_feed_Controller extends Minz_ActionController { if ($ttl == -1) { continue; //Feed refresh is disabled } - if ($feed->lastUpdate() + 10 >= time() - ($ttl == -2 ? FreshRSS_Context::$user_conf->ttl_default : $ttl)) { + if ((!$simplePiePush) && (!$feed_id) && + ($feed->lastUpdate() + 10 >= time() - ($ttl == -2 ? FreshRSS_Context::$user_conf->ttl_default : $ttl))) { //Too early to refresh from source, but check whether the feed was updated by another user $mtime = $feed->cacheModifiedTime(); if ($feed->lastUpdate() + 10 >= $mtime) { diff --git a/p/api/pshb.php b/p/api/pshb.php index 94a0068ed..e9b66b167 100644 --- a/p/api/pshb.php +++ b/p/api/pshb.php @@ -116,6 +116,7 @@ foreach ($users as $userFilename) { Minz_Configuration::register('user', join_path(USERS_PATH, $username, 'config.php'), join_path(USERS_PATH, '_', 'config.default.php')); + new Minz_ModelPdo($username); //TODO: FIXME: Quick-fix while waiting for a better FreshRSS() constructor/init FreshRSS_Context::init(); list($updated_feeds, $feed) = FreshRSS_feed_Controller::actualizeFeed(0, $self, false, $simplePie); if ($updated_feeds > 0) { -- cgit v1.2.3 From cbb6c26db79b5a74e588110d2cf8fc8cf9137ab8 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Mon, 10 Oct 2016 22:07:58 +0200 Subject: Fix share POST https://github.com/FreshRSS/FreshRSS/issues/1289 --- app/Controllers/configureController.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'app/Controllers') diff --git a/app/Controllers/configureController.php b/app/Controllers/configureController.php index 147a2fe06..e73f106a6 100755 --- a/app/Controllers/configureController.php +++ b/app/Controllers/configureController.php @@ -139,7 +139,7 @@ class FreshRSS_configure_Controller extends Minz_ActionController { */ public function sharingAction() { if (Minz_Request::isPost()) { - $params = Minz_Request::fetchGET(); + $params = Minz_Request::fetchPOST(); FreshRSS_Context::$user_conf->sharing = $params['share']; FreshRSS_Context::$user_conf->save(); invalidateHttpCache(); -- cgit v1.2.3 From a0127d980c37b69c48db6982733fac60eaf8601c Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sat, 15 Oct 2016 01:27:39 +0200 Subject: Fix bug JSON import duplicates https://github.com/FreshRSS/FreshRSS/issues/1312 --- app/Controllers/importExportController.php | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) (limited to 'app/Controllers') diff --git a/app/Controllers/importExportController.php b/app/Controllers/importExportController.php index 9dfc479f0..c2e68f465 100644 --- a/app/Controllers/importExportController.php +++ b/app/Controllers/importExportController.php @@ -360,6 +360,14 @@ class FreshRSS_importExport_Controller extends Minz_ActionController { } } + $newGuids = array(); + foreach ($article_object['items'] as $item) { + $newGuids[] = $item['id']; + } + // For this feed, check existing GUIDs already in database. + $existingHashForGuids = $entryDAO->listHashForFeedGuids($feed->id(), $newGuids); + unset($newGuids); + // Then, articles are imported. $this->entryDAO->beginTransaction(); foreach ($article_object['items'] as $item) { @@ -395,7 +403,11 @@ class FreshRSS_importExport_Controller extends Minz_ActionController { } $values = $entry->toArray(); - $id = $this->entryDAO->addEntry($values); + if (isset($existingHashForGuids[$entry->guid()])) { + $id = $this->entryDAO->updateEntry($values); + } else { + $id = $this->entryDAO->addEntry($values); + } if (!$error && ($id === false)) { $error = true; -- cgit v1.2.3 From 50f1e027e3e3a77abf367f9d4559b51573b1b295 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sat, 15 Oct 2016 14:18:23 +0200 Subject: Fix import bug --- app/Controllers/importExportController.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'app/Controllers') diff --git a/app/Controllers/importExportController.php b/app/Controllers/importExportController.php index c2e68f465..d36c57deb 100644 --- a/app/Controllers/importExportController.php +++ b/app/Controllers/importExportController.php @@ -365,7 +365,7 @@ class FreshRSS_importExport_Controller extends Minz_ActionController { $newGuids[] = $item['id']; } // For this feed, check existing GUIDs already in database. - $existingHashForGuids = $entryDAO->listHashForFeedGuids($feed->id(), $newGuids); + $existingHashForGuids = $this->entryDAO->listHashForFeedGuids($feed->id(), $newGuids); unset($newGuids); // Then, articles are imported. -- cgit v1.2.3 From 56f66f4b6168276ca449d18a440b6958c6817088 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sat, 15 Oct 2016 14:58:40 +0200 Subject: Remove superflous category request A category request was systematically done, although it is not always needed. --- app/Controllers/indexController.php | 5 +++++ app/Models/Context.php | 15 +++++++++++---- 2 files changed, 16 insertions(+), 4 deletions(-) (limited to 'app/Controllers') diff --git a/app/Controllers/indexController.php b/app/Controllers/indexController.php index 4e2717920..5ca147ff3 100755 --- a/app/Controllers/indexController.php +++ b/app/Controllers/indexController.php @@ -159,6 +159,11 @@ class FreshRSS_index_Controller extends Minz_ActionController { * - hours (default: 0) */ private function updateContext() { + if (empty(FreshRSS_Context::$categories)) { + $catDAO = new FreshRSS_CategoryDAO(); + FreshRSS_Context::$categories = $catDAO->listCategories(); + } + // Update number of read / unread variables. $entryDAO = FreshRSS_Factory::createEntryDao(); FreshRSS_Context::$total_starred = $entryDAO->countUnreadReadFavorites(); diff --git a/app/Models/Context.php b/app/Models/Context.php index 889ddab1e..fe4fa6281 100644 --- a/app/Models/Context.php +++ b/app/Models/Context.php @@ -48,9 +48,6 @@ class FreshRSS_Context { // Init configuration. self::$system_conf = Minz_Configuration::get('system'); self::$user_conf = Minz_Configuration::get('user'); - - $catDAO = new FreshRSS_CategoryDAO(); - self::$categories = $catDAO->listCategories(); } /** @@ -142,6 +139,11 @@ class FreshRSS_Context { $id = substr($get, 2); $nb_unread = 0; + if (empty(self::$categories)) { + $catDAO = new FreshRSS_CategoryDAO(); + self::$categories = $catDAO->listCategories(); + } + switch($type) { case 'a': self::$current_get['all'] = true; @@ -203,11 +205,16 @@ class FreshRSS_Context { /** * Set the value of $next_get attribute. */ - public static function _nextGet() { + private static function _nextGet() { $get = self::currentGet(); // By default, $next_get == $get self::$next_get = $get; + if (empty(self::$categories)) { + $catDAO = new FreshRSS_CategoryDAO(); + self::$categories = $catDAO->listCategories(); + } + if (self::$user_conf->onread_jump_next && strlen($get) > 2) { $another_unread_id = ''; $found_current_get = false; -- cgit v1.2.3 From 1893fc61e0e576519f878267fd877247445d1055 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Thu, 20 Oct 2016 01:19:59 +0200 Subject: guid and urls should not contain low/high characters It looks like SimplePie does not always filter everything Having a character not in latin1 would create MySQL collate errors --- app/Controllers/feedController.php | 4 +++- app/Controllers/importExportController.php | 4 +++- app/Models/EntryDAO.php | 4 ++++ app/Models/FeedDAO.php | 10 ++++++++++ 4 files changed, 20 insertions(+), 2 deletions(-) (limited to 'app/Controllers') diff --git a/app/Controllers/feedController.php b/app/Controllers/feedController.php index 8751d2fff..d4a6c9955 100755 --- a/app/Controllers/feedController.php +++ b/app/Controllers/feedController.php @@ -314,7 +314,9 @@ class FreshRSS_feed_Controller extends Minz_ActionController { if (count($entries) > 0) { $newGuids = array(); foreach ($entries as $entry) { - $newGuids[] = $entry->guid(); + $guid = $entry->guid(); + $guid = filter_var($guid, FILTER_DEFAULT, FILTER_FLAG_STRIP_LOW | FILTER_FLAG_STRIP_HIGH); + $newGuids[] = $guid; } // For this feed, check existing GUIDs already in database. $existingHashForGuids = $entryDAO->listHashForFeedGuids($feed->id(), $newGuids); diff --git a/app/Controllers/importExportController.php b/app/Controllers/importExportController.php index d36c57deb..e380323c4 100644 --- a/app/Controllers/importExportController.php +++ b/app/Controllers/importExportController.php @@ -362,7 +362,9 @@ class FreshRSS_importExport_Controller extends Minz_ActionController { $newGuids = array(); foreach ($article_object['items'] as $item) { - $newGuids[] = $item['id']; + $guid = $item['id']; + $guid = filter_var($guid, FILTER_DEFAULT, FILTER_FLAG_STRIP_LOW | FILTER_FLAG_STRIP_HIGH); + $newGuids[] = $guid; } // For this feed, check existing GUIDs already in database. $existingHashForGuids = $this->entryDAO->listHashForFeedGuids($feed->id(), $newGuids); diff --git a/app/Models/EntryDAO.php b/app/Models/EntryDAO.php index 3959cb191..466e6f5a3 100644 --- a/app/Models/EntryDAO.php +++ b/app/Models/EntryDAO.php @@ -123,6 +123,7 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable { } $this->addEntryPrepared->bindParam(':id', $valuesTmp['id']); $valuesTmp['guid'] = substr($valuesTmp['guid'], 0, 760); + $valuesTmp['guid'] = filter_var($valuesTmp['guid'], FILTER_DEFAULT, FILTER_FLAG_STRIP_LOW | FILTER_FLAG_STRIP_HIGH); $this->addEntryPrepared->bindParam(':guid', $valuesTmp['guid']); $valuesTmp['title'] = substr($valuesTmp['title'], 0, 255); $this->addEntryPrepared->bindParam(':title', $valuesTmp['title']); @@ -130,6 +131,7 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable { $this->addEntryPrepared->bindParam(':author', $valuesTmp['author']); $this->addEntryPrepared->bindParam(':content', $valuesTmp['content']); $valuesTmp['link'] = substr($valuesTmp['link'], 0, 1023); + $valuesTmp['link'] = filter_var($valuesTmp['link'], FILTER_DEFAULT, FILTER_FLAG_STRIP_LOW | FILTER_FLAG_STRIP_HIGH); $this->addEntryPrepared->bindParam(':link', $valuesTmp['link']); $this->addEntryPrepared->bindParam(':date', $valuesTmp['date'], PDO::PARAM_INT); $valuesTmp['lastSeen'] = time(); @@ -190,6 +192,7 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable { $this->updateEntryPrepared->bindParam(':author', $valuesTmp['author']); $this->updateEntryPrepared->bindParam(':content', $valuesTmp['content']); $valuesTmp['link'] = substr($valuesTmp['link'], 0, 1023); + $valuesTmp['link'] = filter_var($valuesTmp['link'], FILTER_DEFAULT, FILTER_FLAG_STRIP_LOW | FILTER_FLAG_STRIP_HIGH); $this->updateEntryPrepared->bindParam(':link', $valuesTmp['link']); $this->updateEntryPrepared->bindParam(':date', $valuesTmp['date'], PDO::PARAM_INT); $valuesTmp['lastSeen'] = time(); @@ -689,6 +692,7 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable { if (count($guids) < 1) { return array(); } + $guids = array_unique($guids); $sql = 'SELECT guid, ' . $this->sqlHexEncode('hash') . ' AS hex_hash FROM `' . $this->prefix . 'entry` WHERE id_feed=? AND guid IN (' . str_repeat('?,', count($guids) - 1). '?)'; $stm = $this->bd->prepare($sql); $values = array($id_feed); diff --git a/app/Models/FeedDAO.php b/app/Models/FeedDAO.php index c680d270c..33e19d750 100644 --- a/app/Models/FeedDAO.php +++ b/app/Models/FeedDAO.php @@ -5,6 +5,9 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo implements FreshRSS_Searchable { $sql = 'INSERT INTO `' . $this->prefix . 'feed` (url, category, name, website, description, `lastUpdate`, priority, `httpAuth`, error, keep_history, ttl) VALUES(?, ?, ?, ?, ?, ?, 10, ?, 0, -2, -2)'; $stm = $this->bd->prepare($sql); + $valuesTmp['url'] = filter_var($valuesTmp['url'], FILTER_DEFAULT, FILTER_FLAG_STRIP_LOW | FILTER_FLAG_STRIP_HIGH); + $valuesTmp['website'] = filter_var($valuesTmp['website'], FILTER_DEFAULT, FILTER_FLAG_STRIP_LOW | FILTER_FLAG_STRIP_HIGH); + $values = array( substr($valuesTmp['url'], 0, 511), $valuesTmp['category'], @@ -55,6 +58,13 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo implements FreshRSS_Searchable { } public function updateFeed($id, $valuesTmp) { + if (isset($valuesTmp['url'])) { + $valuesTmp['url'] = filter_var($valuesTmp['url'], FILTER_DEFAULT, FILTER_FLAG_STRIP_LOW | FILTER_FLAG_STRIP_HIGH); + } + if (isset($valuesTmp['website'])) { + $valuesTmp['website'] = filter_var($valuesTmp['website'], FILTER_DEFAULT, FILTER_FLAG_STRIP_LOW | FILTER_FLAG_STRIP_HIGH); + } + $set = ''; foreach ($valuesTmp as $key => $v) { $set .= $key . '=?, '; -- cgit v1.2.3 From 7f2b0439ec4158ee7d78571d60e9bcc995e87cac Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Thu, 20 Oct 2016 01:38:23 +0200 Subject: Extract function safe_ascii() --- app/Controllers/feedController.php | 4 +--- app/Controllers/importExportController.php | 4 +--- app/Models/EntryDAO.php | 6 +++--- app/Models/FeedDAO.php | 8 ++++---- lib/lib_rss.php | 3 +++ 5 files changed, 12 insertions(+), 13 deletions(-) (limited to 'app/Controllers') diff --git a/app/Controllers/feedController.php b/app/Controllers/feedController.php index d4a6c9955..ed3229687 100755 --- a/app/Controllers/feedController.php +++ b/app/Controllers/feedController.php @@ -314,9 +314,7 @@ class FreshRSS_feed_Controller extends Minz_ActionController { if (count($entries) > 0) { $newGuids = array(); foreach ($entries as $entry) { - $guid = $entry->guid(); - $guid = filter_var($guid, FILTER_DEFAULT, FILTER_FLAG_STRIP_LOW | FILTER_FLAG_STRIP_HIGH); - $newGuids[] = $guid; + $newGuids[] = safe_ascii($entry->guid()); } // For this feed, check existing GUIDs already in database. $existingHashForGuids = $entryDAO->listHashForFeedGuids($feed->id(), $newGuids); diff --git a/app/Controllers/importExportController.php b/app/Controllers/importExportController.php index e380323c4..a1f789805 100644 --- a/app/Controllers/importExportController.php +++ b/app/Controllers/importExportController.php @@ -362,9 +362,7 @@ class FreshRSS_importExport_Controller extends Minz_ActionController { $newGuids = array(); foreach ($article_object['items'] as $item) { - $guid = $item['id']; - $guid = filter_var($guid, FILTER_DEFAULT, FILTER_FLAG_STRIP_LOW | FILTER_FLAG_STRIP_HIGH); - $newGuids[] = $guid; + $newGuids[] = safe_ascii($item['id']); } // For this feed, check existing GUIDs already in database. $existingHashForGuids = $this->entryDAO->listHashForFeedGuids($feed->id(), $newGuids); diff --git a/app/Models/EntryDAO.php b/app/Models/EntryDAO.php index 466e6f5a3..4c6a9ea20 100644 --- a/app/Models/EntryDAO.php +++ b/app/Models/EntryDAO.php @@ -123,7 +123,7 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable { } $this->addEntryPrepared->bindParam(':id', $valuesTmp['id']); $valuesTmp['guid'] = substr($valuesTmp['guid'], 0, 760); - $valuesTmp['guid'] = filter_var($valuesTmp['guid'], FILTER_DEFAULT, FILTER_FLAG_STRIP_LOW | FILTER_FLAG_STRIP_HIGH); + $valuesTmp['guid'] = safe_ascii($valuesTmp['guid']); $this->addEntryPrepared->bindParam(':guid', $valuesTmp['guid']); $valuesTmp['title'] = substr($valuesTmp['title'], 0, 255); $this->addEntryPrepared->bindParam(':title', $valuesTmp['title']); @@ -131,7 +131,7 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable { $this->addEntryPrepared->bindParam(':author', $valuesTmp['author']); $this->addEntryPrepared->bindParam(':content', $valuesTmp['content']); $valuesTmp['link'] = substr($valuesTmp['link'], 0, 1023); - $valuesTmp['link'] = filter_var($valuesTmp['link'], FILTER_DEFAULT, FILTER_FLAG_STRIP_LOW | FILTER_FLAG_STRIP_HIGH); + $valuesTmp['link'] = safe_ascii($valuesTmp['link']); $this->addEntryPrepared->bindParam(':link', $valuesTmp['link']); $this->addEntryPrepared->bindParam(':date', $valuesTmp['date'], PDO::PARAM_INT); $valuesTmp['lastSeen'] = time(); @@ -192,7 +192,7 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable { $this->updateEntryPrepared->bindParam(':author', $valuesTmp['author']); $this->updateEntryPrepared->bindParam(':content', $valuesTmp['content']); $valuesTmp['link'] = substr($valuesTmp['link'], 0, 1023); - $valuesTmp['link'] = filter_var($valuesTmp['link'], FILTER_DEFAULT, FILTER_FLAG_STRIP_LOW | FILTER_FLAG_STRIP_HIGH); + $valuesTmp['link'] = safe_ascii($valuesTmp['link']); $this->updateEntryPrepared->bindParam(':link', $valuesTmp['link']); $this->updateEntryPrepared->bindParam(':date', $valuesTmp['date'], PDO::PARAM_INT); $valuesTmp['lastSeen'] = time(); diff --git a/app/Models/FeedDAO.php b/app/Models/FeedDAO.php index 33e19d750..b21f19b66 100644 --- a/app/Models/FeedDAO.php +++ b/app/Models/FeedDAO.php @@ -5,8 +5,8 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo implements FreshRSS_Searchable { $sql = 'INSERT INTO `' . $this->prefix . 'feed` (url, category, name, website, description, `lastUpdate`, priority, `httpAuth`, error, keep_history, ttl) VALUES(?, ?, ?, ?, ?, ?, 10, ?, 0, -2, -2)'; $stm = $this->bd->prepare($sql); - $valuesTmp['url'] = filter_var($valuesTmp['url'], FILTER_DEFAULT, FILTER_FLAG_STRIP_LOW | FILTER_FLAG_STRIP_HIGH); - $valuesTmp['website'] = filter_var($valuesTmp['website'], FILTER_DEFAULT, FILTER_FLAG_STRIP_LOW | FILTER_FLAG_STRIP_HIGH); + $valuesTmp['url'] = safe_ascii($valuesTmp['url']); + $valuesTmp['website'] = safe_ascii($valuesTmp['website']); $values = array( substr($valuesTmp['url'], 0, 511), @@ -59,10 +59,10 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo implements FreshRSS_Searchable { public function updateFeed($id, $valuesTmp) { if (isset($valuesTmp['url'])) { - $valuesTmp['url'] = filter_var($valuesTmp['url'], FILTER_DEFAULT, FILTER_FLAG_STRIP_LOW | FILTER_FLAG_STRIP_HIGH); + $valuesTmp['url'] = safe_ascii($valuesTmp['url']); } if (isset($valuesTmp['website'])) { - $valuesTmp['website'] = filter_var($valuesTmp['website'], FILTER_DEFAULT, FILTER_FLAG_STRIP_LOW | FILTER_FLAG_STRIP_HIGH); + $valuesTmp['website'] = safe_ascii($valuesTmp['website']); } $set = ''; diff --git a/lib/lib_rss.php b/lib/lib_rss.php index b18512484..75046fd54 100644 --- a/lib/lib_rss.php +++ b/lib/lib_rss.php @@ -83,6 +83,9 @@ function checkUrl($url) { } } +function safe_ascii($text) { + return filter_var($text, FILTER_DEFAULT, FILTER_FLAG_STRIP_LOW | FILTER_FLAG_STRIP_HIGH); +} /** * Test if a given server address is publicly accessible. -- cgit v1.2.3 From e1f214e9e2e09a83a9920e33fbf617dfe48fbb7e Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sat, 22 Oct 2016 12:58:06 +0200 Subject: CLI list-users and create-user https://github.com/FreshRSS/FreshRSS/issues/1095 https://github.com/FreshRSS/FreshRSS/issues/1090 --- app/Controllers/userController.php | 125 +++++++++++++++++++------------------ app/Models/Context.php | 2 +- app/Models/Feed.php | 2 +- app/actualize_script.php | 4 +- cli/.htaccess | 3 + cli/_cli.php | 39 ++++++++++++ cli/create-user.php | 41 ++++++++++++ cli/index.html | 13 ++++ cli/list-users.php | 14 +++++ lib/lib_rss.php | 9 ++- 10 files changed, 184 insertions(+), 68 deletions(-) create mode 100644 cli/.htaccess create mode 100644 cli/_cli.php create mode 100644 cli/create-user.php create mode 100644 cli/index.html create mode 100644 cli/list-users.php (limited to 'app/Controllers') diff --git a/app/Controllers/userController.php b/app/Controllers/userController.php index c259ffde9..f880b951d 100644 --- a/app/Controllers/userController.php +++ b/app/Controllers/userController.php @@ -24,6 +24,16 @@ class FreshRSS_user_Controller extends Minz_ActionController { } } + private static function hashPassword($passwordPlain) { + if (!function_exists('password_hash')) { + include_once(LIB_PATH . '/password_compat.php'); + } + $passwordHash = password_hash($passwordPlain, PASSWORD_BCRYPT, array('cost' => self::BCRYPT_COST)); + $passwordPlain = ''; + $passwordHash = preg_replace('/^\$2[xy]\$/', '\$2a\$', $passwordHash); //Compatibility with bcrypt.js + return $passwordHash == '' ? '' : $passwordHash; + } + /** * This action displays the user profile page. */ @@ -41,12 +51,7 @@ class FreshRSS_user_Controller extends Minz_ActionController { if ($passwordPlain != '') { Minz_Request::_param('newPasswordPlain'); //Discard plain-text password ASAP $_POST['newPasswordPlain'] = ''; - if (!function_exists('password_hash')) { - include_once(LIB_PATH . '/password_compat.php'); - } - $passwordHash = password_hash($passwordPlain, PASSWORD_BCRYPT, array('cost' => self::BCRYPT_COST)); - $passwordPlain = ''; - $passwordHash = preg_replace('/^\$2[xy]\$/', '\$2a\$', $passwordHash); //Compatibility with bcrypt.js + $passwordHash = self::hashPassword($passwordPlain); $ok &= ($passwordHash != ''); FreshRSS_Context::$user_conf->passwordHash = $passwordHash; } @@ -54,12 +59,7 @@ class FreshRSS_user_Controller extends Minz_ActionController { $passwordPlain = Minz_Request::param('apiPasswordPlain', '', true); if ($passwordPlain != '') { - if (!function_exists('password_hash')) { - include_once(LIB_PATH . '/password_compat.php'); - } - $passwordHash = password_hash($passwordPlain, PASSWORD_BCRYPT, array('cost' => self::BCRYPT_COST)); - $passwordPlain = ''; - $passwordHash = preg_replace('/^\$2[xy]\$/', '\$2a\$', $passwordHash); //Compatibility with bcrypt.js + $passwordHash = self::hashPassword($passwordPlain); $ok &= ($passwordHash != ''); FreshRSS_Context::$user_conf->apiPasswordHash = $passwordHash; } @@ -99,6 +99,53 @@ class FreshRSS_user_Controller extends Minz_ActionController { $this->view->size_user = $entryDAO->size(); } + public static function createUser($new_user_name, $passwordPlain, $apiPasswordPlain, $userConfig = array()) { + if (!is_array($userConfig)) { + $userConfig = array(); + } + + $ok = ($new_user_name != '') && ctype_alnum($new_user_name); + + if ($ok) { + $languages = Minz_Translate::availableLanguages(); + if (empty($userConfig['language']) || !in_array($userConfig['language'], $languages)) { + $userConfig['language'] = 'en'; + } + + $default_user = FreshRSS_Context::$system_conf->default_user; + $ok &= (strcasecmp($new_user_name, $default_user) !== 0); //It is forbidden to alter the default user + + $ok &= !in_array(strtoupper($new_user_name), array_map('strtoupper', listUsers())); //Not an existing user, case-insensitive + + $configPath = join_path(DATA_PATH, 'users', $new_user_name, 'config.php'); + $ok &= !file_exists($configPath); + } + if ($ok) { + $passwordHash = ''; + if ($passwordPlain != '') { + $passwordHash = self::hashPassword($passwordPlain); + $ok &= ($passwordHash != ''); + } + + $apiPasswordHash = ''; + if ($apiPasswordPlain != '') { + $apiPasswordHash = self::hashPassword($apiPasswordPlain); + $ok &= ($apiPasswordHash != ''); + } + } + if ($ok) { + mkdir(join_path(DATA_PATH, 'users', $new_user_name)); + $userConfig['passwordHash'] = $passwordHash; + $userConfig['apiPasswordHash'] = $apiPasswordHash; + $ok &= (file_put_contents($configPath, "createUser($new_user_name, $userConfig['language']); + } + return $ok; + } + /** * This action creates a new user. * @@ -116,57 +163,13 @@ class FreshRSS_user_Controller extends Minz_ActionController { FreshRSS_Auth::hasAccess('admin') || !max_registrations_reached() )) { - $db = FreshRSS_Context::$system_conf->db; - require_once(APP_PATH . '/SQL/install.sql.' . $db['type'] . '.php'); - - $new_user_language = Minz_Request::param('new_user_language', FreshRSS_Context::$user_conf->language); - $languages = Minz_Translate::availableLanguages(); - if (!in_array($new_user_language, $languages)) { - $new_user_language = FreshRSS_Context::$user_conf->language; - } - $new_user_name = Minz_Request::param('new_user_name'); - $ok = ($new_user_name != '') && ctype_alnum($new_user_name); - - if ($ok) { - $default_user = FreshRSS_Context::$system_conf->default_user; - $ok &= (strcasecmp($new_user_name, $default_user) !== 0); //It is forbidden to alter the default user - - $ok &= !in_array(strtoupper($new_user_name), array_map('strtoupper', listUsers())); //Not an existing user, case-insensitive + $passwordPlain = Minz_Request::param('new_user_passwordPlain', '', true); + $new_user_language = Minz_Request::param('new_user_language', FreshRSS_Context::$user_conf->language); - $configPath = join_path(DATA_PATH, 'users', $new_user_name, 'config.php'); - $ok &= !file_exists($configPath); - } - if ($ok) { - $passwordPlain = Minz_Request::param('new_user_passwordPlain', '', true); - $passwordHash = ''; - if ($passwordPlain != '') { - Minz_Request::_param('new_user_passwordPlain'); //Discard plain-text password ASAP - $_POST['new_user_passwordPlain'] = ''; - if (!function_exists('password_hash')) { - include_once(LIB_PATH . '/password_compat.php'); - } - $passwordHash = password_hash($passwordPlain, PASSWORD_BCRYPT, array('cost' => self::BCRYPT_COST)); - $passwordPlain = ''; - $passwordHash = preg_replace('/^\$2[xy]\$/', '\$2a\$', $passwordHash); //Compatibility with bcrypt.js - $ok &= ($passwordHash != ''); - } - if (empty($passwordHash)) { - $passwordHash = ''; - } - } - if ($ok) { - mkdir(join_path(DATA_PATH, 'users', $new_user_name)); - $config_array = array( - 'language' => $new_user_language, - 'passwordHash' => $passwordHash, - ); - $ok &= (file_put_contents($configPath, "createUser($new_user_name, $new_user_language); - } + $ok = self::createUser($new_user_name, $passwordPlain, '', array('language' => $new_user_language)); + Minz_Request::_param('new_user_passwordPlain'); //Discard plain-text password ASAP + $_POST['new_user_passwordPlain'] = ''; invalidateHttpCache(); $notif = array( diff --git a/app/Models/Context.php b/app/Models/Context.php index fe4fa6281..fd0e79fc1 100644 --- a/app/Models/Context.php +++ b/app/Models/Context.php @@ -37,7 +37,7 @@ class FreshRSS_Context { public static $id_max = ''; public static $sinceHours = 0; - public static $isCron = false; + public static $isCli = false; /** * Initialize the context. diff --git a/app/Models/Feed.php b/app/Models/Feed.php index 55c2db4d6..97cb1c47e 100644 --- a/app/Models/Feed.php +++ b/app/Models/Feed.php @@ -141,7 +141,7 @@ class FreshRSS_Feed extends Minz_Model { if (!file_exists($txt)) { file_put_contents($txt, $url); } - if (FreshRSS_Context::$isCron) { + if (FreshRSS_Context::$isCli) { $ico = $favicons_dir . $this->hash() . '.ico'; $ico_mtime = @filemtime($ico); $txt_mtime = @filemtime($txt); diff --git a/app/actualize_script.php b/app/actualize_script.php index 78712d721..deaa1bf7c 100755 --- a/app/actualize_script.php +++ b/app/actualize_script.php @@ -28,13 +28,13 @@ $app = new FreshRSS(); $system_conf = Minz_Configuration::get('system'); $system_conf->auth_type = 'none'; // avoid necessity to be logged in (not saved!) -FreshRSS_Context::$isCron = true; +FreshRSS_Context::$isCli = true; // Create the list of users to actualize. // Users are processed in a random order but always start with admin $users = listUsers(); shuffle($users); -if ($system_conf->default_user !== ''){ +if ($system_conf->default_user !== '') { array_unshift($users, $system_conf->default_user); $users = array_unique($users); } diff --git a/cli/.htaccess b/cli/.htaccess new file mode 100644 index 000000000..9e768397d --- /dev/null +++ b/cli/.htaccess @@ -0,0 +1,3 @@ +Order Allow,Deny +Deny from all +Satisfy all diff --git a/cli/_cli.php b/cli/_cli.php new file mode 100644 index 000000000..cb6d8ec32 --- /dev/null +++ b/cli/_cli.php @@ -0,0 +1,39 @@ + empty($options['language']) ? '' : $options['language'], + 'token' => empty($options['token']) ? '' : $options['token'], + )); + +invalidateHttpCache(FreshRSS_Context::$system_conf->default_user); + +echo 'Result: ', ($ok ? 'success' : 'fail'), ".\n"; +exit($ok ? 0 : 1); diff --git a/cli/index.html b/cli/index.html new file mode 100644 index 000000000..85faaa37e --- /dev/null +++ b/cli/index.html @@ -0,0 +1,13 @@ + + + + + +Redirection + + + + +

    Redirection

    + + diff --git a/cli/list-users.php b/cli/list-users.php new file mode 100644 index 000000000..cc1cf5269 --- /dev/null +++ b/cli/list-users.php @@ -0,0 +1,14 @@ +#!/usr/bin/php +default_user !== '') { + array_unshift($users, $system_conf->default_user); + $users = array_unique($users); +} + +foreach ($users as $user) { + echo $user, "\n"; +} diff --git a/lib/lib_rss.php b/lib/lib_rss.php index 75046fd54..143b55bee 100644 --- a/lib/lib_rss.php +++ b/lib/lib_rss.php @@ -282,9 +282,12 @@ function uSecString() { return str_pad($t['usec'], 6, '0'); } -function invalidateHttpCache() { - Minz_Session::_param('touch', uTimeString()); - return touch(join_path(DATA_PATH, 'users', Minz_Session::param('currentUser', '_'), 'log.txt')); +function invalidateHttpCache($username = '') { + if (($username == '') || (!ctype_alnum($username))) { + Minz_Session::_param('touch', uTimeString()); + $username = Minz_Session::param('currentUser', '_'); + } + return touch(join_path(DATA_PATH, 'users', $username, 'log.txt')); } function listUsers() { -- cgit v1.2.3 From 5b1b43ab57da6a7bc1599c224d47455b2e56d53d Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sat, 22 Oct 2016 20:32:16 +0200 Subject: CLI delete user https://github.com/FreshRSS/FreshRSS/issues/1095 --- app/Controllers/userController.php | 39 ++++++++++++++++++++++---------------- cli/delete-user.php | 33 ++++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+), 16 deletions(-) create mode 100755 cli/delete-user.php (limited to 'app/Controllers') diff --git a/app/Controllers/userController.php b/app/Controllers/userController.php index f880b951d..2f04c7a1d 100644 --- a/app/Controllers/userController.php +++ b/app/Controllers/userController.php @@ -186,6 +186,27 @@ class FreshRSS_user_Controller extends Minz_ActionController { Minz_Request::forward($redirect_url, true); } + public static function deleteUser($username) { + $db = FreshRSS_Context::$system_conf->db; + require_once(APP_PATH . '/SQL/install.sql.' . $db['type'] . '.php'); + + $ok = ctype_alnum($username); + if ($ok) { + $default_user = FreshRSS_Context::$system_conf->default_user; + $ok &= (strcasecmp($username, $default_user) !== 0); //It is forbidden to delete the default user + } + $user_data = join_path(DATA_PATH, 'users', $username); + if ($ok) { + $ok &= is_dir($user_data); + } + if ($ok) { + $userDAO = new FreshRSS_UserDAO(); + $ok &= $userDAO->deleteUser($username); + $ok &= recursive_unlink($user_data); + } + return $ok; + } + /** * This action delete an existing user. * @@ -207,16 +228,7 @@ class FreshRSS_user_Controller extends Minz_ActionController { FreshRSS_Auth::hasAccess('admin') || $self_deletion )) { - $db = FreshRSS_Context::$system_conf->db; - require_once(APP_PATH . '/SQL/install.sql.' . $db['type'] . '.php'); - - $ok = ctype_alnum($username); - $user_data = join_path(DATA_PATH, 'users', $username); - - if ($ok) { - $default_user = FreshRSS_Context::$system_conf->default_user; - $ok &= (strcasecmp($username, $default_user) !== 0); //It is forbidden to delete the default user - } + $ok = true; if ($ok && $self_deletion) { // We check the password if it's a self-destruction $nonce = Minz_Session::param('nonce'); @@ -228,12 +240,7 @@ class FreshRSS_user_Controller extends Minz_ActionController { ); } if ($ok) { - $ok &= is_dir($user_data); - } - if ($ok) { - $userDAO = new FreshRSS_UserDAO(); - $ok &= $userDAO->deleteUser($username); - $ok &= recursive_unlink($user_data); + $ok &= self::deleteUser($username); } if ($ok && $self_deletion) { FreshRSS_Auth::removeAccess(); diff --git a/cli/delete-user.php b/cli/delete-user.php new file mode 100755 index 000000000..46332fe34 --- /dev/null +++ b/cli/delete-user.php @@ -0,0 +1,33 @@ +#!/usr/bin/php +default_user) === 0) { + fail('FreshRSS error: default user must not be deleted: “' . $username . '”'); +} + +echo 'FreshRSS deleting user “', $username, "”…\n"; + +$ok = FreshRSS_user_Controller::deleteUser($username); + +invalidateHttpCache(FreshRSS_Context::$system_conf->default_user); + +echo 'Result: ', ($ok ? 'success' : 'fail'), ".\n"; +exit($ok ? 0 : 1); -- cgit v1.2.3 From 1b8eb6c7e732f1eda4fc8f22e847b363b016f857 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sun, 23 Oct 2016 01:46:14 +0200 Subject: CLI import ZIP/OPML/JSON for user https://github.com/FreshRSS/FreshRSS/issues/1095 https://github.com/FreshRSS/FreshRSS/issues/851 --- CHANGELOG.md | 2 +- README.fr.md | 2 +- README.md | 2 +- app/Controllers/categoryController.php | 5 +- app/Controllers/feedController.php | 6 +- app/Controllers/importExportController.php | 273 ++++++++++++++++++----------- app/Exceptions/ZipException.php | 14 ++ app/Exceptions/ZipMissingException.php | 4 + app/Models/CategoryDAO.php | 11 +- app/i18n/cz/feedback.php | 6 +- app/i18n/cz/sub.php | 4 +- app/i18n/de/feedback.php | 6 +- app/i18n/de/sub.php | 2 +- app/i18n/en/feedback.php | 6 +- app/i18n/en/sub.php | 4 +- app/i18n/fr/feedback.php | 6 +- app/i18n/fr/sub.php | 4 +- app/i18n/it/feedback.php | 6 +- app/i18n/it/sub.php | 4 +- app/i18n/nl/feedback.php | 6 +- app/i18n/nl/sub.php | 4 +- app/i18n/ru/feedback.php | 6 +- app/i18n/ru/sub.php | 4 +- app/i18n/tr/feedback.php | 6 +- app/i18n/tr/sub.php | 4 +- cli/_cli.php | 5 + cli/create-user.php | 17 +- cli/delete-user.php | 3 +- cli/import-for-user.php | 36 ++++ cli/list-users.php | 4 +- lib/Minz/ModelPdo.php | 13 +- 31 files changed, 296 insertions(+), 179 deletions(-) create mode 100644 app/Exceptions/ZipException.php create mode 100644 app/Exceptions/ZipMissingException.php create mode 100644 cli/import-for-user.php (limited to 'app/Controllers') diff --git a/CHANGELOG.md b/CHANGELOG.md index c35b3b578..d24ec0739 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -390,7 +390,7 @@ * Possibility to combine search filters, e.g. `date:2014-05 intitle:FreshRSS intitle:Open great reader #Internet` * Change nav menu with more buttons instead of dropdown menus and add some filters * New system of import / export - * Support OPML, Json (like Google Reader) and Zip archives + * Support OPML, Json (like Google Reader) and ZIP archives * Can export and import articles (specific option for favorites) * Refactor "Origine" theme * Some improvements diff --git a/README.fr.md b/README.fr.md index 3fcedd337..2a2da256d 100644 --- a/README.fr.md +++ b/README.fr.md @@ -34,7 +34,7 @@ Nous sommes une communauté amicale. * Serveur Web Apache2 (recommandé), ou nginx, lighttpd (non testé sur les autres) * PHP 5.3.3+ (PHP 5.4+ recommandé, et PHP 5.5+ pour les performances, et PHP 7+ pour d’encore meilleures performances) * Requis : [DOM](http://php.net/dom), [XML](http://php.net/xml), [PDO_MySQL](http://php.net/pdo-mysql) ou [PDO_SQLite](http://php.net/pdo-sqlite) ou [PDO_PGSQL](http://php.net/pdo-pgsql), [cURL](http://php.net/curl) - * Recommandés : [JSON](http://php.net/json), [GMP](http://php.net/gmp) (pour accès API sur plateformes < 64 bits), [IDN](http://php.net/intl.idn) (pour les noms de domaines internationalisés), [mbstring](http://php.net/mbstring) et/ou [iconv](http://php.net/iconv) (pour conversion d’encodages), [Zip](http://php.net/zip) (pour import/export), [zlib](http://php.net/zlib) (pour les flux compressés) + * Recommandés : [JSON](http://php.net/json), [GMP](http://php.net/gmp) (pour accès API sur plateformes < 64 bits), [IDN](http://php.net/intl.idn) (pour les noms de domaines internationalisés), [mbstring](http://php.net/mbstring) et/ou [iconv](http://php.net/iconv) (pour conversion d’encodages), [ZIP](http://php.net/zip) (pour import/export), [zlib](http://php.net/zlib) (pour les flux compressés) * MySQL 5.5.3+ (recommandé), ou SQLite 3.7.4+, ou PostgreSQL (experimental) * Un navigateur Web récent tel Firefox, Internet Explorer 11 / Edge, Chrome, Opera, Safari. * Fonctionne aussi sur mobile diff --git a/README.md b/README.md index 5c8f586fa..a541d6dea 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,7 @@ We are a friendly community. * A web server: Apache2 (recommended), nginx, lighttpd (not tested on others) * PHP 5.3.3+ (PHP 5.4+ recommended, and PHP 5.5+ for performance, and PHP 7 for even higher performance) * Required extensions: [DOM](http://php.net/dom), [XML](http://php.net/xml), [PDO_MySQL](http://php.net/pdo-mysql) or [PDO_SQLite](http://php.net/pdo-sqlite) or [PDO_PGSQL](http://php.net/pdo-pgsql), [cURL](http://php.net/curl) - * Recommended extensions: [JSON](http://php.net/json), [GMP](http://php.net/gmp) (for API access on platforms < 64 bits), [IDN](http://php.net/intl.idn) (for Internationalized Domain Names), [mbstring](http://php.net/mbstring) and/or [iconv](http://php.net/iconv) (for charset conversion), [Zip](http://php.net/zip) (for import/export), [zlib](http://php.net/zlib) (for compressed feeds) + * Recommended extensions: [JSON](http://php.net/json), [GMP](http://php.net/gmp) (for API access on platforms < 64 bits), [IDN](http://php.net/intl.idn) (for Internationalized Domain Names), [mbstring](http://php.net/mbstring) and/or [iconv](http://php.net/iconv) (for charset conversion), [ZIP](http://php.net/zip) (for import/export), [zlib](http://php.net/zlib) (for compressed feeds) * MySQL 5.5.3+ (recommended), or SQLite 3.7.4+, or PostgreSQL (experimental) * A recent browser like Firefox, Internet Explorer 11 / Edge, Chrome, Opera, Safari. * Works on mobile diff --git a/app/Controllers/categoryController.php b/app/Controllers/categoryController.php index e65c146de..922f92844 100644 --- a/app/Controllers/categoryController.php +++ b/app/Controllers/categoryController.php @@ -117,7 +117,6 @@ class FreshRSS_category_Controller extends Minz_ActionController { public function deleteAction() { $feedDAO = FreshRSS_Factory::createFeedDao(); $catDAO = new FreshRSS_CategoryDAO(); - $default_category = $catDAO->getDefault(); $url_redirect = array('c' => 'subscription', 'a' => 'index'); if (Minz_Request::isPost()) { @@ -128,11 +127,11 @@ class FreshRSS_category_Controller extends Minz_ActionController { Minz_Request::bad(_t('feedback.sub.category.no_id'), $url_redirect); } - if ($id === $default_category->id()) { + if ($id === FreshRSS_CategoryDAO::defaultCategoryId) { Minz_Request::bad(_t('feedback.sub.category.not_delete_default'), $url_redirect); } - if ($feedDAO->changeCategory($id, $default_category->id()) === false) { + if ($feedDAO->changeCategory($id, FreshRSS_CategoryDAO::defaultCategoryId) === false) { Minz_Request::bad(_t('feedback.sub.category.error'), $url_redirect); } diff --git a/app/Controllers/feedController.php b/app/Controllers/feedController.php index ed3229687..c4115584a 100755 --- a/app/Controllers/feedController.php +++ b/app/Controllers/feedController.php @@ -40,9 +40,8 @@ class FreshRSS_feed_Controller extends Minz_ActionController { } if ($cat == null) { $catDAO->checkDefault(); - $cat = $catDAO->getDefault(); } - $cat_id = $cat->id(); + $cat_id = $cat == null ? FreshRSS_CategoryDAO::defaultCategoryId : $cat->id(); $feed = new FreshRSS_Feed($url); //Throws FreshRSS_BadUrl_Exception $feed->_httpAuth($http_auth); @@ -504,8 +503,7 @@ class FreshRSS_feed_Controller extends Minz_ActionController { } if ($cat_id <= 1) { $catDAO->checkDefault(); - $cat = $catDAO->getDefault(); - $cat_id = $cat->id(); + $cat_id = FreshRSS_CategoryDAO::defaultCategoryId; } $feedDAO = FreshRSS_Factory::createFeedDao(); diff --git a/app/Controllers/importExportController.php b/app/Controllers/importExportController.php index a1f789805..fbebb2a78 100644 --- a/app/Controllers/importExportController.php +++ b/app/Controllers/importExportController.php @@ -29,32 +29,14 @@ class FreshRSS_importExport_Controller extends Minz_ActionController { Minz_View::prependTitle(_t('sub.import_export.title') . ' · '); } - /** - * This action handles import action. - * - * It must be reached by a POST request. - * - * Parameter is: - * - file (default: nothing!) - * Available file types are: zip, json or xml. - */ - public function importAction() { - if (!Minz_Request::isPost()) { - Minz_Request::forward(array('c' => 'importExport', 'a' => 'index'), true); - } - - $file = $_FILES['file']; - $status_file = $file['error']; - - if ($status_file !== 0) { - Minz_Log::warning('File cannot be uploaded. Error code: ' . $status_file); - Minz_Request::bad(_t('feedback.import_export.file_cannot_be_uploaded'), - array('c' => 'importExport', 'a' => 'index')); - } + public function importFile($name, $path, $username = null) { + require_once(LIB_PATH . '/lib_opml.php'); - @set_time_limit(300); + $this->catDAO = new FreshRSS_CategoryDAO($username); + $this->entryDAO = FreshRSS_Factory::createEntryDao($username); + $this->feedDAO = FreshRSS_Factory::createFeedDao($username); - $type_file = $this->guessFileType($file['name']); + $type_file = self::guessFileType($name); $list_files = array( 'opml' => array(), @@ -65,21 +47,17 @@ class FreshRSS_importExport_Controller extends Minz_ActionController { // We try to list all files according to their type $list = array(); if ($type_file === 'zip' && extension_loaded('zip')) { - $zip = zip_open($file['tmp_name']); - + $zip = zip_open($path); if (!is_resource($zip)) { // zip_open cannot open file: something is wrong - Minz_Log::warning('Zip archive cannot be imported. Error code: ' . $zip); - Minz_Request::bad(_t('feedback.import_export.zip_error'), - array('c' => 'importExport', 'a' => 'index')); + throw new FreshRSS_Zip_Exception($zip); } - while (($zipfile = zip_read($zip)) !== false) { if (!is_resource($zipfile)) { // zip_entry() can also return an error code! - Minz_Log::warning('Zip file cannot be imported. Error code: ' . $zipfile); + throw new FreshRSS_Zip_Exception($zipfile); } else { - $type_zipfile = $this->guessFileType(zip_entry_name($zipfile)); + $type_zipfile = self::guessFileType(zip_entry_name($zipfile)); if ($type_file !== 'unknown') { $list_files[$type_zipfile][] = zip_entry_read( $zipfile, @@ -88,29 +66,82 @@ class FreshRSS_importExport_Controller extends Minz_ActionController { } } } - zip_close($zip); } elseif ($type_file === 'zip') { - // Zip extension is not loaded - Minz_Request::bad(_t('feedback.import_export.no_zip_extension'), - array('c' => 'importExport', 'a' => 'index')); + // ZIP extension is not loaded + throw new FreshRSS_ZipMissing_Exception(); } elseif ($type_file !== 'unknown') { - $list_files[$type_file][] = file_get_contents($file['tmp_name']); + $list_files[$type_file][] = file_get_contents($path); } // Import file contents. // OPML first(so categories and feeds are imported) // Starred articles then so the "favourite" status is already set // And finally all other files. - $error = false; + $ok = true; foreach ($list_files['opml'] as $opml_file) { - $error = $this->importOpml($opml_file); + if (!$this->importOpml($opml_file)) { + $ok = false; + if (FreshRSS_Context::$isCli) { + fwrite(STDERR, 'FreshRSS error during OPML import' . "\n"); + } + } } foreach ($list_files['json_starred'] as $article_file) { - $error = $this->importJson($article_file, true); + if (!$this->importJson($article_file, true)) { + $ok = false; + if (FreshRSS_Context::$isCli) { + fwrite(STDERR, 'FreshRSS error during JSON stars import' . "\n"); + } + } } foreach ($list_files['json_feed'] as $article_file) { - $error = $this->importJson($article_file); + if (!$this->importJson($article_file)) { + $ok = false; + if (FreshRSS_Context::$isCli) { + fwrite(STDERR, 'FreshRSS error during JSON feeds import' . "\n"); + } + } + } + + return $ok; + } + + /** + * This action handles import action. + * + * It must be reached by a POST request. + * + * Parameter is: + * - file (default: nothing!) + * Available file types are: zip, json or xml. + */ + public function importAction() { + if (!Minz_Request::isPost()) { + Minz_Request::forward(array('c' => 'importExport', 'a' => 'index'), true); + } + + $file = $_FILES['file']; + $status_file = $file['error']; + + if ($status_file !== 0) { + Minz_Log::warning('File cannot be uploaded. Error code: ' . $status_file); + Minz_Request::bad(_t('feedback.import_export.file_cannot_be_uploaded'), + array('c' => 'importExport', 'a' => 'index')); + } + + @set_time_limit(300); + + $error = false; + try { + $error = !$this->importFile($file['name'], $file['tmp_name']); + } catch (FreshRSS_ZipMissing_Exception $zme) { + Minz_Request::bad(_t('feedback.import_export.no_zip_extension'), + array('c' => 'importExport', 'a' => 'index')); + } catch (FreshRSS_Zip_Exception $ze) { + Minz_Log::warning('ZIP archive cannot be imported. Error code: ' . $ze->zipErrorCode()); + Minz_Request::bad(_t('feedback.import_export.zip_error'), + array('c' => 'importExport', 'a' => 'index')); } // And finally, we get import status and redirect to the home page @@ -126,7 +157,7 @@ class FreshRSS_importExport_Controller extends Minz_ActionController { * Itis a *very* basic guess file type function. Only based on filename. * That's could be improved but should be enough for what we have to do. */ - private function guessFileType($filename) { + private static function guessFileType($filename) { if (substr_compare($filename, '.zip', -4) === 0) { return 'zip'; } elseif (substr_compare($filename, '.opml', -5) === 0 || @@ -146,15 +177,19 @@ class FreshRSS_importExport_Controller extends Minz_ActionController { * This method parses and imports an OPML file. * * @param string $opml_file the OPML file content. - * @return boolean true if an error occured, false else. + * @return boolean false if an error occured, true otherwise. */ private function importOpml($opml_file) { $opml_array = array(); try { $opml_array = libopml_parse_string($opml_file, false); } catch (LibOPML_Exception $e) { - Minz_Log::warning($e->getMessage()); - return true; + if (FreshRSS_Context::$isCli) { + fwrite(STDERR, 'FreshRSS error during OPML parsing: ' . $e->getMessage() . "\n"); + } else { + Minz_Log::warning($e->getMessage()); + } + return false; } $this->catDAO->checkDefault(); @@ -167,51 +202,53 @@ class FreshRSS_importExport_Controller extends Minz_ActionController { * * @param array $opml_elements an OPML element (body or outline). * @param string $parent_cat the name of the parent category. - * @return boolean true if an error occured, false else. + * @return boolean false if an error occured, true otherwise. */ private function addOpmlElements($opml_elements, $parent_cat = null) { - $error = false; + $ok = true; $nb_feeds = count($this->feedDAO->listFeeds()); $nb_cats = count($this->catDAO->listCategories(false)); $limits = FreshRSS_Context::$system_conf->limits; foreach ($opml_elements as $elt) { - $is_error = false; if (isset($elt['xmlUrl'])) { // If xmlUrl exists, it means it is a feed - if ($nb_feeds >= $limits['max_feeds']) { - Minz_Log::warning(_t('feedback.sub.feed.over_max', - $limits['max_feeds'])); - $is_error = true; - continue; + if (!FreshRSS_Context::$isCli) { + if ($nb_feeds >= $limits['max_feeds']) { + Minz_Log::warning(_t('feedback.sub.feed.over_max', + $limits['max_feeds'])); + $ok = false; + continue; + } } - $is_error = $this->addFeedOpml($elt, $parent_cat); - if (!$is_error) { - $nb_feeds += 1; + if ($this->addFeedOpml($elt, $parent_cat)) { + $nb_feeds++; + } else { + $ok = false; } } else { // No xmlUrl? It should be a category! $limit_reached = ($nb_cats >= $limits['max_categories']); - if ($limit_reached) { - Minz_Log::warning(_t('feedback.sub.category.over_max', - $limits['max_categories'])); + if (!FreshRSS_Context::$isCli) { + if ($limit_reached) { + Minz_Log::warning(_t('feedback.sub.category.over_max', + $limits['max_categories'])); + } + $ok = false; + continue; } - $is_error = $this->addCategoryOpml($elt, $parent_cat, $limit_reached); - if (!$is_error) { - $nb_cats += 1; + if ($this->addCategoryOpml($elt, $parent_cat, $limit_reached)) { + $nb_cats++; + } else { + $ok = false; } } - - if (!$error && $is_error) { - // oops: there is at least one error! - $error = $is_error; - } } - return $error; + return $ok; } /** @@ -219,21 +256,23 @@ class FreshRSS_importExport_Controller extends Minz_ActionController { * * @param array $feed_elt an OPML element (must be a feed element). * @param string $parent_cat the name of the parent category. - * @return boolean true if an error occured, false else. + * @return boolean false if an error occured, true otherwise. */ private function addFeedOpml($feed_elt, $parent_cat) { - $default_cat = $this->catDAO->getDefault(); - if (is_null($parent_cat)) { + if ($parent_cat == null) { // This feed has no parent category so we get the default one + $this->catDAO->checkDefault(); + $default_cat = $this->catDAO->getDefault(); $parent_cat = $default_cat->name(); } $cat = $this->catDAO->searchByName($parent_cat); - if (is_null($cat)) { + if ($cat == null) { // If there is not $cat, it means parent category does not exist in // database. // If it happens, take the default category. - $cat = $default_cat; + $this->catDAO->checkDefault(); + $cat = $this->catDAO->getDefault(); } // We get different useful information @@ -259,7 +298,7 @@ class FreshRSS_importExport_Controller extends Minz_ActionController { // Call the extension hook $feed = Minz_ExtensionManager::callHook('feed_before_insert', $feed); - if (!is_null($feed)) { + if ($feed != null) { // addFeedObject checks if feed is already in DB so nothing else to // check here $id = $this->feedDAO->addFeedObject($feed); @@ -268,11 +307,23 @@ class FreshRSS_importExport_Controller extends Minz_ActionController { $error = true; } } catch (FreshRSS_Feed_Exception $e) { - Minz_Log::warning($e->getMessage()); + if (FreshRSS_Context::$isCli) { + fwrite(STDERR, 'FreshRSS error during OPML feed import: ' . $e->getMessage() . "\n"); + } else { + Minz_Log::warning($e->getMessage()); + } $error = true; } - return $error; + if ($error) { + if (FreshRSS_Context::$isCli) { + fwrite(STDERR, 'FreshRSS error during OPML feed import from URL: ' . $url . ' in category ' . $cat->id() . "\n"); + } else { + Minz_Log::warning('Error during OPML feed import from URL: ' . $url . ' in category ' . $cat->id()); + } + } + + return !$error; } /** @@ -282,29 +333,34 @@ class FreshRSS_importExport_Controller extends Minz_ActionController { * @param string $parent_cat the name of the parent category. * @param boolean $cat_limit_reached indicates if category limit has been reached. * if yes, category is not added (but we try for feeds!) - * @return boolean true if an error occured, false else. + * @return boolean false if an error occured, true otherwise. */ private function addCategoryOpml($cat_elt, $parent_cat, $cat_limit_reached) { // Create a new Category object - $cat = new FreshRSS_Category(Minz_Helper::htmlspecialchars_utf8($cat_elt['text'])); + $catName = Minz_Helper::htmlspecialchars_utf8($cat_elt['text']); + $cat = new FreshRSS_Category($catName); $error = true; - if (!$cat_limit_reached) { + if (FreshRSS_Context::$isCli || !$cat_limit_reached) { $id = $this->catDAO->addCategoryObject($cat); $error = ($id === false); } + if ($error) { + if (FreshRSS_Context::$isCli) { + fwrite(STDERR, 'FreshRSS error during OPML category import from URL: ' . $catName . "\n"); + } else { + Minz_Log::warning('Error during OPML category import from URL: ' . $catName); + } + } if (isset($cat_elt['@outlines'])) { // Our cat_elt contains more categories or more feeds, so we // add them recursively. // Note: FreshRSS does not support yet category arborescence - $res = $this->addOpmlElements($cat_elt['@outlines'], $cat->name()); - if (!$error && $res) { - $error = true; - } + $error &= !$this->addOpmlElements($cat_elt['@outlines'], $catName); } - return $error; + return !$error; } /** @@ -312,13 +368,17 @@ class FreshRSS_importExport_Controller extends Minz_ActionController { * * @param string $article_file the JSON file content. * @param boolean $starred true if articles from the file must be starred. - * @return boolean true if an error occured, false else. + * @return boolean false if an error occured, true otherwise. */ private function importJson($article_file, $starred = false) { $article_object = json_decode($article_file, true); - if (is_null($article_object)) { - Minz_Log::warning('Try to import a non-JSON file'); - return true; + if ($article_object == null) { + if (FreshRSS_Context::$isCli) { + fwrite(STDERR, 'FreshRSS error trying to import a non-JSON file' . "\n"); + } else { + Minz_Log::warning('Try to import a non-JSON file'); + } + return false; } $is_read = FreshRSS_Context::$user_conf->mark_when['reception'] ? 1 : 0; @@ -337,25 +397,24 @@ class FreshRSS_importExport_Controller extends Minz_ActionController { $feed = new FreshRSS_Feed($item['origin'][$key]); $feed = $this->feedDAO->searchByUrl($feed->url()); - if (is_null($feed)) { + if ($feed == null) { // Feed does not exist in DB,we should to try to add it. - if ($nb_feeds >= $limits['max_feeds']) { + if ((!FreshRSS_Context::$isCli) && ($nb_feeds >= $limits['max_feeds'])) { // Oops, no more place! Minz_Log::warning(_t('feedback.sub.feed.over_max', $limits['max_feeds'])); } else { $feed = $this->addFeedJson($item['origin'], $google_compliant); } - if (is_null($feed)) { + if ($feed == null) { // Still null? It means something went wrong. $error = true; } else { - // Nice! Increase the counter. - $nb_feeds += 1; + $nb_feeds++; } } - if (!is_null($feed)) { + if ($feed != null) { $article_to_feed[$item['id']] = $feed->id(); } } @@ -384,7 +443,7 @@ class FreshRSS_importExport_Controller extends Minz_ActionController { if ($google_compliant) { // Remove tags containing "/state/com.google" which are useless. $tags = array_filter($tags, function($var) { - return strpos($var, '/state/com.google') === false; + return strpos($var, '/state/com.google') !== false; }); } @@ -397,7 +456,7 @@ class FreshRSS_importExport_Controller extends Minz_ActionController { $entry->_tags($tags); $entry = Minz_ExtensionManager::callHook('entry_before_insert', $entry); - if (is_null($entry)) { + if ($entry == null) { // An extension has returned a null value, there is nothing to insert. continue; } @@ -415,7 +474,7 @@ class FreshRSS_importExport_Controller extends Minz_ActionController { } $this->entryDAO->commit(); - return $error; + return !$error; } /** @@ -427,8 +486,6 @@ class FreshRSS_importExport_Controller extends Minz_ActionController { * else null. */ private function addFeedJson($origin, $google_compliant) { - $default_cat = $this->catDAO->getDefault(); - $return = null; $key = $google_compliant ? 'htmlUrl' : 'feedUrl'; $url = $origin[$key]; @@ -438,13 +495,13 @@ class FreshRSS_importExport_Controller extends Minz_ActionController { try { // Create a Feed object and add it in database. $feed = new FreshRSS_Feed($url); - $feed->_category($default_cat->id()); + $feed->_category(FreshRSS_CategoryDAO::defaultCategoryId); $feed->_name($name); $feed->_website($website); // Call the extension hook $feed = Minz_ExtensionManager::callHook('feed_before_insert', $feed); - if (!is_null($feed)) { + if ($feed != null) { // addFeedObject checks if feed is already in DB so nothing else to // check here. $id = $this->feedDAO->addFeedObject($feed); @@ -455,7 +512,11 @@ class FreshRSS_importExport_Controller extends Minz_ActionController { } } } catch (FreshRSS_Feed_Exception $e) { - Minz_Log::warning($e->getMessage()); + if (FreshRSS_Context::$isCli) { + fwrite(STDERR, 'FreshRSS error during JSON feed import: ' . $e->getMessage() . "\n"); + } else { + Minz_Log::warning($e->getMessage()); + } } return $return; @@ -503,18 +564,18 @@ class FreshRSS_importExport_Controller extends Minz_ActionController { $nb_files = count($export_files); if ($nb_files > 1) { - // If there are more than 1 file to export, we need a zip archive. + // If there are more than 1 file to export, we need a ZIP archive. try { $this->exportZip($export_files); } catch (Exception $e) { - # Oops, there is no Zip extension! + # Oops, there is no ZIP extension! Minz_Request::bad(_t('feedback.import_export.export_no_zip_extension'), array('c' => 'importExport', 'a' => 'index')); } } elseif ($nb_files === 1) { // Only one file? Guess its type and export it. $filename = key($export_files); - $type = $this->guessFileType($filename); + $type = self::guessFileType($filename); $this->exportFile('freshrss_' . $filename, $export_files[$filename], $type); } else { // Nothing to do... @@ -555,7 +616,7 @@ class FreshRSS_importExport_Controller extends Minz_ActionController { $this->view->entries = $this->entryDAO->listWhere( 's', '', FreshRSS_Entry::STATE_ALL, 'ASC', $unread_fav['all'] ); - } elseif ($type == 'feed' && !is_null($feed)) { + } elseif ($type === 'feed' && $feed != null) { $this->view->list_title = _t('sub.import_export.feed_list', $feed->name()); $this->view->type = 'feed/' . $feed->id(); $this->view->entries = $this->entryDAO->listWhere( diff --git a/app/Exceptions/ZipException.php b/app/Exceptions/ZipException.php new file mode 100644 index 000000000..8441daedf --- /dev/null +++ b/app/Exceptions/ZipException.php @@ -0,0 +1,14 @@ +zipErrorCode = $zipErrorCode; + } + + public function zipErrorCode() { + return $this->zipErrorCode; + } +} diff --git a/app/Exceptions/ZipMissingException.php b/app/Exceptions/ZipMissingException.php new file mode 100644 index 000000000..864cc3991 --- /dev/null +++ b/app/Exceptions/ZipMissingException.php @@ -0,0 +1,4 @@ +prefix . 'category`(name) VALUES(?)'; $stm = $this->bd->prepare($sql); @@ -50,7 +53,7 @@ class FreshRSS_CategoryDAO extends Minz_ModelPdo implements FreshRSS_Searchable } public function deleteCategory($id) { - if ($id <= 1) { + if ($id <= self::defaultCategoryId) { return false; } $sql = 'DELETE FROM `' . $this->prefix . 'category` WHERE id=?'; @@ -120,7 +123,7 @@ class FreshRSS_CategoryDAO extends Minz_ModelPdo implements FreshRSS_Searchable } public function getDefault() { - $sql = 'SELECT * FROM `' . $this->prefix . 'category` WHERE id=1'; + $sql = 'SELECT * FROM `' . $this->prefix . 'category` WHERE id=' . self::defaultCategoryId; $stm = $this->bd->prepare($sql); $stm->execute(); @@ -134,11 +137,11 @@ class FreshRSS_CategoryDAO extends Minz_ModelPdo implements FreshRSS_Searchable } } public function checkDefault() { - $def_cat = $this->searchById(1); + $def_cat = $this->searchById(self::defaultCategoryId); if ($def_cat == null) { $cat = new FreshRSS_Category(_t('gen.short.default_category')); - $cat->_id(1); + $cat->_id(self::defaultCategoryId); $values = array( 'id' => $cat->id(), diff --git a/app/i18n/cz/feedback.php b/app/i18n/cz/feedback.php index 81302afca..f2bd87c77 100644 --- a/app/i18n/cz/feedback.php +++ b/app/i18n/cz/feedback.php @@ -43,12 +43,12 @@ return array( 'not_found' => '%s neexistuje', ), 'import_export' => array( - 'export_no_zip_extension' => 'Na serveru není naistalována podpora zip. Zkuste prosím exportovat soubory jeden po druhém.', + 'export_no_zip_extension' => 'Na serveru není naistalována podpora ZIP. Zkuste prosím exportovat soubory jeden po druhém.', 'feeds_imported' => 'Vaše kanály byly naimportovány a nyní budou aktualizovány', 'feeds_imported_with_errors' => 'Vaše kanály byly naimportovány, došlo ale k nějakým chybám', 'file_cannot_be_uploaded' => 'Soubor nelze nahrát!', - 'no_zip_extension' => 'Na serveru není naistalována podpora zip.', - 'zip_error' => 'Během importu zip souboru došlo k chybě.', + 'no_zip_extension' => 'Na serveru není naistalována podpora ZIP.', + 'zip_error' => 'Během importu ZIP souboru došlo k chybě.', ), 'sub' => array( 'actualize' => 'Aktualizovat', diff --git a/app/i18n/cz/sub.php b/app/i18n/cz/sub.php index cea0541e3..274cf16e1 100644 --- a/app/i18n/cz/sub.php +++ b/app/i18n/cz/sub.php @@ -44,8 +44,8 @@ return array( 'export_opml' => 'Exportovat seznam kanálů (OPML)', 'export_starred' => 'Exportovat oblíbené', 'feed_list' => 'Seznam %s článků', - 'file_to_import' => 'Soubor k importu
    (OPML, Json nebo Zip)', - 'file_to_import_no_zip' => 'Soubor k importu
    (OPML nebo Json)', + 'file_to_import' => 'Soubor k importu
    (OPML, JSON nebo ZIP)', + 'file_to_import_no_zip' => 'Soubor k importu
    (OPML nebo JSON)', 'import' => 'Import', 'starred_list' => 'Seznam oblíbených článků', 'title' => 'Import / export', diff --git a/app/i18n/de/feedback.php b/app/i18n/de/feedback.php index f93992982..195083b36 100644 --- a/app/i18n/de/feedback.php +++ b/app/i18n/de/feedback.php @@ -43,12 +43,12 @@ return array( 'not_found' => '%s existiert nicht', ), 'import_export' => array( - 'export_no_zip_extension' => 'Die Zip-Erweiterung fehlt auf Ihrem Server. Bitte versuchen Sie die Dateien eine nach der anderen zu exportieren.', + 'export_no_zip_extension' => 'Die ZIP-Erweiterung fehlt auf Ihrem Server. Bitte versuchen Sie die Dateien eine nach der anderen zu exportieren.', 'feeds_imported' => 'Ihre Feeds sind importiert worden und werden jetzt aktualisiert', 'feeds_imported_with_errors' => 'Ihre Feeds sind importiert worden, aber es traten einige Fehler auf', 'file_cannot_be_uploaded' => 'Die Datei kann nicht hochgeladen werden!', - 'no_zip_extension' => 'Die Zip-Erweiterung ist auf Ihrem Server nicht vorhanden.', - 'zip_error' => 'Ein Fehler trat während des Zip-Imports auf.', + 'no_zip_extension' => 'Die ZIP-Erweiterung ist auf Ihrem Server nicht vorhanden.', + 'zip_error' => 'Ein Fehler trat während des ZIP-Imports auf.', ), 'sub' => array( 'actualize' => 'Aktualisieren', diff --git a/app/i18n/de/sub.php b/app/i18n/de/sub.php index 0f05a5635..cc98fd25c 100644 --- a/app/i18n/de/sub.php +++ b/app/i18n/de/sub.php @@ -44,7 +44,7 @@ return array( 'export_opml' => 'Liste der Feeds exportieren (OPML)', 'export_starred' => 'Ihre Favoriten exportieren', 'feed_list' => 'Liste von %s Artikeln', - 'file_to_import' => 'Zu importierende Datei
    (OPML, JSON oder Zip)', + 'file_to_import' => 'Zu importierende Datei
    (OPML, JSON oder ZIP)', 'file_to_import_no_zip' => 'Zu importierende Datei
    (OPML oder JSON)', 'import' => 'Importieren', 'starred_list' => 'Liste der Lieblingsartikel', diff --git a/app/i18n/en/feedback.php b/app/i18n/en/feedback.php index 7ce2ae9cf..e7f6b9f85 100644 --- a/app/i18n/en/feedback.php +++ b/app/i18n/en/feedback.php @@ -43,12 +43,12 @@ return array( 'not_found' => '%s does not exist', ), 'import_export' => array( - 'export_no_zip_extension' => 'Zip extension is not present on your server. Please try to export files one by one.', + 'export_no_zip_extension' => 'ZIP extension is not present on your server. Please try to export files one by one.', 'feeds_imported' => 'Your feeds have been imported and will now be updated', 'feeds_imported_with_errors' => 'Your feeds have been imported but some errors occurred', 'file_cannot_be_uploaded' => 'File cannot be uploaded!', - 'no_zip_extension' => 'Zip extension is not present on your server.', - 'zip_error' => 'An error occured during Zip import.', + 'no_zip_extension' => 'ZIP extension is not present on your server.', + 'zip_error' => 'An error occured during ZIP import.', ), 'sub' => array( 'actualize' => 'Actualise', diff --git a/app/i18n/en/sub.php b/app/i18n/en/sub.php index aaaa02827..789433ee6 100644 --- a/app/i18n/en/sub.php +++ b/app/i18n/en/sub.php @@ -44,8 +44,8 @@ return array( 'export_opml' => 'Export list of feeds (OPML)', 'export_starred' => 'Export your favourites', 'feed_list' => 'List of %s articles', - 'file_to_import' => 'File to import
    (OPML, Json or Zip)', - 'file_to_import_no_zip' => 'File to import
    (OPML or Json)', + 'file_to_import' => 'File to import
    (OPML, JSON or ZIP)', + 'file_to_import_no_zip' => 'File to import
    (OPML or JSON)', 'import' => 'Import', 'starred_list' => 'List of favourite articles', 'title' => 'Import / export', diff --git a/app/i18n/fr/feedback.php b/app/i18n/fr/feedback.php index 15f3ab859..5966fc3a7 100644 --- a/app/i18n/fr/feedback.php +++ b/app/i18n/fr/feedback.php @@ -43,12 +43,12 @@ return array( 'not_found' => '%s n’existe pas', ), 'import_export' => array( - 'export_no_zip_extension' => 'L’extension Zip n’est pas présente sur votre serveur. Veuillez essayer d’exporter les fichiers un par un.', + 'export_no_zip_extension' => 'L’extension ZIP n’est pas présente sur votre serveur. Veuillez essayer d’exporter les fichiers un par un.', 'feeds_imported' => 'Vos flux ont été importés et vont maintenant être actualisés.', 'feeds_imported_with_errors' => 'Vos flux ont été importés mais des erreurs sont survenues.', 'file_cannot_be_uploaded' => 'Le fichier ne peut pas être téléchargé !', - 'no_zip_extension' => 'L’extension Zip n’est pas présente sur votre serveur.', - 'zip_error' => 'Une erreur est survenue durant l’import du fichier Zip.', + 'no_zip_extension' => 'L’extension ZIP n’est pas présente sur votre serveur.', + 'zip_error' => 'Une erreur est survenue durant l’import du fichier ZIP.', ), 'sub' => array( 'actualize' => 'Actualiser', diff --git a/app/i18n/fr/sub.php b/app/i18n/fr/sub.php index e3631eb8b..bb3f2fefc 100644 --- a/app/i18n/fr/sub.php +++ b/app/i18n/fr/sub.php @@ -44,8 +44,8 @@ return array( 'export_opml' => 'Exporter la liste des flux (OPML)', 'export_starred' => 'Exporter les favoris', 'feed_list' => 'Liste des articles de %s', - 'file_to_import' => 'Fichier à importer
    (OPML, Json ou Zip)', - 'file_to_import_no_zip' => 'Fichier à importer
    (OPML ou Json)', + 'file_to_import' => 'Fichier à importer
    (OPML, JSON ou ZIP)', + 'file_to_import_no_zip' => 'Fichier à importer
    (OPML ou JSON)', 'import' => 'Importer', 'starred_list' => 'Liste des articles favoris', 'title' => 'Importer / exporter', diff --git a/app/i18n/it/feedback.php b/app/i18n/it/feedback.php index f217586b0..5851cb2e6 100644 --- a/app/i18n/it/feedback.php +++ b/app/i18n/it/feedback.php @@ -43,12 +43,12 @@ return array( 'not_found' => '%s non disponibile', ), 'import_export' => array( - 'export_no_zip_extension' => 'Estensione Zip non presente sul server. Per favore esporta i files singolarmente.', + 'export_no_zip_extension' => 'Estensione ZIP non presente sul server. Per favore esporta i files singolarmente.', 'feeds_imported' => 'I tuoi feed sono stati importati e saranno aggiornati', 'feeds_imported_with_errors' => 'I tuoi feeds sono stati importati ma si sono verificati alcuni errori', 'file_cannot_be_uploaded' => 'Il file non può essere caricato!', - 'no_zip_extension' => 'Estensione Zip non presente sul server.', - 'zip_error' => 'Si è verificato un errore importando il file Zip', + 'no_zip_extension' => 'Estensione ZIP non presente sul server.', + 'zip_error' => 'Si è verificato un errore importando il file ZIP', ), 'sub' => array( 'actualize' => 'Aggiorna', diff --git a/app/i18n/it/sub.php b/app/i18n/it/sub.php index dfcee2ce3..758e322c5 100644 --- a/app/i18n/it/sub.php +++ b/app/i18n/it/sub.php @@ -44,8 +44,8 @@ return array( 'export_opml' => 'Esporta tutta la lista dei feed (OPML)', 'export_starred' => 'Esporta i tuoi preferiti', 'feed_list' => 'Elenco di %s articoli', - 'file_to_import' => 'File da importare
    (OPML, Json o Zip)', - 'file_to_import_no_zip' => 'File da importare
    (OPML o Json)', + 'file_to_import' => 'File da importare
    (OPML, JSON o ZIP)', + 'file_to_import_no_zip' => 'File da importare
    (OPML o JSON)', 'import' => 'Importa', 'starred_list' => 'Elenco articoli preferiti', 'title' => 'Importa / esporta', diff --git a/app/i18n/nl/feedback.php b/app/i18n/nl/feedback.php index b703c43cf..386b8d415 100644 --- a/app/i18n/nl/feedback.php +++ b/app/i18n/nl/feedback.php @@ -43,12 +43,12 @@ return array( 'not_found' => '%s bestaat niet', ), 'import_export' => array( - 'export_no_zip_extension' => 'Zip uitbreiding is niet aanwezig op uw server. Exporteer a.u.b. uw bestanden één voor één.', + 'export_no_zip_extension' => 'ZIP uitbreiding is niet aanwezig op uw server. Exporteer a.u.b. uw bestanden één voor één.', 'feeds_imported' => 'Uw feeds zijn geimporteerd en worden nu vernieuwd', 'feeds_imported_with_errors' => 'Uw feeds zijn geimporteerd maar er zijn enige fouten opgetreden', 'file_cannot_be_uploaded' => 'Bestand kan niet worden verzonden!', - 'no_zip_extension' => 'Zip uitbreiding is niet aanwezig op uw server.', - 'zip_error' => 'Er is een fout opgetreden tijdens het imporeren van het Zip bestand.', + 'no_zip_extension' => 'ZIP uitbreiding is niet aanwezig op uw server.', + 'zip_error' => 'Er is een fout opgetreden tijdens het imporeren van het ZIP bestand.', ), 'sub' => array( 'actualize' => 'Actualiseren', diff --git a/app/i18n/nl/sub.php b/app/i18n/nl/sub.php index 159a58b27..a1ba3f03d 100644 --- a/app/i18n/nl/sub.php +++ b/app/i18n/nl/sub.php @@ -44,8 +44,8 @@ return array( 'export_opml' => 'Exporteer lijst van feeds (OPML)', 'export_starred' => 'Exporteer je fovorieten', 'feed_list' => 'Lijst van %s artikelen', - 'file_to_import' => 'Bestand om te importeren
    (OPML, Json of Zip)', - 'file_to_import_no_zip' => 'Bestand om te importeren
    (OPML of Json)', + 'file_to_import' => 'Bestand om te importeren
    (OPML, JSON of ZIP)', + 'file_to_import_no_zip' => 'Bestand om te importeren
    (OPML of JSON)', 'import' => 'Importeer', 'starred_list' => 'Lijst van favoriete artikelen', 'title' => 'Importeren / exporteren', diff --git a/app/i18n/ru/feedback.php b/app/i18n/ru/feedback.php index 7ce2ae9cf..e7f6b9f85 100644 --- a/app/i18n/ru/feedback.php +++ b/app/i18n/ru/feedback.php @@ -43,12 +43,12 @@ return array( 'not_found' => '%s does not exist', ), 'import_export' => array( - 'export_no_zip_extension' => 'Zip extension is not present on your server. Please try to export files one by one.', + 'export_no_zip_extension' => 'ZIP extension is not present on your server. Please try to export files one by one.', 'feeds_imported' => 'Your feeds have been imported and will now be updated', 'feeds_imported_with_errors' => 'Your feeds have been imported but some errors occurred', 'file_cannot_be_uploaded' => 'File cannot be uploaded!', - 'no_zip_extension' => 'Zip extension is not present on your server.', - 'zip_error' => 'An error occured during Zip import.', + 'no_zip_extension' => 'ZIP extension is not present on your server.', + 'zip_error' => 'An error occured during ZIP import.', ), 'sub' => array( 'actualize' => 'Actualise', diff --git a/app/i18n/ru/sub.php b/app/i18n/ru/sub.php index aaaa02827..789433ee6 100644 --- a/app/i18n/ru/sub.php +++ b/app/i18n/ru/sub.php @@ -44,8 +44,8 @@ return array( 'export_opml' => 'Export list of feeds (OPML)', 'export_starred' => 'Export your favourites', 'feed_list' => 'List of %s articles', - 'file_to_import' => 'File to import
    (OPML, Json or Zip)', - 'file_to_import_no_zip' => 'File to import
    (OPML or Json)', + 'file_to_import' => 'File to import
    (OPML, JSON or ZIP)', + 'file_to_import_no_zip' => 'File to import
    (OPML or JSON)', 'import' => 'Import', 'starred_list' => 'List of favourite articles', 'title' => 'Import / export', diff --git a/app/i18n/tr/feedback.php b/app/i18n/tr/feedback.php index a53316206..87361ff51 100644 --- a/app/i18n/tr/feedback.php +++ b/app/i18n/tr/feedback.php @@ -43,12 +43,12 @@ return array( 'not_found' => '%s bulunmamaktadır', ), 'import_export' => array( - 'export_no_zip_extension' => 'Zip eklentisi mevcut sunucunuzda yer almıyor. Lütfen başka dosya formatında dışarı aktarmayı deneyin.', + 'export_no_zip_extension' => 'ZIP eklentisi mevcut sunucunuzda yer almıyor. Lütfen başka dosya formatında dışarı aktarmayı deneyin.', 'feeds_imported' => 'Akışlarınız içe aktarıldı ve şimdi güncellenecek', 'feeds_imported_with_errors' => 'Akışlarınız içeri aktarıldı ama bazı hatalar meydana geldi', 'file_cannot_be_uploaded' => 'Dosya yüklenemedi!', - 'no_zip_extension' => 'Zip eklentisi mevcut sunucunuzda yer almıyor.', - 'zip_error' => 'Zip içe aktarımı sırasında hata meydana geldi.', + 'no_zip_extension' => 'ZIP eklentisi mevcut sunucunuzda yer almıyor.', + 'zip_error' => 'ZIP içe aktarımı sırasında hata meydana geldi.', ), 'sub' => array( 'actualize' => 'Güncelleme', diff --git a/app/i18n/tr/sub.php b/app/i18n/tr/sub.php index 5ab367ebb..7592096d9 100644 --- a/app/i18n/tr/sub.php +++ b/app/i18n/tr/sub.php @@ -44,8 +44,8 @@ return array( 'export_opml' => 'Akış listesini dışarı aktar (OPML)', 'export_starred' => 'Favorileri dışarı aktar', 'feed_list' => '%s makalenin listesi', - 'file_to_import' => 'Dosyadan içe aktar
    (OPML, Json or Zip)', - 'file_to_import_no_zip' => 'Dosyadan içe aktar
    (OPML or Json)', + 'file_to_import' => 'Dosyadan içe aktar
    (OPML, JSON or ZIP)', + 'file_to_import_no_zip' => 'Dosyadan içe aktar
    (OPML or JSON)', 'import' => 'İçe aktar', 'starred_list' => 'Favori makaleleirn listesi', 'title' => 'İçe / dışa aktar', diff --git a/cli/_cli.php b/cli/_cli.php index cb6d8ec32..d81d83d66 100644 --- a/cli/_cli.php +++ b/cli/_cli.php @@ -37,3 +37,8 @@ function cliInitUser($username) { return $username; } + +function done($ok) { + echo 'Result: ', ($ok ? 'success' : 'fail'), ".\n"; + exit($ok ? 0 : 1); +} diff --git a/cli/create-user.php b/cli/create-user.php index 08c057af8..387b503b6 100755 --- a/cli/create-user.php +++ b/cli/create-user.php @@ -15,19 +15,19 @@ if (empty($options['user'])) { fail('Usage: ' . basename(__FILE__) . " --user=username --password='password' --api-password='api_password'" . " --language=en --email=user@example.net --token='longRandomString'"); } -$new_user_name = $options['user']; -if (!ctype_alnum($new_user_name)) { - fail('FreshRSS error: invalid username “' . $new_user_name . '”'); +$username = $options['user']; +if (!ctype_alnum($username)) { + fail('FreshRSS error: invalid username “' . $username . '”'); } $usernames = listUsers(); -if (preg_grep("/^$new_user_name$/i", $usernames)) { - fail('FreshRSS error: username already taken “' . $new_user_name . '”'); +if (preg_grep("/^$username$/i", $usernames)) { + fail('FreshRSS error: username already taken “' . $username . '”'); } -echo 'FreshRSS creating user “', $new_user_name, "”…\n"; +echo 'FreshRSS creating user “', $username, "”…\n"; -$ok = FreshRSS_user_Controller::createUser($new_user_name, +$ok = FreshRSS_user_Controller::createUser($username, empty($options['password']) ? '' : $options['password'], empty($options['api-password']) ? '' : $options['api-password'], array( @@ -37,5 +37,4 @@ $ok = FreshRSS_user_Controller::createUser($new_user_name, invalidateHttpCache(FreshRSS_Context::$system_conf->default_user); -echo 'Result: ', ($ok ? 'success' : 'fail'), ".\n"; -exit($ok ? 0 : 1); +done($ok); diff --git a/cli/delete-user.php b/cli/delete-user.php index 46332fe34..da48103f7 100755 --- a/cli/delete-user.php +++ b/cli/delete-user.php @@ -29,5 +29,4 @@ $ok = FreshRSS_user_Controller::deleteUser($username); invalidateHttpCache(FreshRSS_Context::$system_conf->default_user); -echo 'Result: ', ($ok ? 'success' : 'fail'), ".\n"; -exit($ok ? 0 : 1); +done($ok); diff --git a/cli/import-for-user.php b/cli/import-for-user.php new file mode 100644 index 000000000..308786599 --- /dev/null +++ b/cli/import-for-user.php @@ -0,0 +1,36 @@ +#!/usr/bin/php +importFile($filename, $filename, $username); +} catch (FreshRSS_ZipMissing_Exception $zme) { + fail('FreshRSS error: Lacking php-zip extension!'); +} catch (FreshRSS_Zip_Exception $ze) { + fail('FreshRSS error: ZIP archive cannot be imported! Error code: ' . $ze->zipErrorCode()); +} +invalidateHttpCache($username); + +done($ok); diff --git a/cli/list-users.php b/cli/list-users.php index cc1cf5269..e690ff451 100755 --- a/cli/list-users.php +++ b/cli/list-users.php @@ -4,8 +4,8 @@ require('_cli.php'); $users = listUsers(); sort($users); -if ($system_conf->default_user !== '') { - array_unshift($users, $system_conf->default_user); +if (FreshRSS_Context::$system_conf->default_user !== '') { + array_unshift($users, FreshRSS_Context::$system_conf->default_user); $users = array_unique($users); } diff --git a/lib/Minz/ModelPdo.php b/lib/Minz/ModelPdo.php index da28909df..45139b0d6 100644 --- a/lib/Minz/ModelPdo.php +++ b/lib/Minz/ModelPdo.php @@ -36,22 +36,21 @@ class Minz_ModelPdo { * HOST, BASE, USER et PASS définies dans le fichier de configuration */ public function __construct($currentUser = null) { - if (self::$useSharedBd && self::$sharedBd != null && $currentUser === null) { + if ($currentUser === null) { + $currentUser = Minz_Session::param('currentUser', '_'); + } + if (self::$useSharedBd && self::$sharedBd != null && $currentUser === self::$sharedCurrentUser) { $this->bd = self::$sharedBd; $this->prefix = self::$sharedPrefix; $this->current_user = self::$sharedCurrentUser; return; } + $this->current_user = $currentUser; + self::$sharedCurrentUser = $currentUser; $conf = Minz_Configuration::get('system'); $db = $conf->db; - if ($currentUser === null) { - $currentUser = Minz_Session::param('currentUser', '_'); - } - $this->current_user = $currentUser; - self::$sharedCurrentUser = $currentUser; - $driver_options = isset($conf->db['pdo_options']) && is_array($conf->db['pdo_options']) ? $conf->db['pdo_options'] : array(); $dbServer = parse_url('db://' . $db['host']); -- cgit v1.2.3 From fcb9280fc87c159539f5832ab35f174cd515654e Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sun, 23 Oct 2016 13:37:48 +0200 Subject: CLI export ZIP export, OPML export. Corrected height of feeds select in Pafat theme. https://github.com/FreshRSS/FreshRSS/pull/1338 https://github.com/FreshRSS/FreshRSS/issues/1039 https://github.com/FreshRSS/FreshRSS/issues/1277 --- app/Controllers/importExportController.php | 84 +++++++++++++++++++----------- app/Models/FeedDAO.php | 7 +++ app/views/importExport/index.phtml | 2 +- cli/_cli.php | 4 +- cli/create-user.php | 14 ++--- cli/delete-user.php | 2 +- cli/export-opml-for-user.php | 24 +++++++++ cli/export-zip-for-user.php | 30 +++++++++++ cli/import-for-user.php | 3 +- p/themes/Pafat/pafat.css | 3 -- 10 files changed, 128 insertions(+), 45 deletions(-) create mode 100644 cli/export-opml-for-user.php create mode 100644 cli/export-zip-for-user.php (limited to 'app/Controllers') diff --git a/app/Controllers/importExportController.php b/app/Controllers/importExportController.php index fbebb2a78..bb22ac739 100644 --- a/app/Controllers/importExportController.php +++ b/app/Controllers/importExportController.php @@ -522,26 +522,21 @@ class FreshRSS_importExport_Controller extends Minz_ActionController { return $return; } - /** - * This action handles export action. - * - * This action must be reached by a POST request. - * - * Parameters are: - * - export_opml (default: false) - * - export_starred (default: false) - * - export_feeds (default: array()) a list of feed ids - */ - public function exportAction() { - if (!Minz_Request::isPost()) { - Minz_Request::forward(array('c' => 'importExport', 'a' => 'index'), true); - } + public function exportFile($export_opml = true, $export_starred = false, $export_feeds = array(), $maxFeedEntries = 50, $username = null) { + require_once(LIB_PATH . '/lib_opml.php'); - $this->view->_useLayout(false); + $this->catDAO = new FreshRSS_CategoryDAO($username); + $this->entryDAO = FreshRSS_Factory::createEntryDao($username); + $this->feedDAO = FreshRSS_Factory::createFeedDao($username); + + if ($export_feeds === true) { + //All feeds + $export_feeds = $this->feedDAO->listFeedsIds(); + } + if (!is_array($export_feeds)) { + $export_feeds = array(); + } - $export_opml = Minz_Request::param('export_opml', false); - $export_starred = Minz_Request::param('export_starred', false); - $export_feeds = Minz_Request::param('export_feeds', array()); $day = date('Y-m-d'); $export_files = array(); @@ -558,7 +553,7 @@ class FreshRSS_importExport_Controller extends Minz_ActionController { if ($feed) { $filename = "feed_${day}_" . $feed->category() . '_' . $feed->id() . '.json'; - $export_files[$filename] = $this->generateEntries('feed', $feed); + $export_files[$filename] = $this->generateEntries('feed', $feed, $maxFeedEntries); } } @@ -566,18 +561,49 @@ class FreshRSS_importExport_Controller extends Minz_ActionController { if ($nb_files > 1) { // If there are more than 1 file to export, we need a ZIP archive. try { - $this->exportZip($export_files); + $this->sendZip($export_files); } catch (Exception $e) { - # Oops, there is no ZIP extension! - Minz_Request::bad(_t('feedback.import_export.export_no_zip_extension'), - array('c' => 'importExport', 'a' => 'index')); + throw new FreshRSS_ZipMissing_Exception($e); } } elseif ($nb_files === 1) { // Only one file? Guess its type and export it. $filename = key($export_files); $type = self::guessFileType($filename); - $this->exportFile('freshrss_' . $filename, $export_files[$filename], $type); - } else { + $this->sendFile('freshrss_' . $filename, $export_files[$filename], $type); + } + return $nb_files; + } + + /** + * This action handles export action. + * + * This action must be reached by a POST request. + * + * Parameters are: + * - export_opml (default: false) + * - export_starred (default: false) + * - export_feeds (default: array()) a list of feed ids + */ + public function exportAction() { + if (!Minz_Request::isPost()) { + Minz_Request::forward(array('c' => 'importExport', 'a' => 'index'), true); + } + $this->view->_useLayout(false); + + $nb_files = 0; + try { + $nb_files = $this->exportFile( + Minz_Request::param('export_opml', false), + Minz_Request::param('export_starred', false), + Minz_Request::param('export_feeds', array()) + ); + } catch (FreshRSS_ZipMissing_Exception $zme) { + # Oops, there is no ZIP extension! + Minz_Request::bad(_t('feedback.import_export.export_no_zip_extension'), + array('c' => 'importExport', 'a' => 'index')); + } + + if ($nb_files < 1) { // Nothing to do... Minz_Request::forward(array('c' => 'importExport', 'a' => 'index'), true); } @@ -606,7 +632,7 @@ class FreshRSS_importExport_Controller extends Minz_ActionController { * @param FreshRSS_Feed $feed feed of which we want to get entries. * @return string the JSON file content. */ - private function generateEntries($type, $feed = NULL) { + private function generateEntries($type, $feed = NULL, $maxFeedEntries = 50) { $this->view->categories = $this->catDAO->listCategories(); if ($type == 'starred') { @@ -621,7 +647,7 @@ class FreshRSS_importExport_Controller extends Minz_ActionController { $this->view->type = 'feed/' . $feed->id(); $this->view->entries = $this->entryDAO->listWhere( 'f', $feed->id(), FreshRSS_Entry::STATE_ALL, 'ASC', - FreshRSS_Context::$user_conf->posts_per_page + $maxFeedEntries ); $this->view->feed = $feed; } @@ -635,7 +661,7 @@ class FreshRSS_importExport_Controller extends Minz_ActionController { * @param array $files list of files where key is filename and value the content. * @throws Exception if Zip extension is not loaded. */ - private function exportZip($files) { + private function sendZip($files) { if (!extension_loaded('zip')) { throw new Exception(); } @@ -667,7 +693,7 @@ class FreshRSS_importExport_Controller extends Minz_ActionController { * @param string $type the file type (opml, json_feed or json_starred). * If equals to unknown, nothing happens. */ - private function exportFile($filename, $content, $type) { + private function sendFile($filename, $content, $type) { if ($type === 'unknown') { return; } diff --git a/app/Models/FeedDAO.php b/app/Models/FeedDAO.php index b21f19b66..68398efd5 100644 --- a/app/Models/FeedDAO.php +++ b/app/Models/FeedDAO.php @@ -212,6 +212,13 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo implements FreshRSS_Searchable { } } + public function listFeedsIds() { + $sql = 'SELECT id FROM `' . $this->prefix . 'feed`'; + $stm = $this->bd->prepare($sql); + $stm->execute(); + return $stm->fetchAll(PDO::FETCH_COLUMN, 0); + } + public function listFeeds() { $sql = 'SELECT * FROM `' . $this->prefix . 'feed` ORDER BY name'; $stm = $this->bd->prepare($sql); diff --git a/app/views/importExport/index.phtml b/app/views/importExport/index.phtml index c0bc412c3..c5049e3ea 100644 --- a/app/views/importExport/index.phtml +++ b/app/views/importExport/index.phtml @@ -44,7 +44,7 @@ $select_args = ' size="' . min(10, count($this->feeds)) .'" multiple="multiple"'; } ?> - size="10"> '; ?> feeds as $feed) { ?> diff --git a/cli/_cli.php b/cli/_cli.php index d81d83d66..66506f07a 100644 --- a/cli/_cli.php +++ b/cli/_cli.php @@ -10,7 +10,7 @@ Minz_Configuration::register('system', DATA_PATH . '/config.php', DATA_PATH . '/config.default.php'); FreshRSS_Context::$system_conf = Minz_Configuration::get('system'); -Minz_Translate::init(); +Minz_Translate::init('en'); FreshRSS_Context::$isCli = true; @@ -39,6 +39,6 @@ function cliInitUser($username) { } function done($ok) { - echo 'Result: ', ($ok ? 'success' : 'fail'), ".\n"; + fwrite(STDERR, 'Result: ' . ($ok ? 'success' : 'fail') . "\n"); exit($ok ? 0 : 1); } diff --git a/cli/create-user.php b/cli/create-user.php index 387b503b6..243e65a35 100755 --- a/cli/create-user.php +++ b/cli/create-user.php @@ -4,16 +4,16 @@ require('_cli.php'); $options = getopt('', array( 'user:', - 'password::', - 'api-password::', - 'language::', - 'email::', - 'token::', + 'password:', + 'api-password:', + 'language:', + 'email:', + 'token:', )); if (empty($options['user'])) { - fail('Usage: ' . basename(__FILE__) . " --user=username --password='password' --api-password='api_password'" . - " --language=en --email=user@example.net --token='longRandomString'"); + fail('Usage: ' . basename(__FILE__) . " --user username --password 'password' --api-password 'api_password'" . + " --language en --email user@example.net --token 'longRandomString'"); } $username = $options['user']; if (!ctype_alnum($username)) { diff --git a/cli/delete-user.php b/cli/delete-user.php index da48103f7..6f0e86e17 100755 --- a/cli/delete-user.php +++ b/cli/delete-user.php @@ -7,7 +7,7 @@ $options = getopt('', array( )); if (empty($options['user'])) { - fail('Usage: ' . basename(__FILE__) . " --user=username"); + fail('Usage: ' . basename(__FILE__) . " --user username"); } $username = $options['user']; if (!ctype_alnum($username)) { diff --git a/cli/export-opml-for-user.php b/cli/export-opml-for-user.php new file mode 100644 index 000000000..bce4efd63 --- /dev/null +++ b/cli/export-opml-for-user.php @@ -0,0 +1,24 @@ +#!/usr/bin/php + /path/to/file.opml.xml'"); +} + +$username = cliInitUser($options['user']); + +fwrite(STDERR, 'FreshRSS exporting OPML for user “' . $username . "”…\n"); + +$importController = new FreshRSS_importExport_Controller(); + +$ok = false; +$ok = $importController->exportFile(true, false, array(), 0, $username); + +invalidateHttpCache($username); + +done($ok); diff --git a/cli/export-zip-for-user.php b/cli/export-zip-for-user.php new file mode 100644 index 000000000..f8d24238b --- /dev/null +++ b/cli/export-zip-for-user.php @@ -0,0 +1,30 @@ +#!/usr/bin/php + /path/to/file.zip'"); +} + +$username = cliInitUser($options['user']); + +fwrite(STDERR, 'FreshRSS exporting ZIP for user “' . $username . "”…\n"); + +$importController = new FreshRSS_importExport_Controller(); + +$ok = false; +try { + $ok = $importController->exportFile(true, true, true, + empty($options['max-feed-entries']) ? 100 : intval($options['max-feed-entries']), + $username); +} catch (FreshRSS_ZipMissing_Exception $zme) { + fail('FreshRSS error: Lacking php-zip extension!'); +} +invalidateHttpCache($username); + +done($ok); diff --git a/cli/import-for-user.php b/cli/import-for-user.php index 308786599..29084f062 100755 --- a/cli/import-for-user.php +++ b/cli/import-for-user.php @@ -5,11 +5,10 @@ require('_cli.php'); $options = getopt('', array( 'user:', 'filename:', - 'clear-existing', )); if (empty($options['user']) || empty($options['filename'])) { - fail('Usage: ' . basename(__FILE__) . " --user=username --filename='/path/to/file.ext' --clear-existing"); + fail('Usage: ' . basename(__FILE__) . " --user username --filename /path/to/file.ext"); } $username = cliInitUser($options['user']); diff --git a/p/themes/Pafat/pafat.css b/p/themes/Pafat/pafat.css index 5e46a63ca..abe808eab 100644 --- a/p/themes/Pafat/pafat.css +++ b/p/themes/Pafat/pafat.css @@ -48,9 +48,6 @@ input, select, textarea { vertical-align: middle; } -select{ - height:29px; -} option { padding: 0 .5em; } -- cgit v1.2.3 From ab4ece6780cf841f6ce4e89f7b81a1ff1661f615 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Mon, 24 Oct 2016 01:41:09 +0200 Subject: CLI do-install https://github.com/FreshRSS/FreshRSS/issues/1095 https://github.com/FreshRSS/FreshRSS/issues/1090 --- app/Controllers/userController.php | 5 +- app/install.php | 161 +++++++------------------------------ cli/_cli.php | 7 +- cli/create-user.php | 10 ++- cli/do-install.php | 102 +++++++++++++++++++++++ lib/lib_install.php | 115 ++++++++++++++++++++++++++ 6 files changed, 260 insertions(+), 140 deletions(-) create mode 100644 cli/do-install.php create mode 100644 lib/lib_install.php (limited to 'app/Controllers') diff --git a/app/Controllers/userController.php b/app/Controllers/userController.php index 2f04c7a1d..9dee16e8c 100644 --- a/app/Controllers/userController.php +++ b/app/Controllers/userController.php @@ -24,7 +24,7 @@ class FreshRSS_user_Controller extends Minz_ActionController { } } - private static function hashPassword($passwordPlain) { + public static function hashPassword($passwordPlain) { if (!function_exists('password_hash')) { include_once(LIB_PATH . '/password_compat.php'); } @@ -112,9 +112,6 @@ class FreshRSS_user_Controller extends Minz_ActionController { $userConfig['language'] = 'en'; } - $default_user = FreshRSS_Context::$system_conf->default_user; - $ok &= (strcasecmp($new_user_name, $default_user) !== 0); //It is forbidden to alter the default user - $ok &= !in_array(strtoupper($new_user_name), array_map('strtoupper', listUsers())); //Not an existing user, case-insensitive $configPath = join_path(DATA_PATH, 'users', $new_user_name, 'config.php'); diff --git a/app/install.php b/app/install.php index 1972379e5..6956761c7 100644 --- a/app/install.php +++ b/app/install.php @@ -4,15 +4,12 @@ if (function_exists('opcache_reset')) { } header("Content-Security-Policy: default-src 'self'"); -define('BCRYPT_COST', 9); +require(LIB_PATH . '/lib_install.php'); session_name('FreshRSS'); session_set_cookie_params(0, dirname(empty($_SERVER['REQUEST_URI']) ? '/' : dirname($_SERVER['REQUEST_URI'])), null, false, true); session_start(); -Minz_Configuration::register('default_system', join_path(DATA_PATH, 'config.default.php')); -Minz_Configuration::register('default_user', join_path(USERS_PATH, '_', 'config.default.php')); - if (isset($_GET['step'])) { define('STEP',(int)$_GET['step']); } else { @@ -26,13 +23,13 @@ if (STEP === 3 && isset($_POST['type'])) { if (isset($_SESSION['bd_type'])) { switch ($_SESSION['bd_type']) { case 'mysql': - include(APP_PATH . '/SQL/install.sql.mysql.php'); + include_once(APP_PATH . '/SQL/install.sql.mysql.php'); break; case 'sqlite': - include(APP_PATH . '/SQL/install.sql.sqlite.php'); + include_once(APP_PATH . '/SQL/install.sql.sqlite.php'); break; case 'pgsql': - include(APP_PATH . '/SQL/install.sql.pgsql.php'); + include_once(APP_PATH . '/SQL/install.sql.pgsql.php'); break; } } @@ -131,12 +128,7 @@ function saveStep2() { $password_plain = param('passwordPlain', false); if ($password_plain !== false && cryptAvailable()) { - if (!function_exists('password_hash')) { - include_once(LIB_PATH . '/password_compat.php'); - } - $passwordHash = password_hash($password_plain, PASSWORD_BCRYPT, array('cost' => BCRYPT_COST)); - $passwordHash = preg_replace('/^\$2[xy]\$/', '\$2a\$', $passwordHash); //Compatibility with bcrypt.js - $_SESSION['passwordHash'] = $passwordHash; + $_SESSION['passwordHash'] = FreshRSS_user_Controller::hashPassword($password_plain); } if (empty($_SESSION['old_entries']) || @@ -149,7 +141,7 @@ function saveStep2() { return false; } - $_SESSION['salt'] = sha1(uniqid(mt_rand(), true).implode('', stat(__FILE__))); + $_SESSION['salt'] = generateSalt(); if ((!ctype_digit($_SESSION['old_entries'])) ||($_SESSION['old_entries'] < 1)) { $_SESSION['old_entries'] = $user_default_config->old_entries; } @@ -171,7 +163,7 @@ function saveStep2() { recursive_unlink($user_dir); mkdir($user_dir); - file_put_contents($user_config_path, " 0 && $s0['all'] != 'ok') { @@ -279,49 +265,6 @@ function checkStep0() { ); } -function checkStep1() { - $php = version_compare(PHP_VERSION, '5.3.3') >= 0; - $minz = file_exists(join_path(LIB_PATH, 'Minz')); - $curl = extension_loaded('curl'); - $pdo_mysql = extension_loaded('pdo_mysql'); - $pdo_sqlite = extension_loaded('pdo_sqlite'); - $pdo_pgsql = extension_loaded('pdo_pgsql'); - $pdo = $pdo_mysql || $pdo_sqlite || $pdo_pgsql; - $pcre = extension_loaded('pcre'); - $ctype = extension_loaded('ctype'); - $dom = class_exists('DOMDocument'); - $xml = function_exists('xml_parser_create'); - $json = function_exists('json_encode'); - $data = DATA_PATH && is_writable(DATA_PATH); - $cache = CACHE_PATH && is_writable(CACHE_PATH); - $users = USERS_PATH && is_writable(USERS_PATH); - $favicons = is_writable(join_path(DATA_PATH, 'favicons')); - $http_referer = is_referer_from_same_domain(); - - return array( - 'php' => $php ? 'ok' : 'ko', - 'minz' => $minz ? 'ok' : 'ko', - 'curl' => $curl ? 'ok' : 'ko', - 'pdo-mysql' => $pdo_mysql ? 'ok' : 'ko', - 'pdo-sqlite' => $pdo_sqlite ? 'ok' : 'ko', - 'pdo-pgsql' => $pdo_pgsql ? 'ok' : 'ko', - 'pdo' => $pdo ? 'ok' : 'ko', - 'pcre' => $pcre ? 'ok' : 'ko', - 'ctype' => $ctype ? 'ok' : 'ko', - 'dom' => $dom ? 'ok' : 'ko', - 'xml' => $xml ? 'ok' : 'ko', - 'json' => $json ? 'ok' : 'ko', - 'data' => $data ? 'ok' : 'ko', - 'cache' => $cache ? 'ok' : 'ko', - 'users' => $users ? 'ok' : 'ko', - 'favicons' => $favicons ? 'ok' : 'ko', - 'http_referer' => $http_referer ? 'ok' : 'ko', - 'all' => $php && $minz && $curl && $pdo && $pcre && $ctype && $dom && $xml && - $data && $cache && $users && $favicons && $http_referer ? - 'ok' : 'ko' - ); -} - function freshrss_already_installed() { $conf_path = join_path(DATA_PATH, 'config.php'); if (!file_exists($conf_path)) { @@ -392,60 +335,15 @@ function checkStep3() { ); } -function checkBD() { +function checkDbUser(&$dbOptions) { $ok = false; - + $str = $dbOptions['bd_dsn']; + $driver_options = $dbOptions['bd_options']; try { - $str = ''; - $driver_options = null; - switch ($_SESSION['bd_type']) { - case 'mysql': - $driver_options = array( - PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8mb4' - ); - - try { // on ouvre une connexion juste pour créer la base si elle n'existe pas - $str = 'mysql:host=' . $_SESSION['bd_host'] . ';'; - $c = new PDO($str, $_SESSION['bd_user'], $_SESSION['bd_password'], $driver_options); - $sql = sprintf(SQL_CREATE_DB, $_SESSION['bd_base']); - $res = $c->query($sql); - } catch (PDOException $e) { - } - - // on écrase la précédente connexion en sélectionnant la nouvelle BDD - $str = 'mysql:host=' . $_SESSION['bd_host'] . ';dbname=' . $_SESSION['bd_base']; - break; - case 'sqlite': - $str = 'sqlite:' . join_path(USERS_PATH, $_SESSION['default_user'], 'db.sqlite'); - $driver_options = array( - PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, - ); - break; - case 'pgsql': - $driver_options = array( - PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, - ); - - try { // on ouvre une connexion juste pour créer la base si elle n'existe pas - $str = 'pgsql:host=' . $_SESSION['bd_host'] . ';dbname=postgres'; - $c = new PDO($str, $_SESSION['bd_user'], $_SESSION['bd_password'], $driver_options); - $sql = sprintf(SQL_CREATE_DB, $_SESSION['bd_base']); - $res = $c->query($sql); - } catch (PDOException $e) { - syslog(LOG_DEBUG, 'pgsql ' . $e->getMessage()); - } - - // on écrase la précédente connexion en sélectionnant la nouvelle BDD - $str = 'pgsql:host=' . $_SESSION['bd_host'] . ';dbname=' . $_SESSION['bd_base']; - break; - default: - return false; - } - - $c = new PDO($str, $_SESSION['bd_user'], $_SESSION['bd_password'], $driver_options); + $c = new PDO($str, $dbOptions['bd_user'], $dbOptions['bd_password'], $driver_options); if (defined('SQL_CREATE_TABLES')) { - $sql = sprintf(SQL_CREATE_TABLES, $_SESSION['bd_prefix_user'], _t('gen.short.default_category')); + $sql = sprintf(SQL_CREATE_TABLES, $dbOptions['bd_prefix_user'], _t('gen.short.default_category')); $stm = $c->prepare($sql); $ok = $stm->execute(); } else { @@ -453,7 +351,7 @@ function checkBD() { if (is_array($SQL_CREATE_TABLES)) { $ok = true; foreach ($SQL_CREATE_TABLES as $instruction) { - $sql = sprintf($instruction, $_SESSION['bd_prefix_user'], _t('gen.short.default_category')); + $sql = sprintf($instruction, $dbOptions['bd_prefix_user'], _t('gen.short.default_category')); $stm = $c->prepare($sql); $ok &= $stm->execute(); } @@ -461,13 +359,8 @@ function checkBD() { } } catch (PDOException $e) { $ok = false; - $_SESSION['bd_error'] = $e->getMessage(); + $dbOptions['bd_error'] = $e->getMessage(); } - - if (!$ok) { - @unlink(join_path(DATA_PATH, 'config.php')); - } - return $ok; } @@ -510,7 +403,7 @@ function printStep0() { // @todo refactor this view with the check_install action function printStep1() { - $res = checkStep1(); + $res = checkRequirements(); ?> @@ -805,7 +698,9 @@ case 3: case 4: break; case 5: - deleteInstall(); + if (deleteInstall()) { + header('Location: index.php'); + } break; } ?> diff --git a/cli/_cli.php b/cli/_cli.php index 66506f07a..7d1a7c6b2 100644 --- a/cli/_cli.php +++ b/cli/_cli.php @@ -38,7 +38,12 @@ function cliInitUser($username) { return $username; } -function done($ok) { +function accessRights() { + echo '• Remember to re-apply the appropriate access rights, such as:' , "\n", + "\t", 'sudo chown -R :www-data . && sudo chmod -R g+r . && sudo chmod -R g+w ./data/', "\n"; +} + +function done($ok = true) { fwrite(STDERR, 'Result: ' . ($ok ? 'success' : 'fail') . "\n"); exit($ok ? 0 : 1); } diff --git a/cli/create-user.php b/cli/create-user.php index 243e65a35..5e93d4605 100755 --- a/cli/create-user.php +++ b/cli/create-user.php @@ -12,8 +12,8 @@ $options = getopt('', array( )); if (empty($options['user'])) { - fail('Usage: ' . basename(__FILE__) . " --user username --password 'password' --api-password 'api_password'" . - " --language en --email user@example.net --token 'longRandomString'"); + fail('Usage: ' . basename(__FILE__) . " --user username ( --password 'password' --api-password 'api_password'" . + " --language en --email user@example.net --token 'longRandomString' )"); } $username = $options['user']; if (!ctype_alnum($username)) { @@ -35,6 +35,12 @@ $ok = FreshRSS_user_Controller::createUser($username, 'token' => empty($options['token']) ? '' : $options['token'], )); +if (!$ok) { + fail('FreshRSS could not create user!'); +} + invalidateHttpCache(FreshRSS_Context::$system_conf->default_user); +accessRights(); + done($ok); diff --git a/cli/do-install.php b/cli/do-install.php new file mode 100644 index 000000000..5eeedc626 --- /dev/null +++ b/cli/do-install.php @@ -0,0 +1,102 @@ +#!/usr/bin/php + $check) { + if ($check !== 'ok' && $requirement !== 'all') { + $message .= '• ' . $requirement . "\n"; + } + } + fail($message); +} + +if (!ctype_alnum($options['default_user'])) { + fail('FreshRSS invalid default username (must be ASCII alphanumeric): ' . $options['default_user']); +} + +if (!in_array($options['auth_type'], array('form', 'http_auth', 'none'))) { + fail('FreshRSS invalid authentication method (auth_type must be one of { form, http_auth, none }: ' . $options['auth_type']); +} + +$config = array( + 'salt' => generateSalt(), + 'db' => FreshRSS_Context::$system_conf->db, + ); + +foreach ($params as $param) { + $param = rtrim($param, ':'); + if (isset($options[$param])) { + $config[$param] = $options[$param] === false ? true : $options[$param]; + } +} + +if ((!empty($config['base_url'])) && server_is_public($config['base_url'])) { + $config['pubsubhubbub_enabled'] = true; +} + +foreach ($dBparams as $dBparam) { + $dBparam = rtrim($dBparam, ':'); + if (!empty($options[$dBparam])) { + $param = substr($dBparam, strlen('db-')); + $config['db'][$param] = $options[$dBparam]; + } +} + +if (file_put_contents(join_path(DATA_PATH, 'config.php'), "= 0; + $minz = file_exists(join_path(LIB_PATH, 'Minz')); + $curl = extension_loaded('curl'); + $pdo_mysql = extension_loaded('pdo_mysql'); + $pdo_sqlite = extension_loaded('pdo_sqlite'); + $pdo_pgsql = extension_loaded('pdo_pgsql'); + $pdo = $pdo_mysql || $pdo_sqlite || $pdo_pgsql; + $pcre = extension_loaded('pcre'); + $ctype = extension_loaded('ctype'); + $dom = class_exists('DOMDocument'); + $xml = function_exists('xml_parser_create'); + $json = function_exists('json_encode'); + $data = DATA_PATH && is_writable(DATA_PATH); + $cache = CACHE_PATH && is_writable(CACHE_PATH); + $users = USERS_PATH && is_writable(USERS_PATH); + $favicons = is_writable(join_path(DATA_PATH, 'favicons')); + $http_referer = is_referer_from_same_domain(); + + return array( + 'php' => $php ? 'ok' : 'ko', + 'minz' => $minz ? 'ok' : 'ko', + 'curl' => $curl ? 'ok' : 'ko', + 'pdo-mysql' => $pdo_mysql ? 'ok' : 'ko', + 'pdo-sqlite' => $pdo_sqlite ? 'ok' : 'ko', + 'pdo-pgsql' => $pdo_pgsql ? 'ok' : 'ko', + 'pdo' => $pdo ? 'ok' : 'ko', + 'pcre' => $pcre ? 'ok' : 'ko', + 'ctype' => $ctype ? 'ok' : 'ko', + 'dom' => $dom ? 'ok' : 'ko', + 'xml' => $xml ? 'ok' : 'ko', + 'json' => $json ? 'ok' : 'ko', + 'data' => $data ? 'ok' : 'ko', + 'cache' => $cache ? 'ok' : 'ko', + 'users' => $users ? 'ok' : 'ko', + 'favicons' => $favicons ? 'ok' : 'ko', + 'http_referer' => $http_referer ? 'ok' : 'ko', + 'all' => $php && $minz && $curl && $pdo && $pcre && $ctype && $dom && $xml && + $data && $cache && $users && $favicons && $http_referer ? + 'ok' : 'ko' + ); +} + +function generateSalt() { + return sha1(uniqid(mt_rand(), true).implode('', stat(__FILE__))); +} + +function checkDb(&$dbOptions) { + $dsn = ''; + try { + $driver_options = null; + switch ($dbOptions['type']) { + case 'mysql': + include_once(APP_PATH . '/SQL/install.sql.mysql.php'); + $driver_options = array( + PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8mb4' + ); + try { // on ouvre une connexion juste pour créer la base si elle n'existe pas + $dsn = 'mysql:host=' . $dbOptions['host'] . ';'; + $c = new PDO($dsn, $dbOptions['user'], $dbOptions['password'], $driver_options); + $sql = sprintf(SQL_CREATE_DB, $dbOptions['base']); + $res = $c->query($sql); + } catch (PDOException $e) { + syslog(LOG_DEBUG, 'FreshRSS MySQL warning: ' . $e->getMessage()); + } + // on écrase la précédente connexion en sélectionnant la nouvelle BDD + $dsn = 'mysql:host=' . $dbOptions['host'] . ';dbname=' . $dbOptions['base']; + break; + case 'sqlite': + include_once(APP_PATH . '/SQL/install.sql.sqlite.php'); + $dsn = 'sqlite:' . join_path(USERS_PATH, $dbOptions['default_user'], 'db.sqlite'); + $driver_options = array( + PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, + ); + break; + case 'pgsql': + include_once(APP_PATH . '/SQL/install.sql.pgsql.php'); + $driver_options = array( + PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, + ); + try { // on ouvre une connexion juste pour créer la base si elle n'existe pas + $dsn = 'pgsql:host=' . $dbOptions['host'] . ';dbname=postgres'; + $c = new PDO($dsn, $dbOptions['user'], $dbOptions['password'], $driver_options); + $sql = sprintf(SQL_CREATE_DB, $dbOptions['base']); + $res = $c->query($sql); + } catch (PDOException $e) { + syslog(LOG_DEBUG, 'FreshRSS PostgreSQL warning: ' . $e->getMessage()); + } + // on écrase la précédente connexion en sélectionnant la nouvelle BDD + $dsn = 'pgsql:host=' . $dbOptions['host'] . ';dbname=' . $dbOptions['base']; + break; + default: + return false; + } + } catch (PDOException $e) { + $dsn = ''; + $dbOptions['error'] = $e->getMessage(); + } + $dbOptions['dsn'] = $dsn; + $dbOptions['options'] = $driver_options; + return $dsn != ''; +} + +function deleteInstall() { + $path = join_path(DATA_PATH, 'do-install.txt'); + @unlink($path); + return !file_exists($path); +} -- cgit v1.2.3 From 1182129ce5f07892afed190ffbb2ea4c7fc28967 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Mon, 24 Oct 2016 20:29:08 +0200 Subject: CLI option no-default-feeds https://github.com/FreshRSS/FreshRSS/issues/1095 --- app/Controllers/userController.php | 4 ++-- app/Models/UserDAO.php | 18 +++++++++++++++++- app/SQL/install.sql.mysql.php | 3 +++ app/SQL/install.sql.pgsql.php | 4 ++++ app/SQL/install.sql.sqlite.php | 4 ++++ app/install.php | 15 +++++++++++++++ cli/create-user.php | 7 +++++-- 7 files changed, 50 insertions(+), 5 deletions(-) (limited to 'app/Controllers') diff --git a/app/Controllers/userController.php b/app/Controllers/userController.php index 9dee16e8c..9d6ae18e6 100644 --- a/app/Controllers/userController.php +++ b/app/Controllers/userController.php @@ -99,7 +99,7 @@ class FreshRSS_user_Controller extends Minz_ActionController { $this->view->size_user = $entryDAO->size(); } - public static function createUser($new_user_name, $passwordPlain, $apiPasswordPlain, $userConfig = array()) { + public static function createUser($new_user_name, $passwordPlain, $apiPasswordPlain, $userConfig = array(), $insertDefaultFeeds = true) { if (!is_array($userConfig)) { $userConfig = array(); } @@ -138,7 +138,7 @@ class FreshRSS_user_Controller extends Minz_ActionController { } if ($ok) { $userDAO = new FreshRSS_UserDAO(); - $ok &= $userDAO->createUser($new_user_name, $userConfig['language']); + $ok &= $userDAO->createUser($new_user_name, $userConfig['language'], $insertDefaultFeeds); } return $ok; } diff --git a/app/Models/UserDAO.php b/app/Models/UserDAO.php index 597182693..a95ee6bc4 100644 --- a/app/Models/UserDAO.php +++ b/app/Models/UserDAO.php @@ -1,7 +1,7 @@ db; require_once(APP_PATH . '/SQL/install.sql.' . $db['type'] . '.php'); @@ -28,6 +28,22 @@ class FreshRSS_UserDAO extends Minz_ModelPdo { } } } + if ($insertDefaultFeeds) { + if (defined('SQL_INSERT_FEEDS')) { //E.g. MySQL + $sql = sprintf(SQL_INSERT_FEEDS, $bd_prefix_user); + $stm = $userPDO->bd->prepare($sql); + $ok &= $stm && $stm->execute(); + } else { //E.g. SQLite + global $SQL_INSERT_FEEDS; + if (is_array($SQL_INSERT_FEEDS)) { + foreach ($SQL_INSERT_FEEDS as $instruction) { + $sql = sprintf($instruction, $bd_prefix_user); + $stm = $userPDO->bd->prepare($sql); + $ok &= ($stm && $stm->execute()); + } + } + } + } } catch (Exception $e) { Minz_Log::error('Error while creating user: ' . $e->getMessage()); } diff --git a/app/SQL/install.sql.mysql.php b/app/SQL/install.sql.mysql.php index ca181303e..a454829d5 100644 --- a/app/SQL/install.sql.mysql.php +++ b/app/SQL/install.sql.mysql.php @@ -59,6 +59,9 @@ CREATE TABLE IF NOT EXISTS `%1$sentry` ( ENGINE = INNODB; INSERT IGNORE INTO `%1$scategory` (id, name) VALUES(1, "%2$s"); +'); + +define('SQL_INSERT_FEEDS', ' INSERT IGNORE INTO `%1$sfeed` (url, category, name, website, description, ttl) VALUES("http://freshrss.org/feeds/all.atom.xml", 1, "FreshRSS.org", "http://freshrss.org/", "FreshRSS, a free, self-hostable aggregator…", 86400); INSERT IGNORE INTO `%1$sfeed` (url, category, name, website, description, ttl) VALUES("https://github.com/FreshRSS/FreshRSS/releases.atom", 1, "FreshRSS @ GitHub", "https://github.com/FreshRSS/FreshRSS/", "FreshRSS releases @ GitHub", 86400); '); diff --git a/app/SQL/install.sql.pgsql.php b/app/SQL/install.sql.pgsql.php index b343bda86..9f4240b98 100644 --- a/app/SQL/install.sql.pgsql.php +++ b/app/SQL/install.sql.pgsql.php @@ -52,6 +52,10 @@ $SQL_CREATE_TABLES = array( 'CREATE INDEX %1$sentry_lastSeen_index ON "%1$sentry" ("lastSeen");', 'INSERT INTO "%1$scategory" (name) SELECT \'%2$s\' WHERE NOT EXISTS (SELECT id FROM "%1$scategory" WHERE id = 1);', +); + +global $SQL_INSERT_FEEDS; +$SQL_INSERT_FEEDS = array( 'INSERT INTO "%1$sfeed" (url, category, name, website, description, ttl) SELECT \'http://freshrss.org/feeds/all.atom.xml\', 1, \'FreshRSS.org\', \'http://freshrss.org/\', \'FreshRSS, a free, self-hostable aggregator…\', 86400 WHERE NOT EXISTS (SELECT id FROM "%1$sfeed" WHERE url = \'http://freshrss.org/feeds/all.atom.xml\');', 'INSERT INTO "%1$sfeed" (url, category, name, website, description, ttl) SELECT \'https://github.com/FreshRSS/FreshRSS/releases.atom\', 1, \'FreshRSS @ GitHub\', \'https://github.com/FreshRSS/FreshRSS/\', \'FreshRSS releases @ GitHub\', 86400 WHERE NOT EXISTS (SELECT id FROM "%1$sfeed" WHERE url = \'https://github.com/FreshRSS/FreshRSS/releases.atom\');', ); diff --git a/app/SQL/install.sql.sqlite.php b/app/SQL/install.sql.sqlite.php index 1d3a5d92f..68d93ba92 100644 --- a/app/SQL/install.sql.sqlite.php +++ b/app/SQL/install.sql.sqlite.php @@ -55,6 +55,10 @@ $SQL_CREATE_TABLES = array( 'CREATE INDEX IF NOT EXISTS entry_lastSeen_index ON `entry`(`lastSeen`);', //v1.1.1 'INSERT OR IGNORE INTO `category` (id, name) VALUES(1, "%2$s");', +); + +global $SQL_INSERT_FEEDS; +$SQL_INSERT_FEEDS = array( 'INSERT OR IGNORE INTO `feed` (url, category, name, website, description, ttl) VALUES("http://freshrss.org/feeds/all.atom.xml", 1, "FreshRSS.org", "http://freshrss.org/", "FreshRSS, a free, self-hostable aggregator…", 86400);', 'INSERT OR IGNORE INTO `feed` (url, category, name, website, description, ttl) VALUES("https://github.com/FreshRSS/FreshRSS/releases.atom", 1, "FreshRSS releases", "https://github.com/FreshRSS/FreshRSS/", "FreshRSS releases @ GitHub", 86400);', ); diff --git a/app/install.php b/app/install.php index 6956761c7..0daa02b1b 100644 --- a/app/install.php +++ b/app/install.php @@ -357,6 +357,21 @@ function checkDbUser(&$dbOptions) { } } } + + if (defined('SQL_INSERT_FEEDS')) { + $sql = sprintf(SQL_INSERT_FEEDS, $dbOptions['bd_prefix_user']); + $stm = $c->prepare($sql); + $ok &= $stm->execute(); + } else { + global $SQL_INSERT_FEEDS; + if (is_array($SQL_INSERT_FEEDS)) { + foreach ($SQL_INSERT_FEEDS as $instruction) { + $sql = sprintf($instruction, $dbOptions['bd_prefix_user']); + $stm = $c->prepare($sql); + $ok &= $stm->execute(); + } + } + } } catch (PDOException $e) { $ok = false; $dbOptions['bd_error'] = $e->getMessage(); diff --git a/cli/create-user.php b/cli/create-user.php index 5e93d4605..c790acb59 100755 --- a/cli/create-user.php +++ b/cli/create-user.php @@ -9,11 +9,12 @@ $options = getopt('', array( 'language:', 'email:', 'token:', + 'no-default-feeds', )); if (empty($options['user'])) { fail('Usage: ' . basename(__FILE__) . " --user username ( --password 'password' --api-password 'api_password'" . - " --language en --email user@example.net --token 'longRandomString' )"); + " --language en --email user@example.net --token 'longRandomString --no-default-feeds' )"); } $username = $options['user']; if (!ctype_alnum($username)) { @@ -33,7 +34,9 @@ $ok = FreshRSS_user_Controller::createUser($username, array( 'language' => empty($options['language']) ? '' : $options['language'], 'token' => empty($options['token']) ? '' : $options['token'], - )); + ), + !isset($options['no-default-feeds']) + ); if (!$ok) { fail('FreshRSS could not create user!'); -- cgit v1.2.3 From 7dc9862596d9b598c4b1146b29cfb3548dafce40 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Tue, 25 Oct 2016 00:10:49 +0200 Subject: Fix OPML import bug --- app/Controllers/importExportController.php | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) (limited to 'app/Controllers') diff --git a/app/Controllers/importExportController.php b/app/Controllers/importExportController.php index bb22ac739..3ba91a243 100644 --- a/app/Controllers/importExportController.php +++ b/app/Controllers/importExportController.php @@ -84,6 +84,8 @@ class FreshRSS_importExport_Controller extends Minz_ActionController { $ok = false; if (FreshRSS_Context::$isCli) { fwrite(STDERR, 'FreshRSS error during OPML import' . "\n"); + } else { + Minz_Log::warning('Error during OPML import'); } } } @@ -92,6 +94,8 @@ class FreshRSS_importExport_Controller extends Minz_ActionController { $ok = false; if (FreshRSS_Context::$isCli) { fwrite(STDERR, 'FreshRSS error during JSON stars import' . "\n"); + } else { + Minz_Log::warning('Error during JSON stars import'); } } } @@ -100,6 +104,8 @@ class FreshRSS_importExport_Controller extends Minz_ActionController { $ok = false; if (FreshRSS_Context::$isCli) { fwrite(STDERR, 'FreshRSS error during JSON feeds import' . "\n"); + } else { + Minz_Log::warning('Error during JSON feeds import'); } } } @@ -214,13 +220,11 @@ class FreshRSS_importExport_Controller extends Minz_ActionController { foreach ($opml_elements as $elt) { if (isset($elt['xmlUrl'])) { // If xmlUrl exists, it means it is a feed - if (!FreshRSS_Context::$isCli) { - if ($nb_feeds >= $limits['max_feeds']) { - Minz_Log::warning(_t('feedback.sub.feed.over_max', - $limits['max_feeds'])); - $ok = false; - continue; - } + if (FreshRSS_Context::$isCli && $nb_feeds >= $limits['max_feeds']) { + Minz_Log::warning(_t('feedback.sub.feed.over_max', + $limits['max_feeds'])); + $ok = false; + continue; } if ($this->addFeedOpml($elt, $parent_cat)) { @@ -231,11 +235,9 @@ class FreshRSS_importExport_Controller extends Minz_ActionController { } else { // No xmlUrl? It should be a category! $limit_reached = ($nb_cats >= $limits['max_categories']); - if (!FreshRSS_Context::$isCli) { - if ($limit_reached) { - Minz_Log::warning(_t('feedback.sub.category.over_max', - $limits['max_categories'])); - } + if (!FreshRSS_Context::$isCli && $limit_reached) { + Minz_Log::warning(_t('feedback.sub.category.over_max', + $limits['max_categories'])); $ok = false; continue; } -- cgit v1.2.3 From 21e63595083d556bd4a6ff56c4ccaab5cd318dd4 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sat, 5 Nov 2016 15:08:10 +0100 Subject: Add compatibility with git in Web update https://github.com/FreshRSS/FreshRSS/issues/907 https://github.com/FreshRSS/FreshRSS/issues/1355 --- CHANGELOG.md | 3 + README.fr.md | 4 +- README.md | 2 +- app/Controllers/updateController.php | 159 ++++++++++++++++++++++++----------- 4 files changed, 118 insertions(+), 50 deletions(-) (limited to 'app/Controllers') diff --git a/CHANGELOG.md b/CHANGELOG.md index 77ec29aed..140c8cfaf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,9 @@ ## 2016-xx-xx FreshRSS 1.7.0-dev +* Features + * Add git compatibility in Web update system [#1357](https://github.com/FreshRSS/FreshRSS/issues/1357) + * Requires that the initial installation is done with git ## 2016-11-02 FreshRSS 1.6.1 diff --git a/README.fr.md b/README.fr.md index 2587c2d8f..afa8fa1ce 100644 --- a/README.fr.md +++ b/README.fr.md @@ -23,7 +23,7 @@ Voir la [liste des versions](../../releases). * Pour ceux qui veulent bien aider à tester ou déveloper les dernières fonctionnalités, [la branche dev](https://github.com/FreshRSS/FreshRSS/tree/dev) vous ouvre les bras ! # Avertissements -Cette application a été développée pour s’adapter principalement à des besoins personnels, et aucune garantie n'est fournie. +Cette application a été développée pour s’adapter principalement à des besoins personnels, et aucune garantie n’est fournie. Les demandes de fonctionnalités, rapports de bugs, et autres contributions sont les bienvenues. Privilégiez pour cela des [demandes sur GitHub](https://github.com/FreshRSS/FreshRSS/issues). Nous sommes une communauté amicale. @@ -85,7 +85,7 @@ sudo git checkout -b dev origin/dev # Mettre les droits d’accès pour le serveur Web sudo chown -R :www-data . && sudo chmod -R g+r . && sudo chmod -R g+w ./data/ -# Si vous souhaitez permettre les mises à jour par l'interface Web (inutile pour les mises à jour par git) +# Si vous souhaitez permettre les mises à jour par l’interface Web sudo chmod -R g+w . # Publier FreshRSS dans votre répertoire HTML public diff --git a/README.md b/README.md index cfb7b6769..ebf1e3c5f 100644 --- a/README.md +++ b/README.md @@ -85,7 +85,7 @@ sudo git checkout -b dev origin/dev # Set the rights so that your Web server can access the files sudo chown -R :www-data . && sudo chmod -R g+r . && sudo chmod -R g+w ./data/ -# If you would like to allow Web updates (not needed for updates with git) +# If you would like to allow updates from the Web interface sudo chmod -R g+w . # Publish FreshRSS in your public HTML directory diff --git a/app/Controllers/updateController.php b/app/Controllers/updateController.php index 64c984b04..8f939dbdb 100644 --- a/app/Controllers/updateController.php +++ b/app/Controllers/updateController.php @@ -2,6 +2,45 @@ class FreshRSS_update_Controller extends Minz_ActionController { + public static function isGit() { + return is_dir(FRESHRSS_PATH . '/.git/'); + } + + public static function hasGitUpdate() { + $cwd = getcwd(); + chdir(FRESHRSS_PATH); + $output = array(); + try { + exec('git fetch', $output, $return); + if ($return == 0) { + exec('git status -sb --porcelain remote', $output, $return); + } else { + $line = is_array($output) ? implode('; ', $output) : '' . $output; + Minz_Log::warning('git fetch warning:' . $line); + } + } catch (Exception $e) { + Minz_Log::warning('git fetch error:' . $e->getMessage()); + } + chdir($cwd); + $line = is_array($output) ? implode('; ', $output) : '' . $output; + return strpos($line, '[behind') !== false; + } + + public static function gitPull() { + $cwd = getcwd(); + chdir(FRESHRSS_PATH); + $output = array(); + $return = 1; + try { + exec('git pull --ff-only', $output, $return); + } catch (Exception $e) { + Minz_Log::warning('git pull error:' . $e->getMessage()); + } + chdir($cwd); + $line = is_array($output) ? implode('; ', $output) : '' . $output; + return $return == 0 ? true : 'Git error: ' . $line; + } + public function firstAction() { if (!FreshRSS_Auth::hasAccess('admin')) { Minz_Error::error(403); @@ -20,7 +59,7 @@ class FreshRSS_update_Controller extends Minz_ActionController { public function indexAction() { Minz_View::prependTitle(_t('admin.update.title') . ' · '); - if (file_exists(UPDATE_FILENAME) && !is_writable(FRESHRSS_PATH)) { + if (!is_writable(FRESHRSS_PATH)) { $this->view->message = array( 'status' => 'bad', 'title' => _t('gen.short.damn'), @@ -53,49 +92,65 @@ class FreshRSS_update_Controller extends Minz_ActionController { return; } - $auto_update_url = FreshRSS_Context::$system_conf->auto_update_url . '?v=' . FRESHRSS_VERSION; - $c = curl_init($auto_update_url); - curl_setopt($c, CURLOPT_RETURNTRANSFER, true); - curl_setopt($c, CURLOPT_SSL_VERIFYPEER, true); - curl_setopt($c, CURLOPT_SSL_VERIFYHOST, 2); - $result = curl_exec($c); - $c_status = curl_getinfo($c, CURLINFO_HTTP_CODE); - $c_error = curl_error($c); - curl_close($c); - - if ($c_status !== 200) { - Minz_Log::warning( - 'Error during update (HTTP code ' . $c_status . '): ' . $c_error - ); + $script = ''; + $version = ''; - $this->view->message = array( - 'status' => 'bad', - 'title' => _t('gen.short.damn'), - 'body' => _t('feedback.update.server_not_found', $auto_update_url) - ); - return; - } - - $res_array = explode("\n", $result, 2); - $status = $res_array[0]; - if (strpos($status, 'UPDATE') !== 0) { - $this->view->message = array( - 'status' => 'bad', - 'title' => _t('gen.short.damn'), - 'body' => _t('feedback.update.none') - ); + if (self::isGit()) { + if (self::hasGitUpdate()) { + $version = 'git'; + } else { + $this->view->message = array( + 'status' => 'bad', + 'title' => _t('gen.short.damn'), + 'body' => _t('feedback.update.none') + ); + @touch(join_path(DATA_PATH, 'last_update.txt')); + return; + } + } else { + $auto_update_url = FreshRSS_Context::$system_conf->auto_update_url . '?v=' . FRESHRSS_VERSION; + Minz_Log::debug('HTTP GET ' . $auto_update_url); + $c = curl_init($auto_update_url); + curl_setopt($c, CURLOPT_RETURNTRANSFER, true); + curl_setopt($c, CURLOPT_SSL_VERIFYPEER, true); + curl_setopt($c, CURLOPT_SSL_VERIFYHOST, 2); + $result = curl_exec($c); + $c_status = curl_getinfo($c, CURLINFO_HTTP_CODE); + $c_error = curl_error($c); + curl_close($c); + + if ($c_status !== 200) { + Minz_Log::warning( + 'Error during update (HTTP code ' . $c_status . '): ' . $c_error + ); + + $this->view->message = array( + 'status' => 'bad', + 'title' => _t('gen.short.damn'), + 'body' => _t('feedback.update.server_not_found', $auto_update_url) + ); + return; + } - @touch(join_path(DATA_PATH, 'last_update.txt')); + $res_array = explode("\n", $result, 2); + $status = $res_array[0]; + if (strpos($status, 'UPDATE') !== 0) { + $this->view->message = array( + 'status' => 'bad', + 'title' => _t('gen.short.damn'), + 'body' => _t('feedback.update.none') + ); + @touch(join_path(DATA_PATH, 'last_update.txt')); + return; + } - return; + $script = $res_array[1]; + $version = explode(' ', $status, 2); + $version = $version[1]; } - $script = $res_array[1]; if (file_put_contents(UPDATE_FILENAME, $script) !== false) { - $version = explode(' ', $status, 2); - $version = $version[1]; @file_put_contents(join_path(DATA_PATH, 'last_update.txt'), $version); - Minz_Request::forward(array('c' => 'update'), true); } else { $this->view->message = array( @@ -111,10 +166,13 @@ class FreshRSS_update_Controller extends Minz_ActionController { Minz_Request::forward(array('c' => 'update'), true); } - require(UPDATE_FILENAME); - if (Minz_Request::param('post_conf', false)) { - $res = do_post_update(); + if (self::isGit()) { + $res = !self::hasGitUpdate(); + } else { + require(UPDATE_FILENAME); + $res = do_post_update(); + } Minz_ExtensionManager::callHook('post_update'); @@ -126,14 +184,21 @@ class FreshRSS_update_Controller extends Minz_ActionController { Minz_Request::bad(_t('feedback.update.error', $res), array('c' => 'update', 'a' => 'index')); } - } - - if (Minz_Request::isPost()) { - save_info_update(); - } + } else { + $res = false; - if (!need_info_update()) { - $res = apply_update(); + if (self::isGit()) { + $res = self::gitPull(); + } else { + if (Minz_Request::isPost()) { + save_info_update(); + } + if (!need_info_update()) { + $res = apply_update(); + } else { + return; + } + } if ($res === true) { Minz_Request::forward(array( -- cgit v1.2.3 From aeda49a7d271c2196fcba0d3b2b15d31ad0b33b5 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sat, 5 Nov 2016 20:48:46 +0100 Subject: Add CLI for user information + Fix last user activity https://github.com/FreshRSS/FreshRSS/issues/1345 --- CHANGELOG.md | 4 ++++ app/Controllers/feedController.php | 4 ++++ app/Models/Auth.php | 2 +- app/Models/EntryDAO.php | 5 +++++ app/Models/UserDAO.php | 6 +++++- cli/README.md | 16 ++++++++++++++ cli/user-info.php | 43 ++++++++++++++++++++++++++++++++++++++ 7 files changed, 78 insertions(+), 2 deletions(-) create mode 100644 cli/user-info.php (limited to 'app/Controllers') diff --git a/CHANGELOG.md b/CHANGELOG.md index 77ec29aed..92220f1f7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ ## 2016-xx-xx FreshRSS 1.7.0-dev +* CLI + * New command `./cli/user-info.php` to get some user information [#1345](https://github.com/FreshRSS/FreshRSS/issues/1345) +* Bug fixing + * Fix bug in estimating last user activity [#1358](https://github.com/FreshRSS/FreshRSS/issues/1358) ## 2016-11-02 FreshRSS 1.6.1 diff --git a/app/Controllers/feedController.php b/app/Controllers/feedController.php index c4115584a..f71f26a4e 100755 --- a/app/Controllers/feedController.php +++ b/app/Controllers/feedController.php @@ -27,6 +27,7 @@ class FreshRSS_feed_Controller extends Minz_ActionController { } public static function addFeed($url, $title = '', $cat_id = 0, $new_cat_name = '', $http_auth = '') { + FreshRSS_UserDAO::touch(); @set_time_limit(300); $catDAO = new FreshRSS_CategoryDAO(); @@ -484,6 +485,7 @@ class FreshRSS_feed_Controller extends Minz_ActionController { if ($feed_id <= 0 || $feed_name == '') { return false; } + FreshRSS_UserDAO::touch(); $feedDAO = FreshRSS_Factory::createFeedDao(); return $feedDAO->updateFeed($feed_id, array('name' => $feed_name)); } @@ -492,6 +494,7 @@ class FreshRSS_feed_Controller extends Minz_ActionController { if ($feed_id <= 0 || ($cat_id <= 0 && $new_cat_name == '')) { return false; } + FreshRSS_UserDAO::touch(); $catDAO = new FreshRSS_CategoryDAO(); if ($cat_id > 0) { @@ -540,6 +543,7 @@ class FreshRSS_feed_Controller extends Minz_ActionController { } public static function deleteFeed($feed_id) { + FreshRSS_UserDAO::touch(); $feedDAO = FreshRSS_Factory::createFeedDao(); if ($feedDAO->deleteFeed($feed_id)) { // TODO: Delete old favicon diff --git a/app/Models/Auth.php b/app/Models/Auth.php index b93942e19..3313fdf3f 100644 --- a/app/Models/Auth.php +++ b/app/Models/Auth.php @@ -25,7 +25,7 @@ class FreshRSS_Auth { self::giveAccess(); } elseif (self::accessControl()) { self::giveAccess(); - FreshRSS_UserDAO::touch($current_user); + FreshRSS_UserDAO::touch(); } else { // Be sure all accesses are removed! self::removeAccess(); diff --git a/app/Models/EntryDAO.php b/app/Models/EntryDAO.php index 58f2c1a79..d8a4a486d 100644 --- a/app/Models/EntryDAO.php +++ b/app/Models/EntryDAO.php @@ -241,6 +241,7 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable { if (count($ids) < 1) { return 0; } + FreshRSS_UserDAO::touch(); $sql = 'UPDATE `' . $this->prefix . 'entry` ' . 'SET is_favorite=? ' . 'WHERE id IN (' . str_repeat('?,', count($ids) - 1). '?)'; @@ -315,6 +316,7 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable { * @return integer affected rows */ public function markRead($ids, $is_read = true) { + FreshRSS_UserDAO::touch(); if (is_array($ids)) { //Many IDs at once (used by API) if (count($ids) < 6) { //Speed heuristics $affected = 0; @@ -379,6 +381,7 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable { * @return integer affected rows */ public function markReadEntries($idMax = 0, $onlyFavorites = false, $priorityMin = 0, $filter = null, $state = 0) { + FreshRSS_UserDAO::touch(); if ($idMax == 0) { $idMax = time() . '000000'; Minz_Log::debug('Calling markReadEntries(0) is deprecated!'); @@ -421,6 +424,7 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable { * @return integer affected rows */ public function markReadCat($id, $idMax = 0, $filter = null, $state = 0) { + FreshRSS_UserDAO::touch(); if ($idMax == 0) { $idMax = time() . '000000'; Minz_Log::debug('Calling markReadCat(0) is deprecated!'); @@ -458,6 +462,7 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable { * @return integer affected rows */ public function markReadFeed($id_feed, $idMax = 0, $filter = null, $state = 0) { + FreshRSS_UserDAO::touch(); if ($idMax == 0) { $idMax = time() . '000000'; Minz_Log::debug('Calling markReadFeed(0) is deprecated!'); diff --git a/app/Models/UserDAO.php b/app/Models/UserDAO.php index a95ee6bc4..190954b1a 100644 --- a/app/Models/UserDAO.php +++ b/app/Models/UserDAO.php @@ -84,7 +84,11 @@ class FreshRSS_UserDAO extends Minz_ModelPdo { return is_dir(join_path(DATA_PATH , 'users', $username)); } - public static function touch($username) { + public static function touch($username = '') { + if (($username == '') || (!ctype_alnum($username))) { + $username = Minz_Session::param('currentUser', '_'); + } + Minz_Log::debug('touch ' . $username); return touch(join_path(DATA_PATH , 'users', $username, 'config.php')); } diff --git a/cli/README.md b/cli/README.md index 444606b50..09dcbd27e 100644 --- a/cli/README.md +++ b/cli/README.md @@ -55,4 +55,20 @@ cd /usr/share/FreshRSS ./cli/export-opml-for-user.php --user username > /path/to/file.opml.xml ./cli/export-zip-for-user.php --user username ( --max-feed-entries 100 ) > /path/to/file.zip + +./cli/user-info.php -h --user username +# -h is to use a human-readable format +# --user can be a username, or '*' to loop on all users +# Returns a * if the user is admin, the name of the user, the date/time of last action, and the size occupied +``` + + +## Unix piping + +It is possible to invoke a command multiple times, e.g. with different usernames, thanks to the `xargs -n1` command. + +Example showing user information for all users which username starts with 'a': + +```sh +./cli/list-users.php | grep '^a' | xargs -n1 ./cli/user-info.php -h --user ``` diff --git a/cli/user-info.php b/cli/user-info.php new file mode 100644 index 000000000..5b26ecb15 --- /dev/null +++ b/cli/user-info.php @@ -0,0 +1,43 @@ +#!/usr/bin/php +default_user ? '*' : ' ', "\t"; + + if (isset($options['h'])) { //Human format + echo + $username, "\t", + date('c', FreshRSS_UserDAO::mtime($username)), "\t", + formatSize($entryDAO->size()), "\t", + "\n"; + } else { + echo + $username, "\t", + FreshRSS_UserDAO::mtime($username), "\t", + $entryDAO->size(), "\t", + "\n"; + } +} -- cgit v1.2.3 From f59de4e2b679efb1ba4bbfd576a5ea07422cc169 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Tue, 15 Nov 2016 20:43:06 +0100 Subject: Stream JSON export Avoid large in-memory copies https://github.com/FreshRSS/FreshRSS/issues/1372 --- app/Controllers/importExportController.php | 4 +- app/Models/EntryDAO.php | 42 ++++++++------ app/views/helpers/export/articles.phtml | 92 +++++++++++++++++------------- 3 files changed, 78 insertions(+), 60 deletions(-) (limited to 'app/Controllers') diff --git a/app/Controllers/importExportController.php b/app/Controllers/importExportController.php index 3ba91a243..d86587ea9 100644 --- a/app/Controllers/importExportController.php +++ b/app/Controllers/importExportController.php @@ -641,13 +641,13 @@ class FreshRSS_importExport_Controller extends Minz_ActionController { $this->view->list_title = _t('sub.import_export.starred_list'); $this->view->type = 'starred'; $unread_fav = $this->entryDAO->countUnreadReadFavorites(); - $this->view->entries = $this->entryDAO->listWhere( + $this->view->entriesRaw = $this->entryDAO->listWhereRaw( 's', '', FreshRSS_Entry::STATE_ALL, 'ASC', $unread_fav['all'] ); } elseif ($type === 'feed' && $feed != null) { $this->view->list_title = _t('sub.import_export.feed_list', $feed->name()); $this->view->type = 'feed/' . $feed->id(); - $this->view->entries = $this->entryDAO->listWhere( + $this->view->entriesRaw = $this->entryDAO->listWhereRaw( 'f', $feed->id(), FreshRSS_Entry::STATE_ALL, 'ASC', $maxFeedEntries ); diff --git a/app/Models/EntryDAO.php b/app/Models/EntryDAO.php index d8a4a486d..397471baa 100644 --- a/app/Models/EntryDAO.php +++ b/app/Models/EntryDAO.php @@ -518,7 +518,7 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable { $stm->execute($values); $res = $stm->fetchAll(PDO::FETCH_ASSOC); - $entries = self::daoToEntry($res); + $entries = self::daoToEntries($res); return isset($entries[0]) ? $entries[0] : null; } @@ -533,7 +533,7 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable { $stm->execute($values); $res = $stm->fetchAll(PDO::FETCH_ASSOC); - $entries = self::daoToEntry($res); + $entries = self::daoToEntries($res); return isset($entries[0]) ? $entries[0] : null; } @@ -666,7 +666,7 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable { . ($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) { + public function listWhereRaw($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 e0.id, e0.guid, e0.title, e0.author, ' @@ -680,8 +680,12 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable { $stm = $this->bd->prepare($sql); $stm->execute($values); + return $stm; + } - return self::daoToEntry($stm->fetchAll(PDO::FETCH_ASSOC)); + public function listWhere($type = 'a', $id = '', $state = FreshRSS_Entry::STATE_ALL, $order = 'DESC', $limit = 1, $firstId = '', $filter = '', $date_min = 0) { + $stm = $this->listWhereRaw($type, $id, $state, $order, $limit, $firstId, $filter, $date_min); + return self::daoToEntries($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) { //For API @@ -810,15 +814,8 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable { return $res[0]; } - public static function daoToEntry($listDAO) { - $list = array(); - - if (!is_array($listDAO)) { - $listDAO = array($listDAO); - } - - foreach ($listDAO as $key => $dao) { - $entry = new FreshRSS_Entry( + public static function daoToEntry($dao) { + $entry = new FreshRSS_Entry( $dao['id_feed'], $dao['guid'], $dao['title'], @@ -830,10 +827,21 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable { $dao['is_favorite'], $dao['tags'] ); - if (isset($dao['id'])) { - $entry->_id($dao['id']); - } - $list[] = $entry; + if (isset($dao['id'])) { + $entry->_id($dao['id']); + } + return $entry; + } + + private static function daoToEntries($listDAO) { + $list = array(); + + if (!is_array($listDAO)) { + $listDAO = array($listDAO); + } + + foreach ($listDAO as $key => $dao) { + $list[] = self::daoToEntry($dao); } unset($listDAO); diff --git a/app/views/helpers/export/articles.phtml b/app/views/helpers/export/articles.phtml index ffdca1daa..2ad4a3abf 100644 --- a/app/views/helpers/export/articles.phtml +++ b/app/views/helpers/export/articles.phtml @@ -1,47 +1,57 @@ 'user/' . str_replace('/', '', $username) . '/state/org.freshrss/' . $this->type, - 'title' => $this->list_title, - 'author' => $username, - 'items' => array() - ); + $options = 0; + if (version_compare(PHP_VERSION, '5.4.0') >= 0) { + $options = JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE; + } - foreach ($this->entries as $entry) { - if (!isset($this->feed)) { - $feed = FreshRSS_CategoryDAO::findFeed($this->categories, $entry->feed ()); - } else { - $feed = $this->feed; - } + $articles = array( + 'id' => 'user/' . str_replace('/', '', $username) . '/state/org.freshrss/' . $this->type, + 'title' => $this->list_title, + 'author' => $username, + 'items' => array(), + ); - $articles['items'][] = array( - 'id' => $entry->guid(), - 'categories' => array_values($entry->tags()), - 'title' => $entry->title(), - 'author' => $entry->author(), - 'published' => $entry->date(true), - 'updated' => $entry->date(true), - 'alternate' => array(array( - 'href' => $entry->link(), - 'type' => 'text/html' - )), - 'content' => array( - 'content' => $entry->content() - ), - 'origin' => array( - 'streamId' => $feed->id(), - 'title' => $feed->name(), - 'htmlUrl' => $feed->website(), - 'feedUrl' => $feed->url() - ) - ); - } + echo rtrim(json_encode($articles, $options), " ]}\n\r\t"); + $first = true; - $options = 0; - if (version_compare(PHP_VERSION, '5.4.0') >= 0) { - $options = JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE; - } + foreach ($this->entriesRaw as $entryRaw) { + $entry = FreshRSS_EntryDAO::daoToEntry($entryRaw); + if (!isset($this->feed)) { + $feed = FreshRSS_CategoryDAO::findFeed($this->categories, $entry->feed ()); + } else { + $feed = $this->feed; + } - echo json_encode($articles, $options); -?> + $article = array( + 'id' => $entry->guid(), + 'categories' => array_values($entry->tags()), + 'title' => $entry->title(), + 'author' => $entry->author(), + 'published' => $entry->date(true), + 'updated' => $entry->date(true), + 'alternate' => array(array( + 'href' => $entry->link(), + 'type' => 'text/html', + )), + 'content' => array( + 'content' => $entry->content(), + ), + 'origin' => array( + 'streamId' => $feed->id(), + 'title' => $feed->name(), + 'htmlUrl' => $feed->website(), + 'feedUrl' => $feed->url(), + ) + ); + + if ($first) { + $first = false; + } else { + echo ",\n"; + } + echo json_encode($article, $options); + } + + echo "\n]}\n"; -- cgit v1.2.3 From 568b737b6c62ace5aaa6b3f6c968e2595ea70f55 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Tue, 15 Nov 2016 21:38:18 +0100 Subject: Function to disable MySQL buffering for large exports --- app/Controllers/importExportController.php | 2 ++ lib/Minz/ModelPdo.php | 6 ++++++ 2 files changed, 8 insertions(+) (limited to 'app/Controllers') diff --git a/app/Controllers/importExportController.php b/app/Controllers/importExportController.php index d86587ea9..6ae89defb 100644 --- a/app/Controllers/importExportController.php +++ b/app/Controllers/importExportController.php @@ -531,6 +531,8 @@ class FreshRSS_importExport_Controller extends Minz_ActionController { $this->entryDAO = FreshRSS_Factory::createEntryDao($username); $this->feedDAO = FreshRSS_Factory::createFeedDao($username); + $this->entryDAO->disableBuffering(); + if ($export_feeds === true) { //All feeds $export_feeds = $this->feedDAO->listFeedsIds(); diff --git a/lib/Minz/ModelPdo.php b/lib/Minz/ModelPdo.php index 6e8d60bc9..caab1d114 100644 --- a/lib/Minz/ModelPdo.php +++ b/lib/Minz/ModelPdo.php @@ -116,6 +116,12 @@ class Minz_ModelPdo { self::$sharedBd = null; self::$sharedPrefix = ''; } + + public function disableBuffering() { + if ((self::$sharedDbType === 'mysql') && defined('PDO::MYSQL_ATTR_USE_BUFFERED_QUERY')) { + $this->bd->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, false); + } + } } class MinzPDO extends PDO { -- cgit v1.2.3 From 332a4dec8690b658bcb878a20056aea33c673f69 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sat, 24 Dec 2016 16:33:28 +0100 Subject: Option for cookie duration https://github.com/FreshRSS/FreshRSS/issues/1384 --- app/Controllers/authController.php | 4 ++++ app/Models/Auth.php | 11 ++++++++--- app/i18n/cz/gen.php | 2 +- app/i18n/de/gen.php | 2 +- app/i18n/en/gen.php | 2 +- app/i18n/fr/gen.php | 2 +- app/i18n/it/gen.php | 2 +- app/i18n/nl/gen.php | 2 +- app/i18n/ru/gen.php | 2 +- app/i18n/tr/gen.php | 2 +- app/views/auth/formLogin.phtml | 2 +- data/config.default.php | 3 +++ 12 files changed, 24 insertions(+), 12 deletions(-) (limited to 'app/Controllers') diff --git a/app/Controllers/authController.php b/app/Controllers/authController.php index 9decba431..1398e4e49 100644 --- a/app/Controllers/authController.php +++ b/app/Controllers/authController.php @@ -113,6 +113,10 @@ class FreshRSS_auth_Controller extends Minz_ActionController { $file_mtime = @filemtime(PUBLIC_PATH . '/scripts/bcrypt.min.js'); Minz_View::appendScript(Minz_Url::display('/scripts/bcrypt.min.js?' . $file_mtime)); + $conf = Minz_Configuration::get('system'); + $limits = $conf->limits; + $this->view->cookie_days = round($limits['cookie_duration'] / 86400, 1); + if (Minz_Request::isPost()) { $nonce = Minz_Session::param('nonce'); $username = Minz_Request::param('username', ''); diff --git a/app/Models/Auth.php b/app/Models/Auth.php index 3313fdf3f..042210eaf 100644 --- a/app/Models/Auth.php +++ b/app/Models/Auth.php @@ -219,8 +219,8 @@ class FreshRSS_FormAuth { } public static function makeCookie($username, $password_hash) { + $conf = Minz_Configuration::get('system'); do { - $conf = Minz_Configuration::get('system'); $token = sha1($conf->salt . $username . uniqid(mt_rand(), true)); $token_file = DATA_PATH . '/tokens/' . $token . '.txt'; } while (file_exists($token_file)); @@ -229,7 +229,9 @@ class FreshRSS_FormAuth { return false; } - $expire = time() + 2629744; //1 month //TODO: Use a configuration instead + $limits = $conf->limits; + $cookie_duration = empty($limits['cookie_duration']) ? 2629744 : $limits['cookie_duration']; + $expire = time() + $cookie_duration; Minz_Session::setLongTermCookie('FreshRSS_login', $token, $expire); return $token; } @@ -247,7 +249,10 @@ class FreshRSS_FormAuth { } public static function purgeTokens() { - $oldest = time() - 2629744; // 1 month // TODO: Use a configuration instead + $conf = Minz_Configuration::get('system'); + $limits = $conf->limits; + $cookie_duration = empty($limits['cookie_duration']) ? 2629744 : $limits['cookie_duration']; + $oldest = time() - $cookie_duration; foreach (new DirectoryIterator(DATA_PATH . '/tokens/') as $file_info) { // $extension = $file_info->getExtension(); doesn't work in PHP < 5.3.7 $extension = pathinfo($file_info->getFilename(), PATHINFO_EXTENSION); diff --git a/app/i18n/cz/gen.php b/app/i18n/cz/gen.php index e73325c55..6722a02e5 100644 --- a/app/i18n/cz/gen.php +++ b/app/i18n/cz/gen.php @@ -22,7 +22,7 @@ return array( ), 'auth' => array( 'email' => 'Email', - 'keep_logged_in' => 'Zapamatovat přihlášení (1 měsíc)', + 'keep_logged_in' => 'Zapamatovat přihlášení (%s dny)', 'login' => 'Login', 'logout' => 'Odhlášení', 'password' => array( diff --git a/app/i18n/de/gen.php b/app/i18n/de/gen.php index c6e7f1ef3..3f1238edc 100644 --- a/app/i18n/de/gen.php +++ b/app/i18n/de/gen.php @@ -22,7 +22,7 @@ return array( ), 'auth' => array( 'email' => 'E-Mail-Adresse', - 'keep_logged_in' => 'Eingeloggt bleiben (1 Monat)', + 'keep_logged_in' => 'Eingeloggt bleiben (%s Tage)', 'login' => 'Anmelden', 'logout' => 'Abmelden', 'password' => array( diff --git a/app/i18n/en/gen.php b/app/i18n/en/gen.php index 17b47ba2f..c68a0f07b 100644 --- a/app/i18n/en/gen.php +++ b/app/i18n/en/gen.php @@ -22,7 +22,7 @@ return array( ), 'auth' => array( 'email' => 'Email address', - 'keep_logged_in' => 'Keep me logged in (1 month)', + 'keep_logged_in' => 'Keep me logged in (%s days)', 'login' => 'Login', 'logout' => 'Logout', 'password' => array( diff --git a/app/i18n/fr/gen.php b/app/i18n/fr/gen.php index d61a716a7..b5dc098ae 100644 --- a/app/i18n/fr/gen.php +++ b/app/i18n/fr/gen.php @@ -22,7 +22,7 @@ return array( ), 'auth' => array( 'email' => 'Adresse courriel', - 'keep_logged_in' => 'Rester connecté (1 mois)', + 'keep_logged_in' => 'Rester connecté (%s jours)', 'login' => 'Connexion', 'logout' => 'Déconnexion', 'password' => array( diff --git a/app/i18n/it/gen.php b/app/i18n/it/gen.php index c02ddd13a..01c0afba8 100644 --- a/app/i18n/it/gen.php +++ b/app/i18n/it/gen.php @@ -22,7 +22,7 @@ return array( ), 'auth' => array( 'email' => 'Indirizzo email', - 'keep_logged_in' => 'Ricorda i dati (1 mese)', + 'keep_logged_in' => 'Ricorda i dati (%s giorni)', 'login' => 'Accedi', 'logout' => 'Esci', 'password' => array( diff --git a/app/i18n/nl/gen.php b/app/i18n/nl/gen.php index 7e03229c9..a156697d5 100644 --- a/app/i18n/nl/gen.php +++ b/app/i18n/nl/gen.php @@ -22,7 +22,7 @@ return array( ), 'auth' => array( 'email' => 'Email adres', - 'keep_logged_in' => 'Ingelogd blijven voor (1 maand)', + 'keep_logged_in' => 'Ingelogd blijven voor (%s dagen)', 'login' => 'Log in', 'logout' => 'Log uit', 'password' => array( diff --git a/app/i18n/ru/gen.php b/app/i18n/ru/gen.php index eecd72749..130fac4ed 100644 --- a/app/i18n/ru/gen.php +++ b/app/i18n/ru/gen.php @@ -22,7 +22,7 @@ return array( ), 'auth' => array( 'email' => 'Email address', - 'keep_logged_in' => 'Keep me logged in (1 month)', + 'keep_logged_in' => 'Keep me logged in (%s дней)', 'login' => 'Login', 'logout' => 'Logout', 'password' => array( diff --git a/app/i18n/tr/gen.php b/app/i18n/tr/gen.php index 865dbd4e2..7f9d3d8e0 100644 --- a/app/i18n/tr/gen.php +++ b/app/i18n/tr/gen.php @@ -22,7 +22,7 @@ return array( ), 'auth' => array( 'email' => 'Email adresleri', - 'keep_logged_in' => '(1 ay) oturumu açık tut', + 'keep_logged_in' => '(%s günler) oturumu açık tut', 'login' => 'Giriş', 'logout' => 'Çıkış', 'password' => array( diff --git a/app/views/auth/formLogin.phtml b/app/views/auth/formLogin.phtml index 4bbc8ed55..a8213b7ae 100644 --- a/app/views/auth/formLogin.phtml +++ b/app/views/auth/formLogin.phtml @@ -20,7 +20,7 @@

    diff --git a/data/config.default.php b/data/config.default.php index 8b07b85cd..433207a9c 100644 --- a/data/config.default.php +++ b/data/config.default.php @@ -74,6 +74,9 @@ return array( 'limits' => array( + # Duration in seconds of the login cookie. + 'cookie_duration' => 2592000, + # Duration in seconds of the SimplePie cache, # during which a query to the RSS feed will return the local cached version. # Especially important for multi-user setups. -- cgit v1.2.3