aboutsummaryrefslogtreecommitdiff
path: root/app/Models
diff options
context:
space:
mode:
authorGravatar Marien Fressinaud <dev@marienfressinaud.fr> 2015-01-08 14:18:32 +0100
committerGravatar Marien Fressinaud <dev@marienfressinaud.fr> 2015-01-08 14:18:32 +0100
commit73023bc12b81a27045703e1f733faeb2b4e02cec (patch)
tree14aca1a1953d0a813c06794e48a63738abccdcea /app/Models
parent26da4aa448906f857a252507b34d369a386043c6 (diff)
parent0e4e16ac55097aa173c7c439367294ebd7645562 (diff)
Merge branch 'dev' into 252-extensions
Conflicts: app/FreshRSS.php app/Models/Configuration.php app/views/index/index.phtml app/views/index/normal.phtml lib/Minz/Configuration.php lib/Minz/Translate.php lib/lib_rss.php
Diffstat (limited to 'app/Models')
-rw-r--r--app/Models/Auth.php50
-rw-r--r--app/Models/Configuration.php365
-rw-r--r--app/Models/ConfigurationSetter.php368
-rw-r--r--app/Models/Context.php20
-rw-r--r--app/Models/EntryDAO.php2
-rw-r--r--app/Models/EntryDAOSQLite.php2
-rw-r--r--app/Models/Factory.php16
-rw-r--r--app/Models/Feed.php3
-rw-r--r--app/Models/LogDAO.php4
-rw-r--r--app/Models/Share.php232
-rw-r--r--app/Models/UserDAO.php12
11 files changed, 646 insertions, 428 deletions
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 83a00d4bb..000000000
--- a/app/Models/Configuration.php
+++ /dev/null
@@ -1,365 +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,
- 'extensions_enabled' => array(),
- );
-
- private $available_languages = array(
- 'en' => 'English',
- 'fr' => 'Français',
- );
-
- private $shares;
-
- public function __construct($user) {
- $this->filename = DATA_PATH . DIRECTORY_SEPARATOR . $user . '_user.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 = DATA_PATH . DIRECTORY_SEPARATOR . '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';
- }
-
- public function _extensions_enabled($value) {
- if (!is_array($value)) {
- $value = array($value);
- }
- $this->data['extensions_enabled'] = $value;
- }
- public function removeExtension($ext_name) {
- $this->data['extensions_enabled'] = array_diff(
- $this->data['extensions_enabled'],
- array($ext_name)
- );
- }
- public function addExtension($ext_name) {
- $found = array_search($ext_name, $this->data['extensions_enabled']) !== false;
- if (!$found) {
- $this->data['extensions_enabled'][] = $ext_name;
- }
- }
-}
diff --git a/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/EntryDAOSQLite.php b/app/Models/EntryDAOSQLite.php
index bb1539e0c..ffe0f037c 100644
--- a/app/Models/EntryDAOSQLite.php
+++ b/app/Models/EntryDAOSQLite.php
@@ -169,6 +169,6 @@ class FreshRSS_EntryDAOSQLite extends FreshRSS_EntryDAO {
}
public function size($all = false) {
- return @filesize(DATA_PATH . '/' . $this->current_user . '.sqlite');
+ return @filesize(join_path(DATA_PATH, 'users', $this->current_user, 'db.sqlite'));
}
}
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/LogDAO.php b/app/Models/LogDAO.php
index 21593435d..4c56e3150 100644
--- a/app/Models/LogDAO.php
+++ b/app/Models/LogDAO.php
@@ -3,7 +3,7 @@
class FreshRSS_LogDAO {
public static function lines() {
$logs = array();
- $handle = @fopen(LOG_PATH . '/' . Minz_Session::param('currentUser', '_') . '.log', 'r');
+ $handle = @fopen(join_path(DATA_PATH, 'users', Minz_Session::param('currentUser', '_'), 'log.txt'), 'r');
if ($handle) {
while (($line = fgets($handle)) !== false) {
if (preg_match('/^\[([^\[]+)\] \[([^\[]+)\] --- (.*)$/', $line, $matches)) {
@@ -20,6 +20,6 @@ class FreshRSS_LogDAO {
}
public static function truncate() {
- file_put_contents(LOG_PATH . '/' . Minz_Session::param('currentUser', '_') . '.log', '');
+ file_put_contents(join_path(DATA_PATH, 'users', Minz_Session::param('currentUser', '_'), 'log.txt'), '');
}
}
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 f04ae26bf..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,11 +34,11 @@ 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') {
- return unlink(DATA_PATH . '/' . $username . '.sqlite');
+ return unlink(join_path(DATA_PATH, 'users', $username, 'db.sqlite'));
} else {
$userPDO = new Minz_ModelPdo($username);
@@ -55,14 +55,14 @@ class FreshRSS_UserDAO extends Minz_ModelPdo {
}
public static function exist($username) {
- return file_exists(DATA_PATH . '/' . $username . '_user.php');
+ return is_dir(join_path(DATA_PATH , 'users', $username));
}
public static function touch($username) {
- return touch(DATA_PATH . '/' . $username . '_user.php');
+ return touch(join_path(DATA_PATH , 'users', $username, 'config.php'));
}
public static function mtime($username) {
- return @filemtime(DATA_PATH . '/' . $username . '_user.php');
+ return @filemtime(join_path(DATA_PATH , 'users', $username, 'config.php'));
}
}