diff options
| author | 2015-01-08 10:27:01 +0100 | |
|---|---|---|
| committer | 2015-01-08 10:27:01 +0100 | |
| commit | 46e98bad9119c3ee7088b65ebb6b4d1331419602 (patch) | |
| tree | 6f0e081597ba9ced0c0faca9b5e4c04394605aaf | |
| parent | 7584364a4c2b407e97909e94ba274da62620abea (diff) | |
| parent | 9265cd57333b2a91effc6ea284b504fbc977b9ed (diff) | |
Merge branch '730-improve_configuration' into dev
BREAKING FEATURE: please follow instructions from
https://github.com/FreshRSS/FreshRSS/issues/730 to
update your configuration file.
Fix https://github.com/FreshRSS/FreshRSS/issues/730
65 files changed, 1429 insertions, 1162 deletions
diff --git a/app/Controllers/authController.php b/app/Controllers/authController.php index ccc32ec0d..937c0759d 100644 --- a/app/Controllers/authController.php +++ b/app/Controllers/authController.php @@ -27,10 +27,10 @@ class FreshRSS_auth_Controller extends Minz_ActionController { if (Minz_Request::isPost()) { $ok = true; - $current_token = FreshRSS_Context::$conf->token; + $current_token = FreshRSS_Context::$user_conf->token; $token = Minz_Request::param('token', $current_token); - FreshRSS_Context::$conf->_token($token); - $ok &= FreshRSS_Context::$conf->save(); + FreshRSS_Context::$user_conf->token = $token; + $ok &= FreshRSS_Context::$user_conf->save(); $anon = Minz_Request::param('anon_access', false); $anon = ((bool)$anon) && ($anon !== 'no'); @@ -39,18 +39,20 @@ class FreshRSS_auth_Controller extends Minz_ActionController { $auth_type = Minz_Request::param('auth_type', 'none'); $unsafe_autologin = Minz_Request::param('unsafe_autologin', false); $api_enabled = Minz_Request::param('api_enabled', false); - if ($anon != Minz_Configuration::allowAnonymous() || - $auth_type != Minz_Configuration::authType() || - $anon_refresh != Minz_Configuration::allowAnonymousRefresh() || - $unsafe_autologin != Minz_Configuration::unsafeAutologinEnabled() || - $api_enabled != Minz_Configuration::apiEnabled()) { - - Minz_Configuration::_authType($auth_type); - Minz_Configuration::_allowAnonymous($anon); - Minz_Configuration::_allowAnonymousRefresh($anon_refresh); - Minz_Configuration::_enableAutologin($unsafe_autologin); - Minz_Configuration::_enableApi($api_enabled); - $ok &= Minz_Configuration::writeFile(); + if ($anon != FreshRSS_Context::$system_conf->allow_anonymous || + $auth_type != FreshRSS_Context::$system_conf->auth_type || + $anon_refresh != FreshRSS_Context::$system_conf->allow_anonymous_refresh || + $unsafe_autologin != FreshRSS_Context::$system_conf->unsafe_autologin_enabled || + $api_enabled != FreshRSS_Context::$system_conf->api_enabled) { + + // TODO: test values from form + FreshRSS_Context::$system_conf->auth_type = $auth_type; + FreshRSS_Context::$system_conf->allow_anonymous = $anon; + FreshRSS_Context::$system_conf->allow_anonymous_refresh = $anon_refresh; + FreshRSS_Context::$system_conf->unsafe_autologin_enabled = $unsafe_autologin; + FreshRSS_Context::$system_conf->api_enabled = $api_enabled; + + $ok &= FreshRSS_Context::$system_conf->save(); } invalidateHttpCache(); @@ -76,7 +78,7 @@ class FreshRSS_auth_Controller extends Minz_ActionController { Minz_Request::forward(array('c' => 'index', 'a' => 'index'), true); } - $auth_type = Minz_Configuration::authType(); + $auth_type = FreshRSS_Context::$system_conf->auth_type; switch ($auth_type) { case 'form': Minz_Request::forward(array('c' => 'auth', 'a' => 'formLogin')); @@ -118,11 +120,9 @@ class FreshRSS_auth_Controller extends Minz_ActionController { $nonce = Minz_Session::param('nonce'); $username = Minz_Request::param('username', ''); $challenge = Minz_Request::param('challenge', ''); - try { - $conf = new FreshRSS_Configuration($username); - } catch(Minz_Exception $e) { - // $username is not a valid user, nor the configuration file! - Minz_Log::warning('Login failure: ' . $e->getMessage()); + + $conf = get_user_configuration($username); + if (is_null($conf)) { Minz_Request::bad(_t('feedback.auth.login.invalid'), array('c' => 'auth', 'a' => 'login')); } @@ -154,7 +154,7 @@ class FreshRSS_auth_Controller extends Minz_ActionController { Minz_Request::bad(_t('feedback.auth.login.invalid'), array('c' => 'auth', 'a' => 'login')); } - } elseif (Minz_Configuration::unsafeAutologinEnabled()) { + } elseif (FreshRSS_Context::$system_conf->unsafe_autologin_enabled) { $username = Minz_Request::param('u', ''); $password = Minz_Request::param('p', ''); Minz_Request::_param('p'); @@ -163,11 +163,8 @@ class FreshRSS_auth_Controller extends Minz_ActionController { return; } - try { - $conf = new FreshRSS_Configuration($username); - } catch(Minz_Exception $e) { - // $username is not a valid user, nor the configuration file! - Minz_Log::warning('Login failure: ' . $e->getMessage()); + $conf = get_user_configuration($username); + if (is_null($conf)) { return; } @@ -235,13 +232,12 @@ class FreshRSS_auth_Controller extends Minz_ActionController { $persona_file = DATA_PATH . '/persona/' . $email . '.txt'; if (($current_user = @file_get_contents($persona_file)) !== false) { $current_user = trim($current_user); - try { - $conf = new FreshRSS_Configuration($current_user); + $conf = get_user_configuration($current_user); + if (!is_null($conf)) { $login_ok = strcasecmp($email, $conf->mail_login) === 0; - } catch (Minz_Exception $e) { - //Permission denied or conf file does not exist + } else { $reason = 'Invalid configuration for user ' . - '[' . $current_user . '] ' . $e->getMessage(); + '[' . $current_user . ']'; } } } else { @@ -293,7 +289,7 @@ class FreshRSS_auth_Controller extends Minz_ActionController { $this->view->no_form = false; // Enable changement of auth only if Persona! - if (Minz_Configuration::authType() != 'persona') { + if (FreshRSS_Context::$system_conf->auth_type != 'persona') { $this->view->message = array( 'status' => 'bad', 'title' => _t('gen.short.damn'), @@ -303,7 +299,11 @@ class FreshRSS_auth_Controller extends Minz_ActionController { return; } - $conf = new FreshRSS_Configuration(Minz_Configuration::defaultUser()); + $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( @@ -327,8 +327,8 @@ class FreshRSS_auth_Controller extends Minz_ActionController { ); if ($ok) { - Minz_Configuration::_authType('form'); - $ok = Minz_Configuration::writeFile(); + FreshRSS_Context::$system_conf->auth_type = 'form'; + $ok = FreshRSS_Context::$system_conf->save(); if ($ok) { Minz_Request::good(_t('feedback.auth.form.set')); diff --git a/app/Controllers/categoryController.php b/app/Controllers/categoryController.php index 5f1beae90..e65c146de 100644 --- a/app/Controllers/categoryController.php +++ b/app/Controllers/categoryController.php @@ -30,7 +30,7 @@ class FreshRSS_category_Controller extends Minz_ActionController { $catDAO = new FreshRSS_CategoryDAO(); $url_redirect = array('c' => 'subscription', 'a' => 'index'); - $limits = Minz_Configuration::limits(); + $limits = FreshRSS_Context::$system_conf->limits; $this->view->categories = $catDAO->listCategories(false); if (count($this->view->categories) >= $limits['max_categories']) { @@ -141,8 +141,9 @@ class FreshRSS_category_Controller extends Minz_ActionController { } // Remove related queries. - FreshRSS_Context::$conf->remove_query_by_get('c_' . $id); - FreshRSS_Context::$conf->save(); + FreshRSS_Context::$user_conf->queries = remove_query_by_get( + 'c_' . $id, FreshRSS_Context::$user_conf->queries); + FreshRSS_Context::$user_conf->save(); Minz_Request::good(_t('feedback.sub.category.deleted'), $url_redirect); } @@ -177,9 +178,10 @@ class FreshRSS_category_Controller extends Minz_ActionController { // Remove related queries foreach ($feeds as $feed) { - FreshRSS_Context::$conf->remove_query_by_get('f_' . $feed->id()); + FreshRSS_Context::$user_conf->queries = remove_query_by_get( + 'f_' . $feed->id(), FreshRSS_Context::$user_conf->queries); } - FreshRSS_Context::$conf->save(); + FreshRSS_Context::$user_conf->save(); Minz_Request::good(_t('feedback.sub.category.emptied'), $url_redirect); } else { diff --git a/app/Controllers/configureController.php b/app/Controllers/configureController.php index feb5483fb..38ccd2b2d 100755 --- a/app/Controllers/configureController.php +++ b/app/Controllers/configureController.php @@ -41,24 +41,24 @@ class FreshRSS_configure_Controller extends Minz_ActionController { */ public function displayAction() { if (Minz_Request::isPost()) { - FreshRSS_Context::$conf->_language(Minz_Request::param('language', 'en')); - FreshRSS_Context::$conf->_theme(Minz_Request::param('theme', FreshRSS_Themes::$defaultTheme)); - FreshRSS_Context::$conf->_content_width(Minz_Request::param('content_width', 'thin')); - FreshRSS_Context::$conf->_topline_read(Minz_Request::param('topline_read', false)); - FreshRSS_Context::$conf->_topline_favorite(Minz_Request::param('topline_favorite', false)); - FreshRSS_Context::$conf->_topline_date(Minz_Request::param('topline_date', false)); - FreshRSS_Context::$conf->_topline_link(Minz_Request::param('topline_link', false)); - FreshRSS_Context::$conf->_bottomline_read(Minz_Request::param('bottomline_read', false)); - FreshRSS_Context::$conf->_bottomline_favorite(Minz_Request::param('bottomline_favorite', false)); - FreshRSS_Context::$conf->_bottomline_sharing(Minz_Request::param('bottomline_sharing', false)); - FreshRSS_Context::$conf->_bottomline_tags(Minz_Request::param('bottomline_tags', false)); - FreshRSS_Context::$conf->_bottomline_date(Minz_Request::param('bottomline_date', false)); - FreshRSS_Context::$conf->_bottomline_link(Minz_Request::param('bottomline_link', false)); - FreshRSS_Context::$conf->_html5_notif_timeout(Minz_Request::param('html5_notif_timeout', 0)); - FreshRSS_Context::$conf->save(); - - Minz_Session::_param('language', FreshRSS_Context::$conf->language); - Minz_Translate::reset(); + FreshRSS_Context::$user_conf->language = Minz_Request::param('language', 'en'); + FreshRSS_Context::$user_conf->theme = Minz_Request::param('theme', FreshRSS_Themes::$defaultTheme); + FreshRSS_Context::$user_conf->content_width = Minz_Request::param('content_width', 'thin'); + FreshRSS_Context::$user_conf->topline_read = Minz_Request::param('topline_read', false); + FreshRSS_Context::$user_conf->topline_favorite = Minz_Request::param('topline_favorite', false); + FreshRSS_Context::$user_conf->topline_date = Minz_Request::param('topline_date', false); + FreshRSS_Context::$user_conf->topline_link = Minz_Request::param('topline_link', false); + FreshRSS_Context::$user_conf->bottomline_read = Minz_Request::param('bottomline_read', false); + FreshRSS_Context::$user_conf->bottomline_favorite = Minz_Request::param('bottomline_favorite', false); + FreshRSS_Context::$user_conf->bottomline_sharing = Minz_Request::param('bottomline_sharing', false); + FreshRSS_Context::$user_conf->bottomline_tags = Minz_Request::param('bottomline_tags', false); + FreshRSS_Context::$user_conf->bottomline_date = Minz_Request::param('bottomline_date', false); + FreshRSS_Context::$user_conf->bottomline_link = Minz_Request::param('bottomline_link', false); + FreshRSS_Context::$user_conf->html5_notif_timeout = Minz_Request::param('html5_notif_timeout', 0); + FreshRSS_Context::$user_conf->save(); + + Minz_Session::_param('language', FreshRSS_Context::$user_conf->language); + Minz_Translate::reset(FreshRSS_Context::$user_conf->language); invalidateHttpCache(); Minz_Request::good(_t('feedback.conf.updated'), @@ -100,29 +100,26 @@ class FreshRSS_configure_Controller extends Minz_ActionController { */ public function readingAction() { 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(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)); - FreshRSS_Context::$conf->_hide_read_feeds(Minz_Request::param('hide_read_feeds', false)); - FreshRSS_Context::$conf->_onread_jump_next(Minz_Request::param('onread_jump_next', false)); - 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( + FreshRSS_Context::$user_conf->posts_per_page = Minz_Request::param('posts_per_page', 10); + FreshRSS_Context::$user_conf->view_mode = Minz_Request::param('view_mode', 'normal'); + FreshRSS_Context::$user_conf->default_view = Minz_Request::param('default_view', 'adaptive'); + FreshRSS_Context::$user_conf->auto_load_more = Minz_Request::param('auto_load_more', false); + FreshRSS_Context::$user_conf->display_posts = Minz_Request::param('display_posts', false); + FreshRSS_Context::$user_conf->display_categories = Minz_Request::param('display_categories', false); + FreshRSS_Context::$user_conf->hide_read_feeds = Minz_Request::param('hide_read_feeds', false); + FreshRSS_Context::$user_conf->onread_jump_next = Minz_Request::param('onread_jump_next', false); + FreshRSS_Context::$user_conf->lazyload = Minz_Request::param('lazyload', false); + FreshRSS_Context::$user_conf->sticky_post = Minz_Request::param('sticky_post', false); + FreshRSS_Context::$user_conf->reading_confirm = Minz_Request::param('reading_confirm', false); + FreshRSS_Context::$user_conf->auto_remove_article = Minz_Request::param('auto_remove_article', false); + FreshRSS_Context::$user_conf->sort_order = Minz_Request::param('sort_order', 'DESC'); + FreshRSS_Context::$user_conf->mark_when = array( 'article' => Minz_Request::param('mark_open_article', false), 'site' => Minz_Request::param('mark_open_site', false), 'scroll' => Minz_Request::param('mark_scroll', false), 'reception' => Minz_Request::param('mark_upon_reception', false), - )); - FreshRSS_Context::$conf->save(); - - Minz_Session::_param('language', FreshRSS_Context::$conf->language); - Minz_Translate::reset(); + ); + FreshRSS_Context::$user_conf->save(); invalidateHttpCache(); Minz_Request::good(_t('feedback.conf.updated'), @@ -142,8 +139,8 @@ class FreshRSS_configure_Controller extends Minz_ActionController { public function sharingAction() { if (Minz_Request::isPost()) { $params = Minz_Request::params(); - FreshRSS_Context::$conf->_sharing($params['share']); - FreshRSS_Context::$conf->save(); + FreshRSS_Context::$user_conf->sharing = $params['share']; + FreshRSS_Context::$user_conf->save(); invalidateHttpCache(); Minz_Request::good(_t('feedback.conf.updated'), @@ -184,8 +181,8 @@ class FreshRSS_configure_Controller extends Minz_ActionController { } } - FreshRSS_Context::$conf->_shortcuts($shortcuts_ok); - FreshRSS_Context::$conf->save(); + FreshRSS_Context::$user_conf->shortcuts = $shortcuts_ok; + FreshRSS_Context::$user_conf->save(); invalidateHttpCache(); Minz_Request::good(_t('feedback.conf.shortcuts_updated'), @@ -212,10 +209,10 @@ class FreshRSS_configure_Controller extends Minz_ActionController { */ public function archivingAction() { if (Minz_Request::isPost()) { - FreshRSS_Context::$conf->_old_entries(Minz_Request::param('old_entries', 3)); - FreshRSS_Context::$conf->_keep_history_default(Minz_Request::param('keep_history_default', 0)); - FreshRSS_Context::$conf->_ttl_default(Minz_Request::param('ttl_default', -2)); - FreshRSS_Context::$conf->save(); + FreshRSS_Context::$user_conf->old_entries = Minz_Request::param('old_entries', 3); + FreshRSS_Context::$user_conf->keep_history_default = Minz_Request::param('keep_history_default', 0); + FreshRSS_Context::$user_conf->ttl_default = Minz_Request::param('ttl_default', -2); + FreshRSS_Context::$user_conf->save(); invalidateHttpCache(); Minz_Request::good(_t('feedback.conf.updated'), @@ -252,8 +249,8 @@ class FreshRSS_configure_Controller extends Minz_ActionController { $query['name'] = _t('conf.query.number', $key + 1); } } - FreshRSS_Context::$conf->_queries($queries); - FreshRSS_Context::$conf->save(); + FreshRSS_Context::$user_conf->queries = $queries; + FreshRSS_Context::$user_conf->save(); Minz_Request::good(_t('feedback.conf.updated'), array('c' => 'configure', 'a' => 'queries')); @@ -261,7 +258,7 @@ class FreshRSS_configure_Controller extends Minz_ActionController { $this->view->query_get = array(); $cat_dao = new FreshRSS_CategoryDAO(); $feed_dao = FreshRSS_Factory::createFeedDao(); - foreach (FreshRSS_Context::$conf->queries as $key => $query) { + foreach (FreshRSS_Context::$user_conf->queries as $key => $query) { if (!isset($query['get'])) { continue; } @@ -329,7 +326,7 @@ class FreshRSS_configure_Controller extends Minz_ActionController { */ public function addQueryAction() { $whitelist = array('get', 'order', 'name', 'search', 'state'); - $queries = FreshRSS_Context::$conf->queries; + $queries = FreshRSS_Context::$user_conf->queries; $query = Minz_Request::params(); $query['name'] = _t('conf.query.number', count($queries) + 1); foreach ($query as $key => $value) { @@ -338,8 +335,8 @@ class FreshRSS_configure_Controller extends Minz_ActionController { } } $queries[] = $query; - FreshRSS_Context::$conf->_queries($queries); - FreshRSS_Context::$conf->save(); + FreshRSS_Context::$user_conf->queries = $queries; + FreshRSS_Context::$user_conf->save(); Minz_Request::good(_t('feedback.conf.query_created', $query['name']), array('c' => 'configure', 'a' => 'queries')); diff --git a/app/Controllers/entryController.php b/app/Controllers/entryController.php index aae08c413..1d9989f40 100755 --- a/app/Controllers/entryController.php +++ b/app/Controllers/entryController.php @@ -154,7 +154,7 @@ class FreshRSS_entry_Controller extends Minz_ActionController { public function purgeAction() { @set_time_limit(300); - $nb_month_old = max(FreshRSS_Context::$conf->old_entries, 1); + $nb_month_old = max(FreshRSS_Context::$user_conf->old_entries, 1); $date_min = time() - (3600 * 24 * 30 * $nb_month_old); $feedDAO = FreshRSS_Factory::createFeedDao(); @@ -168,7 +168,7 @@ class FreshRSS_entry_Controller extends Minz_ActionController { if ($feed_history == -2) { // TODO: -2 must be a constant! // -2 means we take the default value from configuration - $feed_history = FreshRSS_Context::$conf->keep_history_default; + $feed_history = FreshRSS_Context::$user_conf->keep_history_default; } if ($feed_history >= 0) { diff --git a/app/Controllers/feedController.php b/app/Controllers/feedController.php index 121cb8921..c110fda4e 100755 --- a/app/Controllers/feedController.php +++ b/app/Controllers/feedController.php @@ -14,12 +14,13 @@ class FreshRSS_feed_Controller extends Minz_ActionController { // Token is useful in the case that anonymous refresh is forbidden // and CRON task cannot be used with php command so the user can // set a CRON task to refresh his feeds by using token inside url - $token = FreshRSS_Context::$conf->token; + $token = FreshRSS_Context::$user_conf->token; $token_param = Minz_Request::param('token', ''); $token_is_ok = ($token != '' && $token == $token_param); $action = Minz_Request::actionName(); + $allow_anonymous_refresh = FreshRSS_Context::$system_conf->allow_anonymous_refresh; if ($action !== 'actualize' || - !(Minz_Configuration::allowAnonymousRefresh() || $token_is_ok)) { + !($allow_anonymous_refresh || $token_is_ok)) { Minz_Error::error(403); } } @@ -65,7 +66,7 @@ class FreshRSS_feed_Controller extends Minz_ActionController { 'params' => array(), ); - $limits = Minz_Configuration::limits(); + $limits = FreshRSS_Context::$system_conf->limits; $this->view->feeds = $feedDAO->listFeeds(); if (count($this->view->feeds) >= $limits['max_feeds']) { Minz_Request::bad(_t('feedback.sub.feed.over_max', $limits['max_feeds']), @@ -161,14 +162,14 @@ class FreshRSS_feed_Controller extends Minz_ActionController { $feed->_id($id); $feed->faviconPrepare(); - $is_read = FreshRSS_Context::$conf->mark_when['reception'] ? 1 : 0; + $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::$conf->old_entries; + $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 @@ -272,15 +273,15 @@ class FreshRSS_feed_Controller extends Minz_ActionController { $feeds[] = $feed; } } else { - $feeds = $feedDAO->listFeedsOrderUpdate(FreshRSS_Context::$conf->ttl_default); + $feeds = $feedDAO->listFeedsOrderUpdate(FreshRSS_Context::$user_conf->ttl_default); } // Calculate date of oldest entries we accept in DB. - $nb_month_old = max(FreshRSS_Context::$conf->old_entries, 1); + $nb_month_old = max(FreshRSS_Context::$user_conf->old_entries, 1); $date_min = time() - (3600 * 24 * 30 * $nb_month_old); $updated_feeds = 0; - $is_read = FreshRSS_Context::$conf->mark_when['reception'] ? 1 : 0; + $is_read = FreshRSS_Context::$user_conf->mark_when['reception'] ? 1 : 0; foreach ($feeds as $feed) { if (!$feed->lock()) { Minz_Log::notice('Feed already being actualized: ' . $feed->url()); @@ -302,7 +303,7 @@ class FreshRSS_feed_Controller extends Minz_ActionController { if ($feed_history == -2) { // TODO: -2 must be a constant! // -2 means we take the default value from configuration - $feed_history = FreshRSS_Context::$conf->keep_history_default; + $feed_history = FreshRSS_Context::$user_conf->keep_history_default; } // We want chronological order and SimplePie uses reverse order. @@ -476,8 +477,9 @@ class FreshRSS_feed_Controller extends Minz_ActionController { // TODO: Delete old favicon // Remove related queries - FreshRSS_Context::$conf->remove_query_by_get('f_' . $id); - FreshRSS_Context::$conf->save(); + FreshRSS_Context::$user_conf->queries = remove_query_by_get( + 'f_' . $id, FreshRSS_Context::$user_conf->queries); + FreshRSS_Context::$user_conf->save(); Minz_Request::good(_t('feedback.sub.feed.deleted'), $redirect_url); } else { diff --git a/app/Controllers/importExportController.php b/app/Controllers/importExportController.php index 6eefa0f6f..4ce24719e 100644 --- a/app/Controllers/importExportController.php +++ b/app/Controllers/importExportController.php @@ -174,7 +174,7 @@ class FreshRSS_importExport_Controller extends Minz_ActionController { $nb_feeds = count($this->feedDAO->listFeeds()); $nb_cats = count($this->catDAO->listCategories(false)); - $limits = Minz_Configuration::limits(); + $limits = FreshRSS_Context::$system_conf->limits; foreach ($opml_elements as $elt) { $is_error = false; @@ -315,7 +315,7 @@ class FreshRSS_importExport_Controller extends Minz_ActionController { return true; } - $is_read = FreshRSS_Context::$conf->mark_when['reception'] ? 1 : 0; + $is_read = FreshRSS_Context::$user_conf->mark_when['reception'] ? 1 : 0; $google_compliant = strpos($article_object['id'], 'com.google') !== false; @@ -323,7 +323,7 @@ class FreshRSS_importExport_Controller extends Minz_ActionController { $article_to_feed = array(); $nb_feeds = count($this->feedDAO->listFeeds()); - $limits = Minz_Configuration::limits(); + $limits = FreshRSS_Context::$system_conf->limits; // First, we check feeds of articles are in DB (and add them if needed). foreach ($article_object['items'] as $item) { @@ -532,7 +532,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::$conf->posts_per_page + FreshRSS_Context::$user_conf->posts_per_page ); $this->view->feed = $feed; } diff --git a/app/Controllers/indexController.php b/app/Controllers/indexController.php index 33cd2843c..c53d3223e 100755 --- a/app/Controllers/indexController.php +++ b/app/Controllers/indexController.php @@ -9,7 +9,7 @@ class FreshRSS_index_Controller extends Minz_ActionController { * This action only redirect on the default view mode (normal or global) */ public function indexAction() { - $prefered_output = FreshRSS_Context::$conf->view_mode; + $prefered_output = FreshRSS_Context::$user_conf->view_mode; Minz_Request::forward(array( 'c' => 'index', 'a' => $prefered_output @@ -20,7 +20,8 @@ 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()) { + $allow_anonymous = FreshRSS_Context::$system_conf->allow_anonymous; + if (!FreshRSS_Auth::hasAccess() && !$allow_anonymous) { Minz_Request::forward(array('c' => 'auth', 'a' => 'login')); return; } @@ -82,7 +83,8 @@ class FreshRSS_index_Controller extends Minz_ActionController { * This action displays the global view of FreshRSS. */ public function globalAction() { - if (!FreshRSS_Auth::hasAccess() && !Minz_Configuration::allowAnonymous()) { + $allow_anonymous = FreshRSS_Context::$system_conf->allow_anonymous; + if (!FreshRSS_Auth::hasAccess() && !$allow_anonymous) { Minz_Request::forward(array('c' => 'auth', 'a' => 'login')); return; } @@ -109,13 +111,14 @@ class FreshRSS_index_Controller extends Minz_ActionController { * This action displays the RSS feed of FreshRSS. */ public function rssAction() { - $token = FreshRSS_Context::$conf->token; + $allow_anonymous = FreshRSS_Context::$system_conf->allow_anonymous; + $token = FreshRSS_Context::$user_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() && + !$allow_anonymous && !$token_is_ok) { Minz_Error::error(403); } @@ -160,10 +163,10 @@ class FreshRSS_index_Controller extends Minz_ActionController { FreshRSS_Context::_get(Minz_Request::param('get', 'a')); FreshRSS_Context::$state = Minz_Request::param( - 'state', FreshRSS_Context::$conf->default_state + 'state', FreshRSS_Context::$user_conf->default_state ); $state_forced_by_user = Minz_Request::param('state', false) !== false; - if (FreshRSS_Context::$conf->default_view === 'adaptive' && + if (FreshRSS_Context::$user_conf->default_view === 'adaptive' && FreshRSS_Context::$get_unread <= 0 && !FreshRSS_Context::isStateEnabled(FreshRSS_Entry::STATE_READ) && !$state_forced_by_user) { @@ -172,10 +175,10 @@ class FreshRSS_index_Controller extends Minz_ActionController { FreshRSS_Context::$search = Minz_Request::param('search', ''); FreshRSS_Context::$order = Minz_Request::param( - 'order', FreshRSS_Context::$conf->sort_order + 'order', FreshRSS_Context::$user_conf->sort_order ); FreshRSS_Context::$number = Minz_Request::param( - 'nb', FreshRSS_Context::$conf->posts_per_page + 'nb', FreshRSS_Context::$user_conf->posts_per_page ); FreshRSS_Context::$first_id = Minz_Request::param('next', ''); } diff --git a/app/Controllers/javascriptController.php b/app/Controllers/javascriptController.php index 113f58ea9..421cf6f72 100755 --- a/app/Controllers/javascriptController.php +++ b/app/Controllers/javascriptController.php @@ -8,7 +8,7 @@ class FreshRSS_javascript_Controller extends Minz_ActionController { public function actualizeAction() { header('Content-Type: text/javascript; charset=UTF-8'); $feedDAO = FreshRSS_Factory::createFeedDao(); - $this->view->feeds = $feedDAO->listFeedsOrderUpdate(FreshRSS_Context::$conf->ttl_default); + $this->view->feeds = $feedDAO->listFeedsOrderUpdate(FreshRSS_Context::$user_conf->ttl_default); } public function nbUnreadsPerFeedAction() { @@ -28,11 +28,12 @@ class FreshRSS_javascript_Controller extends Minz_ActionController { $user = isset($_GET['user']) ? $_GET['user'] : ''; if (ctype_alnum($user)) { try { - $conf = new FreshRSS_Configuration($user); + $salt = FreshRSS_Context::$system_conf->salt; + $conf = get_user_configuration($user); $s = $conf->passwordHash; if (strlen($s) >= 60) { $this->view->salt1 = substr($s, 0, 29); //CRYPT_BLOWFISH Salt: "$2a$", a two digit cost parameter, "$", and 22 characters from the alphabet "./0-9A-Za-z". - $this->view->nonce = sha1(Minz_Configuration::salt() . uniqid(mt_rand(), true)); + $this->view->nonce = sha1($salt . uniqid(mt_rand(), true)); Minz_Session::_param('nonce', $this->view->nonce); return; //Success } diff --git a/app/Controllers/userController.php b/app/Controllers/userController.php index 1b1ccaac9..ed01b83c5 100644 --- a/app/Controllers/userController.php +++ b/app/Controllers/userController.php @@ -39,9 +39,9 @@ class FreshRSS_user_Controller extends Minz_ActionController { $passwordPlain = ''; $passwordHash = preg_replace('/^\$2[xy]\$/', '\$2a\$', $passwordHash); //Compatibility with bcrypt.js $ok &= ($passwordHash != ''); - FreshRSS_Context::$conf->_passwordHash($passwordHash); + FreshRSS_Context::$user_conf->passwordHash = $passwordHash; } - Minz_Session::_param('passwordHash', FreshRSS_Context::$conf->passwordHash); + Minz_Session::_param('passwordHash', FreshRSS_Context::$user_conf->passwordHash); $passwordPlain = Minz_Request::param('apiPasswordPlain', '', true); if ($passwordPlain != '') { @@ -52,17 +52,17 @@ class FreshRSS_user_Controller extends Minz_ActionController { $passwordPlain = ''; $passwordHash = preg_replace('/^\$2[xy]\$/', '\$2a\$', $passwordHash); //Compatibility with bcrypt.js $ok &= ($passwordHash != ''); - FreshRSS_Context::$conf->_apiPasswordHash($passwordHash); + FreshRSS_Context::$user_conf->apiPasswordHash = $passwordHash; } // TODO: why do we need of hasAccess here? if (FreshRSS_Auth::hasAccess('admin')) { - FreshRSS_Context::$conf->_mail_login(Minz_Request::param('mail_login', '', true)); + FreshRSS_Context::$user_conf->mail_login = Minz_Request::param('mail_login', '', true); } - $email = FreshRSS_Context::$conf->mail_login; + $email = FreshRSS_Context::$user_conf->mail_login; Minz_Session::_param('mail', $email); - $ok &= FreshRSS_Context::$conf->save(); + $ok &= FreshRSS_Context::$user_conf->save(); if ($email != '') { $personaFile = DATA_PATH . '/persona/' . $email . '.txt'; @@ -105,20 +105,21 @@ class FreshRSS_user_Controller extends Minz_ActionController { public function createAction() { if (Minz_Request::isPost() && FreshRSS_Auth::hasAccess('admin')) { - $db = Minz_Configuration::dataBase(); + $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::$conf->language); - $languages = FreshRSS_Context::$conf->availableLanguages(); + $new_user_language = Minz_Request::param('new_user_language', FreshRSS_Context::$user_conf->language); + $languages = Minz_Translate::availableLanguages(); if (!isset($languages[$new_user_language])) { - $new_user_language = FreshRSS_Context::$conf->language; + $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) { - $ok &= (strcasecmp($new_user_name, Minz_Configuration::defaultUser()) !== 0); //It is forbidden to alter the default user + $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 @@ -179,7 +180,7 @@ class FreshRSS_user_Controller extends Minz_ActionController { public function deleteAction() { if (Minz_Request::isPost() && FreshRSS_Auth::hasAccess('admin')) { - $db = Minz_Configuration::dataBase(); + $db = FreshRSS_Context::$system_conf->db; require_once(APP_PATH . '/SQL/install.sql.' . $db['type'] . '.php'); $username = Minz_Request::param('username'); @@ -187,7 +188,8 @@ class FreshRSS_user_Controller extends Minz_ActionController { $user_data = join_path(DATA_PATH, 'users', $username); if ($ok) { - $ok &= (strcasecmp($username, Minz_Configuration::defaultUser()) !== 0); //It is forbidden to delete the default user + $default_user = FreshRSS_Context::$system_conf->default_user; + $ok &= (strcasecmp($username, $default_user) !== 0); //It is forbidden to delete the default user } if ($ok) { $ok &= is_dir($user_data); diff --git a/app/FreshRSS.php b/app/FreshRSS.php index 6114a5d1a..002a70af5 100644 --- a/app/FreshRSS.php +++ b/app/FreshRSS.php @@ -6,10 +6,30 @@ class FreshRSS extends Minz_FrontController { Minz_Session::init('FreshRSS'); } - // Need to be called just after session init because it initializes - // current user. - FreshRSS_Auth::init(); + $this->initConfiguration(); + $this->initAuth(); + FreshRSS_Context::init(); + $this->initI18n(); + FreshRSS_Share::load(join_path(DATA_PATH, 'shares.php')); + $this->loadStylesAndScripts(); + $this->loadNotifications(); + $this->loadExtensions(); + } + + private function initConfiguration() { + $configuration_setter = new FreshRSS_ConfigurationSetter(); + $current_user = Minz_Session::param('currentUser', '_'); + + Minz_Configuration::register('user', + join_path(USERS_PATH, $current_user, 'config.php'), + join_path(USERS_PATH, '_', 'config.default.php'), + $configuration_setter); + $system_conf = Minz_Configuration::get('system'); + $system_conf->_configurationSetter($configuration_setter); + } + private function initAuth() { + FreshRSS_Auth::init(); if (Minz_Request::isPost() && !is_referer_from_same_domain()) { // Basic protection against XSRF attacks FreshRSS_Auth::removeAccess(); @@ -22,21 +42,19 @@ class FreshRSS extends Minz_FrontController { )) ); } + } - // Load context and configuration. - FreshRSS_Context::init(); - - // Init i18n. - Minz_Session::_param('language', FreshRSS_Context::$conf->language); - Minz_Translate::init(); + private function initI18n() { + Minz_Session::_param('language', FreshRSS_Context::$user_conf->language); - $this->loadStylesAndScripts(); - $this->loadNotifications(); - $this->loadExtensions(); + Minz_Translate::init(array( + 'en' => 'English', + 'fr' => 'Français', + ), FreshRSS_Context::$user_conf->language); } private function loadStylesAndScripts() { - $theme = FreshRSS_Themes::load(FreshRSS_Context::$conf->theme); + $theme = FreshRSS_Themes::load(FreshRSS_Context::$user_conf->theme); if ($theme) { foreach($theme['files'] as $file) { if ($file[0] === '_') { @@ -57,7 +75,7 @@ class FreshRSS extends Minz_FrontController { Minz_View::appendScript(Minz_Url::display('/scripts/shortcut.js?' . @filemtime(PUBLIC_PATH . '/scripts/shortcut.js'))); Minz_View::appendScript(Minz_Url::display('/scripts/main.js?' . @filemtime(PUBLIC_PATH . '/scripts/main.js'))); - if (Minz_Configuration::authType() === 'persona') { + 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'); diff --git a/app/Models/Auth.php b/app/Models/Auth.php index 2971d65c8..4e7a71947 100644 --- a/app/Models/Auth.php +++ b/app/Models/Auth.php @@ -16,7 +16,8 @@ class FreshRSS_Auth { self::$login_ok = Minz_Session::param('loginOk', false); $current_user = Minz_Session::param('currentUser', ''); if ($current_user === '') { - $current_user = Minz_Configuration::defaultUser(); + $conf = Minz_Configuration::get('system'); + $current_user = $conf->default_user; Minz_Session::_param('currentUser', $current_user); } @@ -40,7 +41,9 @@ class FreshRSS_Auth { * @return boolean true if user can be connected, false else. */ private static function accessControl() { - switch (Minz_Configuration::authType()) { + $conf = Minz_Configuration::get('system'); + $auth_type = $conf->auth_type; + switch ($auth_type) { case 'form': $credentials = FreshRSS_FormAuth::getCredentialsFromCookie(); $current_user = ''; @@ -80,21 +83,18 @@ class FreshRSS_Auth { */ public static function giveAccess() { $current_user = Minz_Session::param('currentUser'); - try { - $conf = new FreshRSS_Configuration($current_user); - } catch(Minz_Exception $e) { - die($e->getMessage()); - } + $user_conf = get_user_configuration($current_user); + $system_conf = Minz_Configuration::get('system'); - switch (Minz_Configuration::authType()) { + switch ($system_conf->auth_type) { case 'form': - self::$login_ok = Minz_Session::param('passwordHash') === $conf->passwordHash; + self::$login_ok = Minz_Session::param('passwordHash') === $user_conf->passwordHash; break; case 'http_auth': self::$login_ok = strcasecmp($current_user, httpAuthUser()) === 0; break; case 'persona': - self::$login_ok = strcasecmp(Minz_Session::param('mail'), $conf->mail_login) === 0; + self::$login_ok = strcasecmp(Minz_Session::param('mail'), $user_conf->mail_login) === 0; break; case 'none': self::$login_ok = true; @@ -114,12 +114,14 @@ class FreshRSS_Auth { * @return boolean true if user has corresponding access, false else. */ public static function hasAccess($scope = 'general') { + $conf = Minz_Configuration::get('system'); + $default_user = $conf->default_user; $ok = self::$login_ok; switch ($scope) { case 'general': break; case 'admin': - $ok &= Minz_Session::param('currentUser') === Minz_Configuration::defaultUser(); + $ok &= Minz_Session::param('currentUser') === $default_user; break; default: $ok = false; @@ -133,9 +135,10 @@ class FreshRSS_Auth { public static function removeAccess() { Minz_Session::_param('loginOk'); self::$login_ok = false; - Minz_Session::_param('currentUser', Minz_Configuration::defaultUser()); + $conf = Minz_Configuration::get('system'); + Minz_Session::_param('currentUser', $conf->default_user); - switch (Minz_Configuration::authType()) { + switch ($conf->auth_type) { case 'form': Minz_Session::_param('passwordHash'); FreshRSS_FormAuth::deleteCookie(); @@ -151,6 +154,24 @@ class FreshRSS_Auth { // TODO: extensions } } + + /** + * Return if authentication is enabled on this instance of FRSS. + */ + public static function accessNeedsLogin() { + $conf = Minz_Configuration::get('system'); + $auth_type = $conf->auth_type; + return $auth_type !== 'none'; + } + + /** + * Return if authentication requires a PHP action. + */ + public static function accessNeedsAction() { + $conf = Minz_Configuration::get('system'); + $auth_type = $conf->auth_type; + return $auth_type === 'form' || $auth_type === 'persona'; + } } @@ -194,7 +215,8 @@ class FreshRSS_FormAuth { public static function makeCookie($username, $password_hash) { do { - $token = sha1(Minz_Configuration::salt() . $username . uniqid(mt_rand(), true)); + $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)); diff --git a/app/Models/Configuration.php b/app/Models/Configuration.php deleted file mode 100644 index 8bba8f777..000000000 --- a/app/Models/Configuration.php +++ /dev/null @@ -1,345 +0,0 @@ -<?php - -class FreshRSS_Configuration { - private $filename; - - private $data = array( - 'language' => 'en', - 'old_entries' => 3, - 'keep_history_default' => 0, - 'ttl_default' => 3600, - 'mail_login' => '', - 'token' => '', - 'passwordHash' => '', //CRYPT_BLOWFISH - 'apiPasswordHash' => '', //CRYPT_BLOWFISH - 'posts_per_page' => 20, - 'view_mode' => 'normal', - 'default_view' => 'adaptive', - 'default_state' => FreshRSS_Entry::STATE_NOT_READ, - 'auto_load_more' => true, - 'display_posts' => false, - 'display_categories' => false, - 'hide_read_feeds' => true, - 'onread_jump_next' => true, - 'lazyload' => true, - 'sticky_post' => true, - 'reading_confirm' => false, - 'auto_remove_article' => false, - 'sort_order' => 'DESC', - 'anon_access' => false, - 'mark_when' => array( - 'article' => true, - 'site' => true, - 'scroll' => false, - 'reception' => false, - ), - 'theme' => 'Origine', - 'content_width' => 'thin', - 'shortcuts' => array( - 'mark_read' => 'r', - 'mark_favorite' => 'f', - 'go_website' => 'space', - 'next_entry' => 'j', - 'prev_entry' => 'k', - 'first_entry' => 'home', - 'last_entry' => 'end', - 'collapse_entry' => 'c', - 'load_more' => 'm', - 'auto_share' => 's', - 'focus_search' => 'a', - 'user_filter' => 'u', - 'help' => 'f1', - 'close_dropdown' => 'escape', - ), - 'topline_read' => true, - 'topline_favorite' => true, - 'topline_date' => true, - 'topline_link' => true, - 'bottomline_read' => true, - 'bottomline_favorite' => true, - 'bottomline_sharing' => true, - 'bottomline_tags' => true, - 'bottomline_date' => true, - 'bottomline_link' => true, - 'sharing' => array(), - 'queries' => array(), - 'html5_notif_timeout' => 0, - ); - - private $available_languages = array( - 'en' => 'English', - 'fr' => 'Français', - ); - - private $shares; - - public function __construct($user) { - $this->filename = join_path(DATA_PATH, 'users', $user, 'config.php'); - - $data = @include($this->filename); - if (!is_array($data)) { - throw new Minz_PermissionDeniedException($this->filename); - } - - foreach ($data as $key => $value) { - if (isset($this->data[$key])) { - $function = '_' . $key; - $this->$function($value); - } - } - $this->data['user'] = $user; - - $this->shares = join_path(DATA_PATH, 'shares.php'); - - $shares = @include($this->shares); - if (!is_array($shares)) { - throw new Minz_PermissionDeniedException($this->shares); - } - - $this->data['shares'] = $shares; - } - - public function save() { - @rename($this->filename, $this->filename . '.bak.php'); - unset($this->data['shares']); // Remove shares because it is not intended to be stored in user configuration - if (file_put_contents($this->filename, "<?php\n return " . var_export($this->data, true) . ';', LOCK_EX) === false) { - throw new Minz_PermissionDeniedException($this->filename); - } - if (function_exists('opcache_invalidate')) { - opcache_invalidate($this->filename); //Clear PHP 5.5+ cache for include - } - invalidateHttpCache(); - return true; - } - - public function __get($name) { - if (array_key_exists($name, $this->data)) { - return $this->data[$name]; - } else { - $trace = debug_backtrace(); - trigger_error('Undefined FreshRSS_Configuration->' . $name . 'in ' . $trace[0]['file'] . ' line ' . $trace[0]['line'], E_USER_NOTICE); //TODO: Use Minz exceptions - return null; - } - } - - public function availableLanguages() { - return $this->available_languages; - } - - public function remove_query_by_get($get) { - $final_queries = array(); - foreach ($this->queries as $key => $query) { - if (empty($query['get']) || $query['get'] !== $get) { - $final_queries[$key] = $query; - } - } - $this->_queries($final_queries); - } - - public function _language($value) { - if (!isset($this->available_languages[$value])) { - $value = 'en'; - } - $this->data['language'] = $value; - } - public function _posts_per_page($value) { - $value = intval($value); - $this->data['posts_per_page'] = $value > 0 ? $value : 10; - } - public function _view_mode($value) { - if ($value === 'global' || $value === 'reader') { - $this->data['view_mode'] = $value; - } else { - $this->data['view_mode'] = 'normal'; - } - } - public function _default_view($value) { - switch ($value) { - 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'] = $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'; - } - public function _display_categories($value) { - $this->data['display_categories'] = ((bool)$value) && $value !== 'no'; - } - public function _hide_read_feeds($value) { - $this->data['hide_read_feeds'] = (bool)$value; - } - public function _onread_jump_next($value) { - $this->data['onread_jump_next'] = ((bool)$value) && $value !== 'no'; - } - public function _lazyload($value) { - $this->data['lazyload'] = ((bool)$value) && $value !== 'no'; - } - public function _sticky_post($value) { - $this->data['sticky_post'] = ((bool)$value) && $value !== 'no'; - } - 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'; - } - public function _old_entries($value) { - $value = intval($value); - $this->data['old_entries'] = $value > 0 ? $value : 3; - } - public function _keep_history_default($value) { - $value = intval($value); - $this->data['keep_history_default'] = $value >= -1 ? $value : 0; - } - public function _ttl_default($value) { - $value = intval($value); - $this->data['ttl_default'] = $value >= -1 ? $value : 3600; - } - public function _shortcuts($values) { - foreach ($values as $key => $value) { - if (isset($this->data['shortcuts'][$key])) { - $this->data['shortcuts'][$key] = $value; - } - } - } - public function _passwordHash($value) { - $this->data['passwordHash'] = ctype_graph($value) && (strlen($value) >= 60) ? $value : ''; - } - public function _apiPasswordHash($value) { - $this->data['apiPasswordHash'] = ctype_graph($value) && (strlen($value) >= 60) ? $value : ''; - } - public function _mail_login($value) { - $value = filter_var($value, FILTER_VALIDATE_EMAIL); - if ($value) { - $this->data['mail_login'] = $value; - } else { - $this->data['mail_login'] = ''; - } - } - public function _anon_access($value) { - $this->data['anon_access'] = ((bool)$value) && $value !== 'no'; - } - public function _mark_when($values) { - foreach ($values as $key => $value) { - if (isset($this->data['mark_when'][$key])) { - $this->data['mark_when'][$key] = ((bool)$value) && $value !== 'no'; - } - } - } - public function _sharing($values) { - $this->data['sharing'] = array(); - $unique = array(); - foreach ($values as $value) { - if (!is_array($value)) { - continue; - } - - // Verify URL and add default value when needed - if (isset($value['url'])) { - $is_url = ( - filter_var($value['url'], FILTER_VALIDATE_URL) || - (version_compare(PHP_VERSION, '5.3.3', '<') && - (strpos($value, '-') > 0) && - ($value === filter_var($value, FILTER_SANITIZE_URL))) - ); //PHP bug #51192 - if (!$is_url) { - continue; - } - } else { - $value['url'] = null; - } - - // Add a default name - if (empty($value['name'])) { - $value['name'] = $value['type']; - } - - $json_value = json_encode($value); - if (!in_array($json_value, $unique)) { - $unique[] = $json_value; - $this->data['sharing'][] = $value; - } - } - } - public function _queries($values) { - $this->data['queries'] = array(); - foreach ($values as $value) { - $value = array_filter($value); - $params = $value; - unset($params['name']); - unset($params['url']); - $value['url'] = Minz_Url::display(array('params' => $params)); - - $this->data['queries'][] = $value; - } - } - public function _theme($value) { - $this->data['theme'] = $value; - } - public function _content_width($value) { - if ($value === 'medium' || - $value === 'large' || - $value === 'no_limit') { - $this->data['content_width'] = $value; - } else { - $this->data['content_width'] = 'thin'; - } - } - - public function _html5_notif_timeout($value) { - $value = intval($value); - $this->data['html5_notif_timeout'] = $value >= 0 ? $value : 0; - } - - public function _token($value) { - $this->data['token'] = $value; - } - public function _auto_load_more($value) { - $this->data['auto_load_more'] = ((bool)$value) && $value !== 'no'; - } - public function _topline_read($value) { - $this->data['topline_read'] = ((bool)$value) && $value !== 'no'; - } - public function _topline_favorite($value) { - $this->data['topline_favorite'] = ((bool)$value) && $value !== 'no'; - } - public function _topline_date($value) { - $this->data['topline_date'] = ((bool)$value) && $value !== 'no'; - } - public function _topline_link($value) { - $this->data['topline_link'] = ((bool)$value) && $value !== 'no'; - } - public function _bottomline_read($value) { - $this->data['bottomline_read'] = ((bool)$value) && $value !== 'no'; - } - public function _bottomline_favorite($value) { - $this->data['bottomline_favorite'] = ((bool)$value) && $value !== 'no'; - } - public function _bottomline_sharing($value) { - $this->data['bottomline_sharing'] = ((bool)$value) && $value !== 'no'; - } - public function _bottomline_tags($value) { - $this->data['bottomline_tags'] = ((bool)$value) && $value !== 'no'; - } - public function _bottomline_date($value) { - $this->data['bottomline_date'] = ((bool)$value) && $value !== 'no'; - } - public function _bottomline_link($value) { - $this->data['bottomline_link'] = ((bool)$value) && $value !== 'no'; - } -} diff --git a/app/Models/ConfigurationSetter.php b/app/Models/ConfigurationSetter.php new file mode 100644 index 000000000..9830fed28 --- /dev/null +++ b/app/Models/ConfigurationSetter.php @@ -0,0 +1,368 @@ +<?php + +class FreshRSS_ConfigurationSetter { + /** + * Return if the given key is supported by this setter. + * @param $key the key to test. + * @return true if the key is supported, false else. + */ + public function support($key) { + $name_setter = '_' . $key; + return is_callable(array($this, $name_setter)); + } + + /** + * Set the given key in data with the current value. + * @param $data an array containing the list of all configuration data. + * @param $key the key to update. + * @param $value the value to set. + */ + public function handle(&$data, $key, $value) { + $name_setter = '_' . $key; + call_user_func_array(array($this, $name_setter), array(&$data, $value)); + } + + /** + * A helper to set boolean values. + * + * @param $value the tested value. + * @return true if value is true and different from no, false else. + */ + private function handleBool($value) { + return ((bool)$value) && $value !== 'no'; + } + + /** + * The (long) list of setters for user configuration. + */ + private function _apiPasswordHash(&$data, $value) { + $data['apiPasswordHash'] = ctype_graph($value) && (strlen($value) >= 60) ? $value : ''; + } + + private function _content_width(&$data, $value) { + $value = strtolower($value); + if (!in_array($value, array('thin', 'medium', 'large', 'no_limit'))) { + $value = 'thin'; + } + + $data['content_width'] = $value; + } + + private function _default_state(&$data, $value) { + $data['default_state'] = (int)$value; + } + + private function _default_view(&$data, $value) { + switch ($value) { + case 'all': + $data['default_view'] = $value; + $data['default_state'] = (FreshRSS_Entry::STATE_READ + + FreshRSS_Entry::STATE_NOT_READ); + break; + case 'adaptive': + case 'unread': + default: + $data['default_view'] = $value; + $data['default_state'] = FreshRSS_Entry::STATE_NOT_READ; + } + } + + private function _html5_notif_timeout(&$data, $value) { + $value = intval($value); + $data['html5_notif_timeout'] = $value >= 0 ? $value : 0; + } + + private function _keep_history_default(&$data, $value) { + $value = intval($value); + $data['keep_history_default'] = $value >= -1 ? $value : 0; + } + + // It works for system config too! + private function _language(&$data, $value) { + $value = strtolower($value); + $languages = Minz_Translate::availableLanguages(); + if (!isset($languages[$value])) { + $value = 'en'; + } + $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; + } + + private function _passwordHash(&$data, $value) { + $data['passwordHash'] = ctype_graph($value) && (strlen($value) >= 60) ? $value : ''; + } + + private function _posts_per_page(&$data, $value) { + $value = intval($value); + $data['posts_per_page'] = $value > 0 ? $value : 10; + } + + private function _queries(&$data, $values) { + $data['queries'] = array(); + foreach ($values as $value) { + $value = array_filter($value); + $params = $value; + unset($params['name']); + unset($params['url']); + $value['url'] = Minz_Url::display(array('params' => $params)); + $data['queries'][] = $value; + } + } + + private function _sharing(&$data, $values) { + $data['sharing'] = array(); + foreach ($values as $value) { + if (!is_array($value)) { + continue; + } + + // Verify URL and add default value when needed + if (isset($value['url'])) { + $is_url = ( + filter_var($value['url'], FILTER_VALIDATE_URL) || + (version_compare(PHP_VERSION, '5.3.3', '<') && + (strpos($value, '-') > 0) && + ($value === filter_var($value, FILTER_SANITIZE_URL))) + ); //PHP bug #51192 + if (!$is_url) { + continue; + } + } else { + $value['url'] = null; + } + + $data['sharing'][] = $value; + } + } + + private function _shortcuts(&$data, $values) { + foreach ($values as $key => $value) { + if (isset($data['shortcuts'][$key])) { + $data['shortcuts'][$key] = $value; + } + } + } + + private function _sort_order(&$data, $value) { + $data['sort_order'] = $value === 'ASC' ? 'ASC' : 'DESC'; + } + + private function _ttl_default(&$data, $value) { + $value = intval($value); + $data['ttl_default'] = $value >= -1 ? $value : 3600; + } + + private function _view_mode(&$data, $value) { + $value = strtolower($value); + if (!in_array($value, array('global', 'normal', 'reader'))) { + $value = 'normal'; + } + $data['view_mode'] = $value; + } + + /** + * A list of boolean setters. + */ + private function _anon_access(&$data, $value) { + $data['anon_access'] = $this->handleBool($value); + } + + private function _auto_load_more(&$data, $value) { + $data['auto_load_more'] = $this->handleBool($value); + } + + private function _auto_remove_article(&$data, $value) { + $data['auto_remove_article'] = $this->handleBool($value); + } + + private function _display_categories(&$data, $value) { + $data['display_categories'] = $this->handleBool($value); + } + + private function _display_posts(&$data, $value) { + $data['display_posts'] = $this->handleBool($value); + } + + private function _hide_read_feeds(&$data, $value) { + $data['hide_read_feeds'] = $this->handleBool($value); + } + + private function _lazyload(&$data, $value) { + $data['lazyload'] = $this->handleBool($value); + } + + private function _mark_when(&$data, $values) { + foreach ($values as $key => $value) { + if (isset($data['mark_when'][$key])) { + $data['mark_when'][$key] = $this->handleBool($value); + } + } + } + + private function _onread_jump_next(&$data, $value) { + $data['onread_jump_next'] = $this->handleBool($value); + } + + private function _reading_confirm(&$data, $value) { + $data['reading_confirm'] = $this->handleBool($value); + } + + private function _sticky_post(&$data, $value) { + $data['sticky_post'] = $this->handleBool($value); + } + + private function _bottomline_date(&$data, $value) { + $data['bottomline_date'] = $this->handleBool($value); + } + private function _bottomline_favorite(&$data, $value) { + $data['bottomline_favorite'] = $this->handleBool($value); + } + private function _bottomline_link(&$data, $value) { + $data['bottomline_link'] = $this->handleBool($value); + } + private function _bottomline_read(&$data, $value) { + $data['bottomline_read'] = $this->handleBool($value); + } + private function _bottomline_sharing(&$data, $value) { + $data['bottomline_sharing'] = $this->handleBool($value); + } + private function _bottomline_tags(&$data, $value) { + $data['bottomline_tags'] = $this->handleBool($value); + } + + private function _topline_date(&$data, $value) { + $data['topline_date'] = $this->handleBool($value); + } + private function _topline_favorite(&$data, $value) { + $data['topline_favorite'] = $this->handleBool($value); + } + private function _topline_link(&$data, $value) { + $data['topline_link'] = $this->handleBool($value); + } + private function _topline_read(&$data, $value) { + $data['topline_read'] = $this->handleBool($value); + } + + /** + * The (not so long) list of setters for system configuration. + */ + private function _allow_anonymous(&$data, $value) { + $data['allow_anonymous'] = $this->handleBool($value) && FreshRSS_Auth::accessNeedsAction(); + } + + private function _allow_anonymous_refresh(&$data, $value) { + $data['allow_anonymous_refresh'] = $this->handleBool($value) && $data['allow_anonymous']; + } + + private function _api_enabled(&$data, $value) { + $data['api_enabled'] = $this->handleBool($value); + } + + private function _auth_type(&$data, $value) { + $value = strtolower($value); + if (!in_array($value, array('form', 'http_auth', 'persona', 'none'))) { + $value = 'none'; + } + $data['auth_type'] = $value; + $this->_allow_anonymous($data, $data['allow_anonymous']); + } + + private function _db(&$data, $value) { + if (!isset($value['type'])) { + return; + } + + switch ($value['type']) { + case 'mysql': + if (empty($value['host']) || + empty($value['user']) || + empty($value['base']) || + !isset($value['password'])) { + return; + } + + $data['db']['type'] = $value['type']; + $data['db']['host'] = $value['host']; + $data['db']['user'] = $value['user']; + $data['db']['base'] = $value['base']; + $data['db']['password'] = $value['password']; + $data['db']['prefix'] = isset($value['prefix']) ? $value['prefix'] : ''; + break; + case 'sqlite': + $data['db']['type'] = $value['type']; + $data['db']['host'] = ''; + $data['db']['user'] = ''; + $data['db']['base'] = ''; + $data['db']['password'] = ''; + $data['db']['prefix'] = ''; + break; + default: + return; + } + } + + private function _default_user(&$data, $value) { + $user_list = listUsers(); + if (in_array($value, $user_list)) { + $data['default_user'] = $value; + } + } + + private function _environment(&$data, $value) { + $value = strtolower($value); + if (!in_array($value, array('silent', 'development', 'production'))) { + $value = 'production'; + } + $data['environment'] = $value; + } + + private function _limits(&$data, $values) { + $max_small_int = 16384; + $limits_keys = array( + 'cache_duration' => array( + 'min' => 0, + ), + 'timeout' => array( + 'min' => 0, + ), + 'max_inactivity' => array( + 'min' => 0, + ), + 'max_feeds' => array( + 'min' => 0, + 'max' => $max_small_int, + ), + 'max_categories' => array( + 'min' => 0, + 'max' => $max_small_int, + ), + ); + + foreach ($values as $key => $value) { + if (!isset($limits_keys[$key])) { + continue; + } + + $limits = $limits_keys[$key]; + if ( + (!isset($limits['min']) || $value > $limits['min']) && + (!isset($limits['max']) || $value < $limits['max']) + ) { + $data['limits'][$key] = $value; + } + } + } + + private function _unsafe_autologin_enabled(&$data, $value) { + $data['unsafe_autologin_enabled'] = $this->handleBool($value); + } +} diff --git a/app/Models/Context.php b/app/Models/Context.php index c8a65063a..1c770c756 100644 --- a/app/Models/Context.php +++ b/app/Models/Context.php @@ -5,7 +5,8 @@ * useful functions associated to the current view state. */ class FreshRSS_Context { - public static $conf = null; + public static $user_conf = null; + public static $system_conf = null; public static $categories = array(); public static $name = ''; @@ -37,17 +38,12 @@ class FreshRSS_Context { /** * Initialize the context. * - * Set the correct $conf and $categories variables. + * Set the correct configurations and $categories variables. */ public static function init() { // Init configuration. - $current_user = Minz_Session::param('currentUser'); - try { - self::$conf = new FreshRSS_Configuration($current_user); - } catch(Minz_Exception $e) { - Minz_Log::error('Cannot load configuration file of user `' . $current_user . '`'); - die($e->getMessage()); - } + self::$system_conf = Minz_Configuration::get('system'); + self::$user_conf = Minz_Configuration::get('user'); $catDAO = new FreshRSS_CategoryDAO(); self::$categories = $catDAO->listCategories(); @@ -198,7 +194,7 @@ class FreshRSS_Context { // By default, $next_get == $get self::$next_get = $get; - if (self::$conf->onread_jump_next && strlen($get) > 2) { + if (self::$user_conf->onread_jump_next && strlen($get) > 2) { $another_unread_id = ''; $found_current_get = false; switch ($get[0]) { @@ -276,7 +272,7 @@ class FreshRSS_Context { * @return boolean */ public static function isAutoRemoveAvailable() { - if (!self::$conf->auto_remove_article) { + if (!self::$user_conf->auto_remove_article) { return false; } if (self::isStateEnabled(FreshRSS_Entry::STATE_READ)) { @@ -297,7 +293,7 @@ class FreshRSS_Context { * @return boolean */ public static function isStickyPostEnabled() { - if (self::$conf->sticky_post) { + if (self::$user_conf->sticky_post) { return true; } if (self::isAutoRemoveAvailable()) { diff --git a/app/Models/EntryDAO.php b/app/Models/EntryDAO.php index 4d06ac028..61beeea13 100644 --- a/app/Models/EntryDAO.php +++ b/app/Models/EntryDAO.php @@ -586,7 +586,7 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo { } public function size($all = false) { - $db = Minz_Configuration::dataBase(); + $db = FreshRSS_Context::$system_conf->db; $sql = 'SELECT SUM(data_length + index_length) FROM information_schema.TABLES WHERE table_schema=?'; //MySQL $values = array($db['base']); if (!$all) { diff --git a/app/Models/Factory.php b/app/Models/Factory.php index 91cb84998..db09d155d 100644 --- a/app/Models/Factory.php +++ b/app/Models/Factory.php @@ -3,8 +3,8 @@ class FreshRSS_Factory { public static function createFeedDao($username = null) { - $db = Minz_Configuration::dataBase(); - if ($db['type'] === 'sqlite') { + $conf = Minz_Configuration::get('system'); + if ($conf->db['type'] === 'sqlite') { return new FreshRSS_FeedDAOSQLite($username); } else { return new FreshRSS_FeedDAO($username); @@ -12,8 +12,8 @@ class FreshRSS_Factory { } public static function createEntryDao($username = null) { - $db = Minz_Configuration::dataBase(); - if ($db['type'] === 'sqlite') { + $conf = Minz_Configuration::get('system'); + if ($conf->db['type'] === 'sqlite') { return new FreshRSS_EntryDAOSQLite($username); } else { return new FreshRSS_EntryDAO($username); @@ -21,8 +21,8 @@ class FreshRSS_Factory { } public static function createStatsDAO($username = null) { - $db = Minz_Configuration::dataBase(); - if ($db['type'] === 'sqlite') { + $conf = Minz_Configuration::get('system'); + if ($conf->db['type'] === 'sqlite') { return new FreshRSS_StatsDAOSQLite($username); } else { return new FreshRSS_StatsDAO($username); @@ -30,8 +30,8 @@ class FreshRSS_Factory { } public static function createDatabaseDAO($username = null) { - $db = Minz_Configuration::dataBase(); - if ($db['type'] === 'sqlite') { + $conf = Minz_Configuration::get('system'); + if ($conf->db['type'] === 'sqlite') { return new FreshRSS_DatabaseDAOSQLite($username); } else { return new FreshRSS_DatabaseDAO($username); diff --git a/app/Models/Feed.php b/app/Models/Feed.php index 8f4b60097..86cbb783e 100644 --- a/app/Models/Feed.php +++ b/app/Models/Feed.php @@ -40,7 +40,8 @@ class FreshRSS_Feed extends Minz_Model { public function hash() { if ($this->hash === null) { - $this->hash = hash('crc32b', Minz_Configuration::salt() . $this->url); + $salt = FreshRSS_Context::$system_conf->salt; + $this->hash = hash('crc32b', $salt . $this->url); } return $this->hash; } diff --git a/app/Models/Share.php b/app/Models/Share.php index b146db722..db6feda19 100644 --- a/app/Models/Share.php +++ b/app/Models/Share.php @@ -1,44 +1,240 @@ <?php +/** + * Manage the sharing options in FreshRSS. + */ class FreshRSS_Share { + /** + * The list of available sharing options. + */ + private static $list_sharing = array(); - static public function generateUrl($options, $selected, $link, $title) { - $share = $options[$selected['type']]; + /** + * Register a new sharing option. + * @param $share_options is an array defining the share option. + */ + public static function register($share_options) { + $type = $share_options['type']; + + if (isset(self::$list_sharing[$type])) { + return; + } + + $help_url = isset($share_options['help']) ? $share_options['help'] : ''; + self::$list_sharing[$type] = new FreshRSS_Share( + $type, $share_options['url'], $share_options['transform'], + $share_options['form'], $help_url + ); + } + + /** + * Register sharing options in a file. + * @param $filename the name of the file to load. + */ + public static function load($filename) { + $shares_from_file = @include($filename); + if (!is_array($shares_from_file)) { + $shares_from_file = array(); + } + + foreach ($shares_from_file as $share_type => $share_options) { + $share_options['type'] = $share_type; + self::register($share_options); + } + } + + /** + * Return the list of sharing options. + * @return an array of FreshRSS_Share objects. + */ + public static function enum() { + return self::$list_sharing; + } + + /** + * Return FreshRSS_Share object related to the given type. + * @param $type the share type, null if $type is not registered. + */ + public static function get($type) { + if (!isset(self::$list_sharing[$type])) { + return null; + } + + return self::$list_sharing[$type]; + } + + /** + * + */ + private $type = ''; + private $name = ''; + private $url_transform = ''; + private $transform = array(); + private $form_type = 'simple'; + private $help_url = ''; + private $custom_name = null; + private $base_url = null; + private $title = null; + private $link = null; + + /** + * Create a FreshRSS_Share object. + * @param $type is a unique string defining the kind of share option. + * @param $url_transform defines the url format to use in order to share. + * @param $transform is an array of transformations to apply on link and title. + * @param $form_type defines which form we have to use to complete. "simple" + * is typically for a centralized service while "advanced" is for + * decentralized ones. + * @param $help_url is an optional url to give help on this option. + */ + private function __construct($type, $url_transform, $transform = array(), + $form_type, $help_url = '') { + $this->type = $type; + $this->name = _t('gen.share.' . $type); + $this->url_transform = $url_transform; + $this->help_url = $help_url; + + if (!is_array($transform)) { + $transform = array(); + } + $this->transform = $transform; + + if (!in_array($form_type, array('simple', 'advanced'))) { + $form_type = 'simple'; + } + $this->form_type = $form_type; + } + + /** + * Update a FreshRSS_Share object with information from an array. + * @param $options is a list of informations to update where keys should be + * in this list: name, url, title, link. + */ + public function update($options) { + $available_options = array( + 'name' => 'custom_name', + 'url' => 'base_url', + 'title' => 'title', + 'link' => 'link', + ); + + foreach ($options as $key => $value) { + if (!isset($available_options[$key])) { + continue; + } + + $this->$available_options[$key] = $value; + } + } + + /** + * Return the current type of the share option. + */ + public function type() { + return $this->type; + } + + /** + * Return the current form type of the share option. + */ + public function formType() { + return $this->form_type; + } + + /** + * Return the current help url of the share option. + */ + public function help() { + return $this->help_url; + } + + /** + * Return the current name of the share option. + */ + public function name($real = false) { + if ($real || is_null($this->custom_name)) { + return $this->name; + } else { + return $this->custom_name; + } + } + + /** + * Return the current base url of the share option. + */ + public function baseUrl() { + return $this->base_url; + } + + /** + * Return the current url by merging url_transform and base_url. + */ + public function url() { $matches = array( '~URL~', '~TITLE~', '~LINK~', ); $replaces = array( - $selected['url'], - self::transformData($title, self::getTransform($share, 'title')), - self::transformData($link, self::getTransform($share, 'link')), + $this->base_url, + $this->title(), + $this->link(), ); - $url = str_replace($matches, $replaces, $share['url']); - return $url; + return str_replace($matches, $replaces, $this->url_transform); } - static private function transformData($data, $transform) { - if (!is_array($transform)) { - return $data; + /** + * Return the title. + * @param $raw true if we should get the title without transformations. + */ + public function title($raw = false) { + if ($raw) { + return $this->title; } - if (count($transform) === 0) { + + return $this->transform($this->title, $this->getTransform('title')); + } + + /** + * Return the link. + * @param $raw true if we should get the link without transformations. + */ + public function link($raw = false) { + if ($raw) { + return $this->link; + } + + return $this->transform($this->link, $this->getTransform('link')); + } + + /** + * Transform a data with the given functions. + * @param $data the data to transform. + * @param $tranform an array containing a list of functions to apply. + * @return the transformed data. + */ + private static function transform($data, $transform) { + if (!is_array($transform) || empty($transform)) { return $data; } + foreach ($transform as $action) { $data = call_user_func($action, $data); } + return $data; } - static private function getTransform($options, $type) { - $transform = $options['transform']; - - if (array_key_exists($type, $transform)) { - return $transform[$type]; + /** + * Get the list of transformations for the given attribute. + * @param $attr the attribute of which we want the transformations. + * @return an array containing a list of transformations to apply. + */ + private function getTransform($attr) { + if (array_key_exists($attr, $this->transform)) { + return $this->transform[$attr]; } - return $transform; + return $this->transform; } - } diff --git a/app/Models/UserDAO.php b/app/Models/UserDAO.php index 6514080bc..b55766ab4 100644 --- a/app/Models/UserDAO.php +++ b/app/Models/UserDAO.php @@ -2,7 +2,7 @@ class FreshRSS_UserDAO extends Minz_ModelPdo { public function createUser($username) { - $db = Minz_Configuration::dataBase(); + $db = FreshRSS_Context::$system_conf->db; require_once(APP_PATH . '/SQL/install.sql.' . $db['type'] . '.php'); $userPDO = new Minz_ModelPdo($username); @@ -34,7 +34,7 @@ class FreshRSS_UserDAO extends Minz_ModelPdo { } public function deleteUser($username) { - $db = Minz_Configuration::dataBase(); + $db = FreshRSS_Context::$system_conf->db; require_once(APP_PATH . '/SQL/install.sql.' . $db['type'] . '.php'); if ($db['type'] === 'sqlite') { diff --git a/app/actualize_script.php b/app/actualize_script.php index e8bc67c10..c7959be82 100755 --- a/app/actualize_script.php +++ b/app/actualize_script.php @@ -12,58 +12,63 @@ if (defined('STDOUT')) { fwrite(STDOUT, 'Starting feed actualization at ' . $begin_date->format('c') . "\n"); //Unbuffered } -Minz_Configuration::init(); -$users = listUsers(); -shuffle($users); //Process users in random order +// Set the header params ($_GET) to call the FRSS application. +$_GET['c'] = 'feed'; +$_GET['a'] = 'actualize'; +$_GET['ajax'] = 1; +$_GET['force'] = true; +$_SERVER['HTTP_HOST'] = ''; + + +$app = new FreshRSS(); +$app->init(); -if (Minz_Configuration::defaultUser() !== ''){ - array_unshift($users, Minz_Configuration::defaultUser()); //But always start with admin +$system_conf = Minz_Configuration::get('system'); +$system_conf->auth_type = 'none'; // avoid necessity to be logged in (not saved!) + +// 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 !== ''){ + array_unshift($users, $system_conf->default_user); $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); +$limits = $system_conf->limits; +$min_last_activity = time() - $limits['max_inactivity']; +foreach ($users as $user) { + if (($user !== $system_conf->default_user) && + (FreshRSS_UserDAO::mtime($user) < $min_last_activity)) { + syslog(LOG_INFO, 'FreshRSS skip inactive user ' . $user); if (defined('STDOUT')) { - fwrite(STDOUT, 'FreshRSS skip inactive user ' . $myUser . "\n"); //Unbuffered + fwrite(STDOUT, 'FreshRSS skip inactive user ' . $user . "\n"); //Unbuffered } continue; } - syslog(LOG_INFO, 'FreshRSS actualize ' . $myUser); + syslog(LOG_INFO, 'FreshRSS actualize ' . $user); if (defined('STDOUT')) { - fwrite(STDOUT, 'Actualize ' . $myUser . "...\n"); //Unbuffered + fwrite(STDOUT, 'Actualize ' . $user . "...\n"); //Unbuffered } - echo $myUser, ' '; //Buffered + echo $user, ' '; //Buffered - $_GET['c'] = 'feed'; - $_GET['a'] = 'actualize'; - $_GET['ajax'] = 1; - $_GET['force'] = true; - $_SERVER['HTTP_HOST'] = ''; - $freshRSS = new FreshRSS(); + Minz_Session::_param('currentUser', $user); + FreshRSS_Auth::giveAccess(); + $app->run(); - Minz_Configuration::_authType('none'); - - Minz_Session::init('FreshRSS'); - Minz_Session::_param('currentUser', $myUser); - - $freshRSS->init(); - $freshRSS->run(); if (!invalidateHttpCache()) { - syslog(LOG_NOTICE, 'FreshRSS write access problem in ' . USERS_PATH . '/*/log.txt!'); + syslog(LOG_NOTICE, 'FreshRSS write access problem in ' . join_path(USERS_PATH, $user, 'log.txt')); if (defined('STDERR')) { - fwrite(STDERR, 'Write access problem in ' . USERS_PATH . '/*/log.txt!' . "\n"); + fwrite(STDERR, 'Write access problem in ' . join_path(USERS_PATH, $user, 'log.txt') . "\n"); } } - Minz_Session::unset_session(true); - Minz_ModelPdo::clean(); } + + syslog(LOG_INFO, 'FreshRSS actualize done.'); if (defined('STDOUT')) { fwrite(STDOUT, 'Done.' . "\n"); diff --git a/app/i18n/en/gen.php b/app/i18n/en/gen.php index 43f94f1bc..4a6f8a71b 100644 --- a/app/i18n/en/gen.php +++ b/app/i18n/en/gen.php @@ -128,6 +128,17 @@ return array( 'nothing_to_load' => 'There are no more articles', 'previous' => 'Previous', ), + 'share' => array( + 'blogotext' => 'Blogotext', + 'diaspora' => 'Diaspora*', + 'email' => 'Email', + 'facebook' => 'Facebook', + 'g+' => 'Google+', + 'print' => 'Print', + 'shaarli' => 'Shaarli', + 'twitter' => 'Twitter', + 'wallabag' => 'wallabag', + ), 'short' => array( 'attention' => 'Attention!', 'blank_to_disable' => 'Leave blank to disable', diff --git a/app/i18n/en/index.php b/app/i18n/en/index.php index 941388b68..8e7d81db8 100644 --- a/app/i18n/en/index.php +++ b/app/i18n/en/index.php @@ -55,18 +55,7 @@ return array( 'subscription' => 'Subscriptions management', 'unread' => 'Show only unread', ), - 'share' => array( - '_' => 'Share', - 'blogotext' => 'Blogotext', - 'diaspora' => 'Diaspora*', - 'email' => 'Email', - 'facebook' => 'Facebook', - 'g+' => 'Google+', - 'print' => 'Print', - 'shaarli' => 'Shaarli', - 'twitter' => 'Twitter', - 'wallabag' => 'wallabag', - ), + 'share' => 'Share', 'tag' => array( 'related' => 'Related tags', ), diff --git a/app/i18n/fr/conf.php b/app/i18n/fr/conf.php index 62d6342e9..e91aeb66a 100644 --- a/app/i18n/fr/conf.php +++ b/app/i18n/fr/conf.php @@ -121,7 +121,7 @@ return array( '_' => 'Partage', 'blogotext' => 'Blogotext', 'diaspora' => 'Diaspora*', - 'email' => 'Email', + 'email' => 'Courriel', 'facebook' => 'Facebook', 'g+' => 'Google+', 'more_information' => 'Plus d’informations', diff --git a/app/i18n/fr/gen.php b/app/i18n/fr/gen.php index bb4478360..d990dad4a 100644 --- a/app/i18n/fr/gen.php +++ b/app/i18n/fr/gen.php @@ -128,6 +128,17 @@ return array( 'nothing_to_load' => 'Fin des articles', 'previous' => 'Précédent', ), + 'share' => array( + 'blogotext' => 'Blogotext', + 'diaspora' => 'Diaspora*', + 'email' => 'Courriel', + 'facebook' => 'Facebook', + 'g+' => 'Google+', + 'print' => 'Imprimer', + 'shaarli' => 'Shaarli', + 'twitter' => 'Twitter', + 'wallabag' => 'wallabag', + ), 'short' => array( 'attention' => 'Attention !', 'blank_to_disable' => 'Laissez vide pour désactiver', diff --git a/app/i18n/fr/index.php b/app/i18n/fr/index.php index 3279543bd..f9975c593 100644 --- a/app/i18n/fr/index.php +++ b/app/i18n/fr/index.php @@ -55,18 +55,7 @@ return array( 'subscription' => 'Gestion des abonnements', 'unread' => 'Afficher les non lus', ), - 'share' => array( - '_' => 'Partager', - 'blogotext' => 'Blogotext', - 'diaspora' => 'Diaspora*', - 'email' => 'Courriel', - 'facebook' => 'Facebook', - 'g+' => 'Google+', - 'print' => 'Imprimer', - 'shaarli' => 'Shaarli', - 'twitter' => 'Twitter', - 'wallabag' => 'wallabag', - ), + 'share' => 'Partager', 'tag' => array( 'related' => 'Tags associés', ), diff --git a/app/layout/aside_feed.phtml b/app/layout/aside_feed.phtml index a39aea327..d2612e751 100644 --- a/app/layout/aside_feed.phtml +++ b/app/layout/aside_feed.phtml @@ -1,6 +1,6 @@ <?php $class = ''; - if (FreshRSS_Context::$conf->hide_read_feeds && + if (FreshRSS_Context::$user_conf->hide_read_feeds && FreshRSS_Context::isStateEnabled(FreshRSS_Entry::STATE_NOT_READ) && !FreshRSS_Context::isStateEnabled(FreshRSS_Entry::STATE_READ)) { $class = ' state_unread'; @@ -15,7 +15,7 @@ <a class="btn btn-important" href="<?php echo _url('subscription', 'index'); ?>"><?php echo _t('index.menu.subscription'); ?></a> <a class="btn btn-important" href="<?php echo _url('importExport', 'index'); ?>"><?php echo _i('import'); ?></a> </div> - <?php } elseif (Minz_Configuration::needsLogin()) { ?> + <?php } elseif (FreshRSS_Auth::accessNeedsLogin()) { ?> <a href="<?php echo _url('index', 'about'); ?>"><?php echo _t('index.menu.about'); ?></a> <?php } ?> @@ -39,7 +39,7 @@ $feeds = $cat->feeds(); if (!empty($feeds)) { $c_active = FreshRSS_Context::isCurrentGet('c_' . $cat->id()); - $c_show = $c_active && (!FreshRSS_Context::$conf->display_categories || + $c_show = $c_active && (!FreshRSS_Context::$user_conf->display_categories || FreshRSS_Context::$current_get['feed']); ?> <li class="tree-folder category<?php echo $c_active ? ' active' : ''; ?>" data-unread="<?php echo $cat->nbNotRead(); ?>"> @@ -84,7 +84,7 @@ <li class="item"><a href="<?php echo _url('subscription', 'index', 'id', '!!!!!!'); ?>"><?php echo _t('gen.action.manage'); ?></a></li> <li class="item"><a href="<?php echo _url('feed', 'actualize', 'id', '!!!!!!'); ?>"><?php echo _t('gen.action.actualize'); ?></a></li> <li class="item"> - <?php $confirm = FreshRSS_Context::$conf->reading_confirm ? 'confirm' : ''; ?> + <?php $confirm = FreshRSS_Context::$user_conf->reading_confirm ? 'confirm' : ''; ?> <button class="read_all as-link <?php echo $confirm; ?>" form="mark-read-aside" formaction="<?php echo _url('entry', 'read', 'get', 'f_!!!!!!'); ?>" diff --git a/app/layout/header.phtml b/app/layout/header.phtml index ba13c2a45..0c2e171dd 100644 --- a/app/layout/header.phtml +++ b/app/layout/header.phtml @@ -1,5 +1,6 @@ <?php -if (Minz_Configuration::canLogIn()) { + +if (FreshRSS_Auth::accessNeedsAction()) { ?><ul class="nav nav-head nav-login"><?php if (FreshRSS_Auth::hasAccess()) { ?><li class="item"><?php echo _i('logout'); ?> <a class="signout" href="<?php echo _url('auth', 'logout'); ?>"><?php echo _t('gen.auth.logout'); ?></a></li><?php @@ -15,13 +16,13 @@ if (Minz_Configuration::canLogIn()) { <h1> <a href="<?php echo _url('index', 'index'); ?>"> <img class="logo" src="<?php echo _i('icon', true); ?>" alt="⊚" /> - <?php echo Minz_Configuration::title(); ?> + <?php echo FreshRSS_Context::$system_conf->title; ?> </a> </h1> </div> <div class="item search"> - <?php if (FreshRSS_Auth::hasAccess() || Minz_Configuration::allowAnonymous()) { ?> + <?php if (FreshRSS_Auth::hasAccess() || FreshRSS_Context::$system_conf->allow_anonymous) { ?> <form action="<?php echo _url('index', 'index'); ?>" method="get"> <div class="stick"> <?php $search = Minz_Request::param('search', ''); ?> @@ -76,14 +77,14 @@ if (Minz_Configuration::canLogIn()) { <li class="item"><a href="<?php echo _url('index', 'logs'); ?>"><?php echo _t('gen.menu.logs'); ?></a></li> <li class="item"><a href="<?php echo _url('index', 'about'); ?>"><?php echo _t('gen.menu.about'); ?></a></li> <?php - if (Minz_Configuration::canLogIn()) { + if (FreshRSS_Auth::accessNeedsAction()) { ?><li class="separator"></li> <li class="item"><a class="signout" href="<?php echo _url('auth', 'logout'); ?>"><?php echo _i('logout'), ' ', _t('gen.auth.logout'); ?></a></li><?php } ?> </ul> </div> </div> - <?php } elseif (Minz_Configuration::canLogIn()) { ?> + <?php } elseif (FreshRSS_Auth::accessNeedsAction()) { ?> <div class="item configure"> <?php echo _i('login'); ?><a class="signin" href="<?php echo _url('auth', 'login'); ?>"><?php echo _t('gen.auth.login'); ?></a> </div> diff --git a/app/layout/layout.phtml b/app/layout/layout.phtml index 1827d6c26..083ffd4b3 100644 --- a/app/layout/layout.phtml +++ b/app/layout/layout.phtml @@ -1,5 +1,5 @@ <!DOCTYPE html> -<html lang="<?php echo FreshRSS_Context::$conf->language; ?>" xml:lang="<?php echo FreshRSS_Context::$conf->language; ?>"> +<html lang="<?php echo FreshRSS_Context::$user_conf->language; ?>" xml:lang="<?php echo FreshRSS_Context::$user_conf->language; ?>"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="initial-scale=1.0" /> @@ -34,7 +34,7 @@ <link rel="apple-touch-icon" href="<?php echo Minz_Url::display('/themes/icons/apple-touch-icon.png'); ?>"> <meta name="apple-mobile-web-app-capable" content="yes" /> <meta name="apple-mobile-web-app-status-bar-style" content="black" /> - <meta name="apple-mobile-web-app-title" content="<?php echo Minz_Configuration::title(); ?>"> + <meta name="apple-mobile-web-app-title" content="<?php echo FreshRSS_Context::$system_conf->title; ?>"> <meta name="msapplication-TileColor" content="#FFF" /> <meta name="robots" content="noindex,nofollow" /> </head> diff --git a/app/layout/nav_menu.phtml b/app/layout/nav_menu.phtml index f8abf9032..d35a0b5fb 100644 --- a/app/layout/nav_menu.phtml +++ b/app/layout/nav_menu.phtml @@ -39,13 +39,13 @@ <a class="no-mobile" href="<?php echo _url('configure', 'queries'); ?>"><?php echo _i('configure'); ?></a> </li> - <?php foreach (FreshRSS_Context::$conf->queries as $query) { ?> + <?php foreach (FreshRSS_Context::$user_conf->queries as $query) { ?> <li class="item query"> <a href="<?php echo $query['url']; ?>"><?php echo $query['name']; ?></a> </li> <?php } ?> - <?php if (count(FreshRSS_Context::$conf->queries) > 0) { ?> + <?php if (count(FreshRSS_Context::$user_conf->queries) > 0) { ?> <li class="separator no-mobile"></li> <?php } ?> @@ -82,7 +82,7 @@ <form id="mark-read-menu" method="post" style="display: none"></form> <div class="stick" id="nav_menu_read_all"> - <?php $confirm = FreshRSS_Context::$conf->reading_confirm ? 'confirm' : ''; ?> + <?php $confirm = FreshRSS_Context::$user_conf->reading_confirm ? 'confirm' : ''; ?> <button class="read_all btn <?php echo $confirm; ?>" form="mark-read-menu" formaction="<?php echo Minz_Url::display($mark_read_url); ?>" @@ -145,8 +145,8 @@ <?php $url_output['a'] = 'rss'; - if (FreshRSS_Context::$conf->token) { - $url_output['params']['token'] = FreshRSS_Context::$conf->token; + if (FreshRSS_Context::$user_conf->token) { + $url_output['params']['token'] = FreshRSS_Context::$user_conf->token; } ?> <a class="view_rss btn" target="_blank" title="<?php echo _t('index.menu.rss_view'); ?>" href="<?php echo Minz_Url::display($url_output); ?>"> @@ -193,7 +193,7 @@ <?php echo _i($icon); ?> </a> - <?php if (FreshRSS_Auth::hasAccess() || Minz_Configuration::allowAnonymousRefresh()) { ?> + <?php if (FreshRSS_Auth::hasAccess() || FreshRSS_Context::$system_conf->allow_anonymous_refresh) { ?> <a id="actualize" class="btn" href="<?php echo _url('feed', 'actualize'); ?>" title="<?php echo _t('gen.action.actualize'); ?>"><?php echo _i('refresh'); ?></a> <?php } ?> </div> diff --git a/app/views/auth/index.phtml b/app/views/auth/index.phtml index ee1e2d8b9..f7a862ac9 100644 --- a/app/views/auth/index.phtml +++ b/app/views/auth/index.phtml @@ -10,13 +10,13 @@ <label class="group-name" for="auth_type"><?php echo _t('admin.auth.type'); ?></label> <div class="group-controls"> <select id="auth_type" name="auth_type" required="required"> - <?php if (!in_array(Minz_Configuration::authType(), array('form', 'persona', 'http_auth', 'none'))) { ?> + <?php if (!in_array(FreshRSS_Context::$system_conf->auth_type, array('form', 'persona', 'http_auth', 'none'))) { ?> <option selected="selected"></option> <?php } ?> - <option value="form"<?php echo Minz_Configuration::authType() === 'form' ? ' selected="selected"' : '', cryptAvailable() ? '' : ' disabled="disabled"'; ?>><?php echo _t('admin.auth.form'); ?></option> - <option value="persona"<?php echo Minz_Configuration::authType() === 'persona' ? ' selected="selected"' : '', FreshRSS_Context::$conf->mail_login == '' ? ' disabled="disabled"' : ''; ?>><?php echo _t('admin.auth.persona'); ?></option> - <option value="http_auth"<?php echo Minz_Configuration::authType() === 'http_auth' ? ' selected="selected"' : '', httpAuthUser() == '' ? ' disabled="disabled"' : ''; ?>><?php echo _t('admin.auth.http'); ?> (REMOTE_USER = '<?php echo httpAuthUser(); ?>')</option> - <option value="none"<?php echo Minz_Configuration::authType() === 'none' ? ' selected="selected"' : ''; ?>><?php echo _t('admin.auth.none'); ?></option> + <option value="form"<?php echo FreshRSS_Context::$system_conf->auth_type === 'form' ? ' selected="selected"' : '', cryptAvailable() ? '' : ' disabled="disabled"'; ?>><?php echo _t('admin.auth.form'); ?></option> + <option value="persona"<?php echo FreshRSS_Context::$system_conf->auth_type === 'persona' ? ' selected="selected"' : '', FreshRSS_Context::$user_conf->mail_login == '' ? ' disabled="disabled"' : ''; ?>><?php echo _t('admin.auth.persona'); ?></option> + <option value="http_auth"<?php echo FreshRSS_Context::$system_conf->auth_type === 'http_auth' ? ' selected="selected"' : '', httpAuthUser() == '' ? ' disabled="disabled"' : ''; ?>><?php echo _t('admin.auth.http'); ?> (REMOTE_USER = '<?php echo httpAuthUser(); ?>')</option> + <option value="none"<?php echo FreshRSS_Context::$system_conf->auth_type === 'none' ? ' selected="selected"' : ''; ?>><?php echo _t('admin.auth.none'); ?></option> </select> </div> </div> @@ -24,9 +24,9 @@ <div class="form-group"> <div class="group-controls"> <label class="checkbox" for="anon_access"> - <input type="checkbox" name="anon_access" id="anon_access" value="1"<?php echo Minz_Configuration::allowAnonymous() ? ' checked="checked"' : '', - Minz_Configuration::canLogIn() ? '' : ' disabled="disabled"'; ?> /> - <?php echo _t('admin.auth.allow_anonymous', Minz_Configuration::defaultUser()); ?> + <input type="checkbox" name="anon_access" id="anon_access" value="1"<?php echo FreshRSS_Context::$system_conf->allow_anonymous ? ' checked="checked"' : '', + FreshRSS_Auth::accessNeedsAction() ? '' : ' disabled="disabled"'; ?> /> + <?php echo _t('admin.auth.allow_anonymous', FreshRSS_Context::$system_conf->default_user); ?> </label> </div> </div> @@ -34,8 +34,8 @@ <div class="form-group"> <div class="group-controls"> <label class="checkbox" for="anon_refresh"> - <input type="checkbox" name="anon_refresh" id="anon_refresh" value="1"<?php echo Minz_Configuration::allowAnonymousRefresh() ? ' checked="checked"' : '', - Minz_Configuration::canLogIn() ? '' : ' disabled="disabled"'; ?> /> + <input type="checkbox" name="anon_refresh" id="anon_refresh" value="1"<?php echo FreshRSS_Context::$system_conf->allow_anonymous_refresh ? ' checked="checked"' : '', + FreshRSS_Auth::accessNeedsAction() ? '' : ' disabled="disabled"'; ?> /> <?php echo _t('admin.auth.allow_anonymous_refresh'); ?> </label> </div> @@ -44,21 +44,21 @@ <div class="form-group"> <div class="group-controls"> <label class="checkbox" for="unsafe_autologin"> - <input type="checkbox" name="unsafe_autologin" id="unsafe_autologin" value="1"<?php echo Minz_Configuration::unsafeAutologinEnabled() ? ' checked="checked"' : '', - Minz_Configuration::canLogIn() ? '' : ' disabled="disabled"'; ?> /> + <input type="checkbox" name="unsafe_autologin" id="unsafe_autologin" value="1"<?php echo FreshRSS_Context::$system_conf->unsafe_autologin_enabled ? ' checked="checked"' : '', + FreshRSS_Auth::accessNeedsAction() ? '' : ' disabled="disabled"'; ?> /> <?php echo _t('admin.auth.unsafe_autologin'); ?> <kbd><?php echo Minz_Url::display(array('c' => 'auth', 'a' => 'login', 'params' => array('u' => 'alice', 'p' => '1234')), 'html', true); ?></kbd> </label> </div> </div> - <?php if (Minz_Configuration::canLogIn()) { ?> + <?php if (FreshRSS_Auth::accessNeedsAction()) { ?> <div class="form-group"> <label class="group-name" for="token"><?php echo _t('admin.auth.token'); ?></label> - <?php $token = FreshRSS_Context::$conf->token; ?> + <?php $token = FreshRSS_Context::$user_conf->token; ?> <div class="group-controls"> <input type="text" id="token" name="token" value="<?php echo $token; ?>" placeholder="<?php echo _t('gen.short.blank_to_disable'); ?>"<?php - echo Minz_Configuration::canLogIn() ? '' : ' disabled="disabled"'; ?> /> + echo FreshRSS_Auth::accessNeedsAction() ? '' : ' disabled="disabled"'; ?> /> <?php echo _i('help'); ?> <?php echo _t('admin.auth.token_help'); ?> <kbd><?php echo Minz_Url::display(array('params' => array('output' => 'rss', 'token' => $token)), 'html', true); ?></kbd> </div> @@ -68,8 +68,8 @@ <div class="form-group"> <div class="group-controls"> <label class="checkbox" for="api_enabled"> - <input type="checkbox" name="api_enabled" id="api_enabled" value="1"<?php echo Minz_Configuration::apiEnabled() ? ' checked="checked"' : '', - Minz_Configuration::needsLogin() ? '' : ' disabled="disabled"'; ?> /> + <input type="checkbox" name="api_enabled" id="api_enabled" value="1"<?php echo FreshRSS_Context::$system_conf->api_enabled ? ' checked="checked"' : '', + FreshRSS_Auth::accessNeedsLogin() ? '' : ' disabled="disabled"'; ?> /> <?php echo _t('admin.auth.api_enabled'); ?> </label> </div> diff --git a/app/views/configure/archiving.phtml b/app/views/configure/archiving.phtml index 4e8dfd385..875463137 100644 --- a/app/views/configure/archiving.phtml +++ b/app/views/configure/archiving.phtml @@ -10,7 +10,7 @@ <div class="form-group"> <label class="group-name" for="old_entries"><?php echo _t('conf.archiving.delete_after'); ?></label> <div class="group-controls"> - <input type="number" id="old_entries" name="old_entries" min="1" max="1200" value="<?php echo FreshRSS_Context::$conf->old_entries; ?>" /> <?php echo _t('gen.date.month'); ?> + <input type="number" id="old_entries" name="old_entries" min="1" max="1200" value="<?php echo FreshRSS_Context::$user_conf->old_entries; ?>" /> <?php echo _t('gen.date.month'); ?> <a class="btn confirm" href="<?php echo _url('entry', 'purge'); ?>"><?php echo _t('conf.archiving.purge_now'); ?></a> </div> </div> @@ -19,7 +19,7 @@ <div class="group-controls"> <select class="number" name="keep_history_default" id="keep_history_default" required="required"><?php foreach (array('' => '', 0 => '0', 10 => '10', 50 => '50', 100 => '100', 500 => '500', 1000 => '1 000', 5000 => '5 000', 10000 => '10 000', -1 => '∞') as $v => $t) { - echo '<option value="' . $v . (FreshRSS_Context::$conf->keep_history_default == $v ? '" selected="selected' : '') . '">' . $t . ' </option>'; + echo '<option value="' . $v . (FreshRSS_Context::$user_conf->keep_history_default == $v ? '" selected="selected' : '') . '">' . $t . ' </option>'; } ?></select> (<?php echo _t('gen.short.by_default'); ?>) </div> @@ -34,13 +34,13 @@ 36000 => '10h', 43200 => '12h', 64800 => '18h', 86400 => '1d', 129600 => '1.5d', 172800 => '2d', 259200 => '3d', 345600 => '4d', 432000 => '5d', 518400 => '6d', 604800 => '1wk', -1 => '∞') as $v => $t) { - echo '<option value="' . $v . (FreshRSS_Context::$conf->ttl_default == $v ? '" selected="selected' : '') . '">' . $t . '</option>'; - if (FreshRSS_Context::$conf->ttl_default == $v) { + echo '<option value="' . $v . (FreshRSS_Context::$user_conf->ttl_default == $v ? '" selected="selected' : '') . '">' . $t . '</option>'; + if (FreshRSS_Context::$user_conf->ttl_default == $v) { $found = true; } } if (!$found) { - echo '<option value="' . intval(FreshRSS_Context::$conf->ttl_default) . '" selected="selected">' . intval(FreshRSS_Context::$conf->ttl_default) . 's</option>'; + echo '<option value="' . intval(FreshRSS_Context::$user_conf->ttl_default) . '" selected="selected">' . intval(FreshRSS_Context::$user_conf->ttl_default) . 's</option>'; } ?></select> (<?php echo _t('gen.short.by_default'); ?>) </div> diff --git a/app/views/configure/display.phtml b/app/views/configure/display.phtml index a245c8f5e..36a075ea7 100644 --- a/app/views/configure/display.phtml +++ b/app/views/configure/display.phtml @@ -10,9 +10,9 @@ <label class="group-name" for="language"><?php echo _t('conf.display.language'); ?></label> <div class="group-controls"> <select name="language" id="language"> - <?php $languages = FreshRSS_Context::$conf->availableLanguages(); ?> + <?php $languages = Minz_Translate::availableLanguages(); ?> <?php foreach ($languages as $short => $lib) { ?> - <option value="<?php echo $short; ?>"<?php echo FreshRSS_Context::$conf->language === $short ? ' selected="selected"' : ''; ?>><?php echo $lib; ?></option> + <option value="<?php echo $short; ?>"<?php echo FreshRSS_Context::$user_conf->language === $short ? ' selected="selected"' : ''; ?>><?php echo $lib; ?></option> <?php } ?> </select> </div> @@ -24,7 +24,7 @@ <ul class="slides"> <?php $slides = count($this->themes); $i = 1; ?> <?php foreach($this->themes as $theme) { ?> - <input type="radio" name="theme" id="img-<?php echo $i ?>" <?php if (FreshRSS_Context::$conf->theme === $theme['id']) {echo "checked";}?> value="<?php echo $theme['id'] ?>"/> + <input type="radio" name="theme" id="img-<?php echo $i ?>" <?php if (FreshRSS_Context::$user_conf->theme === $theme['id']) {echo "checked";}?> value="<?php echo $theme['id'] ?>"/> <li class="slide-container"> <div class="slide"> <img src="<?php echo Minz_Url::display('/themes/' . $theme['id'] . '/thumbs/original.png')?>"/> @@ -49,7 +49,7 @@ </div> </div> - <?php $width = FreshRSS_Context::$conf->content_width; ?> + <?php $width = FreshRSS_Context::$user_conf->content_width; ?> <div class="form-group"> <label class="group-name" for="content_width"><?php echo _t('conf.display.width.content'); ?></label> <div class="group-controls"> @@ -87,20 +87,20 @@ <tbody> <tr> <th><?php echo _t('conf.display.icon.top_line'); ?></th> - <td><input type="checkbox" name="topline_read" value="1"<?php echo FreshRSS_Context::$conf->topline_read ? ' checked="checked"' : ''; ?> /></td> - <td><input type="checkbox" name="topline_favorite" value="1"<?php echo FreshRSS_Context::$conf->topline_favorite ? ' checked="checked"' : ''; ?> /></td> + <td><input type="checkbox" name="topline_read" value="1"<?php echo FreshRSS_Context::$user_conf->topline_read ? ' checked="checked"' : ''; ?> /></td> + <td><input type="checkbox" name="topline_favorite" value="1"<?php echo FreshRSS_Context::$user_conf->topline_favorite ? ' checked="checked"' : ''; ?> /></td> <td><input type="checkbox" disabled="disabled" /></td> <td><input type="checkbox" disabled="disabled" /></td> - <td><input type="checkbox" name="topline_date" value="1"<?php echo FreshRSS_Context::$conf->topline_date ? ' checked="checked"' : ''; ?> /></td> - <td><input type="checkbox" name="topline_link" value="1"<?php echo FreshRSS_Context::$conf->topline_link ? ' checked="checked"' : ''; ?> /></td> + <td><input type="checkbox" name="topline_date" value="1"<?php echo FreshRSS_Context::$user_conf->topline_date ? ' checked="checked"' : ''; ?> /></td> + <td><input type="checkbox" name="topline_link" value="1"<?php echo FreshRSS_Context::$user_conf->topline_link ? ' checked="checked"' : ''; ?> /></td> </tr><tr> <th><?php echo _t('conf.display.icon.bottom_line'); ?></th> - <td><input type="checkbox" name="bottomline_read" value="1"<?php echo FreshRSS_Context::$conf->bottomline_read ? ' checked="checked"' : ''; ?> /></td> - <td><input type="checkbox" name="bottomline_favorite" value="1"<?php echo FreshRSS_Context::$conf->bottomline_favorite ? ' checked="checked"' : ''; ?> /></td> - <td><input type="checkbox" name="bottomline_sharing" value="1"<?php echo FreshRSS_Context::$conf->bottomline_sharing ? ' checked="checked"' : ''; ?> /></td> - <td><input type="checkbox" name="bottomline_tags" value="1"<?php echo FreshRSS_Context::$conf->bottomline_tags ? ' checked="checked"' : ''; ?> /></td> - <td><input type="checkbox" name="bottomline_date" value="1"<?php echo FreshRSS_Context::$conf->bottomline_date ? ' checked="checked"' : ''; ?> /></td> - <td><input type="checkbox" name="bottomline_link" value="1"<?php echo FreshRSS_Context::$conf->bottomline_link ? ' checked="checked"' : ''; ?> /></td> + <td><input type="checkbox" name="bottomline_read" value="1"<?php echo FreshRSS_Context::$user_conf->bottomline_read ? ' checked="checked"' : ''; ?> /></td> + <td><input type="checkbox" name="bottomline_favorite" value="1"<?php echo FreshRSS_Context::$user_conf->bottomline_favorite ? ' checked="checked"' : ''; ?> /></td> + <td><input type="checkbox" name="bottomline_sharing" value="1"<?php echo FreshRSS_Context::$user_conf->bottomline_sharing ? ' checked="checked"' : ''; ?> /></td> + <td><input type="checkbox" name="bottomline_tags" value="1"<?php echo FreshRSS_Context::$user_conf->bottomline_tags ? ' checked="checked"' : ''; ?> /></td> + <td><input type="checkbox" name="bottomline_date" value="1"<?php echo FreshRSS_Context::$user_conf->bottomline_date ? ' checked="checked"' : ''; ?> /></td> + <td><input type="checkbox" name="bottomline_link" value="1"<?php echo FreshRSS_Context::$user_conf->bottomline_link ? ' checked="checked"' : ''; ?> /></td> </tr> </tbody> </table><br /> @@ -109,7 +109,7 @@ <div class="form-group"> <label class="group-name" for="posts_per_page"><?php echo _t('conf.display.notif_html5.timeout'); ?></label> <div class="group-controls"> - <input type="number" id="html5_notif_timeout" name="html5_notif_timeout" value="<?php echo FreshRSS_Context::$conf->html5_notif_timeout; ?>" /> <?php echo _t('conf.display.notif_html5.seconds'); ?> + <input type="number" id="html5_notif_timeout" name="html5_notif_timeout" value="<?php echo FreshRSS_Context::$user_conf->html5_notif_timeout; ?>" /> <?php echo _t('conf.display.notif_html5.seconds'); ?> </div> </div> diff --git a/app/views/configure/queries.phtml b/app/views/configure/queries.phtml index 1b3a08c91..5f449deb3 100644 --- a/app/views/configure/queries.phtml +++ b/app/views/configure/queries.phtml @@ -6,7 +6,7 @@ <form method="post" action="<?php echo _url('configure', 'queries'); ?>"> <legend><?php echo _t('conf.query'); ?></legend> - <?php foreach (FreshRSS_Context::$conf->queries as $key => $query) { ?> + <?php foreach (FreshRSS_Context::$user_conf->queries as $key => $query) { ?> <div class="form-group" id="query-group-<?php echo $key; ?>"> <label class="group-name" for="queries_<?php echo $key; ?>_name"> <?php echo _t('conf.query.number', $key + 1); ?> @@ -82,7 +82,7 @@ </div> <?php } ?> - <?php if (count(FreshRSS_Context::$conf->queries) > 0) { ?> + <?php if (count(FreshRSS_Context::$user_conf->queries) > 0) { ?> <div class="form-group form-actions"> <div class="group-controls"> <button type="submit" class="btn btn-important"><?php echo _t('gen.action.submit'); ?></button> diff --git a/app/views/configure/reading.phtml b/app/views/configure/reading.phtml index 440ad1df8..636671f14 100644 --- a/app/views/configure/reading.phtml +++ b/app/views/configure/reading.phtml @@ -9,7 +9,7 @@ <div class="form-group"> <label class="group-name" for="posts_per_page"><?php echo _t('conf.reading.articles_per_page'); ?></label> <div class="group-controls"> - <input type="number" id="posts_per_page" name="posts_per_page" value="<?php echo FreshRSS_Context::$conf->posts_per_page; ?>" min="5" max="50" /> + <input type="number" id="posts_per_page" name="posts_per_page" value="<?php echo FreshRSS_Context::$user_conf->posts_per_page; ?>" min="5" max="50" /> <?php echo _i('help'); ?> <?php echo _t('conf.reading.number_divided_when_reader'); ?> </div> </div> @@ -18,8 +18,8 @@ <label class="group-name" for="sort_order"><?php echo _t('conf.reading.sort'); ?></label> <div class="group-controls"> <select name="sort_order" id="sort_order"> - <option value="DESC"<?php echo FreshRSS_Context::$conf->sort_order === 'DESC' ? ' selected="selected"' : ''; ?>><?php echo _t('conf.reading.sort.newer_first'); ?></option> - <option value="ASC"<?php echo FreshRSS_Context::$conf->sort_order === 'ASC' ? ' selected="selected"' : ''; ?>><?php echo _t('conf.reading.sort.older_first'); ?></option> + <option value="DESC"<?php echo FreshRSS_Context::$user_conf->sort_order === 'DESC' ? ' selected="selected"' : ''; ?>><?php echo _t('conf.reading.sort.newer_first'); ?></option> + <option value="ASC"<?php echo FreshRSS_Context::$user_conf->sort_order === 'ASC' ? ' selected="selected"' : ''; ?>><?php echo _t('conf.reading.sort.older_first'); ?></option> </select> </div> </div> @@ -28,9 +28,9 @@ <label class="group-name" for="view_mode"><?php echo _t('conf.reading.view.default'); ?></label> <div class="group-controls"> <select name="view_mode" id="view_mode"> - <option value="normal"<?php echo FreshRSS_Context::$conf->view_mode === 'normal' ? ' selected="selected"' : ''; ?>><?php echo _t('conf.reading.view.normal'); ?></option> - <option value="reader"<?php echo FreshRSS_Context::$conf->view_mode === 'reader' ? ' selected="selected"' : ''; ?>><?php echo _t('conf.reading.view.reader'); ?></option> - <option value="global"<?php echo FreshRSS_Context::$conf->view_mode === 'global' ? ' selected="selected"' : ''; ?>><?php echo _t('conf.reading.view.global'); ?></option> + <option value="normal"<?php echo FreshRSS_Context::$user_conf->view_mode === 'normal' ? ' selected="selected"' : ''; ?>><?php echo _t('conf.reading.view.normal'); ?></option> + <option value="reader"<?php echo FreshRSS_Context::$user_conf->view_mode === 'reader' ? ' selected="selected"' : ''; ?>><?php echo _t('conf.reading.view.reader'); ?></option> + <option value="global"<?php echo FreshRSS_Context::$user_conf->view_mode === 'global' ? ' selected="selected"' : ''; ?>><?php echo _t('conf.reading.view.global'); ?></option> </select> </div> </div> @@ -39,9 +39,9 @@ <label class="group-name" for="view_mode"><?php echo _t('conf.reading.show'); ?></label> <div class="group-controls"> <select name="default_view" id="default_view"> - <option value="adaptive"<?php echo FreshRSS_Context::$conf->default_view === 'adaptive' ? ' selected="selected"' : ''; ?>><?php echo _t('conf.reading.show.adaptive'); ?></option> - <option value="all"<?php echo FreshRSS_Context::$conf->default_view === 'all' ? ' selected="selected"' : ''; ?>><?php echo _t('conf.reading.show.all_articles'); ?></option> - <option value="unread"<?php echo FreshRSS_Context::$conf->default_view === 'unread' ? ' selected="selected"' : ''; ?>><?php echo _t('conf.reading.show.unread'); ?></option> + <option value="adaptive"<?php echo FreshRSS_Context::$user_conf->default_view === 'adaptive' ? ' selected="selected"' : ''; ?>><?php echo _t('conf.reading.show.adaptive'); ?></option> + <option value="all"<?php echo FreshRSS_Context::$user_conf->default_view === 'all' ? ' selected="selected"' : ''; ?>><?php echo _t('conf.reading.show.all_articles'); ?></option> + <option value="unread"<?php echo FreshRSS_Context::$user_conf->default_view === 'unread' ? ' selected="selected"' : ''; ?>><?php echo _t('conf.reading.show.unread'); ?></option> </select> </div> </div> @@ -49,7 +49,7 @@ <div class="form-group"> <div class="group-controls"> <label class="checkbox" for="hide_read_feeds"> - <input type="checkbox" name="hide_read_feeds" id="hide_read_feeds" value="1"<?php echo FreshRSS_Context::$conf->hide_read_feeds ? ' checked="checked"' : ''; ?> /> + <input type="checkbox" name="hide_read_feeds" id="hide_read_feeds" value="1"<?php echo FreshRSS_Context::$user_conf->hide_read_feeds ? ' checked="checked"' : ''; ?> /> <?php echo _t('conf.reading.hide_read_feeds'); ?> </label> </div> @@ -58,7 +58,7 @@ <div class="form-group"> <div class="group-controls"> <label class="checkbox" for="display_posts"> - <input type="checkbox" name="display_posts" id="display_posts" value="1"<?php echo FreshRSS_Context::$conf->display_posts ? ' checked="checked"' : ''; ?> /> + <input type="checkbox" name="display_posts" id="display_posts" value="1"<?php echo FreshRSS_Context::$user_conf->display_posts ? ' checked="checked"' : ''; ?> /> <?php echo _t('conf.reading.display_articles_unfolded'); ?> <noscript> — <strong><?php echo _t('gen.js.should_be_activated'); ?></strong></noscript> </label> @@ -68,7 +68,7 @@ <div class="form-group"> <div class="group-controls"> <label class="checkbox" for="display_categories"> - <input type="checkbox" name="display_categories" id="display_categories" value="1"<?php echo FreshRSS_Context::$conf->display_categories ? ' checked="checked"' : ''; ?> /> + <input type="checkbox" name="display_categories" id="display_categories" value="1"<?php echo FreshRSS_Context::$user_conf->display_categories ? ' checked="checked"' : ''; ?> /> <?php echo _t('conf.reading.display_categories_unfolded'); ?> <noscript> — <strong><?php echo _t('gen.js.should_be_activated'); ?></strong></noscript> </label> @@ -78,7 +78,7 @@ <div class="form-group"> <div class="group-controls"> <label class="checkbox" for="sticky_post"> - <input type="checkbox" name="sticky_post" id="sticky_post" value="1"<?php echo FreshRSS_Context::$conf->sticky_post ? ' checked="checked"' : ''; ?> /> + <input type="checkbox" name="sticky_post" id="sticky_post" value="1"<?php echo FreshRSS_Context::$user_conf->sticky_post ? ' checked="checked"' : ''; ?> /> <?php echo _t('conf.reading.sticky_post'); ?> <noscript> — <strong><?php echo _t('gen.js.should_be_activated'); ?></strong></noscript> </label> @@ -88,7 +88,7 @@ <div class="form-group"> <div class="group-controls"> <label class="checkbox" for="auto_load_more"> - <input type="checkbox" name="auto_load_more" id="auto_load_more" value="1"<?php echo FreshRSS_Context::$conf->auto_load_more ? ' checked="checked"' : ''; ?> /> + <input type="checkbox" name="auto_load_more" id="auto_load_more" value="1"<?php echo FreshRSS_Context::$user_conf->auto_load_more ? ' checked="checked"' : ''; ?> /> <?php echo _t('conf.reading.auto_load_more'); ?> <noscript> — <strong><?php echo _t('gen.js.should_be_activated'); ?></strong></noscript> </label> @@ -98,7 +98,7 @@ <div class="form-group"> <div class="group-controls"> <label class="checkbox" for="lazyload"> - <input type="checkbox" name="lazyload" id="lazyload" value="1"<?php echo FreshRSS_Context::$conf->lazyload ? ' checked="checked"' : ''; ?> /> + <input type="checkbox" name="lazyload" id="lazyload" value="1"<?php echo FreshRSS_Context::$user_conf->lazyload ? ' checked="checked"' : ''; ?> /> <?php echo _t('conf.reading.img_with_lazyload'); ?> <noscript> — <strong><?php echo _t('gen.js.should_be_activated'); ?></strong></noscript> </label> @@ -108,7 +108,7 @@ <div class="form-group"> <div class="group-controls"> <label class="checkbox" for="reading_confirm"> - <input type="checkbox" name="reading_confirm" id="reading_confirm" value="1"<?php echo FreshRSS_Context::$conf->reading_confirm ? ' checked="checked"' : ''; ?> /> + <input type="checkbox" name="reading_confirm" id="reading_confirm" value="1"<?php echo FreshRSS_Context::$user_conf->reading_confirm ? ' checked="checked"' : ''; ?> /> <?php echo _t('conf.reading.confirm_enabled'); ?> <noscript> — <strong><?php echo _t('gen.js.should_be_activated'); ?></strong></noscript> </label> @@ -118,7 +118,7 @@ <div class="form-group"> <div class="group-controls"> <label class="checkbox" for="auto_remove_article"> - <input type="checkbox" name="auto_remove_article" id="auto_remove_article" value="1"<?php echo FreshRSS_Context::$conf->auto_remove_article ? ' checked="checked"' : ''; ?> /> + <input type="checkbox" name="auto_remove_article" id="auto_remove_article" value="1"<?php echo FreshRSS_Context::$user_conf->auto_remove_article ? ' checked="checked"' : ''; ?> /> <?php echo _t('conf.reading.auto_remove_article'); ?> <noscript> — <strong><?php echo _t('gen.js.should_be_activated'); ?></strong></noscript> </label> @@ -129,19 +129,19 @@ <label class="group-name"><?php echo _t('conf.reading.read.when'); ?></label> <div class="group-controls"> <label class="checkbox" for="check_open_article"> - <input type="checkbox" name="mark_open_article" id="check_open_article" value="1"<?php echo FreshRSS_Context::$conf->mark_when['article'] ? ' checked="checked"' : ''; ?> /> + <input type="checkbox" name="mark_open_article" id="check_open_article" value="1"<?php echo FreshRSS_Context::$user_conf->mark_when['article'] ? ' checked="checked"' : ''; ?> /> <?php echo _t('conf.reading.read.article_viewed'); ?> </label> <label class="checkbox" for="check_open_site"> - <input type="checkbox" name="mark_open_site" id="check_open_site" value="1"<?php echo FreshRSS_Context::$conf->mark_when['site'] ? ' checked="checked"' : ''; ?> /> + <input type="checkbox" name="mark_open_site" id="check_open_site" value="1"<?php echo FreshRSS_Context::$user_conf->mark_when['site'] ? ' checked="checked"' : ''; ?> /> <?php echo _t('conf.reading.read.article_open_on_website'); ?> </label> <label class="checkbox" for="check_scroll"> - <input type="checkbox" name="mark_scroll" id="check_scroll" value="1"<?php echo FreshRSS_Context::$conf->mark_when['scroll'] ? ' checked="checked"' : ''; ?> /> + <input type="checkbox" name="mark_scroll" id="check_scroll" value="1"<?php echo FreshRSS_Context::$user_conf->mark_when['scroll'] ? ' checked="checked"' : ''; ?> /> <?php echo _t('conf.reading.read.scroll'); ?> </label> <label class="checkbox" for="check_reception"> - <input type="checkbox" name="mark_upon_reception" id="check_reception" value="1"<?php echo FreshRSS_Context::$conf->mark_when['reception'] ? ' checked="checked"' : ''; ?> /> + <input type="checkbox" name="mark_upon_reception" id="check_reception" value="1"<?php echo FreshRSS_Context::$user_conf->mark_when['reception'] ? ' checked="checked"' : ''; ?> /> <?php echo _t('conf.reading.read.upon_reception'); ?> </label> </div> @@ -151,7 +151,7 @@ <label class="group-name"><?php echo _t('conf.reading.after_onread'); ?></label> <div class="group-controls"> <label class="checkbox" for="onread_jump_next"> - <input type="checkbox" name="onread_jump_next" id="onread_jump_next" value="1"<?php echo FreshRSS_Context::$conf->onread_jump_next ? ' checked="checked"' : ''; ?> /> + <input type="checkbox" name="onread_jump_next" id="onread_jump_next" value="1"<?php echo FreshRSS_Context::$user_conf->onread_jump_next ? ' checked="checked"' : ''; ?> /> <?php echo _t('conf.reading.jump_next'); ?> </label> </div> diff --git a/app/views/configure/sharing.phtml b/app/views/configure/sharing.phtml index ffe3c039b..da7557480 100644 --- a/app/views/configure/sharing.phtml +++ b/app/views/configure/sharing.phtml @@ -15,22 +15,25 @@ <a target="_blank" class="btn" title="<?php echo _t('conf.sharing.more_information'); ?>" href="##help##"><?php echo _i('help'); ?></a> </div></div>'> <legend><?php echo _t('conf.sharing'); ?></legend> - <?php foreach (FreshRSS_Context::$conf->sharing as $key => $sharing) { ?> - <?php $share = FreshRSS_Context::$conf->shares[$sharing['type']]; ?> - <div class="form-group" id="group-share-<?php echo $key; ?>"> + <?php + foreach (FreshRSS_Context::$user_conf->sharing as $key => $share_options) { + $share = FreshRSS_Share::get($share_options['type']); + $share->update($share_options); + ?> + <div class="form-group group-share" id="group-share-<?php echo $key; ?>"> <label class="group-name"> - <?php echo _t('conf.sharing.' . $sharing['type']); ?> + <?php echo $share->name(true); ?> </label> <div class="group-controls"> - <input type='hidden' id='share_<?php echo $key;?>_type' name="share[<?php echo $key;?>][type]" value='<?php echo $sharing['type']?>' /> - <?php if ($share['form'] === 'advanced') { ?> + <input type='hidden' id='share_<?php echo $key; ?>_type' name="share[<?php echo $key; ?>][type]" value='<?php echo $share->type(); ?>' /> + <?php if ($share->formType() === 'advanced') { ?> <div class="stick"> - <input type="text" id="share_<?php echo $key;?>_name" name="share[<?php echo $key;?>][name]" class="extend" value="<?php echo $sharing['name']?>" placeholder="<?php echo _t('conf.sharing.share_name'); ?>" size="64" /> - <input type="url" id="share_<?php echo $key;?>_url" name="share[<?php echo $key;?>][url]" class="extend" value="<?php echo $sharing['url']?>" placeholder="<?php echo _t('conf.sharing.share_url'); ?>" size="64" /> + <input type="text" id="share_<?php echo $key; ?>_name" name="share[<?php echo $key; ?>][name]" class="extend" value="<?php echo $share->name(); ?>" placeholder="<?php echo _t('conf.sharing.share_name'); ?>" size="64" /> + <input type="url" id="share_<?php echo $key; ?>_url" name="share[<?php echo $key; ?>][url]" class="extend" value="<?php echo $share->baseUrl(); ?>" placeholder="<?php echo _t('conf.sharing.share_url'); ?>" size="64" /> <a href='#' class='remove btn btn-attention' data-remove="group-share-<?php echo $key; ?>"><?php echo _i('close'); ?></a> </div> - <a target="_blank" class="btn" title="<?php echo _t('conf.sharing.more_information'); ?>" href="<?php echo $share['help']?>"><?php echo _i('help'); ?></a> + <a target="_blank" class="btn" title="<?php echo _t('conf.sharing.more_information'); ?>" href="<?php echo $share->help(); ?>"><?php echo _i('help'); ?></a> <?php } else { ?> <a href='#' class='remove btn btn-attention' data-remove="group-share-<?php echo $key; ?>"><?php echo _i('close'); ?></a> <?php } ?> @@ -41,8 +44,10 @@ <div class="form-group"> <div class="group-controls"> <select> - <?php foreach(FreshRSS_Context::$conf->shares as $key => $params) { ?> - <option value='<?php echo $key?>' data-form='<?php echo $params['form']?>' data-help='<?php if (!empty($params['help'])) {echo $params['help'];}?>'><?php echo _t('conf.sharing.' . $key) ?></option> + <?php foreach (FreshRSS_Share::enum() as $share) { ?> + <option value='<?php echo $share->type(); ?>' data-form='<?php echo $share->formType(); ?>' data-help='<?php echo $share->help(); ?>'> + <?php echo $share->name(true); ?> + </option> <?php } ?> </select> <a href='#' class='share add btn'><?php echo _i('add'); ?></a> diff --git a/app/views/configure/shortcut.phtml b/app/views/configure/shortcut.phtml index dca8b6ef8..fdbeed3ea 100644 --- a/app/views/configure/shortcut.phtml +++ b/app/views/configure/shortcut.phtml @@ -9,7 +9,7 @@ <?php } ?> </datalist> - <?php $s = FreshRSS_Context::$conf->shortcuts; ?> + <?php $s = FreshRSS_Context::$user_conf->shortcuts; ?> <form method="post" action="<?php echo _url('configure', 'shortcut'); ?>"> <legend><?php echo _t('conf.shortcut'); ?></legend> diff --git a/app/views/helpers/export/opml.phtml b/app/views/helpers/export/opml.phtml index 8622d9144..236cca303 100644 --- a/app/views/helpers/export/opml.phtml +++ b/app/views/helpers/export/opml.phtml @@ -2,7 +2,7 @@ $opml_array = array( 'head' => array( - 'title' => Minz_Configuration::title(), + 'title' => FreshRSS_Context::$system_conf->title, 'dateCreated' => date('D, d M Y H:i:s') ), 'body' => array() diff --git a/app/views/helpers/javascript_vars.phtml b/app/views/helpers/javascript_vars.phtml index 6577e0109..fec3a6f7c 100644 --- a/app/views/helpers/javascript_vars.phtml +++ b/app/views/helpers/javascript_vars.phtml @@ -1,12 +1,12 @@ "use strict"; <?php -$mark = FreshRSS_Context::$conf->mark_when; +$mark = FreshRSS_Context::$user_conf->mark_when; $mail = Minz_Session::param('mail', false); $auto_actualize = Minz_Session::param('actualize_feeds', false); -$hide_posts = (FreshRSS_Context::$conf->display_posts || +$hide_posts = (FreshRSS_Context::$user_conf->display_posts || Minz_Request::param('output') === 'reader'); -$s = FreshRSS_Context::$conf->shortcuts; +$s = FreshRSS_Context::$user_conf->shortcuts; $url_login = Minz_Url::display(array( 'c' => 'auth', @@ -20,16 +20,16 @@ $url_logout = Minz_Url::display(array( 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), '",', + 'display_order:"', Minz_Request::param('order', FreshRSS_Context::$user_conf->sort_order), '",', 'auto_mark_article:', $mark['article'] ? 'true' : 'false', ',', 'auto_mark_site:', $mark['site'] ? 'true' : 'false', ',', 'auto_mark_scroll:', $mark['scroll'] ? 'true' : 'false', ',', - 'auto_load_more:', FreshRSS_Context::$conf->auto_load_more ? 'true' : 'false', ',', + 'auto_load_more:', FreshRSS_Context::$user_conf->auto_load_more ? 'true' : 'false', ',', 'auto_actualize_feeds:', $auto_actualize ? 'true' : 'false', ',', - 'does_lazyload:', FreshRSS_Context::$conf->lazyload ? 'true' : 'false', ',', + 'does_lazyload:', FreshRSS_Context::$user_conf->lazyload ? 'true' : 'false', ',', 'sticky_post:', FreshRSS_Context::isStickyPostEnabled() ? 'true' : 'false', ',', - 'html5_notif_timeout:', FreshRSS_Context::$conf->html5_notif_timeout, ',', - 'auth_type:"', Minz_Configuration::authType(), '",', + '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::param('output', 'normal'), '"', "},\n"; diff --git a/app/views/helpers/pagination.phtml b/app/views/helpers/pagination.phtml index 8b40e4336..b20201c4b 100755 --- a/app/views/helpers/pagination.phtml +++ b/app/views/helpers/pagination.phtml @@ -24,7 +24,7 @@ </a> <?php } elseif ($url_mark_read) { ?> <button id="bigMarkAsRead" - class="as-link <?php echo FreshRSS_Context::$conf->reading_confirm ? 'confirm' : ''; ?>" + class="as-link <?php echo FreshRSS_Context::$user_conf->reading_confirm ? 'confirm' : ''; ?>" form="mark-read-pagination" formaction="<?php echo Minz_Url::display($url_mark_read); ?>" type="submit"> diff --git a/app/views/index/global.phtml b/app/views/index/global.phtml index ae7f5ffbc..cf95bd0f5 100644 --- a/app/views/index/global.phtml +++ b/app/views/index/global.phtml @@ -2,7 +2,7 @@ $this->partial('nav_menu'); $class = ''; - if (FreshRSS_Context::$conf->hide_read_feeds && + if (FreshRSS_Context::$user_conf->hide_read_feeds && FreshRSS_Context::isStateEnabled(FreshRSS_Entry::STATE_NOT_READ) && !FreshRSS_Context::isStateEnabled(FreshRSS_Entry::STATE_READ)) { $class = ' state_unread'; @@ -50,5 +50,5 @@ <div id="overlay"> <a class="close" href="#"><?php echo _i('close'); ?></a> </div> -<div id="panel"<?php echo FreshRSS_Context::$conf->display_posts ? '' : ' class="hide_posts"'; ?>> +<div id="panel"<?php echo FreshRSS_Context::$user_conf->display_posts ? '' : ' class="hide_posts"'; ?>> </div> diff --git a/app/views/index/index.phtml b/app/views/index/index.phtml index 8b93461dd..8b94c7f7d 100644 --- a/app/views/index/index.phtml +++ b/app/views/index/index.phtml @@ -2,7 +2,7 @@ $output = Minz_Request::param('output', 'normal'); -if (FreshRSS_Auth::hasAccess() || Minz_Configuration::allowAnonymous()) { +if (FreshRSS_Auth::hasAccess() || FreshRSS_Context::$system_conf->allow_anonymous) { if ($output === 'normal') { $this->renderHelper('view/normal_view'); } elseif ($output === 'reader') { diff --git a/app/views/index/normal.phtml b/app/views/index/normal.phtml index b8a78cc3d..8c6ddd1ee 100644 --- a/app/views/index/normal.phtml +++ b/app/views/index/normal.phtml @@ -8,24 +8,24 @@ if (!empty($this->entries)) { $display_yesterday = true; $display_others = true; if (FreshRSS_Auth::hasAccess()) { - $sharing = FreshRSS_Context::$conf->sharing; + $sharing = FreshRSS_Context::$user_conf->sharing; } else { $sharing = array(); } - $hidePosts = !FreshRSS_Context::$conf->display_posts; - $lazyload = FreshRSS_Context::$conf->lazyload; - $topline_read = FreshRSS_Context::$conf->topline_read; - $topline_favorite = FreshRSS_Context::$conf->topline_favorite; - $topline_date = FreshRSS_Context::$conf->topline_date; - $topline_link = FreshRSS_Context::$conf->topline_link; - $bottomline_read = FreshRSS_Context::$conf->bottomline_read; - $bottomline_favorite = FreshRSS_Context::$conf->bottomline_favorite; - $bottomline_sharing = FreshRSS_Context::$conf->bottomline_sharing && (count($sharing)); - $bottomline_tags = FreshRSS_Context::$conf->bottomline_tags; - $bottomline_date = FreshRSS_Context::$conf->bottomline_date; - $bottomline_link = FreshRSS_Context::$conf->bottomline_link; + $hidePosts = !FreshRSS_Context::$user_conf->display_posts; + $lazyload = FreshRSS_Context::$user_conf->lazyload; + $topline_read = FreshRSS_Context::$user_conf->topline_read; + $topline_favorite = FreshRSS_Context::$user_conf->topline_favorite; + $topline_date = FreshRSS_Context::$user_conf->topline_date; + $topline_link = FreshRSS_Context::$user_conf->topline_link; + $bottomline_read = FreshRSS_Context::$user_conf->bottomline_read; + $bottomline_favorite = FreshRSS_Context::$user_conf->bottomline_favorite; + $bottomline_sharing = FreshRSS_Context::$user_conf->bottomline_sharing && (count($sharing)); + $bottomline_tags = FreshRSS_Context::$user_conf->bottomline_tags; + $bottomline_date = FreshRSS_Context::$user_conf->bottomline_date; + $bottomline_link = FreshRSS_Context::$user_conf->bottomline_link; - $content_width = FreshRSS_Context::$conf->content_width; + $content_width = FreshRSS_Context::$user_conf->content_width; $today = @strtotime('today'); ?> @@ -129,8 +129,6 @@ if (!empty($this->entries)) { } ?> <li class="item"><?php if ($bottomline_sharing) { - $link = urlencode($item->link()); - $title = urlencode($item->title() . ' · ' . $feed->name()); ?><div class="dropdown"> <div id="dropdown-share-<?php echo $item->id();?>" class="dropdown-target"></div> <a class="dropdown-toggle" href="#dropdown-share-<?php echo $item->id();?>"> @@ -139,19 +137,19 @@ if (!empty($this->entries)) { </a> <ul class="dropdown-menu"> - <li class="dropdown-close"><a href="#close">❌</a></li> - <?php - foreach ($sharing as $share) { - $type_share = FreshRSS_Context::$conf->shares[$share['type']]; - $has_specific_title = ($type_share['form'] === 'advanced'); - ?> - <li class="item share"> - <a target="_blank" href="<?php echo FreshRSS_Share::generateUrl(FreshRSS_Context::$conf->shares, $share, $item->link(), $item->title() . ' . ' . $feed->name())?>"> - <?php echo $has_specific_title ? $share['name'] : _t('index.share.' . $share['name']); ?> - </a> - </li> - <?php } ?> - </ul> + <li class="dropdown-close"><a href="#close">❌</a></li><?php + $link = $item->link(); + $title = $item->title() . ' · ' . $feed->name(); + foreach (FreshRSS_Context::$user_conf->sharing as $share_options) { + $share = FreshRSS_Share::get($share_options['type']); + $share_options['link'] = $link; + $share_options['title'] = $title; + $share->update($share_options); + ?><li class="item share"> + <a target="_blank" href="<?php echo $share->url(); ?>"><?php echo $share->name(); ?></a> + </li><?php + } + ?></ul> </div> <?php } ?> </li><?php diff --git a/app/views/index/reader.phtml b/app/views/index/reader.phtml index 1eab86dd2..017297710 100644 --- a/app/views/index/reader.phtml +++ b/app/views/index/reader.phtml @@ -2,8 +2,8 @@ $this->partial('nav_menu'); if (!empty($this->entries)) { - $lazyload = FreshRSS_Context::$conf->lazyload; - $content_width = FreshRSS_Context::$conf->content_width; + $lazyload = FreshRSS_Context::$user_conf->lazyload; + $content_width = FreshRSS_Context::$user_conf->content_width; ?> <div id="stream" class="reader"> diff --git a/app/views/user/manage.phtml b/app/views/user/manage.phtml index b175d48df..11c42a857 100644 --- a/app/views/user/manage.phtml +++ b/app/views/user/manage.phtml @@ -10,9 +10,9 @@ <label class="group-name" for="new_user_language"><?php echo _t('admin.user.language'); ?></label> <div class="group-controls"> <select name="new_user_language" id="new_user_language"> - <?php $languages = FreshRSS_Context::$conf->availableLanguages(); ?> + <?php $languages = Minz_Translate::availableLanguages(); ?> <?php foreach ($languages as $short => $lib) { ?> - <option value="<?php echo $short; ?>"<?php echo FreshRSS_Context::$conf->language === $short ? ' selected="selected"' : ''; ?>><?php echo $lib; ?></option> + <option value="<?php echo $short; ?>"<?php echo FreshRSS_Context::$user_conf->language === $short ? ' selected="selected"' : ''; ?>><?php echo $lib; ?></option> <?php } ?> </select> </div> @@ -38,7 +38,7 @@ <div class="form-group"> <label class="group-name" for="new_user_email"><?php echo _t('admin.user.email_persona'); ?></label> - <?php $mail = FreshRSS_Context::$conf->mail_login; ?> + <?php $mail = FreshRSS_Context::$user_conf->mail_login; ?> <div class="group-controls"> <input type="email" id="new_user_email" name="new_user_email" class="extend" autocomplete="off" placeholder="alice@example.net" /> </div> diff --git a/app/views/user/profile.phtml b/app/views/user/profile.phtml index fc9b24674..d85499ad8 100644 --- a/app/views/user/profile.phtml +++ b/app/views/user/profile.phtml @@ -28,7 +28,7 @@ </div> </div> - <?php if (Minz_Configuration::apiEnabled()) { ?> + <?php if (FreshRSS_Context::$system_conf->api_enabled) { ?> <div class="form-group"> <label class="group-name" for="apiPasswordPlain"><?php echo _t('conf.profile.password_api'); ?></label> <div class="group-controls"> @@ -42,7 +42,7 @@ <div class="form-group"> <label class="group-name" for="mail_login"><?php echo _t('conf.profile.email_persona'); ?></label> - <?php $mail = FreshRSS_Context::$conf->mail_login; ?> + <?php $mail = FreshRSS_Context::$user_conf->mail_login; ?> <div class="group-controls"> <input type="email" id="mail_login" name="mail_login" class="extend" autocomplete="off" value="<?php echo $mail; ?>" <?php echo FreshRSS_Auth::hasAccess('admin') ? '' : 'disabled="disabled"'; ?> placeholder="alice@example.net" /> <noscript><b><?php echo _t('gen.js.should_be_activated'); ?></b></noscript> diff --git a/data/config.default.php b/data/config.default.php new file mode 100644 index 000000000..193ac5726 --- /dev/null +++ b/data/config.default.php @@ -0,0 +1,30 @@ +<?php + +return array( + 'environment' => 'production', + 'salt' => '', + 'base_url' => '', + 'language' => 'en', + 'title' => 'FreshRSS', + 'default_user' => '_', + 'allow_anonymous' => false, + 'allow_anonymous_refresh' => false, + 'auth_type' => 'none', + 'api_enabled' => false, + 'unsafe_autologin_enabled' => false, + 'limits' => array( + 'cache_duration' => 800, + 'timeout' => 10, + 'max_inactivity' => PHP_INT_MAX, + 'max_feeds' => 16384, + 'max_categories' => 16384, + ), + 'db' => array( + 'type' => 'sqlite', + 'host' => '', + 'user' => '', + 'password' => '', + 'base' => '', + 'prefix' => '', + ), +); diff --git a/data/users/_/.gitkeep b/data/users/_/.gitkeep deleted file mode 100644 index e69de29bb..000000000 --- a/data/users/_/.gitkeep +++ /dev/null diff --git a/data/users/_/config.default.php b/data/users/_/config.default.php new file mode 100644 index 000000000..56d54b293 --- /dev/null +++ b/data/users/_/config.default.php @@ -0,0 +1,66 @@ +<?php + +return array ( + 'language' => 'en', + 'old_entries' => 3, + 'keep_history_default' => 0, + 'ttl_default' => 3600, + 'mail_login' => '', + 'token' => '', + 'passwordHash' => '', + 'apiPasswordHash' => '', + 'posts_per_page' => 20, + 'view_mode' => 'normal', + 'default_view' => 'adaptive', + 'default_state' => FreshRSS_Entry::STATE_NOT_READ, + 'auto_load_more' => true, + 'display_posts' => false, + 'display_categories' => false, + 'hide_read_feeds' => true, + 'onread_jump_next' => true, + 'lazyload' => true, + 'sticky_post' => true, + 'reading_confirm' => false, + 'auto_remove_article' => false, + 'sort_order' => 'DESC', + 'anon_access' => false, + 'mark_when' => array ( + 'article' => true, + 'site' => true, + 'scroll' => false, + 'reception' => false, + ), + 'theme' => 'Origine', + 'content_width' => 'thin', + 'shortcuts' => array ( + 'mark_read' => 'r', + 'mark_favorite' => 'f', + 'go_website' => 'space', + 'next_entry' => 'j', + 'prev_entry' => 'k', + 'first_entry' => 'home', + 'last_entry' => 'end', + 'collapse_entry' => 'c', + 'load_more' => 'm', + 'auto_share' => 's', + 'focus_search' => 'a', + 'user_filter' => 'u', + 'help' => 'f1', + 'close_dropdown' => 'escape', + ), + 'topline_read' => true, + 'topline_favorite' => true, + 'topline_date' => true, + 'topline_link' => true, + 'bottomline_read' => true, + 'bottomline_favorite' => true, + 'bottomline_sharing' => true, + 'bottomline_tags' => true, + 'bottomline_date' => true, + 'bottomline_link' => true, + 'sharing' => array ( + ), + 'queries' => array ( + ), + 'html5_notif_timeout' => 0, +); diff --git a/lib/Minz/BadConfigurationException.php b/lib/Minz/BadConfigurationException.php deleted file mode 100644 index a7b77d687..000000000 --- a/lib/Minz/BadConfigurationException.php +++ /dev/null @@ -1,9 +0,0 @@ -<?php -class Minz_BadConfigurationException extends Minz_Exception { - public function __construct ($part_missing, $code = self::ERROR) { - $message = '`' . $part_missing - . '` in the configuration file is missing or is misconfigured'; - - parent::__construct ($message, $code); - } -} diff --git a/lib/Minz/Configuration.php b/lib/Minz/Configuration.php index 6cbc9fc0b..6044fc269 100644 --- a/lib/Minz/Configuration.php +++ b/lib/Minz/Configuration.php @@ -1,419 +1,215 @@ <?php -/** - * MINZ - Copyright 2011 Marien Fressinaud - * Sous licence AGPL3 <http://www.gnu.org/licenses/> -*/ /** - * La classe Configuration permet de gérer la configuration de l'application + * Manage configuration for the application. */ class Minz_Configuration { - const CONF_PATH_NAME = '/config.php'; + /** + * The list of configurations. + */ + private static $config_list = array(); /** - * VERSION est la version actuelle de MINZ + * Add a new configuration to the list of configuration. + * + * @param $namespace the name of the current configuration + * @param $config_filename the filename of the configuration + * @param $default_filename a filename containing default values for the configuration + * @param $configuration_setter an optional helper to set values in configuration + * @throws Minz_ConfigurationNamespaceException if the namespace already exists. */ - const VERSION = '1.3.1.freshrss'; // version spéciale FreshRSS + public static function register($namespace, $config_filename, $default_filename = null, + $configuration_setter = null) { + if (isset(self::$config_list[$namespace])) { + throw new Minz_ConfigurationNamespaceException( + $namespace . ' namespace already exists' + ); + } + + self::$config_list[$namespace] = new Minz_Configuration( + $namespace, $config_filename, $default_filename, $configuration_setter + ); + } /** - * valeurs possibles pour l'"environment" - * SILENT rend l'application muette (pas de log) - * PRODUCTION est recommandée pour une appli en production - * (log les erreurs critiques) - * DEVELOPMENT log toutes les erreurs + * Parse a file and return its data. + * + * If the file does not contain a valid PHP code returning an array, an + * empty array is returned anyway. + * + * @param $filename the name of the file to parse. + * @return an array of values + * @throws Minz_FileNotExistException if the file does not exist. */ - const SILENT = 0; - const PRODUCTION = 1; - const DEVELOPMENT = 2; + public static function load($filename) { + if (!file_exists($filename)) { + throw new Minz_FileNotExistException($filename); + } + + $data = @include($filename); + if (is_array($data)) { + return $data; + } else { + return array(); + } + } /** - * définition des variables de configuration - * $salt une chaîne de caractères aléatoires (obligatoire) - * $environment gère le niveau d'affichage pour log et erreurs - * $base_url le chemin de base pour accéder à l'application - * $title le nom de l'application - * $language la langue par défaut de l'application - * $db paramètres pour la base de données (tableau) - * - host le serveur de la base - * - user nom d'utilisateur - * - password mot de passe de l'utilisateur - * - base le nom de la base de données + * Return the configuration related to a given namespace. + * + * @param $namespace the name of the configuration to get. + * @return a Minz_Configuration object + * @throws Minz_ConfigurationNamespaceException if the namespace does not exist. */ - private static $salt = ''; - private static $environment = Minz_Configuration::PRODUCTION; - private static $base_url = ''; - private static $title = ''; - private static $language = 'en'; - private static $default_user = ''; - private static $allow_anonymous = false; - private static $allow_anonymous_refresh = false; - private static $auth_type = 'none'; - private static $api_enabled = false; - private static $unsafe_autologin_enabled = false; + public static function get($namespace) { + if (!isset(self::$config_list[$namespace])) { + throw new Minz_ConfigurationNamespaceException( + $namespace . ' namespace does not exist' + ); + } - private static $db = array ( - 'type' => 'mysql', - 'host' => '', - 'user' => '', - 'password' => '', - 'base' => '', - 'prefix' => '', - ); + return self::$config_list[$namespace]; + } - const MAX_SMALL_INT = 16384; - 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, - ); + /** + * The namespace of the current configuration. + */ + private $namespace = ''; - /* - * Getteurs + /** + * The filename for the current configuration. */ - public static function salt () { - return self::$salt; - } - public static function environment ($str = false) { - $env = self::$environment; + private $config_filename = ''; - if ($str) { - switch (self::$environment) { - case self::SILENT: - $env = 'silent'; - break; - case self::DEVELOPMENT: - $env = 'development'; - break; - case self::PRODUCTION: - default: - $env = 'production'; - } - } + /** + * The filename for the current default values, null by default. + */ + private $default_filename = null; - return $env; - } - public static function baseUrl () { - return self::$base_url; - } - public static function title () { - return self::$title; - } - public static function language () { - return self::$language; - } - public static function dataBase () { - return self::$db; - } - public static function limits() { - return self::$limits; - } - public static function defaultUser () { - return self::$default_user; - } - public static function allowAnonymous() { - return self::$allow_anonymous; - } - public static function allowAnonymousRefresh() { - return self::$allow_anonymous_refresh; - } - public static function authType() { - return self::$auth_type; - } - public static function needsLogin() { - return self::$auth_type !== 'none'; - } - public static function canLogIn() { - return self::$auth_type === 'form' || self::$auth_type === 'persona'; - } - public static function apiEnabled() { - return self::$api_enabled; - } - public static function unsafeAutologinEnabled() { - return self::$unsafe_autologin_enabled; - } + /** + * The configuration values, an empty array by default. + */ + private $data = array(); - public static function _allowAnonymous($allow = false) { - self::$allow_anonymous = ((bool)$allow) && self::canLogIn(); - } - public static function _allowAnonymousRefresh($allow = false) { - self::$allow_anonymous_refresh = ((bool)$allow) && self::allowAnonymous(); - } - public static function _authType($value) { - $value = strtolower($value); - switch ($value) { - case 'form': - case 'http_auth': - case 'persona': - case 'none': - self::$auth_type = $value; - break; - } - self::_allowAnonymous(self::$allow_anonymous); - } + /** + * The default values, an empty array by default. + */ + private $data_default = array(); - public static function _enableApi($value = false) { - self::$api_enabled = (bool)$value; - } - public static function _enableAutologin($value = false) { - self::$unsafe_autologin_enabled = (bool)$value; - } + /** + * An object which help to set good values in configuration. + */ + private $configuration_setter = null; /** - * Initialise les variables de configuration - * @exception Minz_FileNotExistException si le CONF_PATH_NAME n'existe pas - * @exception Minz_BadConfigurationException si CONF_PATH_NAME mal formaté + * Create a new Minz_Configuration object. + * + * @param $namespace the name of the current configuration. + * @param $config_filename the file containing configuration values. + * @param $default_filename the file containing default values, null by default. + * @param $configuration_setter an optional helper to set values in configuration */ - public static function init () { + private function __construct($namespace, $config_filename, $default_filename = null, + $configuration_setter = null) { + $this->namespace = $namespace; + $this->config_filename = $config_filename; + try { - self::parseFile (); - self::setReporting (); + $this->data = self::load($this->config_filename); } catch (Minz_FileNotExistException $e) { - throw $e; - } catch (Minz_BadConfigurationException $e) { - throw $e; + if (is_null($default_filename)) { + throw $e; + } } - } - public static function writeFile() { - $ini_array = array( - 'general' => array( - 'environment' => self::environment(true), - 'salt' => self::$salt, - 'base_url' => self::$base_url, - 'title' => self::$title, - 'default_user' => self::$default_user, - 'allow_anonymous' => self::$allow_anonymous, - 'allow_anonymous_refresh' => self::$allow_anonymous_refresh, - 'auth_type' => self::$auth_type, - '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'); - $result = file_put_contents(DATA_PATH . self::CONF_PATH_NAME, "<?php\n return " . var_export($ini_array, true) . ';'); - if (function_exists('opcache_invalidate')) { - opcache_invalidate(DATA_PATH . self::CONF_PATH_NAME); //Clear PHP 5.5+ cache for include + $this->default_filename = $default_filename; + if (!is_null($this->default_filename)) { + $this->data_default = self::load($this->default_filename); } - return (bool)$result; + + $this->_configurationSetter($configuration_setter); } /** - * Parse un fichier de configuration - * @exception Minz_PermissionDeniedException si le CONF_PATH_NAME n'est pas accessible - * @exception Minz_BadConfigurationException si CONF_PATH_NAME mal formaté + * Set a configuration setter for the current configuration. + * @param $configuration_setter the setter to call when modifying data. It + * must implement an handle($key, $value) method. */ - private static function parseFile () { - $ini_array = include(DATA_PATH . self::CONF_PATH_NAME); - - if (!is_array($ini_array)) { - throw new Minz_PermissionDeniedException ( - DATA_PATH . self::CONF_PATH_NAME, - Minz_Exception::ERROR - ); + public function _configurationSetter($configuration_setter) { + if (is_callable(array($configuration_setter, 'handle'))) { + $this->configuration_setter = $configuration_setter; } + } - // [general] est obligatoire - if (!isset ($ini_array['general'])) { - throw new Minz_BadConfigurationException ( - '[general]', - Minz_Exception::ERROR - ); - } - $general = $ini_array['general']; - - // salt est obligatoire - if (!isset ($general['salt'])) { - if (isset($general['sel_application'])) { //v0.6 - $general['salt'] = $general['sel_application']; - } else { - throw new Minz_BadConfigurationException ( - 'salt', - Minz_Exception::ERROR - ); - } + /** + * Return the value of the given param. + * + * @param $key the name of the param. + * @param $default default value to return if key does not exist. + * @return the value corresponding to the key. + * @throws Minz_ConfigurationParamException if the param does not exist + */ + public function param($key, $default = null) { + if (isset($this->data[$key])) { + return $this->data[$key]; + } elseif (!is_null($default)) { + return $default; + } elseif (isset($this->data_default[$key])) { + return $this->data_default[$key]; + } else { + Minz_Log::warning($key . ' does not exist in configuration'); + return null; } - self::$salt = $general['salt']; + } - if (isset ($general['environment'])) { - switch ($general['environment']) { - case 'silent': - self::$environment = Minz_Configuration::SILENT; - break; - case 'development': - self::$environment = Minz_Configuration::DEVELOPMENT; - break; - case 'production': - self::$environment = Minz_Configuration::PRODUCTION; - break; - default: - if ($general['environment'] >= 0 && - $general['environment'] <= 2) { - // fallback 0.7-beta - self::$environment = $general['environment']; - } else { - throw new Minz_BadConfigurationException ( - 'environment', - Minz_Exception::ERROR - ); - } - } + /** + * A wrapper for param(). + */ + public function __get($key) { + return $this->param($key); + } + /** + * Set or remove a param. + * + * @param $key the param name to set. + * @param $value the value to set. If null, the key is removed from the configuration. + */ + public function _param($key, $value = null) { + if (!is_null($this->configuration_setter) && $this->configuration_setter->support($key)) { + $this->configuration_setter->handle($this->data, $key, $value); + } elseif (isset($this->data[$key]) && is_null($value)) { + unset($this->data[$key]); + } elseif (!is_null($value)) { + $this->data[$key] = $value; } - if (isset ($general['base_url'])) { - self::$base_url = $general['base_url']; - } + } - if (isset ($general['title'])) { - self::$title = $general['title']; - } - if (isset ($general['language'])) { - self::$language = $general['language']; - } - if (isset ($general['default_user'])) { - self::$default_user = $general['default_user']; - } - if (isset ($general['auth_type'])) { - self::_authType($general['auth_type']); - } - if (isset ($general['allow_anonymous'])) { - self::$allow_anonymous = ( - ((bool)($general['allow_anonymous'])) && - ($general['allow_anonymous'] !== 'no') - ); - } - if (isset ($general['allow_anonymous_refresh'])) { - self::$allow_anonymous_refresh = ( - ((bool)($general['allow_anonymous_refresh'])) && - ($general['allow_anonymous_refresh'] !== 'no') - ); - } - if (isset ($general['api_enabled'])) { - self::$api_enabled = ( - ((bool)($general['api_enabled'])) && - ($general['api_enabled'] !== 'no') - ); - } - if (isset ($general['unsafe_autologin_enabled'])) { - self::$unsafe_autologin_enabled = ( - ((bool)($general['unsafe_autologin_enabled'])) && - ($general['unsafe_autologin_enabled'] !== 'no') - ); - } + /** + * A wrapper for _param(). + */ + public function __set($key, $value) { + $this->_param($key, $value); + } - if (isset($ini_array['limits'])) { - $limits = $ini_array['limits']; - if (isset($limits['cache_duration'])) { - $v = intval($limits['cache_duration']); - if ($v > 0) { - self::$limits['cache_duration'] = $v; - } - } - if (isset($limits['timeout'])) { - $v = intval($limits['timeout']); - if ($v > 0) { - 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) { - self::$limits['max_feeds'] = $v; - } - } - if (isset($limits['max_categories'])) { - $v = intval($limits['max_categories']); - if ($v > 0 && $v < Minz_Configuration::MAX_SMALL_INT) { - self::$limits['max_categories'] = $v; - } - } - } + /** + * Save the current configuration in the configuration file. + */ + public function save() { + $back_filename = $this->config_filename . '.bak.php'; + @rename($this->config_filename, $back_filename); - // Base de données - if (isset ($ini_array['db'])) { - $db = $ini_array['db']; - if (empty($db['type'])) { - throw new Minz_BadConfigurationException ( - 'type', - Minz_Exception::ERROR - ); - } - switch ($db['type']) { - case 'mysql': - if (empty($db['host'])) { - throw new Minz_BadConfigurationException ( - 'host', - Minz_Exception::ERROR - ); - } - if (empty($db['user'])) { - throw new Minz_BadConfigurationException ( - 'user', - Minz_Exception::ERROR - ); - } - if (!isset($db['password'])) { - throw new Minz_BadConfigurationException ( - 'password', - Minz_Exception::ERROR - ); - } - if (empty($db['base'])) { - throw new Minz_BadConfigurationException ( - 'base', - Minz_Exception::ERROR - ); - } - self::$db['host'] = $db['host']; - self::$db['user'] = $db['user']; - self::$db['password'] = $db['password']; - self::$db['base'] = $db['base']; - if (isset($db['prefix'])) { - self::$db['prefix'] = $db['prefix']; - } - break; - case 'sqlite': - self::$db['host'] = ''; - self::$db['user'] = ''; - self::$db['password'] = ''; - self::$db['base'] = ''; - self::$db['prefix'] = ''; - break; - default: - throw new Minz_BadConfigurationException ( - 'type', - Minz_Exception::ERROR - ); - break; - } - self::$db['type'] = $db['type']; + if (file_put_contents($this->config_filename, + "<?php\nreturn " . var_export($this->data, true) . ';', + LOCK_EX) === false) { + return false; } - } - private static function setReporting() { - switch (self::$environment) { - case self::PRODUCTION: - error_reporting(E_ALL); - ini_set('display_errors','Off'); - ini_set('log_errors', 'On'); - break; - case self::DEVELOPMENT: - error_reporting(E_ALL); - ini_set('display_errors','On'); - ini_set('log_errors', 'On'); - break; - case self::SILENT: - error_reporting(0); - break; + // Clear PHP 5.5+ cache for include + if (function_exists('opcache_invalidate')) { + opcache_invalidate($this->config_filename); } + + return true; } } diff --git a/lib/Minz/ConfigurationException.php b/lib/Minz/ConfigurationException.php new file mode 100644 index 000000000..f294c3341 --- /dev/null +++ b/lib/Minz/ConfigurationException.php @@ -0,0 +1,8 @@ +<?php + +class Minz_ConfigurationException extends Minz_Exception { + public function __construct($error, $code = self::ERROR) { + $message = 'Configuration error: ' . $error; + parent::__construct($message, $code); + } +} diff --git a/lib/Minz/ConfigurationNamespaceException.php b/lib/Minz/ConfigurationNamespaceException.php new file mode 100644 index 000000000..f4278c5d6 --- /dev/null +++ b/lib/Minz/ConfigurationNamespaceException.php @@ -0,0 +1,4 @@ +<?php + +class Minz_ConfigurationNamespaceException extends Minz_ConfigurationException { +} diff --git a/lib/Minz/ConfigurationParamException.php b/lib/Minz/ConfigurationParamException.php new file mode 100644 index 000000000..eac977935 --- /dev/null +++ b/lib/Minz/ConfigurationParamException.php @@ -0,0 +1,4 @@ +<?php + +class Minz_ConfigurationParamException extends Minz_ConfigurationException { +} diff --git a/lib/Minz/Error.php b/lib/Minz/Error.php index e5f3dff07..3eadc6d98 100644 --- a/lib/Minz/Error.php +++ b/lib/Minz/Error.php @@ -82,7 +82,8 @@ class Minz_Error { * > en fonction de l'environment */ private static function processLogs ($logs) { - $env = Minz_Configuration::environment (); + $conf = Minz_Configuration::get('system'); + $env = $conf->environment; $logs_ok = array (); $error = array (); $warning = array (); @@ -98,10 +99,10 @@ class Minz_Error { $notice = $logs['notice']; } - if ($env == Minz_Configuration::PRODUCTION) { + if ($env == 'production') { $logs_ok = $error; } - if ($env == Minz_Configuration::DEVELOPMENT) { + if ($env == 'development') { $logs_ok = array_merge ($error, $warning, $notice); } diff --git a/lib/Minz/FrontController.php b/lib/Minz/FrontController.php index 3dac1e438..f9eff3db6 100644 --- a/lib/Minz/FrontController.php +++ b/lib/Minz/FrontController.php @@ -31,9 +31,12 @@ class Minz_FrontController { */ public function __construct () { try { - Minz_Configuration::init (); + Minz_Configuration::register('system', + DATA_PATH . '/config.php', + DATA_PATH . '/config.default.php'); + $this->setReporting(); - Minz_Request::init (); + Minz_Request::init(); $url = $this->buildUrl(); $url['params'] = array_merge ( @@ -110,4 +113,23 @@ class Minz_FrontController { } exit ('### Application problem ###<br />'."\n".$txt); } + + private function setReporting() { + $conf = Minz_Configuration::get('system'); + switch($conf->environment) { + case 'production': + error_reporting(E_ALL); + ini_set('display_errors','Off'); + ini_set('log_errors', 'On'); + break; + case 'development': + error_reporting(E_ALL); + ini_set('display_errors','On'); + ini_set('log_errors', 'On'); + break; + case 'silent': + error_reporting(0); + break; + } + } } diff --git a/lib/Minz/Log.php b/lib/Minz/Log.php index d19edc1dc..2a9e10993 100644 --- a/lib/Minz/Log.php +++ b/lib/Minz/Log.php @@ -31,10 +31,15 @@ class Minz_Log { * @param $file_name fichier de log */ public static function record ($information, $level, $file_name = null) { - $env = Minz_Configuration::environment (); + try { + $conf = Minz_Configuration::get('system'); + $env = $conf->environment; + } catch (Minz_ConfigurationException $e) { + $env = 'production'; + } - if (! ($env === Minz_Configuration::SILENT - || ($env === Minz_Configuration::PRODUCTION + if (! ($env === 'silent' + || ($env === 'production' && ($level >= Minz_Log::NOTICE)))) { if ($file_name === null) { $file_name = join_path(USERS_PATH, Minz_Session::param('currentUser', '_'), 'log.txt'); diff --git a/lib/Minz/ModelPdo.php b/lib/Minz/ModelPdo.php index 118d89ad2..ac7a1bed7 100644 --- a/lib/Minz/ModelPdo.php +++ b/lib/Minz/ModelPdo.php @@ -44,7 +44,8 @@ class Minz_ModelPdo { return; } - $db = Minz_Configuration::dataBase(); + $conf = Minz_Configuration::get('system'); + $db = $conf->db; if ($currentUser === null) { $currentUser = Minz_Session::param('currentUser', '_'); diff --git a/lib/Minz/Request.php b/lib/Minz/Request.php index 4b97a3caf..6db2e9c7a 100644 --- a/lib/Minz/Request.php +++ b/lib/Minz/Request.php @@ -96,7 +96,8 @@ class Minz_Request { * @return la base de l'url */ public static function getBaseUrl() { - $defaultBaseUrl = Minz_Configuration::baseUrl(); + $conf = Minz_Configuration::get('system'); + $defaultBaseUrl = $conf->base_url; if (!empty($defaultBaseUrl)) { return $defaultBaseUrl; } elseif (isset($_SERVER['REQUEST_URI'])) { diff --git a/lib/Minz/Session.php b/lib/Minz/Session.php index af4de75bb..cfe8debe9 100644 --- a/lib/Minz/Session.php +++ b/lib/Minz/Session.php @@ -55,7 +55,7 @@ class Minz_Session { if (!$force) { self::_param('language', $language); - Minz_Translate::reset(); + Minz_Translate::reset($language); } } diff --git a/lib/Minz/Translate.php b/lib/Minz/Translate.php index e7efb8665..1b4102ca9 100644 --- a/lib/Minz/Translate.php +++ b/lib/Minz/Translate.php @@ -10,6 +10,11 @@ */ class Minz_Translate { /** + * $lang_list is the list of available languages. + */ + private static $lang_list = array(); + + /** * $lang_name is the name of the current language to use. */ private static $lang_name; @@ -25,19 +30,30 @@ class Minz_Translate { private static $translates = array(); /** - * Load $lang_name and $lang_path based on configuration and selected language. + * Init the translation object. + * @param $lang_list the list of available languages. + * @param $lang_name the lang to show. */ - public static function init() { - $l = Minz_Configuration::language(); - self::$lang_name = Minz_Session::param('language', $l); + public static function init($lang_list, $lang_name) { + self::$lang_list = $lang_list; + self::$lang_name = $lang_name; self::$lang_path = APP_PATH . '/i18n/' . self::$lang_name . '/'; } /** - * Alias for init(). + * Reset the translation object with a new language. + * @param $lang_name the new language to use + */ + public static function reset($lang_name) { + self::init(self::$lang_list, $lang_name); + } + + /** + * Return the list of available languages. + * @return an array. */ - public static function reset() { - self::init(); + public static function availableLanguages() { + return self::$lang_list; } /** diff --git a/lib/Minz/View.php b/lib/Minz/View.php index b40448491..481b0376d 100644 --- a/lib/Minz/View.php +++ b/lib/Minz/View.php @@ -28,7 +28,9 @@ class Minz_View { public function __construct () { $this->change_view(Minz_Request::controllerName(), Minz_Request::actionName()); - self::$title = Minz_Configuration::title (); + + $conf = Minz_Configuration::get('system'); + self::$title = $conf->title; } /** diff --git a/lib/lib_rss.php b/lib/lib_rss.php index d450ec858..ffd56eae4 100644 --- a/lib/lib_rss.php +++ b/lib/lib_rss.php @@ -119,7 +119,8 @@ function html_only_entity_decode($text) { } function customSimplePie() { - $limits = Minz_Configuration::limits(); + $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_cache_location(CACHE_PATH); @@ -236,6 +237,33 @@ function listUsers() { return $final_list; } + +/** + * Register and return the configuration for a given user. + * + * Note this function has been created to generate temporary configuration + * objects. If you need a long-time configuration, please don't use this function. + * + * @param $username the name of the user of which we want the configuration. + * @return a Minz_Configuration object, null if the configuration cannot be loaded. + */ +function get_user_configuration($username) { + $namespace = time() . '_user_' . $username; + try { + Minz_Configuration::register($namespace, + join_path(USERS_PATH, $username, 'config.php'), + join_path(USERS_PATH, '_', 'config.default.php')); + } catch (Minz_ConfigurationNamespaceException $e) { + // namespace already exists, do nothing. + } catch (Minz_FileNotExistException $e) { + Minz_Log::warning($e->getMessage()); + return null; + } + + return Minz_Configuration::get($namespace); +} + + function httpAuthUser() { return isset($_SERVER['REMOTE_USER']) ? $_SERVER['REMOTE_USER'] : ''; } @@ -359,3 +387,20 @@ function recursive_unlink($dir) { } return rmdir($dir); } + + +/** + * Remove queries where $get is appearing. + * @param $get the get attribute which should be removed. + * @param $queries an array of queries. + * @return the same array whithout those where $get is appearing. + */ +function remove_query_by_get($get, $queries) { + $final_queries = array(); + foreach ($queries as $key => $query) { + if (empty($query['get']) || $query['get'] !== $get) { + $final_queries[$key] = $query; + } + } + return $final_queries; +} diff --git a/p/api/greader.php b/p/api/greader.php index 80714d478..30530d60d 100644 --- a/p/api/greader.php +++ b/p/api/greader.php @@ -150,13 +150,12 @@ function authorizationToUserConf() { if (count($headerAuthX) === 2) { $user = $headerAuthX[0]; if (ctype_alnum($user)) { - try { - $conf = new FreshRSS_Configuration($user); - } catch (Exception $e) { - logMe($e->getMessage() . "\n"); + $conf = get_user_configuration($user); + if (is_null($conf)) { unauthorized(); } - if ($headerAuthX[1] === sha1(Minz_Configuration::salt() . $conf->user . $conf->apiPasswordHash)) { + $system_conf = Minz_Configuration::get('system'); + if ($headerAuthX[1] === sha1($system_conf->salt . $conf->user . $conf->apiPasswordHash)) { return $conf; } else { logMe('Invalid API authorisation for user ' . $user . ': ' . $headerAuthX[1] . "\n"); @@ -177,16 +176,16 @@ function clientLogin($email, $pass) { //http://web.archive.org/web/2013060409104 if (!function_exists('password_verify')) { include_once(LIB_PATH . '/password_compat.php'); } - try { - $conf = new FreshRSS_Configuration($email); - } catch (Exception $e) { - logMe($e->getMessage() . "\n"); - Minz_Log::warning('Invalid API user ' . $email); + + $conf = get_user_configuration($email); + if (is_null($conf)) { unauthorized(); } + if ($conf->apiPasswordHash != '' && password_verify($pass, $conf->apiPasswordHash)) { header('Content-Type: text/plain; charset=UTF-8'); - $auth = $email . '/' . sha1(Minz_Configuration::salt() . $conf->user . $conf->apiPasswordHash); + $system_conf = Minz_Configuration::get('system'); + $auth = $email . '/' . sha1($system_conf->salt . $conf->user . $conf->apiPasswordHash); echo 'SID=', $auth, "\n", 'Auth=', $auth, "\n"; exit(); @@ -204,7 +203,8 @@ 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 logMe('token('. $conf->user . ")\n"); //TODO: Implement real token that expires - $token = str_pad(sha1(Minz_Configuration::salt() . $conf->user . $conf->apiPasswordHash), 57, 'Z'); //Must have 57 characters + $system_conf = Minz_Configuration::get('system'); + $token = str_pad(sha1($system_conf->salt . $conf->user . $conf->apiPasswordHash), 57, 'Z'); //Must have 57 characters echo $token, "\n"; exit(); } @@ -212,7 +212,8 @@ function token($conf) { function checkToken($conf, $token) { //http://code.google.com/p/google-reader-api/wiki/ActionToken logMe('checkToken(' . $token . ")\n"); - if ($token === str_pad(sha1(Minz_Configuration::salt() . $conf->user . $conf->apiPasswordHash), 57, 'Z')) { + $system_conf = Minz_Configuration::get('system'); + if ($token === str_pad(sha1($system_conf->salt . $conf->user . $conf->apiPasswordHash), 57, 'Z')) { return true; } unauthorized(); @@ -536,9 +537,11 @@ logMe('----------------------------------------------------------------'."\n"); $pathInfo = empty($_SERVER['PATH_INFO']) ? '/Error' : urldecode($_SERVER['PATH_INFO']); $pathInfos = explode('/', $pathInfo); -Minz_Configuration::init(); - -if (!Minz_Configuration::apiEnabled()) { +Minz_Configuration::register('system', + DATA_PATH . '/config.php', + DATA_PATH . '/config.default.php'); +$system_conf = Minz_Configuration::get('system'); +if (!$system_conf->api_enabled) { serviceUnavailable(); } diff --git a/p/i/index.php b/p/i/index.php index 009d56bc3..d3fc0b37c 100755 --- a/p/i/index.php +++ b/p/i/index.php @@ -33,7 +33,7 @@ if (file_exists(DATA_PATH . '/do-install.txt')) { $currentUser = Minz_Session::param('currentUser', ''); $dateLastModification = $currentUser === '' ? time() : max( @filemtime(join_path(USERS_PATH, $currentUser, 'log.txt')), - @filemtime(join_path(DATA_PATH . 'config.php')) + @filemtime(join_path(DATA_PATH, 'config.php')) ); if (httpConditional($dateLastModification, 0, 0, false, PHP_COMPRESSION, true)) { exit(); //No need to send anything diff --git a/p/scripts/main.js b/p/scripts/main.js index e48630d89..e8bd66fc1 100644 --- a/p/scripts/main.js +++ b/p/scripts/main.js @@ -1086,7 +1086,7 @@ function init_print_action() { } function init_share_observers() { - shares = $('.form-group:not(".form-actions")').length; + shares = $('.group-share').length; $('.share.add').on('click', function(e) { var opt = $(this).siblings('select').find(':selected'); |
