From bd2314170dc183c154c2af05686ddb0224b5d133 Mon Sep 17 00:00:00 2001 From: Andrew Dolgov Date: Thu, 25 Feb 2021 12:46:13 +0300 Subject: [PATCH] implement prefs UI based on new prefs class and a few more things --- classes/digest.php | 6 +- classes/opml.php | 2 +- classes/pref/prefs.php | 41 +++++--------- classes/prefs.php | 106 ++++++++++++++++++++++++++++++++--- classes/rpc.php | 3 +- classes/userhelper.php | 4 -- include/functions.php | 10 ++-- plugins/auth_remote/init.php | 2 +- 8 files changed, 124 insertions(+), 50 deletions(-) diff --git a/classes/digest.php b/classes/digest.php index a6a0c47de..e158af85d 100644 --- a/classes/digest.php +++ b/classes/digest.php @@ -21,8 +21,8 @@ class Digest while ($line = $res->fetch()) { - if (@get_pref('DIGEST_ENABLE', $line['id'], false)) { - $preferred_ts = strtotime(get_pref('DIGEST_PREFERRED_TIME', $line['id'], '00:00')); + if (get_pref('DIGEST_ENABLE', $line['id'])) { + $preferred_ts = strtotime(get_pref('DIGEST_PREFERRED_TIME', $line['id'])); // try to send digests within 2 hours of preferred time if ($preferred_ts && time() >= $preferred_ts && @@ -31,7 +31,7 @@ class Digest Debug::log("Sending digest for UID:" . $line['id'] . " - " . $line["email"]); - $do_catchup = get_pref('DIGEST_CATCHUP', $line['id'], false); + $do_catchup = get_pref('DIGEST_CATCHUP', $line['id']); global $tz_offset; diff --git a/classes/opml.php b/classes/opml.php index cbc1269e3..6c7cab606 100644 --- a/classes/opml.php +++ b/classes/opml.php @@ -153,7 +153,7 @@ class OPML extends Handler_Protected { if ($include_settings) { $out .= ""; - $sth = $this->pdo->prepare("SELECT pref_name, value FROM ttrss_user_prefs WHERE + $sth = $this->pdo->prepare("SELECT pref_name, value FROM ttrss_user_prefs2 WHERE profile IS NULL AND owner_uid = ? ORDER BY pref_name"); $sth->execute([$owner_uid]); diff --git a/classes/pref/prefs.php b/classes/pref/prefs.php index ffee57ed5..60d395af7 100644 --- a/classes/pref/prefs.php +++ b/classes/pref/prefs.php @@ -185,7 +185,7 @@ class Pref_Prefs extends Handler_Protected { if (get_pref('DIGEST_PREFERRED_TIME') != $value) { $sth = $this->pdo->prepare("UPDATE ttrss_users SET - last_digest_sent = NULL WHERE id = ?"); + last_digest_sent = NULL WHERE id = ?"); $sth->execute([$_SESSION['uid']]); } @@ -205,7 +205,9 @@ class Pref_Prefs extends Handler_Protected { break; } - set_pref($pref_name, $value); + if (Prefs::is_valid($pref_name)) { + Prefs::set($pref_name, $value, $_SESSION["uid"], $_SESSION["profile"] ?? null); + } } if ($need_reload) { @@ -260,17 +262,9 @@ class Pref_Prefs extends Handler_Protected { } function resetconfig() { + Prefs::reset($_SESSION["uid"], $_SESSION["profile"]); - $_SESSION["prefs_op_result"] = "reset-to-defaults"; - - $sth = $this->pdo->prepare("DELETE FROM ttrss_user_prefs - WHERE (profile = :profile OR (:profile IS NULL AND profile IS NULL)) - AND owner_uid = :uid"); - $sth->execute([":profile" => $_SESSION['profile'], ":uid" => $_SESSION['uid']]); - - $this->_init_user_prefs($_SESSION["uid"], $_SESSION["profile"]); - - echo __("Your preferences are now set to default values."); + print "PREFS_NEED_RELOAD"; } private function index_auth_personal() { @@ -568,14 +562,11 @@ class Pref_Prefs extends Handler_Protected { if ($profile) { print_notice(__("Some preferences are only available in default profile.")); - $this->_init_user_prefs($_SESSION["uid"], $profile); - } else { - $this->_init_user_prefs($_SESSION["uid"]); } $prefs_available = []; - $sth = $this->pdo->prepare("SELECT DISTINCT + /*$sth = $this->pdo->prepare("SELECT DISTINCT ttrss_user_prefs.pref_name,value,type_name, ttrss_prefs_sections.order_id, def_value,section_id @@ -586,17 +577,17 @@ class Pref_Prefs extends Handler_Protected { ttrss_user_prefs.pref_name = ttrss_prefs.pref_name AND owner_uid = :uid ORDER BY ttrss_prefs_sections.order_id,pref_name"); - $sth->execute([":uid" => $_SESSION['uid'], ":profile" => $profile]); + $sth->execute([":uid" => $_SESSION['uid'], ":profile" => $profile]);*/ $listed_boolean_prefs = []; - while ($line = $sth->fetch()) { + foreach (Prefs::get_all($_SESSION["uid"], $profile) as $line) { if (in_array($line["pref_name"], $this->pref_blacklist)) { continue; } - if ($profile && in_array($line["pref_name"], $this->profile_blacklist)) { + if ($profile && in_array($line["pref_name"], Prefs::_PROFILE_BLACKLIST)) { continue; } @@ -607,7 +598,7 @@ class Pref_Prefs extends Handler_Protected { continue; $prefs_available[$pref_name] = [ - 'type_name' => $line["type_name"], + 'type_hint' => $line['type_hint'], 'value' => $line['value'], 'help_text' => $this->_get_help_text($pref_name), 'short_desc' => $short_desc @@ -640,7 +631,7 @@ class Pref_Prefs extends Handler_Protected { print ""; $value = $item['value']; - $type_name = $item['type_name']; + $type_hint = $item['type_hint']; if ($pref_name == "USER_LANGUAGE") { print \Controls\select_hash($pref_name, $value, get_translations(), @@ -701,7 +692,7 @@ class Pref_Prefs extends Handler_Protected { print \Controls\select_tag($pref_name, $value, Pref_Feeds::get_ts_languages()); - } else if ($type_name == "bool") { + } else if ($type_hint == Config::T_BOOL) { array_push($listed_boolean_prefs, $pref_name); @@ -726,7 +717,7 @@ class Pref_Prefs extends Handler_Protected { $attributes = ["required" => true]; } - if ($type_name == 'integer') + if ($type_hint == Config::T_INT) print \Controls\number_spinner_tag($pref_name, $value, $attributes); else print \Controls\input_tag($pref_name, $value, "text", $attributes); @@ -757,7 +748,7 @@ class Pref_Prefs extends Handler_Protected { $item['help_text'] .= ". " . T_sprintf("Current server time: %s", date("H:i")); } else { - $regexp = ($type_name == 'integer') ? 'regexp="^\d*$"' : ''; + $regexp = ($type_hint == Config::T_INT) ? 'regexp="^\d*$"' : ''; print ""; } @@ -1370,8 +1361,6 @@ class Pref_Prefs extends Handler_Protected { static function _init_user_prefs($uid, $profile = false) { - Prefs::initialize($uid, $profile); - if (get_schema_version() < 63) $profile_qpart = ""; $pdo = Db::pdo(); diff --git a/classes/prefs.php b/classes/prefs.php index 21006e34a..29a4ed25d 100644 --- a/classes/prefs.php +++ b/classes/prefs.php @@ -114,7 +114,7 @@ class Prefs { Prefs::_PREFS_MIGRATED => [ false, Config::T_BOOL ], ]; - private const _PROFILE_BLACKLIST = [ + const _PROFILE_BLACKLIST = [ Prefs::ALLOW_DUPLICATE_POSTS, Prefs::PURGE_OLD_DAYS, Prefs::PURGE_UNREAD_ARTICLES, @@ -143,18 +143,73 @@ class Prefs { return self::$instance; } + static function is_valid(string $pref_name) { + return isset(self::_DEFAULTS[$pref_name]); + } + function __construct() { $this->pdo = Db::pdo(); - /*$ref = new ReflectionClass(get_class($this)); + if (!empty($_SESSION["uid"])) { + $owner_uid = (int) $_SESSION["uid"]; + $profile_id = $_SESSION["profile"] ?? null; + + $this->migrate($owner_uid, $profile_id); + $this->cache_all($owner_uid, $profile_id); + }; + } + + static function get_all(int $owner_uid, int $profile_id = null) { + return self::get_instance()->_get_all($owner_uid, $profile_id); + } + + private function _get_all(int $owner_uid, int $profile_id = null) { + $rv = []; + + $ref = new ReflectionClass(get_class($this)); foreach ($ref->getConstants() as $const => $cvalue) { if (isset($this::_DEFAULTS[$const])) { - list ($defval, $deftype) = $this::_DEFAULTS[$const]; + list ($def_val, $type_hint) = $this::_DEFAULTS[$const]; - $this->cache[$cvalue] = [ Config::cast_to($defval, $deftype), $deftype ]; + array_push($rv, [ + "pref_name" => $const, + "value" => $this->_get($const, $owner_uid, $profile_id), + "type_hint" => $type_hint, + ]); } - }*/ + } + + return $rv; + } + + private function cache_all(int $owner_uid, $profile_id = null) { + if (!$profile_id) $profile_id = null; + + // fill cache with defaults + $ref = new ReflectionClass(get_class($this)); + foreach ($ref->getConstants() as $const => $cvalue) { + if (isset($this::_DEFAULTS[$const])) { + list ($def_val, $type_hint) = $this::_DEFAULTS[$const]; + + $this->_set_cache($const, $def_val, $owner_uid, $profile_id); + } + } + + // fill in any overrides from the database + $sth = $this->pdo->prepare("SELECT pref_name, value FROM ttrss_user_prefs2 + WHERE owner_uid = :uid AND + (profile = :profile OR (:profile IS NULL AND profile IS NULL))"); + + $sth->execute(["uid" => $owner_uid, "profile" => $profile_id]); + + while ($row = $sth->fetch()) { + $this->_set_cache($row["pref_name"], $row["value"], $owner_uid, $profile_id); + } + } + + static function get(string $pref_name, int $owner_uid, int $profile_id = null) { + return self::get_instance()->_get($pref_name, $owner_uid, $profile_id); } private function _get(string $pref_name, int $owner_uid, int $profile_id = null) { @@ -184,6 +239,8 @@ class Prefs { return $def_val; } } + } else { + user_error("Attempt to get invalid preference key: $pref_name (UID: $owner_uid, profile: $profile_id)", E_USER_WARNING); } return null; @@ -204,13 +261,38 @@ class Prefs { $this->cache[$cache_key] = $value; } - private function _set(string $pref_name, $value, int $owner_uid, int $profile_id = null) { + static function set(string $pref_name, $value, int $owner_uid, int $profile_id = null, bool $strip_tags = true) { + return self::get_instance()->_set($pref_name, $value, $owner_uid, $profile_id); + } + + private function _delete(string $pref_name, int $owner_uid, int $profile_id = null) { + $sth = $this->pdo->prepare("DELETE FROM ttrss_user_prefs2 + WHERE pref_name = :name AND owner_uid = :uid AND + (profile = :profile OR (:profile IS NULL AND profile IS NULL))"); + + return $sth->execute(["uid" => $owner_uid, "profile" => $profile_id, "name" => $pref_name ]); + } + + private function _set(string $pref_name, $value, int $owner_uid, int $profile_id = null, bool $strip_tags = true) { if (!$profile_id) $profile_id = null; if ($profile_id && in_array($pref_name, self::_PROFILE_BLACKLIST)) return false; if (isset(self::_DEFAULTS[$pref_name])) { + list ($def_val, $type_hint) = self::_DEFAULTS[$pref_name]; + + if ($strip_tags) + $value = trim(strip_tags($value)); + + $value = Config::cast_to($value, $type_hint); + + // is this a good idea or not? probably not (user-set value remains user-set even if its at default) + //if ($value == $def_val) + // return $this->_delete($pref_name, $owner_uid, $profile_id); + + if ($value == $this->_get($pref_name, $owner_uid, $profile_id)) + return false; $this->_set_cache($pref_name, $value, $owner_uid, $profile_id); @@ -237,6 +319,8 @@ class Prefs { return $sth->execute(["uid" => $owner_uid, "profile" => $profile_id, "name" => $pref_name, "value" => $value ]); } } + } else { + user_error("Attempt to set invalid preference key: $pref_name (UID: $owner_uid, profile: $profile_id)", E_USER_WARNING); } return false; @@ -271,9 +355,13 @@ class Prefs { } } - static function initialize(int $owner_uid, int $profile_id = null) { - $instance = self::get_instance(); + static function reset(int $owner_uid, int $profile_id = null) { + if (!$profile_id) $profile_id = null; - $instance->migrate($owner_uid, $profile_id); + $sth = Db::pdo()->prepare("DELETE FROM ttrss_user_prefs2 + WHERE owner_uid = :uid AND pref_name != :mig_key AND + (profile = :profile OR (:profile IS NULL AND profile IS NULL))"); + + $sth->execute(["uid" => $owner_uid, "mig_key" => self::_PREFS_MIGRATED, "profile" => $profile_id]); } } diff --git a/classes/rpc.php b/classes/rpc.php index 8945823c6..fe6075f75 100755 --- a/classes/rpc.php +++ b/classes/rpc.php @@ -91,7 +91,6 @@ class RPC extends Handler_Protected { else $label_ids = array_map("intval", clean($_REQUEST["label_ids"] ?? [])); - // @phpstan-ignore-next-line $counters = is_array($feed_ids) ? Counters::get_conditional($feed_ids, $label_ids) : Counters::get_all(); $reply = [ @@ -394,7 +393,7 @@ class RPC extends Handler_Protected { $params["is_default_pw"] = Pref_Prefs::isdefaultpassword(); $params["label_base_index"] = LABEL_BASE_INDEX; - $theme = get_pref( "USER_CSS_THEME", false, false); + $theme = get_pref("USER_CSS_THEME", false); $params["theme"] = theme_exists($theme) ? $theme : ""; $params["plugins"] = implode(", ", PluginHost::getInstance()->get_plugin_names()); diff --git a/classes/userhelper.php b/classes/userhelper.php index 949c8a5cf..1c4b547a5 100644 --- a/classes/userhelper.php +++ b/classes/userhelper.php @@ -43,8 +43,6 @@ class UserHelper { $_SESSION["user_agent"] = sha1($_SERVER['HTTP_USER_AGENT']); $_SESSION["pwd_hash"] = $row["pwd_hash"]; - Pref_Prefs::_init_user_prefs($_SESSION["uid"]); - return true; } @@ -66,8 +64,6 @@ class UserHelper { $_SESSION["ip_address"] = UserHelper::get_user_ip(); - Pref_Prefs::_init_user_prefs($_SESSION["uid"]); - return true; } } diff --git a/include/functions.php b/include/functions.php index 7b07a31f7..3ed024d11 100644 --- a/include/functions.php +++ b/include/functions.php @@ -42,12 +42,14 @@ define('SUBSTRING_FOR_DATE', 'SUBSTRING'); } - function get_pref($pref_name, $user_id = false, $die_on_error = false) { - return Db_Prefs::get()->read($pref_name, $user_id, $die_on_error); + function get_pref(string $pref_name, int $owner_uid = null) { + return Prefs::get($pref_name, $owner_uid ? $owner_uid : $_SESSION["uid"]); + //return Db_Prefs::get()->read($pref_name, $user_id, $die_on_error); } - function set_pref($pref_name, $value, $user_id = false, $strip_tags = true) { - return Db_Prefs::get()->write($pref_name, $value, $user_id, $strip_tags); + function set_pref(string $pref_name, $value, int $owner_uid = null, bool $strip_tags = true) { + return Prefs::set($pref_name, $value, $owner_uid ? $owner_uid : $_SESSION["uid"], $_SESSION["profile"] ?? null, $strip_tags); + //return Db_Prefs::get()->write($pref_name, $value, $user_id, $strip_tags); } function get_translations() { diff --git a/plugins/auth_remote/init.php b/plugins/auth_remote/init.php index f2dcfb318..f24364ffd 100644 --- a/plugins/auth_remote/init.php +++ b/plugins/auth_remote/init.php @@ -21,7 +21,7 @@ class Auth_Remote extends Auth_Base { $cert_serial = get_ssl_certificate_id(); if ($cert_serial) { - $sth = $this->pdo->prepare("SELECT login FROM ttrss_user_prefs, ttrss_users + $sth = $this->pdo->prepare("SELECT login FROM ttrss_user_prefs2, ttrss_users WHERE pref_name = 'SSL_CERT_SERIAL' AND value = ? AND owner_uid = ttrss_users.id"); $sth->execute([$cert_serial]);