From f2d3cba2316a39e3d27e2e93e52562e72e7bd99d Mon Sep 17 00:00:00 2001
From: Andrew Dolgov
Date: Fri, 12 Feb 2021 21:20:04 +0300
Subject: add HTTP_ACCEPT_LANGUAGE handling for php8
---
include/functions.php | 78 +++++++++++++------
include/sessions.php | 1 -
lib/accept-to-gettext.php | 186 ----------------------------------------------
3 files changed, 55 insertions(+), 210 deletions(-)
delete mode 100644 lib/accept-to-gettext.php
diff --git a/include/functions.php b/include/functions.php
index f870f3382..6362adbbe 100644
--- a/include/functions.php
+++ b/include/functions.php
@@ -91,14 +91,8 @@
define('SUBSTRING_FOR_DATE', 'SUBSTRING');
}
- /**
- * Return available translations names.
- *
- * @access public
- * @return array A array of available translations.
- */
function get_translations() {
- $tr = array(
+ $t = array(
"auto" => __("Detect automatically"),
"ar_SA" => "العربيّة (Arabic)",
"bg_BG" => "Bulgarian",
@@ -129,38 +123,76 @@
"fi_FI" => "Suomi",
"tr_TR" => "Türkçe");
- return $tr;
+ return $t;
}
- require_once "lib/accept-to-gettext.php";
require_once "lib/gettext/gettext.inc.php";
function startup_gettext() {
- # Get locale from Accept-Language header
- if (version_compare(PHP_VERSION, '8.0.0', '<')) {
- $lang = al2gt(array_keys(get_translations()), "text/html");
- } else {
- $lang = ""; // FIXME: do something with accept-to-gettext.php
- }
+ $selected_locale = "";
+
+ // https://www.codingwithjesse.com/blog/use-accept-language-header/
+ if (!empty($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
+ $valid_langs = [];
+ $translations = array_keys(get_translations());
+
+ array_shift($translations); // remove "auto"
+
+ // full locale first
+ foreach ($translations as $t) {
+ $lang = strtolower(str_replace("_", "-", (string)$t));
+ $valid_langs[$lang] = $t;
+
+ $lang = substr($lang, 0, 2);
+ if (!isset($valid_langs[$lang]))
+ $valid_langs[$lang] = $t;
+ }
- if (defined('_TRANSLATION_OVERRIDE_DEFAULT')) {
- $lang = _TRANSLATION_OVERRIDE_DEFAULT;
+ // break up string into pieces (languages and q factors)
+ preg_match_all('/([a-z]{1,8}(-[a-z]{1,8})?)\s*(;\s*q\s*=\s*(1|0\.[0-9]+))?/i',
+ $_SERVER['HTTP_ACCEPT_LANGUAGE'], $lang_parse);
+
+ if (count($lang_parse[1])) {
+ // create a list like "en" => 0.8
+ $langs = array_combine($lang_parse[1], $lang_parse[4]);
+
+ if (is_array($langs)) {
+ // set default to 1 for any without q factor
+ foreach ($langs as $lang => $val) {
+ if ($val === '') $langs[$lang] = 1;
+ }
+
+ // sort list based on value
+ arsort($langs, SORT_NUMERIC);
+
+ foreach (array_keys($langs) as $lang) {
+ $lang = strtolower($lang);
+
+ foreach ($valid_langs as $vlang => $vlocale) {
+ if ($vlang == $lang) {
+ $selected_locale = $vlocale;
+ break 2;
+ }
+ }
+ }
+ }
+ }
}
if (!empty($_SESSION["uid"]) && get_schema_version() >= 120) {
- $pref_lang = get_pref("USER_LANGUAGE", $_SESSION["uid"]);
+ $pref_locale = get_pref("USER_LANGUAGE", $_SESSION["uid"]);
- if ($pref_lang && $pref_lang != 'auto') {
- $lang = $pref_lang;
+ if (!empty($pref_locale) && $pref_locale != 'auto') {
+ $selected_locale = $pref_locale;
}
}
- if ($lang) {
+ if ($selected_locale) {
if (defined('LC_MESSAGES')) {
- _setlocale(LC_MESSAGES, $lang);
+ _setlocale(LC_MESSAGES, $selected_locale);
} else if (defined('LC_ALL')) {
- _setlocale(LC_ALL, $lang);
+ _setlocale(LC_ALL, $selected_locale);
}
_bindtextdomain("messages", "locale");
diff --git a/include/sessions.php b/include/sessions.php
index d7dde782e..3119a4e07 100644
--- a/include/sessions.php
+++ b/include/sessions.php
@@ -5,7 +5,6 @@
require_once "classes/db.php";
require_once "autoload.php";
require_once "errorhandler.php";
- require_once "lib/accept-to-gettext.php";
require_once "lib/gettext/gettext.inc.php";
$session_expire = min(2147483647 - time() - 1, max(SESSION_COOKIE_LIFETIME, 86400));
diff --git a/lib/accept-to-gettext.php b/lib/accept-to-gettext.php
deleted file mode 100644
index c86a62b2e..000000000
--- a/lib/accept-to-gettext.php
+++ /dev/null
@@ -1,186 +0,0 @@
-
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Usage:
- *
- * $locale=al2gt(,
- * );
- * setlocale('LC_ALL', $locale); // or 'LC_MESSAGES', or whatever...
- *
- * Example:
- *
- * $langs=array('nl_BE.ISO-8859-15','nl_BE.UTF-8','en_US.UTF-8','en_GB.UTF-8');
- * $locale=al2gt($langs, 'text/html');
- * setlocale('LC_ALL', $locale);
- *
- * Note that this will send out header information (to be
- * RFC2616-compliant), so it must be called before anything is sent to
- * the user.
- *
- * Assumptions made:
- * * Charset encodings are written the same way as the Accept-Charset
- * HTTP header specifies them (RFC2616), except that they're parsed
- * case-insensitive.
- * * Country codes and language codes are the same in both gettext and
- * the Accept-Language syntax (except for the case differences, which
- * are dealt with easily). If not, some input may be ignored.
- * * The provided gettext-strings are fully qualified; i.e., no "en_US";
- * always "en_US.ISO-8859-15" or "en_US.UTF-8", or whichever has been
- * used. "en.ISO-8859-15" is OK, though.
- * * The language is more important than the charset; i.e., if the
- * following is given:
- *
- * Accept-Language: nl-be, nl;q=0.8, en-us;q=0.5, en;q=0.3
- * Accept-Charset: ISO-8859-15, utf-8;q=0.5
- *
- * And the supplied parameter contains (amongst others) nl_BE.UTF-8
- * and nl.ISO-8859-15, then nl_BE.UTF-8 will be picked.
- *
- * $Log: accept-to-gettext.inc,v $
- * Revision 1.1.1.1 2003/11/19 19:31:15 wouter
- * * moved to new CVS repo after death of the old
- * * Fixed code to apply a default to both Accept-Charset and
- * Accept-Language if none of those headers are supplied; patch from
- * Dominic Chambers
- *
- * Revision 1.2 2003/08/14 10:23:59 wouter
- * Removed little error in Content-Type header syntaxis.
- *
- * 2007-04-01
- * add '@' before use of arrays, to avoid PHP warnings.
- */
-
-/* not really important, this one; perhaps I could've put it inline with
- * the rest. */
-function find_match($curlscore,$curcscore,$curgtlang,$langval,$charval,
- $gtlang)
-{
- if($curlscore < $langval) {
- $curlscore=$langval;
- $curcscore=$charval;
- $curgtlang=$gtlang;
- } else if ($curlscore == $langval) {
- if($curcscore < $charval) {
- $curcscore=$charval;
- $curgtlang=$gtlang;
- }
- }
- return array($curlscore, $curcscore, $curgtlang);
-}
-
-function al2gt($gettextlangs, $mime) {
- /* default to "everything is acceptable", as RFC2616 specifies */
- $acceptLang=(($_SERVER["HTTP_ACCEPT_LANGUAGE"] == '') ? '*' :
- $_SERVER["HTTP_ACCEPT_LANGUAGE"]);
- $acceptChar=(($_SERVER["HTTP_ACCEPT_CHARSET"] == '') ? '*' :
- $_SERVER["HTTP_ACCEPT_CHARSET"]);
- $alparts=@preg_split("/,/",$acceptLang);
- $acparts=@preg_split("/,/",$acceptChar);
-
- /* Parse the contents of the Accept-Language header.*/
- foreach($alparts as $part) {
- $part=trim($part);
- if(preg_match("/;/", $part)) {
- $lang=@preg_split("/;/",$part);
- $score=@preg_split("/=/",$lang[1]);
- $alscores[$lang[0]]=$score[1];
- } else {
- $alscores[$part]=1;
- }
- }
-
- /* Do the same for the Accept-Charset header. */
-
- /* RFC2616: ``If no "*" is present in an Accept-Charset field, then
- * all character sets not explicitly mentioned get a quality value of
- * 0, except for ISO-8859-1, which gets a quality value of 1 if not
- * explicitly mentioned.''
- *
- * Making it 2 for the time being, so that we
- * can distinguish between "not specified" and "specified as 1" later
- * on. */
- $acscores["ISO-8859-1"]=2;
-
- foreach($acparts as $part) {
- $part=trim($part);
- if(preg_match("/;/", $part)) {
- $cs=@preg_split("/;/",$part);
- $score=@preg_split("/=/",$cs[1]);
- $acscores[strtoupper($cs[0])]=$score[1];
- } else {
- $acscores[strtoupper($part)]=1;
- }
- }
- if($acscores["ISO-8859-1"]==2) {
- $acscores["ISO-8859-1"]=(isset($acscores["*"])?$acscores["*"]:1);
- }
-
- /*
- * Loop through the available languages/encodings, and pick the one
- * with the highest score, excluding the ones with a charset the user
- * did not include.
- */
- $curlscore=0;
- $curcscore=0;
- $curgtlang=NULL;
- foreach($gettextlangs as $gtlang) {
-
- $tmp1=preg_replace("/\_/","-",$gtlang);
- $tmp2=@preg_split("/\./",$tmp1);
- $allang=strtolower($tmp2[0]);
- $gtcs=strtoupper($tmp2[1]);
- $noct=@preg_split("/-/",$allang);
-
- $testvals=array(
- array(@$alscores[$allang], @$acscores[$gtcs]),
- array(@$alscores[$noct[0]], @$acscores[$gtcs]),
- array(@$alscores[$allang], @$acscores["*"]),
- array(@$alscores[$noct[0]], @$acscores["*"]),
- array(@$alscores["*"], @$acscores[$gtcs]),
- array(@$alscores["*"], @$acscores["*"]));
-
- $found=FALSE;
- foreach($testvals as $tval) {
- if(!$found && isset($tval[0]) && isset($tval[1])) {
- $arr=find_match($curlscore, $curcscore, $curgtlang, $tval[0],
- $tval[1], $gtlang);
- $curlscore=$arr[0];
- $curcscore=$arr[1];
- $curgtlang=$arr[2];
- $found=TRUE;
- }
- }
- }
-
- /* We must re-parse the gettext-string now, since we may have found it
- * through a "*" qualifier.*/
-
- $gtparts=@preg_split("/\./",$curgtlang);
- $tmp=strtolower($gtparts[0]);
- $lang=preg_replace("/\_/", "-", $tmp);
- $charset=$gtparts[1];
-
- header("Content-Language: $lang");
- header("Content-Type: $mime; charset=$charset");
-
- return $curgtlang;
-}
-
-?>
--
cgit v1.2.3-54-g00ecf
From 119a4226d812918733a815a896cfed8380188c15 Mon Sep 17 00:00:00 2001
From: Andrew Dolgov
Date: Fri, 12 Feb 2021 21:21:23 +0300
Subject: validate_csrf: remove warning
---
include/functions.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/include/functions.php b/include/functions.php
index 6362adbbe..eaf7d8243 100644
--- a/include/functions.php
+++ b/include/functions.php
@@ -310,7 +310,7 @@
}
function validate_csrf($csrf_token) {
- return isset($csrf_token) && hash_equals($_SESSION['csrf_token'], $csrf_token);
+ return isset($csrf_token) && hash_equals($_SESSION['csrf_token'] ?? "", $csrf_token);
}
function truncate_string($str, $max_len, $suffix = '…') {
--
cgit v1.2.3-54-g00ecf
From e6624cf631f772f2a1eac9412e7a96d6545e91e6 Mon Sep 17 00:00:00 2001
From: Andrew Dolgov
Date: Fri, 12 Feb 2021 21:24:49 +0300
Subject: fix a few more session-related warnings
---
backend.php | 2 +-
classes/handler/protected.php | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/backend.php b/backend.php
index dec79f46f..2ea396987 100644
--- a/backend.php
+++ b/backend.php
@@ -46,7 +46,7 @@
UserHelper::authenticate( "admin", null);
}
- if ($_SESSION["uid"]) {
+ if (!empty($_SESSION["uid"])) {
if (!validate_session()) {
header("Content-Type: text/json");
print error_json(6);
diff --git a/classes/handler/protected.php b/classes/handler/protected.php
index 765b17480..8e9e5ca1d 100644
--- a/classes/handler/protected.php
+++ b/classes/handler/protected.php
@@ -2,6 +2,6 @@
class Handler_Protected extends Handler {
function before($method) {
- return parent::before($method) && $_SESSION['uid'];
+ return parent::before($method) && !empty($_SESSION['uid']);
}
}
--
cgit v1.2.3-54-g00ecf
From 6af83e3881b3f38104027275913f7fc55251d020 Mon Sep 17 00:00:00 2001
From: Andrew Dolgov
Date: Fri, 12 Feb 2021 21:43:38 +0300
Subject: drop ENABLE_GZIP_OUTPUT; system prefs: load php info only if needed
---
api/index.php | 8 +-------
backend.php | 4 ----
classes/pref/system.php | 20 +++++++++++++-------
config.php-dist | 7 -------
include/sanity_config.php | 4 ++--
js/PrefHelpers.js | 7 +++++++
public.php | 4 ----
7 files changed, 23 insertions(+), 31 deletions(-)
diff --git a/api/index.php b/api/index.php
index 77552af46..9e998df84 100644
--- a/api/index.php
+++ b/api/index.php
@@ -22,13 +22,7 @@
ini_set('session.use_cookies', 0);
ini_set("session.gc_maxlifetime", 86400);
- if (defined('ENABLE_GZIP_OUTPUT') && ENABLE_GZIP_OUTPUT &&
- function_exists("ob_gzhandler")) {
-
- ob_start("ob_gzhandler");
- } else {
- ob_start();
- }
+ ob_start();
$input = file_get_contents("php://input");
diff --git a/backend.php b/backend.php
index 2ea396987..030676dcb 100644
--- a/backend.php
+++ b/backend.php
@@ -38,10 +38,6 @@
header("Content-Type: text/json; charset=utf-8");
- if (ENABLE_GZIP_OUTPUT && function_exists("ob_gzhandler")) {
- ob_start("ob_gzhandler");
- }
-
if (SINGLE_USER_MODE) {
UserHelper::authenticate( "admin", null);
}
diff --git a/classes/pref/system.php b/classes/pref/system.php
index d91339698..a7512915a 100644
--- a/classes/pref/system.php
+++ b/classes/pref/system.php
@@ -25,6 +25,15 @@ class Pref_System extends Handler_Protected {
$this->pdo->query("DELETE FROM ttrss_error_log");
}
+ function getphpinfo() {
+ ob_start();
+ phpinfo();
+ $info = ob_get_contents();
+ ob_end_clean();
+
+ print preg_replace( '%^.*(.*).*$%ms','$1', $info);
+ }
+
private function log_viewer(int $page, int $severity) {
$errno_values = [];
@@ -167,14 +176,11 @@ class Pref_System extends Handler_Protected {
print "";
- ob_start();
- phpinfo();
- $info = ob_get_contents();
- ob_end_clean();
+ print "";
- print "
";
- print preg_replace( '%^.*(.*).*$%ms','$1', $info);
- print "
";
+ print "
" . __("Loading, please wait...") . "
";
print "
"; # accordion pane
diff --git a/config.php-dist b/config.php-dist
index cd0ee0078..2ee1c719d 100644
--- a/config.php-dist
+++ b/config.php-dist
@@ -122,13 +122,6 @@
define('CHECK_FOR_UPDATES', true);
// Check for updates automatically if running Git version
- define('ENABLE_GZIP_OUTPUT', false);
- // Selectively gzip output to improve wire performance. This requires
- // PHP Zlib extension on the server.
- // Enabling this can break tt-rss in several httpd/php configurations,
- // if you experience weird errors and tt-rss failing to start, blank pages
- // after login, or content encoding errors, disable it.
-
define('PLUGINS', 'auth_internal, note');
// Comma-separated list of plugins to load automatically for all users.
// System plugins have to be specified here. Please enable at least one
diff --git a/include/sanity_config.php b/include/sanity_config.php
index 7aa4f6b0f..5059ee83b 100644
--- a/include/sanity_config.php
+++ b/include/sanity_config.php
@@ -1,3 +1,3 @@
-
+$required_defines = array( 'DB_TYPE', 'DB_HOST', 'DB_USER', 'DB_NAME', 'DB_PASS', 'MYSQL_CHARSET', 'SELF_URL_PATH', 'SINGLE_USER_MODE', 'SIMPLE_UPDATE_MODE', 'PHP_EXECUTABLE', 'LOCK_DIRECTORY', 'CACHE_DIR', 'ICONS_DIR', 'ICONS_URL', 'AUTH_AUTO_CREATE', 'AUTH_AUTO_LOGIN', 'FORCE_ARTICLE_PURGE', 'SESSION_COOKIE_LIFETIME', 'SMTP_FROM_NAME', 'SMTP_FROM_ADDRESS', 'DIGEST_SUBJECT', 'CHECK_FOR_UPDATES', 'PLUGINS', 'LOG_DESTINATION', 'CONFIG_VERSION'); ?>
diff --git a/js/PrefHelpers.js b/js/PrefHelpers.js
index 5bb76d179..3b9e985a6 100644
--- a/js/PrefHelpers.js
+++ b/js/PrefHelpers.js
@@ -51,6 +51,13 @@ const Helpers = {
return false;
},
+ System: {
+ getPHPInfo: function(widget) {
+ xhrPost("backend.php", {op: 'pref-system', method: 'getphpinfo'}, (transport) => {
+ widget.attr('content', transport.responseText);
+ });
+ }
+ },
EventLog: {
log_page: 0,
refresh: function() {
diff --git a/public.php b/public.php
index 36308e25e..3e4a9e023 100644
--- a/public.php
+++ b/public.php
@@ -16,10 +16,6 @@
if (!init_plugins()) return;
- if (ENABLE_GZIP_OUTPUT && function_exists("ob_gzhandler")) {
- ob_start("ob_gzhandler");
- }
-
$method = $_REQUEST["op"];
$override = PluginHost::getInstance()->lookup_handler("public", $method);
--
cgit v1.2.3-54-g00ecf
From 481bd7610059cfa09282a03e1a9c8dbc213f4819 Mon Sep 17 00:00:00 2001
From: Andrew Dolgov
Date: Fri, 12 Feb 2021 21:51:32 +0300
Subject: pref helpers: move some methods to their own sections
---
classes/pref/feeds.php | 2 +-
classes/pref/prefs.php | 8 +-
js/PrefHelpers.js | 270 +++++++++++++++++++++++++------------------------
3 files changed, 143 insertions(+), 137 deletions(-)
diff --git a/classes/pref/feeds.php b/classes/pref/feeds.php
index 47e5689ec..ff9e69336 100755
--- a/classes/pref/feeds.php
+++ b/classes/pref/feeds.php
@@ -1394,7 +1394,7 @@ class Pref_Feeds extends Handler_Protected {
print "".
__('Display URL')."
- ".
+ ".
__('Clear all generated URLs')." ";
PluginHost::getInstance()->run_hooks(PluginHost::HOOK_PREFS_TAB_SECTION, "prefFeedsPublishedGenerated");
diff --git a/classes/pref/prefs.php b/classes/pref/prefs.php
index d40dc87c0..cfe63ce85 100644
--- a/classes/pref/prefs.php
+++ b/classes/pref/prefs.php
@@ -715,7 +715,7 @@ class Pref_Prefs extends Handler_Protected {
print "";
print " " . __('Customize') . " ";
+ onclick=\"Helpers.Prefs.customizeCSS()\">" . __('Customize') . " ";
print "
open_in_new ".__("More themes...")." ";
@@ -830,10 +830,10 @@ class Pref_Prefs extends Handler_Protected {
";
- print "".
+ print "".
__('Manage profiles')." ";
- print "".
+ print "".
__('Reset to defaults')." ";
print " ";
@@ -968,7 +968,7 @@ class Pref_Prefs extends Handler_Protected {
if (count($tmppluginhost->get_all($plugin)) > 0) {
if (in_array($name, $system_enabled) || in_array($name, $user_enabled)) {
print "
+ onclick=\"Helpers.Prefs.clearPluginData('$name')\">
clear ".__("Clear data")." ";
}
}
diff --git a/js/PrefHelpers.js b/js/PrefHelpers.js
index 3b9e985a6..b09beb995 100644
--- a/js/PrefHelpers.js
+++ b/js/PrefHelpers.js
@@ -40,16 +40,18 @@ const Helpers = {
}
},
},
- clearFeedAccessKeys: function() {
- if (confirm(__("This will invalidate all previously generated feed URLs. Continue?"))) {
- Notify.progress("Clearing URLs...");
+ Feeds: {
+ clearFeedAccessKeys: function() {
+ if (confirm(__("This will invalidate all previously generated feed URLs. Continue?"))) {
+ Notify.progress("Clearing URLs...");
- xhrPost("backend.php", {op: "pref-feeds", method: "clearKeys"}, () => {
- Notify.info("Generated URLs cleared.");
- });
- }
+ xhrPost("backend.php", {op: "pref-feeds", method: "clearKeys"}, () => {
+ Notify.info("Generated URLs cleared.");
+ });
+ }
- return false;
+ return false;
+ },
},
System: {
getPHPInfo: function(widget) {
@@ -90,151 +92,155 @@ const Helpers = {
}
},
},
- editProfiles: function() {
- const dialog = new fox.SingleUseDialog({
- id: "profileEditDlg",
- title: __("Settings Profiles"),
- getSelectedProfiles: function () {
- return Tables.getSelected("pref-profiles-list");
- },
- removeSelected: function () {
- const sel_rows = this.getSelectedProfiles();
-
- if (sel_rows.length > 0) {
- if (confirm(__("Remove selected profiles? Active and default profiles will not be removed."))) {
- Notify.progress("Removing selected profiles...", true);
-
- const query = {
- op: "rpc", method: "remprofiles",
- ids: sel_rows.toString()
- };
+ Profiles: {
+ edit: function() {
+ const dialog = new fox.SingleUseDialog({
+ id: "profileEditDlg",
+ title: __("Settings Profiles"),
+ getSelectedProfiles: function () {
+ return Tables.getSelected("pref-profiles-list");
+ },
+ removeSelected: function () {
+ const sel_rows = this.getSelectedProfiles();
+
+ if (sel_rows.length > 0) {
+ if (confirm(__("Remove selected profiles? Active and default profiles will not be removed."))) {
+ Notify.progress("Removing selected profiles...", true);
+
+ const query = {
+ op: "rpc", method: "remprofiles",
+ ids: sel_rows.toString()
+ };
+
+ xhrPost("backend.php", query, () => {
+ Notify.close();
+ dialog.refresh();
+ });
+ }
+
+ } else {
+ alert(__("No profiles selected."));
+ }
+ },
+ addProfile: function () {
+ if (this.validate()) {
+ Notify.progress("Creating profile...", true);
+
+ const query = {op: "rpc", method: "addprofile", title: dialog.attr('value').newprofile};
xhrPost("backend.php", query, () => {
Notify.close();
dialog.refresh();
});
- }
-
- } else {
- alert(__("No profiles selected."));
- }
- },
- addProfile: function () {
- if (this.validate()) {
- Notify.progress("Creating profile...", true);
-
- const query = {op: "rpc", method: "addprofile", title: dialog.attr('value').newprofile};
- xhrPost("backend.php", query, () => {
- Notify.close();
- dialog.refresh();
+ }
+ },
+ refresh: function() {
+ xhrPost("backend.php", {op: 'pref-prefs', method: 'editPrefProfiles'}, (transport) => {
+ dialog.attr('content', transport.responseText);
});
+ },
+ execute: function () {
+ const sel_rows = this.getSelectedProfiles();
- }
- },
- refresh: function() {
- xhrPost("backend.php", {op: 'pref-prefs', method: 'editPrefProfiles'}, (transport) => {
- dialog.attr('content', transport.responseText);
- });
- },
- execute: function () {
- const sel_rows = this.getSelectedProfiles();
+ if (sel_rows.length == 1) {
+ if (confirm(__("Activate selected profile?"))) {
+ Notify.progress("Loading, please wait...");
- if (sel_rows.length == 1) {
- if (confirm(__("Activate selected profile?"))) {
- Notify.progress("Loading, please wait...");
+ xhrPost("backend.php", {op: "rpc", method: "setprofile", id: sel_rows.toString()}, () => {
+ window.location.reload();
+ });
+ }
- xhrPost("backend.php", {op: "rpc", method: "setprofile", id: sel_rows.toString()}, () => {
- window.location.reload();
- });
+ } else {
+ alert(__("Please choose a profile to activate."));
}
+ },
+ content: ""
+ });
- } else {
- alert(__("Please choose a profile to activate."));
- }
- },
- content: ""
- });
-
- dialog.refresh();
- dialog.show();
+ dialog.refresh();
+ dialog.show();
+ },
},
- customizeCSS: function() {
- xhrJson("backend.php", {op: "pref-prefs", method: "customizeCSS"}, (reply) => {
+ Prefs: {
+ customizeCSS: function() {
+ xhrJson("backend.php", {op: "pref-prefs", method: "customizeCSS"}, (reply) => {
+
+ const dialog = new fox.SingleUseDialog({
+ title: __("Customize stylesheet"),
+ apply: function() {
+ xhrPost("backend.php", this.attr('value'), () => {
+ new Effect.Appear("css_edit_apply_msg");
+ $("user_css_style").innerText = this.attr('value');
+ });
+ },
+ execute: function () {
+ Notify.progress('Saving data...', true);
- const dialog = new fox.SingleUseDialog({
- title: __("Customize stylesheet"),
- apply: function() {
- xhrPost("backend.php", this.attr('value'), () => {
- new Effect.Appear("css_edit_apply_msg");
- $("user_css_style").innerText = this.attr('value');
- });
- },
- execute: function () {
- Notify.progress('Saving data...', true);
+ xhrPost("backend.php", this.attr('value'), () => {
+ window.location.reload();
+ });
+ },
+ content: `
+
+ ${__("You can override colors, fonts and layout of your currently selected theme with custom CSS declarations here.")}
+
- xhrPost("backend.php", this.attr('value'), () => {
- window.location.reload();
- });
- },
- content: `
-
- ${__("You can override colors, fonts and layout of your currently selected theme with custom CSS declarations here.")}
-
-
- ${App.FormFields.hidden('op', 'rpc')}
- ${App.FormFields.hidden('method', 'setpref')}
- ${App.FormFields.hidden('key', 'USER_STYLESHEET')}
-
-
-
- ${__("User CSS has been applied, you might need to reload the page to see all changes.")}
+ ${App.FormFields.hidden('op', 'rpc')}
+ ${App.FormFields.hidden('method', 'setpref')}
+ ${App.FormFields.hidden('key', 'USER_STYLESHEET')}
+
+
+
+ ${__("User CSS has been applied, you might need to reload the page to see all changes.")}
+
-
-
-
-
-
-
- ${__('Apply')}
-
-
- ${__('Save and reload')}
-
-
- ${__('Cancel')}
-
-
- `
- });
- dialog.show();
+
+
+
+
+ ${__('Apply')}
+
+
+ ${__('Save and reload')}
+
+
+ ${__('Cancel')}
+
+
+ `
+ });
+
+ dialog.show();
- });
- },
- confirmReset: function() {
- if (confirm(__("Reset to defaults?"))) {
- xhrPost("backend.php", {op: "pref-prefs", method: "resetconfig"}, (transport) => {
- Helpers.refresh();
- Notify.info(transport.responseText);
});
- }
- },
- clearPluginData: function(name) {
- if (confirm(__("Clear stored data for this plugin?"))) {
- Notify.progress("Loading, please wait...");
+ },
+ confirmReset: function() {
+ if (confirm(__("Reset to defaults?"))) {
+ xhrPost("backend.php", {op: "pref-prefs", method: "resetconfig"}, (transport) => {
+ Helpers.Prefs.refresh();
+ Notify.info(transport.responseText);
+ });
+ }
+ },
+ clearPluginData: function(name) {
+ if (confirm(__("Clear stored data for this plugin?"))) {
+ Notify.progress("Loading, please wait...");
- xhrPost("backend.php", {op: "pref-prefs", method: "clearplugindata", name: name}, () => {
- Helpers.refresh();
+ xhrPost("backend.php", {op: "pref-prefs", method: "clearplugindata", name: name}, () => {
+ Helpers.Prefs.refresh();
+ });
+ }
+ },
+ refresh: function() {
+ xhrPost("backend.php", { op: "pref-prefs" }, (transport) => {
+ dijit.byId('prefsTab').attr('content', transport.responseText);
+ Notify.close();
});
- }
- },
- refresh: function() {
- xhrPost("backend.php", { op: "pref-prefs" }, (transport) => {
- dijit.byId('prefsTab').attr('content', transport.responseText);
- Notify.close();
- });
+ },
},
OPML: {
import: function() {
--
cgit v1.2.3-54-g00ecf
From d3940b625962048b6a7f951ba76f872ce2c1f6d2 Mon Sep 17 00:00:00 2001
From: Andrew Dolgov
Date: Fri, 12 Feb 2021 22:00:33 +0300
Subject: fix a bunch of warnings related to generated feeds
---
classes/handler/public.php | 22 ++++++++++------------
1 file changed, 10 insertions(+), 12 deletions(-)
diff --git a/classes/handler/public.php b/classes/handler/public.php
index fca471122..db8a924ad 100755
--- a/classes/handler/public.php
+++ b/classes/handler/public.php
@@ -163,7 +163,7 @@ class Handler_Public extends Handler {
$tpl->addBlock('feed');
$tpl->generateOutputToString($tmp);
- if (@!clean($_REQUEST["noxml"])) {
+ if (empty($_REQUEST["noxml"])) {
header("Content-Type: text/xml; charset=utf-8");
} else {
header("Content-Type: text/plain; charset=utf-8");
@@ -460,19 +460,17 @@ class Handler_Public extends Handler {
function rss() {
$feed = clean($_REQUEST["id"]);
$key = clean($_REQUEST["key"]);
- $is_cat = clean($_REQUEST["is_cat"]);
- $limit = (int)clean($_REQUEST["limit"]);
- $offset = (int)clean($_REQUEST["offset"]);
+ $is_cat = clean($_REQUEST["is_cat"] ?? false);
+ $limit = (int)clean($_REQUEST["limit"] ?? 0);
+ $offset = (int)clean($_REQUEST["offset"] ?? 0);
- $search = clean($_REQUEST["q"]);
- $view_mode = clean($_REQUEST["view-mode"]);
- $order = clean($_REQUEST["order"]);
- $start_ts = clean($_REQUEST["ts"]);
+ $search = clean($_REQUEST["q"] ?? "");
+ $view_mode = clean($_REQUEST["view-mode"] ?? "");
+ $order = clean($_REQUEST["order"] ?? "");
+ $start_ts = (int)clean($_REQUEST["ts"] ?? 0);
- $format = clean($_REQUEST['format']);
- $orig_guid = clean($_REQUEST["orig_guid"]);
-
- if (!$format) $format = 'atom';
+ $format = clean($_REQUEST['format'] ?? "atom");
+ $orig_guid = clean($_REQUEST["orig_guid"] ?? false);
if (SINGLE_USER_MODE) {
UserHelper::authenticate("admin", null);
--
cgit v1.2.3-54-g00ecf
From eec5871f5f0de01e7a4bf5ba69c81315a8ea88e3 Mon Sep 17 00:00:00 2001
From: Andrew Dolgov
Date: Sat, 13 Feb 2021 10:10:44 +0300
Subject: fail better if requested article URL is blank
---
classes/article.php | 28 +++++++++++++++++++++++-----
classes/rpc.php | 17 -----------------
js/Article.js | 4 +++-
js/CommonFilters.js | 2 +-
4 files changed, 27 insertions(+), 24 deletions(-)
diff --git a/classes/article.php b/classes/article.php
index 6d3746968..7f5311668 100755
--- a/classes/article.php
+++ b/classes/article.php
@@ -5,7 +5,7 @@ class Article extends Handler_Protected {
const ARTICLE_KIND_YOUTUBE = 3;
function redirect() {
- $id = clean($_REQUEST['id']);
+ $id = (int) clean($_REQUEST['id'] ?? 0);
$sth = $this->pdo->prepare("SELECT link FROM ttrss_entries, ttrss_user_entries
WHERE id = ? AND id = ref_id AND owner_uid = ?
@@ -13,11 +13,14 @@ class Article extends Handler_Protected {
$sth->execute([$id, $_SESSION['uid']]);
if ($row = $sth->fetch()) {
- $article_url = $row['link'];
- $article_url = str_replace("\n", "", $article_url);
+ $article_url = UrlHelper::validate(str_replace("\n", "", $row['link']));
- header("Location: $article_url");
- return;
+ if ($article_url) {
+ header("Location: $article_url");
+ } else {
+ header($_SERVER["SERVER_PROTOCOL"]." 404 Not Found");
+ print "URL of article $id is blank.";
+ }
} else {
print_error(__("Article not found."));
@@ -595,6 +598,21 @@ class Article extends Handler_Protected {
";
}
+ function get_metadata_by_id() {
+ $id = clean($_REQUEST['id']);
+
+ $sth = $this->pdo->prepare("SELECT link, title FROM ttrss_entries, ttrss_user_entries
+ WHERE ref_id = ? AND ref_id = id AND owner_uid = ?");
+ $sth->execute([$id, $_SESSION['uid']]);
+
+ if ($row = $sth->fetch()) {
+ $link = $row['link'];
+ $title = $row['title'];
+
+ echo json_encode(["link" => $link, "title" => $title]);
+ }
+ }
+
static function get_article_enclosures($id) {
$pdo = Db::pdo();
diff --git a/classes/rpc.php b/classes/rpc.php
index f8af1d660..f6b57775d 100755
--- a/classes/rpc.php
+++ b/classes/rpc.php
@@ -382,23 +382,6 @@ class RPC extends Handler_Protected {
$sth->execute(array_merge($ids, [$_SESSION['uid']]));
}
- function getlinktitlebyid() {
- $id = clean($_REQUEST['id']);
-
- $sth = $this->pdo->prepare("SELECT link, title FROM ttrss_entries, ttrss_user_entries
- WHERE ref_id = ? AND ref_id = id AND owner_uid = ?");
- $sth->execute([$id, $_SESSION['uid']]);
-
- if ($row = $sth->fetch()) {
- $link = $row['link'];
- $title = $row['title'];
-
- echo json_encode(array("link" => $link, "title" => $title));
- } else {
- echo json_encode(array("error" => "ARTICLE_NOT_FOUND"));
- }
- }
-
function log() {
$msg = clean($_REQUEST['msg']);
$file = basename(clean($_REQUEST['file']));
diff --git a/js/Article.js b/js/Article.js
index 61368dfed..f8b0415b9 100644
--- a/js/Article.js
+++ b/js/Article.js
@@ -123,11 +123,13 @@ const Article = {
Article.setActive(0);
},
displayUrl: function (id) {
- const query = {op: "rpc", method: "getlinktitlebyid", id: id};
+ const query = {op: "article", method: "get_metadata_by_id", id: id};
xhrJson("backend.php", query, (reply) => {
if (reply && reply.link) {
prompt(__("Article URL:"), reply.link);
+ } else {
+ alert(__("No URL could be displayed for this article."));
}
});
},
diff --git a/js/CommonFilters.js b/js/CommonFilters.js
index 802cf478d..15403b8c4 100644
--- a/js/CommonFilters.js
+++ b/js/CommonFilters.js
@@ -332,7 +332,7 @@ const Filters = {
} else {
- const query = {op: "rpc", method: "getlinktitlebyid", id: Article.getActive()};
+ const query = {op: "article", method: "get_metadata_by_id", id: Article.getActive()};
xhrPost("backend.php", query, (transport) => {
const reply = JSON.parse(transport.responseText);
--
cgit v1.2.3-54-g00ecf
From e7924c6dacef405a6e20b41d078f4a90a210cb51 Mon Sep 17 00:00:00 2001
From: Andrew Dolgov
Date: Sat, 13 Feb 2021 13:17:34 +0300
Subject: label editor: use client dialog
---
classes/pref/labels.php | 68 ++------------------
js/App.js | 4 +-
js/PrefLabelTree.js | 167 ++++++++++++++++++++++++++++++++----------------
3 files changed, 120 insertions(+), 119 deletions(-)
diff --git a/classes/pref/labels.php b/classes/pref/labels.php
index a787ce388..6102ab8dd 100644
--- a/classes/pref/labels.php
+++ b/classes/pref/labels.php
@@ -10,72 +10,14 @@ class Pref_Labels extends Handler_Protected {
function edit() {
$label_id = clean($_REQUEST['id']);
- $sth = $this->pdo->prepare("SELECT * FROM ttrss_labels2 WHERE
+ $sth = $this->pdo->prepare("SELECT id, caption, fg_color, bg_color FROM ttrss_labels2 WHERE
id = ? AND owner_uid = ?");
$sth->execute([$label_id, $_SESSION['uid']]);
- if ($line = $sth->fetch()) {
-
- print_hidden("id", "$label_id");
- print_hidden("op", "pref-labels");
- print_hidden("method", "save");
-
- print "";
+ if ($line = $sth->fetch(PDO::FETCH_ASSOC)) {
+ print json_encode($line);
+ } else {
+ print json_encode(["error" => "LABEL_NOT_FOUND"]);
}
}
diff --git a/js/App.js b/js/App.js
index 514a6d4b7..4646145ea 100644
--- a/js/App.js
+++ b/js/App.js
@@ -18,8 +18,8 @@ const App = {
is_prefs: false,
LABEL_BASE_INDEX: -1024,
FormFields: {
- hidden: function(name, value) {
- return ` `
+ hidden: function(name, value, id = "") {
+ return ` `
}
},
Scrollable: {
diff --git a/js/PrefLabelTree.js b/js/PrefLabelTree.js
index 73f375f2d..88e88b669 100644
--- a/js/PrefLabelTree.js
+++ b/js/PrefLabelTree.js
@@ -1,5 +1,5 @@
/* eslint-disable prefer-rest-params */
-/* global __, define, lib, dijit, dojo, xhrPost, Notify, fox */
+/* global __, define, lib, dijit, dojo, xhrPost, Notify, fox, App */
define(["dojo/_base/declare", "dojo/dom-construct", "lib/CheckBoxTree", "dijit/form/DropDownButton"], function (declare, domConstruct) {
@@ -61,70 +61,129 @@ define(["dojo/_base/declare", "dojo/dom-construct", "lib/CheckBoxTree", "dijit/f
});
},
editLabel: function(id) {
- const dialog = new fox.SingleUseDialog({
- id: "labelEditDlg",
- title: __("Label Editor"),
- style: "width: 650px",
- setLabelColor: function (id, fg, bg) {
-
- let kind = '';
- let color = '';
-
- if (fg && bg) {
- kind = 'both';
- } else if (fg) {
- kind = 'fg';
- color = fg;
- } else if (bg) {
- kind = 'bg';
- color = bg;
- }
-
- const e = $("icon-label-" + id);
-
- if (e) {
- if (bg) e.style.color = bg;
- }
+ xhrJson("backend.php", {op: "pref-labels", method: "edit", id: id}, (reply) => {
- const query = {
- op: "pref-labels", method: "colorset", kind: kind,
- ids: id, fg: fg, bg: bg, color: color
- };
+ console.log(reply);
- xhrPost("backend.php", query, () => {
- const tree = dijit.byId("filterTree");
- if (tree) tree.reload(); // maybe there's labels in there
- });
+ const fg_color = reply['fg_color'];
+ const bg_color = reply['bg_color'] ? reply['bg_color'] : '#fff7d5';
+
+ const dialog = new fox.SingleUseDialog({
+ id: "labelEditDlg",
+ title: __("Label Editor"),
+ style: "width: 650px",
+ setLabelColor: function (id, fg, bg) {
+
+ let kind = '';
+ let color = '';
- },
- execute: function () {
- if (this.validate()) {
- const caption = this.attr('value').caption;
- const fg_color = this.attr('value').fg_color;
- const bg_color = this.attr('value').bg_color;
+ if (fg && bg) {
+ kind = 'both';
+ } else if (fg) {
+ kind = 'fg';
+ color = fg;
+ } else if (bg) {
+ kind = 'bg';
+ color = bg;
+ }
- dijit.byId('labelTree').setNameById(id, caption);
- this.setLabelColor(id, fg_color, bg_color);
- this.hide();
+ const e = $("icon-label-" + id);
- xhrPost("backend.php", this.attr('value'), () => {
+ if (e) {
+ if (bg) e.style.color = bg;
+ }
+
+ const query = {
+ op: "pref-labels", method: "colorset", kind: kind,
+ ids: id, fg: fg, bg: bg, color: color
+ };
+
+ xhrPost("backend.php", query, () => {
const tree = dijit.byId("filterTree");
if (tree) tree.reload(); // maybe there's labels in there
});
- }
- },
- content: __("Loading, please wait...")
- });
- const tmph = dojo.connect(dialog, 'onShow', function () {
- dojo.disconnect(tmph);
+ },
+ execute: function () {
+ if (this.validate()) {
+ const caption = this.attr('value').caption;
+ const fg_color = this.attr('value').fg_color;
+ const bg_color = this.attr('value').bg_color;
+
+ dijit.byId('labelTree').setNameById(id, caption);
+ this.setLabelColor(id, fg_color, bg_color);
+ this.hide();
+
+ xhrPost("backend.php", this.attr('value'), () => {
+ const tree = dijit.byId("filterTree");
+ if (tree) tree.reload(); // maybe there's labels in there
+ });
+ }
+ },
+ content: `
+
+ `
+ });
- xhrPost("backend.php", {op: "pref-labels", method: "edit", id: id}, (transport) => {
- dialog.attr('content', transport.responseText);
- })
- });
+ dialog.show();
- dialog.show();
+ });
},
resetColors: function() {
const labels = this.getSelectedLabels();
--
cgit v1.2.3-54-g00ecf
From 46f6d7c11a85f78ffaad649b7f591effff52706f Mon Sep 17 00:00:00 2001
From: Andrew Dolgov
Date: Sat, 13 Feb 2021 13:26:17 +0300
Subject: pref-labels/index: cleanup
---
classes/pref/labels.php | 115 +++++++++++++++++++++++-------------------------
1 file changed, 56 insertions(+), 59 deletions(-)
diff --git a/classes/pref/labels.php b/classes/pref/labels.php
index 6102ab8dd..acaabb233 100644
--- a/classes/pref/labels.php
+++ b/classes/pref/labels.php
@@ -190,65 +190,62 @@ class Pref_Labels extends Handler_Protected {
}
function index() {
-
- print "";
- print "
";
- print "
";
-
- print "
".
- "
" . __('Select')." ";
- print "
";
- print "
".__('All')."
";
- print "
".__('None')."
";
- print "
";
-
- print"
".
- __('Create label')." ";
-
- print "
".
- __('Remove')." ";
-
- print "
".
- __('Clear colors')." ";
-
-
- print "
"; #toolbar
- print "
"; #pane
- print "
";
-
- print "
-
".
- __("Loading, please wait...")."
";
-
- print "
-
-
+ ?>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ run_hooks(PluginHost::HOOK_PREFS_TAB, "prefLabels") ?>
-
-
-
-
";
-
- print "
"; #pane
-
- PluginHost::getInstance()->run_hooks(PluginHost::HOOK_PREFS_TAB, "prefLabels");
-
- print "
"; #container
-
+
Date: Sat, 13 Feb 2021 13:37:57 +0300
Subject: pref-labels index: use cleaner markup
---
classes/pref/system.php | 56 +++++++++++++++++++++----------------------------
1 file changed, 24 insertions(+), 32 deletions(-)
diff --git a/classes/pref/system.php b/classes/pref/system.php
index a7512915a..763440d78 100644
--- a/classes/pref/system.php
+++ b/classes/pref/system.php
@@ -150,43 +150,35 @@ class Pref_System extends Handler_Protected {
}
print "";
+ print "
";
+ print "";
}
function index() {
$severity = (int) ($_REQUEST["severity"] ?? E_USER_WARNING);
$page = (int) ($_REQUEST["page"] ?? 0);
-
- print "";
- print "
";
-
- if (LOG_DESTINATION == "sql") {
-
- $this->log_viewer($page, $severity);
-
- } else {
- print_notice("Please set LOG_DESTINATION to 'sql' in config.php to enable database logging.");
- }
-
- print "
"; # content pane
- print "
"; # container
- print ""; # accordion pane
-
- print "";
-
- print "";
-
- print "
" . __("Loading, please wait...") . "
";
-
- print "
"; # accordion pane
-
- PluginHost::getInstance()->run_hooks(PluginHost::HOOK_PREFS_TAB, "prefSystem");
-
- print ""; #container
+ ?>
+
+
'>
+ log_viewer($page, $severity);
+ } else {
+ print_notice("Please set LOG_DESTINATION to 'sql' in config.php to enable database logging.");
+ }
+ ?>
+
+
+
+
+ run_hooks(PluginHost::HOOK_PREFS_TAB, "prefSystem") ?>
+
+
Date: Sat, 13 Feb 2021 13:50:53 +0300
Subject: prefs system: markup cleanup
---
classes/pref/labels.php | 2 +-
classes/pref/system.php | 164 ++++++++++++++++++++++++------------------------
2 files changed, 84 insertions(+), 82 deletions(-)
diff --git a/classes/pref/labels.php b/classes/pref/labels.php
index acaabb233..92acabd9e 100644
--- a/classes/pref/labels.php
+++ b/classes/pref/labels.php
@@ -139,7 +139,7 @@ class Pref_Labels extends Handler_Protected {
$sth->execute([$caption, $old_caption, $_SESSION['uid']]);
- print clean($_REQUEST["value"]);
+ print clean($_REQUEST["caption"]);
} else {
print $old_caption;
}
diff --git a/classes/pref/system.php b/classes/pref/system.php
index 763440d78..994e024c7 100644
--- a/classes/pref/system.php
+++ b/classes/pref/system.php
@@ -31,7 +31,7 @@ class Pref_System extends Handler_Protected {
$info = ob_get_contents();
ob_end_clean();
- print preg_replace( '%^.*(.*).*$%ms','$1', $info);
+ print preg_replace( '%^.*(.*).*$%ms','$1', (string)$info);
}
private function log_viewer(int $page, int $severity) {
@@ -71,87 +71,89 @@ class Pref_System extends Handler_Protected {
$total_pages = 0;
}
- print "";
-
- print "
";
-
- print "
".__('Refresh')." ";
-
- $prev_page_disabled = $page <= 0 ? "disabled" : "";
-
- print "
".__('<<')." ";
-
- print "
".T_sprintf('Page %d of %d', $page+1, $total_pages+1)." ";
-
- $next_page_disabled = $page >= $total_pages ? "disabled" : "";
-
- print "
".__('>>')." ";
-
- print "
".__('Clear')." ";
-
- print "
";
-
- print __("Severity:") . " ";
- print_select_hash("severity", $severity,
- [
- E_USER_ERROR => __("Errors"),
- E_USER_WARNING => __("Warnings"),
- E_USER_NOTICE => __("Everything")
- ], 'dojoType="fox.form.Select" onchange="Helpers.EventLog.refresh()"');
-
- print "
"; # pull-right
-
- print "
"; # toolbar
-
- print '
';
-
- print "
";
-
- print "
- ".__("Error")."
- ".__("Filename")."
- ".__("Message")."
- ".__("User")."
- ".__("Date")."
- ";
-
- $sth = $this->pdo->prepare("SELECT
- errno, errstr, filename, lineno, created_at, login, context
- FROM
- ttrss_error_log LEFT JOIN ttrss_users ON (owner_uid = ttrss_users.id)
- WHERE
- $errno_filter_qpart
- ORDER BY
- ttrss_error_log.id DESC
- LIMIT $limit OFFSET $offset");
-
- $sth->execute($errno_values);
-
- while ($line = $sth->fetch()) {
- print "";
-
- foreach ($line as $k => $v) {
- $line[$k] = htmlspecialchars($v);
- }
-
- print "" . Logger::$errornames[$line["errno"]] . " (" . $line["errno"] . ") ";
- print "" . $line["filename"] . ":" . $line["lineno"] . " ";
- print "" . $line["errstr"] . "\n" . $line["context"] . " ";
- print "" . $line["login"] . " ";
-
- print "" .
- TimeHelper::make_local_datetime($line["created_at"], false) . " ";
-
- print " ";
- }
+ ?>
+
+
+
+
+
+
+
+
+ onclick='Helpers.EventLog.prevPage()'>
+
+
+
+
+
+
+
+
= $total_pages ? "disabled" : "") ?>
+ onclick='Helpers.EventLog.nextPage()'>
+
+
+
+
+
+
+
+
+
+
+ __("Errors"),
+ E_USER_WARNING => __("Warnings"),
+ E_USER_NOTICE => __("Everything")
+ ], 'dojoType="fox.form.Select" onchange="Helpers.EventLog.refresh()"') ?>
+
+
- print "
";
- print "
";
- print "
";
+
+
+
+
+
+
+
+
+
+
+
+
+ pdo->prepare("SELECT
+ errno, errstr, filename, lineno, created_at, login, context
+ FROM
+ ttrss_error_log LEFT JOIN ttrss_users ON (owner_uid = ttrss_users.id)
+ WHERE
+ $errno_filter_qpart
+ ORDER BY
+ ttrss_error_log.id DESC
+ LIMIT $limit OFFSET $offset");
+
+ $sth->execute($errno_values);
+
+ while ($line = $sth->fetch()) {
+ foreach ($line as $k => $v) { $line[$k] = htmlspecialchars($v); }
+ ?>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Date: Sat, 13 Feb 2021 14:05:25 +0300
Subject: pref filters index: markup cleanup
---
classes/pref/filters.php | 133 ++++++++++++++++++++++-------------------------
1 file changed, 61 insertions(+), 72 deletions(-)
diff --git a/classes/pref/filters.php b/classes/pref/filters.php
index a24a05b05..c80a10c64 100755
--- a/classes/pref/filters.php
+++ b/classes/pref/filters.php
@@ -710,81 +710,70 @@ class Pref_Filters extends Handler_Protected {
$filter_search = ($_SESSION["prefs_filter_search"] ?? "");
}
- print "";
- print "
";
- print "
";
-
- print "
-
- ".
- __('Search')."
-
";
-
- print "
".
- "
" . __('Select')." ";
- print "
";
- print "
".__('All')."
";
- print "
".__('None')."
";
- print "
";
-
- print "
".
- __('Create filter')." ";
-
- print "
".
- __('Combine')." ";
-
- print "
".
- __('Edit')." ";
-
- print "
".
- __('Reset sort order')." ";
-
-
- print "
".
- __('Remove')." ";
-
- print "
"; # toolbar
- print "
"; # toolbar-frame
- print "
";
+ ?>
+
+
+
+
+
+
+
+
+
- print "
-
".
- __("Loading, please wait...")."
";
+
- print "
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ run_hooks(PluginHost::HOOK_PREFS_TAB, "prefFilters") ?>
-
-
-
-
-
";
-
- print "
"; #pane
-
- PluginHost::getInstance()->run_hooks(PluginHost::HOOK_PREFS_TAB, "prefFilters");
-
- print "
"; #container
-
+
Date: Sat, 13 Feb 2021 16:07:52 +0300
Subject: minor fixes re: previous
---
classes/pref/filters.php | 2 +-
classes/pref/system.php | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/classes/pref/filters.php b/classes/pref/filters.php
index c80a10c64..c83299678 100755
--- a/classes/pref/filters.php
+++ b/classes/pref/filters.php
@@ -717,7 +717,7 @@ class Pref_Filters extends Handler_Protected {
+ value="">
diff --git a/classes/pref/system.php b/classes/pref/system.php
index 994e024c7..72e15e4f3 100644
--- a/classes/pref/system.php
+++ b/classes/pref/system.php
@@ -146,7 +146,7 @@ class Pref_System extends Handler_Protected {
-
+
--
cgit v1.2.3-54-g00ecf
From 17413078a72e1298c6dc8953c40e8d83ce38c49c Mon Sep 17 00:00:00 2001
From: Andrew Dolgov
Date: Sat, 13 Feb 2021 18:32:02 +0300
Subject: pref feeds: index cleanup, split into several methods, use tabs to
maximize space for feed tree, persist feed tree state
---
classes/pref/feeds.php | 333 +++++++++++++++++++++++++----------------------
classes/pref/filters.php | 6 -
classes/pref/labels.php | 7 -
js/PrefFeedTree.js | 37 +++++-
plugins/share/init.php | 6 +-
themes/compact.css | 15 +--
themes/compact_night.css | 15 +--
themes/light.css | 15 +--
themes/light/prefs.less | 14 +-
themes/night.css | 15 +--
themes/night_blue.css | 15 +--
11 files changed, 235 insertions(+), 243 deletions(-)
diff --git a/classes/pref/feeds.php b/classes/pref/feeds.php
index ff9e69336..d8495a59c 100755
--- a/classes/pref/feeds.php
+++ b/classes/pref/feeds.php
@@ -1197,12 +1197,7 @@ class Pref_Feeds extends Handler_Protected {
$opml->opml_import($_SESSION["uid"]);
}
- function index() {
-
- print "";
- print "
rss_feed ".__('Feeds')."\">";
-
+ private function index_feeds() {
$sth = $this->pdo->prepare("SELECT COUNT(id) AS num_errors
FROM ttrss_feeds WHERE last_error != '' AND owner_uid = ?");
$sth->execute([$_SESSION['uid']]);
@@ -1214,16 +1209,15 @@ class Pref_Feeds extends Handler_Protected {
}
if ($num_errors > 0) {
- $error_button = "
" .
- __("Feeds with errors") . " ";
+ $error_button = "
".
+ __("Feeds with errors")." ";
} else {
$error_button = "";
}
- $inactive_button = "
" .
__("Inactive feeds") . " ";
@@ -1235,175 +1229,202 @@ class Pref_Feeds extends Handler_Protected {
$feed_search = $_SESSION["prefs_feed_search"] ?? "";
}
- print '
';
-
- print "
"; #toolbar
-
- print "
-
- ".
- __('Search')."
-
";
-
- print "
".
- "
" . __('Select')." ";
- print "
";
- print "
".__('All')."
";
- print "
".__('None')."
";
- print "
";
-
- print "
".
- "
" . __('Feeds')." ";
- print "
";
- print "
".__('Subscribe to feed')."
";
- print "
".__('Edit selected feeds')."
";
- print "
".__('Reset sort order')."
";
- print "
".__('Batch subscribe')."
";
- print "
"
- .__('Unsubscribe')."
";
- print "
";
-
- if (get_pref('ENABLE_FEED_CATS')) {
- print "
".
- "
" . __('Categories')." ";
- print "
";
- print "
".__('Add category')."
";
- print "
".__('Reset sort order')."
";
- print "
".__('Remove selected')."
";
- print "
";
-
- }
-
- print $error_button;
- print $inactive_button;
-
- print "
"; # toolbar
-
- //print '
';
- print '
';
-
- print "
-
".
- __("Loading, please wait...")."
";
-
- $auto_expand = $feed_search != "" ? "true" : "false";
-
- print "
-
-
+ ?>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
"
+ persist="true"
+ model="feedModel"
+ openOnClick="false">
+
+
+
+
-
-
-
-
";
-
-# print "
-# ".__('Hint: you can drag feeds and categories around.')."
-#
";
+ ';
- print '
';
-
- print "
"; # feeds pane
+ }
- print "
";
+ private function index_opml() {
+ ?>
- print "
" . __("Using OPML you can export and import your feeds, filters, labels and Tiny Tiny RSS settings.") . " ";
+
- print_notice("Only main settings profile can be migrated using OPML.");
+
- print "
- print "
";
+
- print "" .
- __('Export OPML') . " ";
+
+
+
+
- print " ";
- print_checkbox("include_settings", true, "1", "");
- print " " . __("Include settings");
- print " ";
-
- print " ";
+
+
+
+
+
- print "
";
+
- print "
" . __("Published OPML") . " ";
+
- print "
" . __('Your OPML can be published publicly and can be subscribed by anyone who knows the URL below.') .
- " " .
- __("Published OPML does not include your Tiny Tiny RSS settings, feeds that require authentication or feeds hidden from Popular feeds.") . "
";
+
+
+
+
- print "
".
- __('Display published OPML URL')." ";
+
+
+
+ run_hooks(PluginHost::HOOK_PREFS_TAB_SECTION, "prefFeedsOPML");
+ }
- print "
"; # pane
-
- print "
share ".__('Published & shared articles / Generated feeds')."\">";
-
- print "
" . __('Published articles can be subscribed by anyone who knows the following URL:') . " ";
-
+ private function index_shared() {
$rss_url = htmlspecialchars(get_self_url_prefix() .
- "/public.php?op=rss&id=-2&view-mode=all_articles");;
+ "/public.php?op=rss&id=-2&view-mode=all_articles");
+ ?>
- print "".
- __('Display URL')."
- ".
- __('Clear all generated URLs')." ";
+
- PluginHost::getInstance()->run_hooks(PluginHost::HOOK_PREFS_TAB_SECTION, "prefFeedsPublishedGenerated");
+
+
+
- print ""; #pane
+
+
+
- PluginHost::getInstance()->run_hooks(PluginHost::HOOK_PREFS_TAB, "prefFeeds");
+ run_hooks(PluginHost::HOOK_PREFS_TAB_SECTION, "prefFeedsPublishedGenerated");
+ }
- print "
"; #container
+ function index() {
+ ?>
+
+
+
+ index_feeds() ?>
+
+
+
+ index_opml() ?>
+
+
+
+ index_shared() ?>
+
+
+ run_hooks(PluginHost::HOOK_PREFS_TAB, "prefFeeds");
+ $plugin_data = trim((string)ob_get_contents());
+ ob_end_clean();
+ ?>
+
+
+
+
+
+
-
-
-
@@ -758,9 +755,6 @@ class Pref_Filters extends Handler_Protected {
-
diff --git a/js/PrefFeedTree.js b/js/PrefFeedTree.js
index e17b8744d..e0a2dd932 100644
--- a/js/PrefFeedTree.js
+++ b/js/PrefFeedTree.js
@@ -209,6 +209,13 @@ define(["dojo/_base/declare", "dojo/dom-construct", "lib/CheckBoxTree", "dojo/_b
return false;
},
+ checkErrorFeeds: function() {
+ xhrJson("backend.php", {op: "pref-feeds", method: "feedsWithErrors"}, (reply) => {
+ if (reply.length > 0) {
+ Element.show(dijit.byId("pref_feeds_errors_btn").domNode);
+ }
+ });
+ },
checkInactiveFeeds: function() {
xhrJson("backend.php", {op: "pref-feeds", method: "inactivefeeds"}, (reply) => {
if (reply.length > 0) {
diff --git a/themes/compact.css b/themes/compact.css
index f923b2ee1..36c5aec9f 100644
--- a/themes/compact.css
+++ b/themes/compact.css
@@ -1456,7 +1456,7 @@ body.ttrss_prefs #feedsTab {
body.ttrss_prefs .dijitDialog #pref-profiles-list .dijitInlineEditBoxDisplayMode {
padding: 0px;
}
-body.ttrss_prefs #errorButton {
+body.ttrss_prefs #pref_feeds_errors_btn {
color: red;
}
body.ttrss_prefs .user-css-editor {
diff --git a/themes/compact_night.css b/themes/compact_night.css
index e512e8176..e39b7020a 100644
--- a/themes/compact_night.css
+++ b/themes/compact_night.css
@@ -1456,7 +1456,7 @@ body.ttrss_prefs #feedsTab {
body.ttrss_prefs .dijitDialog #pref-profiles-list .dijitInlineEditBoxDisplayMode {
padding: 0px;
}
-body.ttrss_prefs #errorButton {
+body.ttrss_prefs #pref_feeds_errors_btn {
color: red;
}
body.ttrss_prefs .user-css-editor {
diff --git a/themes/light.css b/themes/light.css
index a19467c41..b6c487b66 100644
--- a/themes/light.css
+++ b/themes/light.css
@@ -1456,7 +1456,7 @@ body.ttrss_prefs #feedsTab {
body.ttrss_prefs .dijitDialog #pref-profiles-list .dijitInlineEditBoxDisplayMode {
padding: 0px;
}
-body.ttrss_prefs #errorButton {
+body.ttrss_prefs #pref_feeds_errors_btn {
color: red;
}
body.ttrss_prefs .user-css-editor {
diff --git a/themes/light/prefs.less b/themes/light/prefs.less
index 0206916ae..ec3006ce5 100644
--- a/themes/light/prefs.less
+++ b/themes/light/prefs.less
@@ -65,7 +65,7 @@ body.ttrss_prefs {
padding : 0px;
}
- #errorButton {
+ #pref_feeds_errors_btn {
color : red;
}
diff --git a/themes/night.css b/themes/night.css
index e2bd50142..5941fd8e1 100644
--- a/themes/night.css
+++ b/themes/night.css
@@ -1457,7 +1457,7 @@ body.ttrss_prefs #feedsTab {
body.ttrss_prefs .dijitDialog #pref-profiles-list .dijitInlineEditBoxDisplayMode {
padding: 0px;
}
-body.ttrss_prefs #errorButton {
+body.ttrss_prefs #pref_feeds_errors_btn {
color: red;
}
body.ttrss_prefs .user-css-editor {
diff --git a/themes/night_blue.css b/themes/night_blue.css
index 93027e8be..99bb191a2 100644
--- a/themes/night_blue.css
+++ b/themes/night_blue.css
@@ -1457,7 +1457,7 @@ body.ttrss_prefs #feedsTab {
body.ttrss_prefs .dijitDialog #pref-profiles-list .dijitInlineEditBoxDisplayMode {
padding: 0px;
}
-body.ttrss_prefs #errorButton {
+body.ttrss_prefs #pref_feeds_errors_btn {
color: red;
}
body.ttrss_prefs .user-css-editor {
--
cgit v1.2.3-54-g00ecf
From 15fd23c374eb32c50733de1906065f552afbfbc4 Mon Sep 17 00:00:00 2001
From: Andrew Dolgov
Date: Sun, 14 Feb 2021 09:15:51 +0300
Subject: use shortcut echo syntax for php templates
---
classes/feeds.php | 10 +++---
classes/handler/public.php | 44 +++++++++++------------
classes/pref/feeds.php | 74 +++++++++++++++++++-------------------
classes/pref/filters.php | 20 +++++------
classes/pref/labels.php | 12 +++----
classes/pref/system.php | 42 +++++++++++-----------
include/login_form.php | 34 +++++++++---------
index.php | 78 ++++++++++++++++++++---------------------
plugins/af_redditimgur/init.php | 4 +--
plugins/auth_internal/init.php | 18 +++++-----
plugins/toggle_sidebar/init.php | 2 +-
prefs.php | 28 +++++++--------
12 files changed, 183 insertions(+), 183 deletions(-)
diff --git a/classes/feeds.php b/classes/feeds.php
index 031a671ae..e6bd1459d 100755
--- a/classes/feeds.php
+++ b/classes/feeds.php
@@ -838,14 +838,14 @@ class Feeds extends Handler_Protected {
-
Feed Debugger: getFeedTitle($feed_id) ?>
+
Feed Debugger: = "$feed_id: " . $this->getFeedTitle($feed_id) ?>
-
+
-
+
@@ -856,11 +856,11 @@ class Feeds extends Handler_Protected {
- > Force refetch
+ > Force refetch
- > Force rehash
+ > Force rehash
Continue
diff --git a/classes/handler/public.php b/classes/handler/public.php
index db8a924ad..481145606 100755
--- a/classes/handler/public.php
+++ b/classes/handler/public.php
@@ -519,7 +519,7 @@ class Handler_Public extends Handler {
-
+ = __("Share with Tiny Tiny RSS") ?>
-
-
+ = __("Title:") ?>
+
-
-
+ = __("URL:") ?>
+
-
+ = __("Content:") ?>
-
+ = __("Labels:") ?>
-
-
-
+ = __('Share') ?>
+ = __('Cancel') ?>
+ = __("Shared article will appear in the Published feed.") ?>
@@ -635,24 +635,24 @@ class Handler_Public extends Handler {
-
+
-
+ = __("Login:") ?>
" />
+ required="1" value="= $_SESSION["fake_login"] ?>" />
-
+ = __("Password:") ?>
"/>
+ value="= $_SESSION["fake_password"] ?>"/>
@@ -660,7 +660,7 @@ class Handler_Public extends Handler {
-
+ = __('Log in') ?>
@@ -781,7 +781,7 @@ class Handler_Public extends Handler {
};
-
+
= __("Subscribe to feed...") ?>
Feed or site URL:
-
+
-
+ = __("Subscribe") ?>
-
+
= __("Return to Tiny Tiny RSS") ?>
Database Updater
-
+ = stylesheet_tag("themes/light.css") ?>
-
+
= __("Database Updater") ?>
diff --git a/classes/pref/feeds.php b/classes/pref/feeds.php
index 72a8344ad..6b5df0289 100755
--- a/classes/pref/feeds.php
+++ b/classes/pref/feeds.php
@@ -1223,52 +1223,52 @@ class Pref_Feeds extends Handler_Protected {
+ value="= htmlspecialchars($feed_search) ?>">
-
+ = __('Search') ?>
-
+
= __('Select') ?>
+ dojoType="dijit.MenuItem">= __('All') ?>
+ dojoType="dijit.MenuItem">= __('None') ?>
-
+
= __('Feeds') ?>
+ dojoType="dijit.MenuItem">= __('Subscribe to feed') ?>
+ dojoType="dijit.MenuItem">= __('Edit selected feeds') ?>
+ dojoType="dijit.MenuItem">= __('Reset sort order') ?>
+ dojoType="dijit.MenuItem">= __('Batch subscribe') ?>
-
+ = __('Unsubscribe') ?>
-
+
= __('Categories') ?>
+ dojoType="dijit.MenuItem">= __('Add category') ?>
+ dojoType="dijit.MenuItem">= __('Reset sort order') ?>
+ dojoType="dijit.MenuItem">= __('Remove selected') ?>
-
-
+ = $error_button ?>
+ = $inactive_button ?>
"
+ autoExpand="= (!empty($feed_search) ? "true" : "false") ?>"
persist="true"
model="feedModel"
openOnClick="false">
@@ -1311,19 +1311,19 @@ class Pref_Feeds extends Handler_Protected {
private function index_opml() {
?>
-
+
= __("Using OPML you can export and import your feeds, filters, labels and Tiny Tiny RSS settings.") ?>
-
+ = __("Choose file...") ?>
-
+
-
+ = __('Import OPML') ?>
@@ -1331,26 +1331,26 @@ class Pref_Feeds extends Handler_Protected {
-
+ = __('Export OPML') ?>
-
+ = __("Include settings") ?>
-
+
= __("Published OPML") ?>
-
-
+ = __('Your OPML can be published publicly and can be subscribed by anyone who knows the URL below.') ?>
+ = __("Published OPML does not include your Tiny Tiny RSS settings, feeds that require authentication or feeds hidden from Popular feeds.") ?>
-
+ = __('Display published OPML URL') ?>
-
+
= __('Published articles can be subscribed by anyone who knows the following URL:') ?>
-
+ onclick='CommonDialogs.generatedFeed(-2, false, "= $rss_url ?>", "= __("Published articles") ?>")'>
+ = __('Display URL') ?>
-
+ = __('Clear all generated URLs') ?>
+ title="rss_feed = __('My feeds') ?>">
index_feeds() ?>
+ title="import_export = __('OPML') ?>">
index_opml() ?>
+ title="share = __('Sharing') ?>">
index_shared() ?>
@@ -1405,10 +1405,10 @@ class Pref_Feeds extends Handler_Protected {
+ title="
extension = __('Plugins') ?>">
-
+ = $plugin_data ?>
diff --git a/classes/pref/filters.php b/classes/pref/filters.php
index 571ddce4a..c898a8b67 100755
--- a/classes/pref/filters.php
+++ b/classes/pref/filters.php
@@ -717,31 +717,31 @@ class Pref_Filters extends Handler_Protected {
+ value="= htmlspecialchars($filter_search) ?>">
-
+ = __('Search') ?>
-
+
= __('Select') ?>
+ dojoType="dijit.MenuItem">= __('All') ?>
+ dojoType="dijit.MenuItem">= __('None') ?>
-
+ = __('Create filter') ?>
-
+ = __('Combine') ?>
-
+ = __('Edit') ?>
-
+ = __('Reset sort order') ?>
-
+ = __('Remove') ?>
diff --git a/classes/pref/labels.php b/classes/pref/labels.php
index 22a2dddea..d182a0995 100644
--- a/classes/pref/labels.php
+++ b/classes/pref/labels.php
@@ -195,23 +195,23 @@ class Pref_Labels extends Handler_Protected {
-
+
= __('Select') ?>
+ dojoType='dijit.MenuItem'>=('All') ?>
+ dojoType='dijit.MenuItem'>=('None') ?>
-
+ =('Create label') ?>
-
+ =('Remove') ?>
-
+ =('Clear colors') ?>
diff --git a/classes/pref/system.php b/classes/pref/system.php
index 72e15e4f3..1adddf116 100644
--- a/classes/pref/system.php
+++ b/classes/pref/system.php
@@ -76,30 +76,30 @@ class Pref_System extends Handler_Protected {
-
+ = __('Refresh') ?>
-
+
onclick='Helpers.EventLog.prevPage()'>
-
+ = __('<<') ?>
-
+ = T_sprintf('Page %d of %d', $page+1, $total_pages+1) ?>
- = $total_pages ? "disabled" : "") ?>
+ = $total_pages ? "disabled" : "") ?>
onclick='Helpers.EventLog.nextPage()'>
-
+ = __('>>') ?>
-
+ = __('Clear') ?>
-
+ = __("Severity:") ?>
-
-
-
-
-
+ = __("Error") ?>
+ = __("Filename") ?>
+ = __("Message") ?>
+ = __("User") ?>
+ = __("Date") ?>
-
+ = Logger::$errornames[$line["errno"]] . " (" . $line["errno"] . ")" ?>
-
-
-
+ = $line["filename"] . ":" . $line["lineno"] ?>
+ = $line["errstr"] . "\n" . $line["context"] ?>
+ = $line["login"] ?>
-
+ = TimeHelper::make_local_datetime($line["created_at"], false) ?>
@@ -162,7 +162,7 @@ class Pref_System extends Handler_Protected {
$page = (int) ($_REQUEST["page"] ?? 0);
?>
-
'>
+
'>
log_viewer($page, $severity);
@@ -172,11 +172,11 @@ class Pref_System extends Handler_Protected {
?>
-
'>
+
'>
-
+
= __("Loading, please wait...") ?>
run_hooks(PluginHost::HOOK_PREFS_TAB, "prefSystem") ?>
diff --git a/include/login_form.php b/include/login_form.php
index aec305b13..aa6a72260 100755
--- a/include/login_form.php
+++ b/include/login_form.php
@@ -92,29 +92,29 @@
-
+
= "Authentication" ?>
-
-
+ = format_error($_SESSION["login_error_msg"]) ?>
-
+ = __("Login:") ?>
" />
+ required="1" value="= $_SESSION["fake_login"] ?? "" ?>" />
-
+ = __("Password:") ?>
"/>
+ value="= $_SESSION["fake_password"] ?? "" ?>"/>
-
+ = __("I forgot my password") ?>
-
+ = __("Profile:") ?>
-
+ = __("Default profile") ?>
@@ -143,11 +143,11 @@
-
+ = __("Use less traffic") ?>
-
+ = __("Does not display images in articles, reduces automatic refreshes."); ?>
@@ -155,11 +155,11 @@
-
+ = __("Safe mode") ?>
-
+ = __("Uses default theme and prevents all plugins from loading."); ?>
0) { ?>
@@ -167,7 +167,7 @@
-
+ = __("Remember me") ?>
@@ -177,7 +177,7 @@
-
+ = __('Log in') ?>
@@ -185,7 +185,7 @@
diff --git a/index.php b/index.php
index fa23570ff..8bfca1af2 100644
--- a/index.php
+++ b/index.php
@@ -47,7 +47,7 @@
} ?>
@@ -68,7 +68,7 @@
@@ -50,7 +50,7 @@
";
+ private function index_auth_personal() {
$sth = $this->pdo->prepare("SELECT email,full_name,otp_enabled,
access_level FROM ttrss_users
@@ -311,179 +285,214 @@ class Pref_Prefs extends Handler_Protected {
$full_name = htmlspecialchars($row["full_name"]);
$otp_enabled = sql_bool_to_bool($row["otp_enabled"]);
- print "
";
- print "".__('Full name:')." ";
- print " ";
- print " ";
-
- print "
";
- print "".__('E-mail:')." ";
- print " ";
- print " ";
-
- if (!SINGLE_USER_MODE && !empty($_SESSION["hide_hello"])) {
+ ?>
+
- $access_level = $row["access_level"];
- print "";
- print "".__('Access level:')." ";
- print $access_level_names[$access_level];
- print " ";
- }
-
- print_hidden("op", "pref-prefs");
- print_hidden("method", "changeemail");
-
- print " ";
+
+
- print "".
- __("Save data")." ";
-
- print " ";
+
+
+
+ = __('Full name:') ?>
+
+
+
+
+ = __('E-mail:') ?>
+
+
+
+
+
+ = __('Access level:') ?>
+ = $access_level_names[$row["access_level"]] ?>
+
+
+
+
+
+
+ = __("Save data") ?>
+
+
+ get_plugin($_SESSION["auth_module"]);
} else {
$authenticator = false;
}
- print "
"; # content pane
+ private function index_auth_app_passwords() {
+ print_notice("You can create separate passwords for API clients. Using one is required if you enable OTP.");
+ ?>
- print "
";
+
+ appPasswordList() ?>
+
- print_notice("You can create separate passwords for API clients. Using one is required if you enable OTP.");
+
- print "
";
- $this->appPasswordList();
- print "
";
+
+ = __('Generate new password') ?>
+
+
+
+ = __('Remove selected passwords') ?>
+
- print "
";
+ " .
- __('Generate new password') . " ";
+ private function is_otp_enabled() {
+ $sth = $this->pdo->prepare("SELECT otp_enabled FROM ttrss_users
+ WHERE id = ?");
+ $sth->execute([$_SESSION["uid"]]);
- print "
" .
- __('Remove selected passwords') . " ";
+ if ($row = $sth->fetch()) {
+ return sql_bool_to_bool($row["otp_enabled"]);
+ }
- print "
"; # content pane
+ return false;
+ }
- print "
"; # content pane
-
- print "
"; # tab container
-
- PluginHost::getInstance()->run_hooks(PluginHost::HOOK_PREFS_TAB_SECTION, "prefPrefsAuth");
-
- print "
"; #pane
-
- print "
settings ".__('Preferences')."\">";
-
- print "
";
-
- print "";
-
- print '';
-
- print '
';
+ private function index_auth() {
+ ?>
+
+
+ index_auth_personal() ?>
+
+
+ index_auth_password() ?>
+
+
+ index_auth_app_passwords() ?>
+
+
+ index_auth_2fa() ?>
+
+
+ initialize_user_prefs($_SESSION["uid"], $profile);
} else {
$this->initialize_user_prefs($_SESSION["uid"]);
@@ -660,7 +649,9 @@ class Pref_Prefs extends Handler_Protected {
continue;
}
- if (isset($prefs_available[$pref_name]) &&$item = $prefs_available[$pref_name]) {
+ if (isset($prefs_available[$pref_name])) {
+
+ $item = $prefs_available[$pref_name];
print "
";
@@ -735,16 +726,16 @@ class Pref_Prefs extends Handler_Protected {
array_push($listed_boolean_prefs, $pref_name);
- $checked = ($value == "true") ? "checked=\"checked\"" : "";
+ $is_checked = ($value == "true") ? "checked=\"checked\"" : "";
if ($pref_name == "PURGE_UNREAD_ARTICLES" && FORCE_ARTICLE_PURGE != 0) {
- $disabled = "disabled=\"1\"";
- $checked = "checked=\"checked\"";
+ $is_disabled = "disabled=\"1\"";
+ $is_checked = "checked=\"checked\"";
} else {
- $disabled = "";
+ $is_disabled = "";
}
- print " ";
} else if (in_array($pref_name, ['FRESH_ARTICLE_MAX_AGE',
@@ -753,19 +744,19 @@ class Pref_Prefs extends Handler_Protected {
$regexp = ($type_name == 'integer') ? 'regexp="^\d*$"' : '';
if ($pref_name == "PURGE_OLD_DAYS" && FORCE_ARTICLE_PURGE != 0) {
- $disabled = "disabled='1'";
+ $is_disabled = "disabled='1'";
$value = FORCE_ARTICLE_PURGE;
} else {
- $disabled = "";
+ $is_disabled = "";
}
if ($type_name == 'integer')
print " ";
else
print " ";
} else if ($pref_name == "SSL_CERT_SERIAL") {
@@ -808,204 +799,246 @@ class Pref_Prefs extends Handler_Protected {
}
}
}
+ print_hidden("boolean_prefs", htmlspecialchars(join(",", $listed_boolean_prefs)));
+ }
- $listed_boolean_prefs = htmlspecialchars(join(",", $listed_boolean_prefs));
-
- print_hidden("boolean_prefs", "$listed_boolean_prefs");
-
- PluginHost::getInstance()->run_hooks(PluginHost::HOOK_PREFS_TAB_SECTION, "prefPrefsPrefsInside");
-
- print ' '; # inside pane
- print '
';
-
- print_hidden("op", "pref-prefs");
- print_hidden("method", "saveconfig");
+ private function index_prefs() {
+ ?>
+
+
+
+
+
+
+
+ index_prefs_list() ?>
+ run_hooks(PluginHost::HOOK_PREFS_TAB_SECTION, "prefPrefsPrefsInside") ?>
+
+
+
+
+
= __('Save configuration') ?>
+
+
+ = __("Save and exit preferences") ?>
+
+
+
+
+
+ = __('Manage profiles') ?>
+
+
+
+ = __('Reset to defaults') ?>
+
+
+ run_hooks(PluginHost::HOOK_PREFS_TAB_SECTION, "prefPrefsPrefsOutside") ?>
+
- ";
-
- print "
".
- __('Manage profiles')." ";
-
- print "
".
- __('Reset to defaults')." ";
-
- print " ";
-
- PluginHost::getInstance()->run_hooks(PluginHost::HOOK_PREFS_TAB_SECTION, "prefPrefsPrefsOutside");
-
- print "";
- print '
'; # inner pane
- print ' '; # border container
-
- print "
"; #pane
-
- print "
extension ".__('Plugins')."\">";
-
- print "
";
-
- print "";
-
- print_hidden("op", "pref-prefs");
- print_hidden("method", "setplugins");
-
- print '';
- print '
';
-
- if (ini_get("open_basedir") && function_exists("curl_init") && !defined("NO_CURL")) {
- print_warning("Your PHP configuration has open_basedir restrictions enabled. Some plugins relying on CURL for functionality may not work correctly.");
- }
-
- if ($_SESSION["safe_mode"]) {
- print_error("You have logged in using safe mode, no user plugins will be actually enabled until you login again.");
- }
-
- $feed_handler_whitelist = [ "Af_Comics" ];
-
- $feed_handlers = array_merge(
- PluginHost::getInstance()->get_hooks(PluginHost::HOOK_FEED_FETCHED),
- PluginHost::getInstance()->get_hooks(PluginHost::HOOK_FEED_PARSED),
- PluginHost::getInstance()->get_hooks(PluginHost::HOOK_FETCH_FEED));
-
- $feed_handlers = array_filter($feed_handlers, function($plugin) use ($feed_handler_whitelist) {
- return in_array(get_class($plugin), $feed_handler_whitelist) === false; });
-
- if (count($feed_handlers) > 0) {
- print_error(
- T_sprintf("The following plugins use per-feed content hooks. This may cause excessive data usage and origin server load resulting in a ban of your instance:
%s " ,
- implode(", ", array_map(function($plugin) { return get_class($plugin); }, $feed_handlers))
- ) . " (
".__("More info...")." )"
- );
- }
+
+ ".__("System plugins")."";
+ private function index_plugins_system() {
print_notice("System plugins are enabled in
config.php for all users.");
- $system_enabled = array_map("trim", explode(",", PLUGINS));
- $user_enabled = array_map("trim", explode(",", get_pref("_ENABLED_PLUGINS")));
+ $system_enabled = array_map("trim", explode(",", (string)PLUGINS));
$tmppluginhost = new PluginHost();
$tmppluginhost->load_all($tmppluginhost::KIND_ALL, $_SESSION["uid"], true);
- //$tmppluginhost->load_data(true);
foreach ($tmppluginhost->get_plugins() as $name => $plugin) {
$about = $plugin->about();
if ($about[3] ?? false) {
- if (in_array($name, $system_enabled)) {
- $checked = "checked='1'";
- } else {
- $checked = "";
- }
-
- print "
- $name:
-
-
- ".htmlspecialchars($about[1]). " ";
-
- if ($about[4] ?? false) {
- print "
- open_in_new ".__("More info...")." ";
- }
-
- print "".
- htmlspecialchars(T_sprintf("v%.2f, by %s", $about[0], $about[2])).
- "
";
-
- print " ";
-
+ $is_checked = in_array($name, $system_enabled) ? "checked" : "";
+ ?>
+
+ = $name ?>:
+
+ type='checkbox'>= htmlspecialchars($about[1]) ?>
+
+
+
+
+ open_in_new = __("More info...") ?>
+
+
+
+ = htmlspecialchars(T_sprintf("v%.2f, by %s", $about[0], $about[2])) ?>
+
+
+ ".__("User plugins")."";
+ private function index_plugins_user() {
+ $system_enabled = array_map("trim", explode(",", (string)PLUGINS));
+ $user_enabled = array_map("trim", explode(",", get_pref("_ENABLED_PLUGINS")));
+
+ $tmppluginhost = new PluginHost();
+ $tmppluginhost->load_all($tmppluginhost::KIND_ALL, $_SESSION["uid"], true);
foreach ($tmppluginhost->get_plugins() as $name => $plugin) {
$about = $plugin->about();
if (empty($about[3]) || $about[3] == false) {
- $checked = "";
- $disabled = "";
+ $is_checked = "";
+ $is_disabled = "";
if (in_array($name, $system_enabled)) {
- $checked = "checked='1'";
- $disabled = "disabled='1'";
+ $is_checked = "checked='1'";
+ $is_disabled = "disabled='1'";
} else if (in_array($name, $user_enabled)) {
- $checked = "checked='1'";
+ $is_checked = "checked='1'";
}
- print "
- $name:
-
-
- ".htmlspecialchars($about[1])." ";
-
- if (count($tmppluginhost->get_all($plugin)) > 0) {
- if (in_array($name, $system_enabled) || in_array($name, $user_enabled)) {
- print "
- clear ".__("Clear data")." ";
- }
- }
+ ?>
+
+
+ = $name ?>:
+
+ = $is_disabled ?> type='checkbox'>
+ = htmlspecialchars($about[1]) ?>
+
+
+
+ get_all($plugin)) > 0) {
+ if (in_array($name, $system_enabled) || in_array($name, $user_enabled)) { ?>
+
+ clear = __("Clear data") ?>
+
+
+
+
+ open_in_new = __("More info...") ?>
+
+
+
+ = htmlspecialchars(T_sprintf("v%.2f, by %s", $about[0], $about[2])) ?>
+
+
+
+
- open_in_new ".__("More info...")."";
+ private function index_plugins() {
+ ?>
+
+
- print "".
- htmlspecialchars(T_sprintf("v%.2f, by %s", $about[0], $about[2])).
- "
";
+
+
- print " ";
- }
- }
+
+
+ "; #content-pane
- print '
';
+ $feed_handler_whitelist = [ "Af_Comics" ];
- print "
- help ".__("More info...")." ";
+ $feed_handlers = array_merge(
+ PluginHost::getInstance()->get_hooks(PluginHost::HOOK_FEED_FETCHED),
+ PluginHost::getInstance()->get_hooks(PluginHost::HOOK_FEED_PARSED),
+ PluginHost::getInstance()->get_hooks(PluginHost::HOOK_FETCH_FEED));
- print "".
- __("Enable selected plugins")." ";
- print "
"; #pane
+ $feed_handlers = array_filter($feed_handlers, function($plugin) use ($feed_handler_whitelist) {
+ return in_array(get_class($plugin), $feed_handler_whitelist) === false; });
- print "
"; #pane
- print "
"; #border-container
+ if (count($feed_handlers) > 0) {
+ print_error(
+ T_sprintf("The following plugins use per-feed content hooks. This may cause excessive data usage and origin server load resulting in a ban of your instance:
%s " ,
+ implode(", ", array_map(function($plugin) { return get_class($plugin); }, $feed_handlers))
+ ) . " (
".__("More info...")." )"
+ );
+ }
+ ?>
- print "";
+
= __("System plugins") ?>
+
+ index_plugins_system() ?>
- PluginHost::getInstance()->run_hooks(PluginHost::HOOK_PREFS_TAB, "prefPrefs");
+
= __("User plugins") ?>
- print "
"; #container
+ index_plugins_user() ?>
+
+
+
+ help = __("More info...") ?>
+
+
+ = __("Enable selected plugins") ?>
+
+
+
+
+
+
+
+ index_auth() ?>
+
+
+ index_prefs() ?>
+
+
+ index_plugins() ?>
+
+ run_hooks(PluginHost::HOOK_PREFS_TAB, "prefPrefs") ?>
+
+
Date: Sun, 14 Feb 2021 11:39:26 +0300
Subject: appPasswordList: markup cleanup
---
classes/pref/prefs.php | 90 ++++++++++++++++++++++++--------------------------
1 file changed, 44 insertions(+), 46 deletions(-)
diff --git a/classes/pref/prefs.php b/classes/pref/prefs.php
index a37ae99b5..ec7fbf607 100644
--- a/classes/pref/prefs.php
+++ b/classes/pref/prefs.php
@@ -1317,53 +1317,51 @@ class Pref_Prefs extends Handler_Protected {
}
private function appPasswordList() {
- print "
";
- print "
" .
- "
" . __('Select') . " ";
- print "
";
- print "
" . __('All') . "
";
- print "
" . __('None') . "
";
- print "
";
- print "
"; #toolbar
-
- print "
";
+
+
Date: Sun, 14 Feb 2021 12:25:41 +0300
Subject: pref prefs: load secondary tabs when needed
---
classes/pref/prefs.php | 26 ++++++++++++++++++++++----
1 file changed, 22 insertions(+), 4 deletions(-)
diff --git a/classes/pref/prefs.php b/classes/pref/prefs.php
index ec7fbf607..19f5221eb 100644
--- a/classes/pref/prefs.php
+++ b/classes/pref/prefs.php
@@ -564,7 +564,7 @@ class Pref_Prefs extends Handler_Protected {
}
}
- private function index_auth() {
+ function index_auth() {
?>
@@ -953,7 +953,7 @@ class Pref_Prefs extends Handler_Protected {
}
}
- private function index_plugins() {
+ function index_plugins() {
?>
+ = __("Loading, please wait...") ?>
index_prefs() ?>
- index_plugins() ?>
+
+ = __("Loading, please wait...") ?>
run_hooks(PluginHost::HOOK_PREFS_TAB, "prefPrefs") ?>
--
cgit v1.2.3-54-g00ecf
From 1c7e4782aa426dd1a003948756c51cf9d61f2163 Mon Sep 17 00:00:00 2001
From: Andrew Dolgov
Date: Sun, 14 Feb 2021 12:29:08 +0300
Subject: prefs system: load phpinfo using inline method
---
classes/pref/prefs.php | 2 --
classes/pref/system.php | 13 +++++++++----
js/PrefHelpers.js | 6 +-----
3 files changed, 10 insertions(+), 11 deletions(-)
diff --git a/classes/pref/prefs.php b/classes/pref/prefs.php
index 19f5221eb..6e4deb223 100644
--- a/classes/pref/prefs.php
+++ b/classes/pref/prefs.php
@@ -1032,7 +1032,6 @@ class Pref_Prefs extends Handler_Protected {
if (this.domNode.querySelector('.loading'))
window.setTimeout(() => {
xhrPost("backend.php", {op: 'pref-prefs', method: 'index_auth'}, (transport) => {
- console.log(this);
this.attr('content', transport.responseText);
});
}, 100);
@@ -1047,7 +1046,6 @@ class Pref_Prefs extends Handler_Protected {
if (this.domNode.querySelector('.loading'))
window.setTimeout(() => {
xhrPost("backend.php", {op: 'pref-prefs', method: 'index_plugins'}, (transport) => {
- console.log(this);
this.attr('content', transport.responseText);
});
}, 200);
diff --git a/classes/pref/system.php b/classes/pref/system.php
index 1adddf116..14df6f8d1 100644
--- a/classes/pref/system.php
+++ b/classes/pref/system.php
@@ -173,10 +173,15 @@ class Pref_System extends Handler_Protected {
'>
-
-
= __("Loading, please wait...") ?>
+
+
= __("Loading, please wait...") ?>
run_hooks(PluginHost::HOOK_PREFS_TAB, "prefSystem") ?>
diff --git a/js/PrefHelpers.js b/js/PrefHelpers.js
index b09beb995..7a3d38d02 100644
--- a/js/PrefHelpers.js
+++ b/js/PrefHelpers.js
@@ -54,11 +54,7 @@ const Helpers = {
},
},
System: {
- getPHPInfo: function(widget) {
- xhrPost("backend.php", {op: 'pref-system', method: 'getphpinfo'}, (transport) => {
- widget.attr('content', transport.responseText);
- });
- }
+ //
},
EventLog: {
log_page: 0,
--
cgit v1.2.3-54-g00ecf
From 2547ece0cacb7080060ad3bc32b879fee6b52230 Mon Sep 17 00:00:00 2001
From: Andrew Dolgov
Date: Sun, 14 Feb 2021 14:59:22 +0300
Subject: pref-users: cleanup index
---
classes/pref/users.php | 214 +++++++++++++++++++++----------------------------
1 file changed, 93 insertions(+), 121 deletions(-)
diff --git a/classes/pref/users.php b/classes/pref/users.php
index 5c622a9b1..0454a1292 100644
--- a/classes/pref/users.php
+++ b/classes/pref/users.php
@@ -251,12 +251,8 @@ class Pref_Users extends Handler_Protected {
print T_sprintf("Added user %s with password %s",
$login, $tmp_user_pwd);
- $this->initialize_user($new_uid);
-
} else {
-
print T_sprintf("Could not create user %s", $login);
-
}
} else {
print T_sprintf("User %s already exists.", $login);
@@ -303,10 +299,6 @@ class Pref_Users extends Handler_Protected {
global $access_level_names;
- print "";
- print "
";
- print "
";
-
$user_search = clean($_REQUEST["search"] ?? "");
if (array_key_exists("search", $_REQUEST)) {
@@ -315,137 +307,117 @@ class Pref_Users extends Handler_Protected {
$user_search = ($_SESSION["prefs_user_search"] ?? "");
}
- print "
-
- ".
- __('Search')."
-
";
-
$sort = clean($_REQUEST["sort"] ?? "");
if (!$sort || $sort == "undefined") {
$sort = "login";
}
- print "
".
- "
" . __('Select')." ";
- print "
";
- print "
".__('All')."
";
- print "
".__('None')."
";
- print "
";
-
- print "
".__('Create user')." ";
-
- print "
-
".
- __('Edit')."
-
".
- __('Remove')."
-
".
- __('Reset password')." ";
-
- PluginHost::getInstance()->run_hooks(PluginHost::HOOK_PREFS_TAB_SECTION, "prefUsersToolbar");
-
- print "
"; #toolbar
- print "
"; #pane
- print "
";
-
$sort = $this->validate_field($sort,
["login", "access_level", "created", "num_feeds", "created", "last_login"], "login");
if ($sort != "login") $sort = "$sort DESC";
- $sth = $this->pdo->prepare("SELECT
- tu.id,
- login,access_level,email,
- ".SUBSTRING_FOR_DATE."(last_login,1,16) as last_login,
- ".SUBSTRING_FOR_DATE."(created,1,16) as created,
- (SELECT COUNT(id) FROM ttrss_feeds WHERE owner_uid = tu.id) AS num_feeds
- FROM
- ttrss_users tu
- WHERE
- (:search = '' OR login LIKE :search) AND tu.id > 0
- ORDER BY $sort");
- $sth->execute([":search" => $user_search ? "%$user_search%" : ""]);
-
- print "
";
-
- if ($lnum == 0) {
- if (!$user_search) {
- print_warning(__('No users defined.'));
- } else {
- print_warning(__('No matching users found.'));
- }
- }
-
- print "
"; #pane
-
- PluginHost::getInstance()->run_hooks(PluginHost::HOOK_PREFS_TAB, "prefUsers");
-
- print "
"; #container
-
- }
+ ?>
+
+
+
+
+
+
+
+
+ = __('Search') ?>
+
+
+
+
+
= __('Select') ?>
+
+
= __('All') ?>
+
= __('None') ?>
+
+
+
+
+ = __('Create user') ?>
+
+
+
+ = __('Edit') ?>
+
+
+
+ = __('Remove') ?>
+
+
+
+ = __('Reset password') ?>
+
+
+ run_hooks(PluginHost::HOOK_PREFS_TAB_SECTION, "prefUsersToolbar") ?>
+
+
+
+
+
+
+
+
+
+ = ('Login') ?>
+ = ('Access Level') ?>
+ = ('Subscribed feeds') ?>
+ = ('Registered') ?>
+ = ('Last login') ?>
+
+
+ pdo->prepare("SELECT
+ tu.id,
+ login,access_level,email,
+ ".SUBSTRING_FOR_DATE."(last_login,1,16) as last_login,
+ ".SUBSTRING_FOR_DATE."(created,1,16) as created,
+ (SELECT COUNT(id) FROM ttrss_feeds WHERE owner_uid = tu.id) AS num_feeds
+ FROM
+ ttrss_users tu
+ WHERE
+ (:search = '' OR login LIKE :search) AND tu.id > 0
+ ORDER BY $sort");
+ $sth->execute([":search" => $user_search ? "%$user_search%" : ""]);
+
+ while ($row = $sth->fetch()) { ?>
+
+
+
+
+
+
+ person = htmlspecialchars($row["login"]) ?>
+ = $access_level_names[$row["access_level"]] ?>
+ = $row["num_feeds"] ?>
+ = TimeHelper::make_local_datetime($row["created"], false) ?>
+ = TimeHelper::make_local_datetime($row["last_login"], false) ?>
+
+
+
+
+ run_hooks(PluginHost::HOOK_PREFS_TAB, "prefUsers") ?>
+
+ prepare("insert into ttrss_feeds (owner_uid,title,feed_url)
- values (?, 'Tiny Tiny RSS: Forum',
- 'https://tt-rss.org/forum/rss.php')");
- $sth->execute([$uid]);
- }
-
static function logout_user() {
if (session_status() === PHP_SESSION_ACTIVE)
session_destroy();
--
cgit v1.2.3-54-g00ecf
From a8cc43a0ff1cf6297577fae8536408287518baf4 Mon Sep 17 00:00:00 2001
From: Andrew Dolgov
Date: Sun, 14 Feb 2021 15:31:03 +0300
Subject: move logout_user() to UserHelper
---
classes/api.php | 2 +-
classes/handler/public.php | 2 +-
classes/pref/users.php | 11 -----------
classes/userhelper.php | 14 +++++++++++++-
4 files changed, 15 insertions(+), 14 deletions(-)
diff --git a/classes/api.php b/classes/api.php
index 6a919be64..9299c34ea 100755
--- a/classes/api.php
+++ b/classes/api.php
@@ -81,7 +81,7 @@ class API extends Handler {
}
function logout() {
- Pref_Users::logout_user();
+ UserHelper::logout();
$this->wrap(self::STATUS_OK, array("status" => "OK"));
}
diff --git a/classes/handler/public.php b/classes/handler/public.php
index 481145606..79f3a9e6c 100755
--- a/classes/handler/public.php
+++ b/classes/handler/public.php
@@ -286,7 +286,7 @@ class Handler_Public extends Handler {
function logout() {
if (validate_csrf($_POST["csrf_token"])) {
- Pref_Users::logout_user();
+ UserHelper::logout();
header("Location: index.php");
} else {
header("Content-Type: text/json");
diff --git a/classes/pref/users.php b/classes/pref/users.php
index 0454a1292..24d28e62a 100644
--- a/classes/pref/users.php
+++ b/classes/pref/users.php
@@ -418,15 +418,4 @@ class Pref_Users extends Handler_Protected {
return $default;
}
- static function logout_user() {
- if (session_status() === PHP_SESSION_ACTIVE)
- session_destroy();
-
- if (isset($_COOKIE[session_name()])) {
- setcookie(session_name(), '', time()-42000, '/');
-
- }
- session_commit();
- }
-
}
diff --git a/classes/userhelper.php b/classes/userhelper.php
index c9c4dd102..8eb97f5d0 100644
--- a/classes/userhelper.php
+++ b/classes/userhelper.php
@@ -105,7 +105,7 @@ class UserHelper {
}
if (empty($_SESSION["uid"])) {
- Pref_Users::logout_user();
+ UserHelper::logout();
Handler_Public::render_login_form();
exit;
@@ -157,4 +157,16 @@ class UserHelper {
return false;
}
+
+ static function logout() {
+ if (session_status() === PHP_SESSION_ACTIVE)
+ session_destroy();
+
+ if (isset($_COOKIE[session_name()])) {
+ setcookie(session_name(), '', time()-42000, '/');
+
+ }
+ session_commit();
+ }
+
}
--
cgit v1.2.3-54-g00ecf
From 0fbf10991237b3f91ee5c77349637d7197a22bdc Mon Sep 17 00:00:00 2001
From: Andrew Dolgov
Date: Sun, 14 Feb 2021 15:38:45 +0300
Subject: * remove users/filters toolbar edit button (just click on it) * fix
title of edit filter dialog always showing create filter
---
classes/pref/filters.php | 2 --
classes/pref/users.php | 4 ----
js/CommonFilters.js | 2 +-
js/PrefFilterTree.js | 17 -----------------
js/PrefUsers.js | 15 ---------------
5 files changed, 1 insertion(+), 39 deletions(-)
diff --git a/classes/pref/filters.php b/classes/pref/filters.php
index c898a8b67..1c264f642 100755
--- a/classes/pref/filters.php
+++ b/classes/pref/filters.php
@@ -736,8 +736,6 @@ class Pref_Filters extends Handler_Protected {
= __('Create filter') ?>
= __('Combine') ?>
-
- = __('Edit') ?>
= __('Reset sort order') ?>
diff --git a/classes/pref/users.php b/classes/pref/users.php
index 24d28e62a..7adb09ab2 100644
--- a/classes/pref/users.php
+++ b/classes/pref/users.php
@@ -346,10 +346,6 @@ class Pref_Users extends Handler_Protected {
= __('Create user') ?>
-
- = __('Edit') ?>
-
-
= __('Remove') ?>
diff --git a/js/CommonFilters.js b/js/CommonFilters.js
index 15403b8c4..06e0410c7 100644
--- a/js/CommonFilters.js
+++ b/js/CommonFilters.js
@@ -243,7 +243,7 @@ const Filters = {
try {
const dialog = new fox.SingleUseDialog({
id: "filterEditDlg",
- title: __("Create Filter"),
+ title: id ? __("Edit Filter") : __("Create Filter"),
test: function () {
Filters.test(this.attr('value'));
},
diff --git a/js/PrefFilterTree.js b/js/PrefFilterTree.js
index abfdbb3b0..e7d4efdc1 100644
--- a/js/PrefFilterTree.js
+++ b/js/PrefFilterTree.js
@@ -119,23 +119,6 @@ define(["dojo/_base/declare", "dojo/dom-construct", "lib/CheckBoxTree"], functio
});
}
},
- editSelectedFilter: function() {
- const rows = this.getSelectedFilters();
-
- if (rows.length == 0) {
- alert(__("No filters selected."));
- return;
- }
-
- if (rows.length > 1) {
- alert(__("Please select only one filter."));
- return;
- }
-
- Notify.close();
-
- this.editFilter(rows[0]);
- },
removeSelectedFilters: function() {
const sel_rows = this.getSelectedFilters();
diff --git a/js/PrefUsers.js b/js/PrefUsers.js
index 0a7e635fe..e5c281811 100644
--- a/js/PrefUsers.js
+++ b/js/PrefUsers.js
@@ -93,21 +93,6 @@ const Users = {
alert(__("No users selected."));
}
},
- editSelected: function() {
- const rows = this.getSelection();
-
- if (rows.length == 0) {
- alert(__("No users selected."));
- return;
- }
-
- if (rows.length > 1) {
- alert(__("Please select one user."));
- return;
- }
-
- this.edit(rows[0]);
- },
getSelection :function() {
return Tables.getSelected("users-list");
}
--
cgit v1.2.3-54-g00ecf
From 33ea46c2bc5c91d7767f11c230a941cc635c0e67 Mon Sep 17 00:00:00 2001
From: Andrew Dolgov
Date: Sun, 14 Feb 2021 15:42:12 +0300
Subject: pref-users/add: remove unused variable
---
classes/pref/users.php | 2 --
1 file changed, 2 deletions(-)
diff --git a/classes/pref/users.php b/classes/pref/users.php
index 7adb09ab2..9d9ea4d8e 100644
--- a/classes/pref/users.php
+++ b/classes/pref/users.php
@@ -246,8 +246,6 @@ class Pref_Users extends Handler_Protected {
if ($new_uid = UserHelper::find_user_by_login($login)) {
- $new_uid = $row['id'];
-
print T_sprintf("Added user %s with password %s",
$login, $tmp_user_pwd);
--
cgit v1.2.3-54-g00ecf
From 0b7377238a556708035b0cd51a9e58693fb648f6 Mon Sep 17 00:00:00 2001
From: Andrew Dolgov
Date: Sun, 14 Feb 2021 15:50:46 +0300
Subject: add Handler_Administrative
---
classes/handler/administrative.php | 11 +++++++++++
classes/pref/system.php | 13 +------------
classes/pref/users.php | 13 +------------
3 files changed, 13 insertions(+), 24 deletions(-)
create mode 100644 classes/handler/administrative.php
diff --git a/classes/handler/administrative.php b/classes/handler/administrative.php
new file mode 100644
index 000000000..52dfed8b7
--- /dev/null
+++ b/classes/handler/administrative.php
@@ -0,0 +1,11 @@
+= 10) {
+ return true;
+ }
+ }
+ return false;
+ }
+}
diff --git a/classes/pref/system.php b/classes/pref/system.php
index 14df6f8d1..2a97ec6f0 100644
--- a/classes/pref/system.php
+++ b/classes/pref/system.php
@@ -1,20 +1,9 @@
Date: Sun, 14 Feb 2021 16:44:41 +0300
Subject: pref-users edit: use client dialog
---
classes/pref/users.php | 112 +++++++------------------------------------------
js/App.js | 9 ++++
js/PrefUsers.js | 84 +++++++++++++++++++++++++++++++++++--
3 files changed, 105 insertions(+), 100 deletions(-)
diff --git a/classes/pref/users.php b/classes/pref/users.php
index b34f85d88..bc125d0ce 100644
--- a/classes/pref/users.php
+++ b/classes/pref/users.php
@@ -1,7 +1,7 @@
";
+ $id = (int)clean($_REQUEST["id"]);
- print '
-
';
-
- //print "
";
-
- $id = (int) clean($_REQUEST["id"]);
-
- print_hidden("id", "$id");
- print_hidden("op", "pref-users");
- print_hidden("method", "editSave");
-
- $sth = $this->pdo->prepare("SELECT * FROM ttrss_users WHERE id = ?");
+ $sth = $this->pdo->prepare("SELECT id, login, access_level, email FROM ttrss_users WHERE id = ?");
$sth->execute([$id]);
- if ($row = $sth->fetch()) {
-
- $login = $row["login"];
- $access_level = $row["access_level"];
- $email = $row["email"];
-
- $sel_disabled = ($id == $_SESSION["uid"] || $login == "admin") ? "disabled" : "";
-
- print "";
- print "";
-
- print "";
- print "";
-
- print "";
- print "";
-
- print "";
-
+ if ($row = $sth->fetch(PDO::FETCH_ASSOC)) {
+ print json_encode([
+ "user" => $row,
+ "access_level_names" => $access_level_names
+ ]);
+ } else {
+ print json_encode(["error" => "USER_NOT_FOUND"]);
}
-
- print ' '; #tab
- print "
";
-
- print '
';
- print '
';
-
- print "
- ".
- __('Save')."
- ".
- __('Cancel')."
- ";
-
- print "";
-
- return;
}
function userdetails() {
@@ -186,6 +100,12 @@ class Pref_Users extends Handler_Administrative {
$email = clean($_REQUEST["email"]);
$password = clean($_REQUEST["password"]);
+ // no blank usernames
+ if (!$login) return;
+
+ // forbid renaming admin
+ if ($uid == 1) $login = "admin";
+
if ($password) {
$salt = substr(bin2hex(get_random_bytes(125)), 0, 250);
$pwd_hash = encrypt_password($password, $salt, true);
diff --git a/js/App.js b/js/App.js
index 4646145ea..1e6e5fdb1 100644
--- a/js/App.js
+++ b/js/App.js
@@ -20,6 +20,15 @@ const App = {
FormFields: {
hidden: function(name, value, id = "") {
return ` `
+ },
+ select_hash: function(name, value, values, attributes) {
+ return `
+
+ ${Object.keys(values).map((vk) =>
+ `${App.escapeHtml(values[vk])} `
+ ).join("")}
+
+ `
}
},
Scrollable: {
diff --git a/js/PrefUsers.js b/js/PrefUsers.js
index e5c281811..1fe4db150 100644
--- a/js/PrefUsers.js
+++ b/js/PrefUsers.js
@@ -1,7 +1,7 @@
'use strict'
/* global __ */
-/* global xhrPost, dojo, dijit, Notify, Tables, fox */
+/* global xhrPost, xhrJson, dojo, dijit, Notify, Tables, App, fox */
const Users = {
reload: function(sort) {
@@ -27,7 +27,10 @@ const Users = {
}
},
edit: function(id) {
- xhrPost('backend.php', {op: 'pref-users', method: 'edit', id: id}, (transport) => {
+ xhrJson('backend.php', {op: 'pref-users', method: 'edit', id: id}, (reply) => {
+ const user = reply.user;
+ const is_disabled = (user.id == 1) ? "disabled='disabled'" : '';
+
const dialog = new fox.SingleUseDialog({
id: "userEditDlg",
title: __("User Editor"),
@@ -35,13 +38,86 @@ const Users = {
if (this.validate()) {
Notify.progress("Saving data...", true);
- xhrPost("backend.php", dojo.formToObject("user_edit_form"), (/* transport */) => {
+ xhrPost("backend.php", this.attr('value'), () => {
dialog.hide();
Users.reload();
});
}
},
- content: transport.responseText
+ content: `
+
+
+ ${App.FormFields.hidden('id', user.id.toString())}
+ ${App.FormFields.hidden('op', 'pref-users')}
+ ${App.FormFields.hidden('method', 'editSave')}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ${__("Loading, please wait...")}
+
+
+
+
+
+ ${__('Save')}
+
+
+ ${__('Cancel')}
+
+
+
+ `
});
dialog.show();
--
cgit v1.2.3-54-g00ecf
From ff6031d3c914fa2c7ac514243394fa70a56c6bd7 Mon Sep 17 00:00:00 2001
From: Andrew Dolgov
Date: Sun, 14 Feb 2021 18:59:09 +0300
Subject: remove old-style markup from exception dialog
---
js/App.js | 44 +++++++++++++++++++++++---------------------
themes/compact.css | 15 +++------------
themes/compact_night.css | 15 +++------------
themes/light.css | 15 +++------------
themes/light/tt-rss.less | 28 +++++++---------------------
themes/night.css | 15 +++------------
themes/night_blue.css | 15 +++------------
7 files changed, 45 insertions(+), 102 deletions(-)
diff --git a/js/App.js b/js/App.js
index 1e6e5fdb1..0a72d1b12 100644
--- a/js/App.js
+++ b/js/App.js
@@ -542,29 +542,31 @@ const App = {
}
try {
- let stack_msg = "";
-
- if (error.stack)
- stack_msg += `Stack trace:
- ${error.stack} `;
-
- if (params.info)
- stack_msg += `Additional information:
- ${params.info} `;
-
- const content = `
-
${message}
- ${stack_msg}
-
- ${__('Close this window')}
-
-
`;
-
const dialog = new fox.SingleUseDialog({
- id: "exceptionDlg",
title: params.title || __("Unhandled exception"),
- content: content
+ content: `
+
+
${message}
+
+
+
+
+ ${params && params.info ?
+ `
+ ${__('Additional information')}
+
+ ` : ''}
+
+
+
+ ${__('Close this window')}
+
+
+ `
});
dialog.show();
diff --git a/themes/compact.css b/themes/compact.css
index 36c5aec9f..24380d428 100644
--- a/themes/compact.css
+++ b/themes/compact.css
@@ -526,22 +526,13 @@ body.ttrss_main #feed_browser_spinner {
height: 18px;
width: 18px;
}
-body.ttrss_main #exceptionDlg .dijitDialogTitleBar {
- background: red;
- color: white;
-}
-body.ttrss_main #exceptionDlg .dijitDialogPaneContent {
- background: #fcc;
-}
-body.ttrss_main #exceptionDlg .error-contents .message {
+body.ttrss_main .exception-contents h3 {
color: red;
}
-body.ttrss_main #exceptionDlg .error-contents textarea {
+body.ttrss_main .exception-contents textarea {
width: 99%;
height: 200px;
-}
-body.ttrss_main #exceptionDlg .error-contents .dlgButtons {
- text-align: center;
+ font-size: 11px;
}
body.ttrss_main #content-wrap {
padding: 0px;
diff --git a/themes/compact_night.css b/themes/compact_night.css
index e39b7020a..a366404a4 100644
--- a/themes/compact_night.css
+++ b/themes/compact_night.css
@@ -526,22 +526,13 @@ body.ttrss_main #feed_browser_spinner {
height: 18px;
width: 18px;
}
-body.ttrss_main #exceptionDlg .dijitDialogTitleBar {
- background: red;
- color: white;
-}
-body.ttrss_main #exceptionDlg .dijitDialogPaneContent {
- background: #fcc;
-}
-body.ttrss_main #exceptionDlg .error-contents .message {
+body.ttrss_main .exception-contents h3 {
color: red;
}
-body.ttrss_main #exceptionDlg .error-contents textarea {
+body.ttrss_main .exception-contents textarea {
width: 99%;
height: 200px;
-}
-body.ttrss_main #exceptionDlg .error-contents .dlgButtons {
- text-align: center;
+ font-size: 11px;
}
body.ttrss_main #content-wrap {
padding: 0px;
diff --git a/themes/light.css b/themes/light.css
index b6c487b66..d3f5d7978 100644
--- a/themes/light.css
+++ b/themes/light.css
@@ -526,22 +526,13 @@ body.ttrss_main #feed_browser_spinner {
height: 18px;
width: 18px;
}
-body.ttrss_main #exceptionDlg .dijitDialogTitleBar {
- background: red;
- color: white;
-}
-body.ttrss_main #exceptionDlg .dijitDialogPaneContent {
- background: #fcc;
-}
-body.ttrss_main #exceptionDlg .error-contents .message {
+body.ttrss_main .exception-contents h3 {
color: red;
}
-body.ttrss_main #exceptionDlg .error-contents textarea {
+body.ttrss_main .exception-contents textarea {
width: 99%;
height: 200px;
-}
-body.ttrss_main #exceptionDlg .error-contents .dlgButtons {
- text-align: center;
+ font-size: 11px;
}
body.ttrss_main #content-wrap {
padding: 0px;
diff --git a/themes/light/tt-rss.less b/themes/light/tt-rss.less
index 65ec33bc3..d13ffff3e 100644
--- a/themes/light/tt-rss.less
+++ b/themes/light/tt-rss.less
@@ -609,28 +609,14 @@ body.ttrss_main {
width : 18px;
}
- #exceptionDlg {
- .dijitDialogTitleBar {
- background : red;
- color : white;
- }
-
- .dijitDialogPaneContent {
- background : #fcc;
+ .exception-contents {
+ h3 {
+ color : red;
}
-
- .error-contents {
- .message {
- color : red;
- }
-
- textarea {
- width : 99%;
- height : 200px;
- }
- .dlgButtons {
- text-align : center;
- }
+ textarea {
+ width : 99%;
+ height : 200px;
+ font-size : 11px;
}
}
diff --git a/themes/night.css b/themes/night.css
index 5941fd8e1..87a68a3c0 100644
--- a/themes/night.css
+++ b/themes/night.css
@@ -527,22 +527,13 @@ body.ttrss_main #feed_browser_spinner {
height: 18px;
width: 18px;
}
-body.ttrss_main #exceptionDlg .dijitDialogTitleBar {
- background: red;
- color: white;
-}
-body.ttrss_main #exceptionDlg .dijitDialogPaneContent {
- background: #fcc;
-}
-body.ttrss_main #exceptionDlg .error-contents .message {
+body.ttrss_main .exception-contents h3 {
color: red;
}
-body.ttrss_main #exceptionDlg .error-contents textarea {
+body.ttrss_main .exception-contents textarea {
width: 99%;
height: 200px;
-}
-body.ttrss_main #exceptionDlg .error-contents .dlgButtons {
- text-align: center;
+ font-size: 11px;
}
body.ttrss_main #content-wrap {
padding: 0px;
diff --git a/themes/night_blue.css b/themes/night_blue.css
index 99bb191a2..02a66656b 100644
--- a/themes/night_blue.css
+++ b/themes/night_blue.css
@@ -527,22 +527,13 @@ body.ttrss_main #feed_browser_spinner {
height: 18px;
width: 18px;
}
-body.ttrss_main #exceptionDlg .dijitDialogTitleBar {
- background: red;
- color: white;
-}
-body.ttrss_main #exceptionDlg .dijitDialogPaneContent {
- background: #fcc;
-}
-body.ttrss_main #exceptionDlg .error-contents .message {
+body.ttrss_main .exception-contents h3 {
color: red;
}
-body.ttrss_main #exceptionDlg .error-contents textarea {
+body.ttrss_main .exception-contents textarea {
width: 99%;
height: 200px;
-}
-body.ttrss_main #exceptionDlg .error-contents .dlgButtons {
- text-align: center;
+ font-size: 11px;
}
body.ttrss_main #content-wrap {
padding: 0px;
--
cgit v1.2.3-54-g00ecf
From 37a81ba594c2b848b8ecec805527ee8766f1ed14 Mon Sep 17 00:00:00 2001
From: Andrew Dolgov
Date: Sun, 14 Feb 2021 19:19:25 +0300
Subject: SingleUseDialog: destroy existing widget with same id on create
---
js/SingleUseDialog.js | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/js/SingleUseDialog.js b/js/SingleUseDialog.js
index 944f24c6f..2de6f83ff 100644
--- a/js/SingleUseDialog.js
+++ b/js/SingleUseDialog.js
@@ -1,6 +1,17 @@
+/* eslint-disable prefer-rest-params */
/* global dijit, define */
define(["dojo/_base/declare", "dijit/Dialog"], function (declare) {
return declare("fox.SingleUseDialog", dijit.Dialog, {
+ create: function(params) {
+ const extant = dijit.byId(params.id);
+
+ if (extant) {
+ console.warn('SingleUseDialog: destroying existing widget:', params.id, '=', extant)
+ extant.destroyRecursive();
+ }
+
+ return this.inherited(arguments);
+ },
onHide: function() {
this.destroyRecursive();
}
--
cgit v1.2.3-54-g00ecf
From 68e2ccb35477d9270f598a3e1750782fc81bfb16 Mon Sep 17 00:00:00 2001
From: Joseph
Date: Sun, 14 Feb 2021 17:31:01 +0000
Subject: Lazy load image attachments
---
classes/article.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/classes/article.php b/classes/article.php
index 7f5311668..5ea936985 100755
--- a/classes/article.php
+++ b/classes/article.php
@@ -443,7 +443,7 @@ class Article extends Handler_Protected {
$encsize .= ' height="' . intval($entry['height']) . '"';
if ($entry['width'] > 0)
$encsize .= ' width="' . intval($entry['width']) . '"';
- $rv .= "
";
--
cgit v1.2.3-54-g00ecf
From a2e688fcb2d463a5db700ebd013c783e3a8f4971 Mon Sep 17 00:00:00 2001
From: Andrew Dolgov
Date: Sun, 14 Feb 2021 22:17:13 +0300
Subject: render headline-specific toolbar on the client
---
classes/feeds.php | 123 +++++++++--------------------------------------
classes/pref/feeds.php | 22 ++++++---
index.php | 4 +-
js/CommonDialogs.js | 13 ++---
js/Headlines.js | 61 +++++++++++++++++++++--
plugins/mail/init.php | 7 ++-
plugins/mailto/init.php | 5 ++
themes/compact.css | 5 +-
themes/compact_night.css | 5 +-
themes/light.css | 5 +-
themes/light/tt-rss.less | 4 +-
themes/night.css | 5 +-
themes/night_blue.css | 5 +-
13 files changed, 136 insertions(+), 128 deletions(-)
diff --git a/classes/feeds.php b/classes/feeds.php
index e6bd1459d..0a3e77a1a 100755
--- a/classes/feeds.php
+++ b/classes/feeds.php
@@ -16,103 +16,6 @@ class Feeds extends Handler_Protected {
return array_search($method, $csrf_ignored) !== false;
}
- private function format_headline_subtoolbar($feed_site_url, $feed_title,
- $feed_id, $is_cat, $search,
- $error, $feed_last_updated) {
-
- $cat_q = $is_cat ? "&is_cat=$is_cat" : "";
-
- if ($search) {
- $search_q = "&q=$search";
- } else {
- $search_q = "";
- }
-
- $reply = "";
-
- $rss_link = htmlspecialchars(get_self_url_prefix() .
- "/public.php?op=rss&id=${feed_id}${cat_q}${search_q}");
-
- $reply .= "";
-
- $reply .= "
- rss_feed ";
-
- $reply .= "";
-
- if ($feed_site_url) {
- $last_updated = T_sprintf("Last updated: %s", $feed_last_updated);
-
- $reply .= "".
- truncate_string(strip_tags($feed_title), 30)." ";
- } else {
- $reply .= strip_tags($feed_title);
- }
-
- if ($error)
- $reply .= " error ";
-
- $reply .= " ";
- $reply .= " ";
- $reply .= " ";
-
- $reply .= "";
- $reply .= " ";
- $reply .= " ";
-
- $reply .= "
-
".__("Select...")."
-
-
".__('All')."
-
".__('Unread')."
-
".__('Invert')."
-
".__('None')."
-
-
".__('Toggle unread')."
-
".__('Toggle starred')."
-
".__('Toggle published')."
-
-
".__('Mark as read')."
-
".__('Set score')."
";
-
- // TODO: move to mail plugin
- if (PluginHost::getInstance()->get_plugin("mail")) {
- $reply .= "
".__('Forward by email')."
";
- }
-
- // TODO: move to mailto plugin
- if (PluginHost::getInstance()->get_plugin("mailto")) {
- $reply .= "
".__('Forward by email')."
";
- }
-
- PluginHost::getInstance()->chain_hooks_callback(PluginHost::HOOK_HEADLINE_TOOLBAR_SELECT_MENU_ITEM,
- function ($result) use (&$reply) {
- $reply .= $result;
- },
- $feed_id, $is_cat);
-
- if ($feed_id == 0 && !$is_cat) {
- $reply .= "
-
".__('Delete permanently')."
";
- }
-
- $reply .= "
"; /* menu */
-
- $reply .= "
"; /* dropdown */
-
- PluginHost::getInstance()->chain_hooks_callback(PluginHost::HOOK_HEADLINE_TOOLBAR_BUTTON,
- function ($result) use (&$reply) {
- $reply .= $result;
- },
- $feed_id, $is_cat);
-
- $reply .= " ";
-
- return $reply;
- }
-
private function format_headlines_list($feed, $method, $view_mode, $limit, $cat_view,
$offset, $override_order = false, $include_children = false, $check_first_id = false,
$skip_first_id_check = false, $order_by = false) {
@@ -222,10 +125,28 @@ class Feeds extends Handler_Protected {
$reply['search_query'] = [$search, $search_language];
$reply['vfeed_group_enabled'] = $vfeed_group_enabled;
- $reply['toolbar'] = $this->format_headline_subtoolbar($feed_site_url,
- $feed_title,
- $feed, $cat_view, $search,
- $last_error, $last_updated);
+ $plugin_menu_items = "";
+ PluginHost::getInstance()->chain_hooks_callback(PluginHost::HOOK_HEADLINE_TOOLBAR_SELECT_MENU_ITEM,
+ function ($result) use (&$plugin_menu_items) {
+ $plugin_menu_items .= $result;
+ },
+ $feed, $cat_view);
+
+ $plugin_buttons = "";
+ PluginHost::getInstance()->chain_hooks_callback(PluginHost::HOOK_HEADLINE_TOOLBAR_BUTTON,
+ function ($result) use (&$plugin_buttons) {
+ $plugin_buttons .= $result;
+ },
+ $feed, $cat_view);
+
+ $reply['toolbar'] = [
+ 'site_url' => $feed_site_url,
+ 'title' => truncate_string(strip_tags($feed_title), 30),
+ 'error' => $last_error,
+ 'last_updated' => $last_updated,
+ 'plugin_menu_items' => $plugin_menu_items,
+ 'plugin_buttons' => $plugin_buttons,
+ ];
$reply['content'] = [];
diff --git a/classes/pref/feeds.php b/classes/pref/feeds.php
index 6b5df0289..e225949f2 100755
--- a/classes/pref/feeds.php
+++ b/classes/pref/feeds.php
@@ -1358,14 +1358,12 @@ class Pref_Feeds extends Handler_Protected {
}
private function index_shared() {
- $rss_url = htmlspecialchars(get_self_url_prefix() .
- "/public.php?op=rss&id=-2&view-mode=all_articles");
?>
= __('Published articles can be subscribed by anyone who knows the following URL:') ?>
+ onclick="CommonDialogs.generatedFeed(-2, false)">
= __('Display URL') ?>
@@ -1603,11 +1601,23 @@ class Pref_Feeds extends Handler_Protected {
print json_encode(["link" => $new_key]);
}
- function getFeedKey() {
+ function getsharedurl() {
$feed_id = clean($_REQUEST['id']);
- $is_cat = clean($_REQUEST['is_cat']);
+ $is_cat = clean($_REQUEST['is_cat']) == "true";
+ $search = clean($_REQUEST['search']);
+
+ $link = get_self_url_prefix() . "/public.php?" . http_build_query([
+ 'op' => 'rss',
+ 'id' => $feed_id,
+ 'is_cat' => (int)$is_cat,
+ 'q' => $search,
+ 'key' => Feeds::get_feed_access_key($feed_id, $is_cat, $_SESSION["uid"])
+ ]);
- print json_encode(["link" => Feeds::get_feed_access_key($feed_id, $is_cat, $_SESSION["uid"])]);
+ print json_encode([
+ "title" => Feeds::getFeedTitle($feed_id, $is_cat),
+ "link" => $link
+ ]);
}
private function update_feed_access_key($feed_id, $is_cat, $owner_uid) {
diff --git a/index.php b/index.php
index 8bfca1af2..d53fb54a8 100644
--- a/index.php
+++ b/index.php
@@ -176,9 +176,9 @@
});
?>
-
+
-
+
diff --git a/js/CommonDialogs.js b/js/CommonDialogs.js
index 5a72f705b..e6b1822c2 100644
--- a/js/CommonDialogs.js
+++ b/js/CommonDialogs.js
@@ -433,24 +433,19 @@ const CommonDialogs = {
}
});
},
- generatedFeed: function(feed, is_cat, rss_url, feed_title) {
+ generatedFeed: function(feed, is_cat, search = "") {
Notify.progress("Loading, please wait...", true);
- xhrJson("backend.php", {op: "pref-feeds", method: "getFeedKey", id: feed, is_cat: is_cat}, (reply) => {
+ xhrJson("backend.php", {op: "pref-feeds", method: "getsharedurl", id: feed, is_cat: is_cat, search: search}, (reply) => {
try {
- if (!feed_title && typeof Feeds != "undefined")
- feed_title = Feeds.getName(feed, is_cat);
-
- const secret_url = rss_url + "&key=" + encodeURIComponent(reply.link);
-
const dialog = new fox.SingleUseDialog({
title: __("Show as feed"),
content: `
- ${__("%s can be accessed via the following secret URL:").replace("%s", feed_title)}
+ ${__("%s can be accessed via the following secret URL:").replace("%s", App.escapeHtml(reply.title))}
- ";
+
subscribe_to_feed_url());
- //$confirm_str = str_replace("'", "\'", __('Subscribe to %s in Tiny Tiny RSS?'));
- //$bm_subscribe_url = htmlspecialchars("javascript:{if(confirm('$confirm_str'.replace('%s',window.location.href)))window.location.href='$bm_subscribe_url'+encodeURIComponent(window.location.href)}");
-
- //$bm_share_url = htmlspecialchars("javascript:(function(){var d=document,w=window,e=w.getSelection,k=d.getSelection,x=d.selection,s=(e?e():(k)?k():(x?x.createRange().text:0)),f='".get_self_url_prefix()."/public.php?op=sharepopup',l=d.location,e=encodeURIComponent,g=f+'&title='+((e(s))?e(s):e(document.title))+'&url='+e(l.href);function a(){if(!w.open(g,'t','toolbar=0,resizable=0,scrollbars=1,status=1,width=500,height=250')){l.href=g;}}a();})()");
?>
Date: Sat, 20 Feb 2021 10:26:09 +0300
Subject: wip: feed editor client-side
---
classes/pref/feeds.php | 72 ++++++++++++++--
js/App.js | 24 +++---
js/CommonDialogs.js | 219 +++++++++++++++++++++++++++++++++++++++++++++++--
3 files changed, 291 insertions(+), 24 deletions(-)
diff --git a/classes/pref/feeds.php b/classes/pref/feeds.php
index 97c529d07..2c275349b 100755
--- a/classes/pref/feeds.php
+++ b/classes/pref/feeds.php
@@ -464,8 +464,10 @@ class Pref_Feeds extends Handler_Protected {
if (is_uploaded_file($_FILES['icon_file']['tmp_name'])) {
$tmp_file = tempnam(CACHE_DIR . '/upload', 'icon');
- $result = move_uploaded_file($_FILES['icon_file']['tmp_name'],
- $tmp_file);
+ if (!$tmp_file)
+ return;
+
+ $result = move_uploaded_file($_FILES['icon_file']['tmp_name'], $tmp_file);
if (!$result) {
return;
@@ -478,7 +480,7 @@ class Pref_Feeds extends Handler_Protected {
$feed_id = clean($_REQUEST["feed_id"]);
$rc = 2; // failed
- if (is_file($icon_file) && $feed_id) {
+ if ($icon_file && is_file($icon_file) && $feed_id) {
if (filesize($icon_file) < 65535) {
$sth = $this->pdo->prepare("SELECT id FROM ttrss_feeds
@@ -486,8 +488,12 @@ class Pref_Feeds extends Handler_Protected {
$sth->execute([$feed_id, $_SESSION['uid']]);
if ($row = $sth->fetch()) {
- @unlink(ICONS_DIR . "/$feed_id.ico");
- if (rename($icon_file, ICONS_DIR . "/$feed_id.ico")) {
+ $new_filename = ICONS_DIR . "/$feed_id.ico";
+
+ if (file_exists($new_filename)) unlink($new_filename);
+
+ if (rename($icon_file, $new_filename)) {
+ chmod($new_filename, 644);
$sth = $this->pdo->prepare("UPDATE ttrss_feeds SET
favicon_avg_color = ''
@@ -502,7 +508,9 @@ class Pref_Feeds extends Handler_Protected {
}
}
- if (is_file($icon_file)) @unlink($icon_file);
+ if ($icon_file && is_file($icon_file)) {
+ unlink($icon_file);
+ }
print $rc;
return;
@@ -512,12 +520,62 @@ class Pref_Feeds extends Handler_Protected {
global $purge_intervals;
global $update_intervals;
- $feed_id = clean($_REQUEST["id"]);
+ $feed_id = (int)clean($_REQUEST["id"]);
$sth = $this->pdo->prepare("SELECT * FROM ttrss_feeds WHERE id = ? AND
owner_uid = ?");
$sth->execute([$feed_id, $_SESSION['uid']]);
+ if ($row = $sth->fetch(PDO::FETCH_ASSOC)) {
+
+ ob_start();
+ PluginHost::getInstance()->run_hooks(PluginHost::HOOK_PREFS_EDIT_FEED, $feed_id);
+ $plugin_data = trim((string)ob_get_contents());
+ ob_end_clean();
+
+ $row["icon"] = Feeds::_get_icon($feed_id);
+
+ $local_update_intervals = $update_intervals;
+ $local_update_intervals[0] .= sprintf(" (%s)", $update_intervals[get_pref("DEFAULT_UPDATE_INTERVAL")]);
+
+ if (FORCE_ARTICLE_PURGE == 0) {
+ $local_purge_intervals = $purge_intervals;
+ $default_purge_interval = get_pref("PURGE_OLD_DAYS");
+
+ if ($default_purge_interval > 0)
+ $local_purge_intervals[0] .= " " . T_nsprintf('(%d day)', '(%d days)', $default_purge_interval, $default_purge_interval);
+ else
+ $local_purge_intervals[0] .= " " . sprintf("(%s)", __("Disabled"));
+
+ } else {
+ $purge_interval = FORCE_ARTICLE_PURGE;
+ $local_purge_intervals = [ T_nsprintf('%d day', '%d days', $purge_interval, $purge_interval) ];
+ }
+
+ print json_encode([
+ "feed" => $row,
+ "cats" => [
+ "enabled" => get_pref('ENABLE_FEED_CATS'),
+ "select" => \Controls\select_feeds_cats("cat_id", $row["cat_id"]),
+ ],
+ "plugin_data" => $plugin_data,
+ "force_purge" => (int)FORCE_ARTICLE_PURGE,
+ "intervals" => [
+ "update" => $local_update_intervals,
+ "purge" => $local_purge_intervals,
+ ],
+ "lang" => [
+ "enabled" => DB_TYPE == "pgsql",
+ "default" => get_pref('DEFAULT_SEARCH_LANGUAGE'),
+ "all" => $this::get_ts_languages(),
+ ]
+ ]);
+ } else {
+ print json_encode(["error" => "FEED_NOT_FOUND"]);
+ }
+
+ return;
+
if ($row = $sth->fetch()) {
print '
';
diff --git a/js/App.js b/js/App.js
index 764003ca9..a3618409a 100644
--- a/js/App.js
+++ b/js/App.js
@@ -343,16 +343,20 @@ const App = {
});
},
// htmlspecialchars()-alike for headlines data-content attribute
- escapeHtml: function(text) {
- const map = {
- '&': '&',
- '<': '<',
- '>': '>',
- '"': '"',
- "'": '''
- };
-
- return text.replace(/[&<>"']/g, function(m) { return map[m]; });
+ escapeHtml: function(p) {
+ if (typeof p == "string") {
+ const map = {
+ '&': '&',
+ '<': '<',
+ '>': '>',
+ '"': '"',
+ "'": '''
+ };
+
+ return p.replace(/[&<>"']/g, function(m) { return map[m]; });
+ } else {
+ return p;
+ }
},
displayIfChecked: function(checkbox, elemId) {
if (checkbox.checked) {
diff --git a/js/CommonDialogs.js b/js/CommonDialogs.js
index a75b36ed8..5477e9ecd 100644
--- a/js/CommonDialogs.js
+++ b/js/CommonDialogs.js
@@ -389,19 +389,20 @@ const CommonDialogs = {
return false;
},
- editFeed: function (feed) {
- if (feed <= 0)
+ editFeed: function (feed_id) {
+ if (feed_id <= 0)
return alert(__("You can't edit this kind of feed."));
- const query = {op: "pref-feeds", method: "editfeed", id: feed};
+ const query = {op: "pref-feeds", method: "editfeed", id: feed_id};
console.log("editFeed", query);
const dialog = new fox.SingleUseDialog({
id: "feedEditDlg",
title: __("Edit Feed"),
- unsubscribeFeed: function(feed_id, title) {
- if (confirm(__("Unsubscribe from %s?").replace("%s", title))) {
+ feed_title: "",
+ unsubscribe: function() {
+ if (confirm(__("Unsubscribe from %s?").replace("%s", this.feed_title))) {
dialog.hide();
CommonDialogs.unsubscribeFeed(feed_id);
}
@@ -430,8 +431,212 @@ const CommonDialogs = {
const tmph = dojo.connect(dialog, 'onShow', function () {
dojo.disconnect(tmph);
- xhr.post("backend.php", {op: "pref-feeds", method: "editfeed", id: feed}, (reply) => {
- dialog.attr('content', reply);
+ xhr.json("backend.php", {op: "pref-feeds", method: "editfeed", id: feed_id}, (reply) => {
+ const feed = reply.feed;
+
+ // for unsub prompt
+ dialog.feed_title = feed.title;
+
+ dialog.attr('content',
+ `
+
+
+
+ ${App.FormFields.hidden_tag("id", feed_id)}
+ ${App.FormFields.hidden_tag("op", "pref-feeds")}
+ ${App.FormFields.hidden_tag("method", "editSave")}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ${__("Choose file...")}
+
+
+
+ ${App.FormFields.hidden_tag("op", "pref-feeds")}
+ ${App.FormFields.hidden_tag("feed_id", feed_id)}
+ ${App.FormFields.hidden_tag("method", "uploadIcon")}
+ ${App.FormFields.hidden_tag("csrf_token", App.getInitParam("csrf_token"))}
+
+ ${App.FormFields.submit_tag(__("Replace"), {onclick: "return CommonDialogs.uploadFeedIcon()"})}
+ ${App.FormFields.submit_tag(__("Remove"), {class: "alt-danger", onclick: "return CommonDialogs.removeFeedIcon("+feed_id+")"})}
+
+
+
+
+ ${reply.plugin_data}
+
+
+
+
+
+ ${App.FormFields.button_tag(__("Unsubscribe"), "", {class: "pull-left alt-danger", onclick: "App.dialogOf(this).unsubscribe()"})}
+ ${App.FormFields.submit_tag(__("Save"), {onclick: "return App.dialogOf(this).execute()"})}
+ ${App.FormFields.cancel_dialog_tag(__("Cancel"))}
+
+ `);
})
});
--
cgit v1.2.3-54-g00ecf
From 22fe9b54d2150e543338dbc7541f134c0a7c61f6 Mon Sep 17 00:00:00 2001
From: Andrew Dolgov
Date: Sat, 20 Feb 2021 13:32:09 +0300
Subject: feed editor: use client dialog
---
classes/api.php | 2 +-
classes/pref/feeds.php | 310 +----------------------------------
js/CommonDialogs.js | 437 +++++++++++++++++++++----------------------------
3 files changed, 197 insertions(+), 552 deletions(-)
diff --git a/classes/api.php b/classes/api.php
index 8c32967a2..03eea1927 100755
--- a/classes/api.php
+++ b/classes/api.php
@@ -843,7 +843,7 @@ class API extends Handler {
$_REQUEST['force_show_empty'] = $include_empty;
$this->_wrap(self::STATUS_OK,
- array("categories" => $pf->makefeedtree()));
+ array("categories" => $pf->_makefeedtree()));
}
// only works for labels or uncategorized for the time being
diff --git a/classes/pref/feeds.php b/classes/pref/feeds.php
index 2c275349b..cf9e7c95e 100755
--- a/classes/pref/feeds.php
+++ b/classes/pref/feeds.php
@@ -1,7 +1,7 @@
makefeedtree());
+ print json_encode($this->_makefeedtree());
}
- function makefeedtree() {
+ function _makefeedtree() {
if (clean($_REQUEST['mode'] ?? 0) != 2)
$search = $_SESSION["prefs_feed_search"] ?? "";
@@ -500,7 +496,7 @@ class Pref_Feeds extends Handler_Protected {
WHERE id = ?");
$sth->execute([$feed_id]);
- $rc = 0;
+ $rc = Feeds::_get_icon($feed_id);
}
}
} else {
@@ -573,298 +569,6 @@ class Pref_Feeds extends Handler_Protected {
} else {
print json_encode(["error" => "FEED_NOT_FOUND"]);
}
-
- return;
-
- if ($row = $sth->fetch()) {
- print '
-
';
-
- $title = htmlspecialchars($row["title"]);
-
- print \Controls\hidden_tag("id", "$feed_id");
- print \Controls\hidden_tag("op", "pref-feeds");
- print \Controls\hidden_tag("method", "editSave");
-
- print "
";
- print "
";
-
- print "
";
- print "
";
-
- /* Update Interval */
-
- $update_interval = $row["update_interval"];
-
- print "";
-
- print "".__("Interval:")." ";
-
- $local_update_intervals = $update_intervals;
- $local_update_intervals[0] .= sprintf(" (%s)", $update_intervals[get_pref("DEFAULT_UPDATE_INTERVAL")]);
-
- print \Controls\select_hash("update_interval", $update_interval, $local_update_intervals);
-
- print " ";
-
- /* Purge intl */
-
- $purge_interval = $row["purge_interval"];
-
- print "";
-
- print "" . __('Article purging:') . " ";
-
- if (FORCE_ARTICLE_PURGE == 0) {
- $local_purge_intervals = $purge_intervals;
- $default_purge_interval = get_pref("PURGE_OLD_DAYS");
-
- if ($default_purge_interval > 0)
- $local_purge_intervals[0] .= " " . T_nsprintf('(%d day)', '(%d days)', $default_purge_interval, $default_purge_interval);
- else
- $local_purge_intervals[0] .= " " . sprintf("(%s)", __("Disabled"));
-
- } else {
- $purge_interval = FORCE_ARTICLE_PURGE;
- $local_purge_intervals = [ T_nsprintf('%d day', '%d days', $purge_interval, $purge_interval) ];
- }
-
- print \Controls\select_hash("purge_interval",
- $purge_interval,
- $local_purge_intervals,
- (FORCE_ARTICLE_PURGE == 0) ? [] : ["disabled" => 1]);
-
- print " ";
-
- print " ";
-
- $auth_login = htmlspecialchars($row["auth_login"]);
- $auth_pass = htmlspecialchars($row["auth_pass"]);
-
- $auth_enabled = $auth_login !== '' || $auth_pass !== '';
-
- $auth_style = $auth_enabled ? '' : 'display: none';
- print "
";
- print "";
- print "
";
-
- $auth_checked = $auth_enabled ? 'checked' : '';
- print "
-
- ".__('This feed requires authentication.')." ";
-
- print '
';
-
- print "
';
-
- /* Icon */
-
- print "
";
-
- print "
- ".__("Choose file...")."
-
-
-
-
-
-
- ".__('Replace')."
- ".__('Remove')."
- ";
-
- print "";
-
- print '
';
-
- PluginHost::getInstance()->run_hooks(PluginHost::HOOK_PREFS_EDIT_FEED, $feed_id);
-
- print "
";
-
- $title = htmlspecialchars($title, ENT_QUOTES);
-
- print "
- ".
- __('Unsubscribe')."
- ".__('Save')."
- ".__('Cancel')."
- ";
- }
}
function editfeeds() {
@@ -1036,7 +740,7 @@ class Pref_Feeds extends Handler_Protected {
return $this->editsaveops(false);
}
- function editsaveops($batch) {
+ private function editsaveops($batch) {
$feed_title = clean($_POST["title"]);
$feed_url = clean($_POST["feed_url"]);
@@ -1064,10 +768,6 @@ class Pref_Feeds extends Handler_Protected {
$feed_language = clean($_POST["feed_language"]);
if (!$batch) {
- if (clean($_POST["need_auth"] ?? "") !== 'on') {
- $auth_login = '';
- $auth_pass = '';
- }
/* $sth = $this->pdo->prepare("SELECT feed_url FROM ttrss_feeds WHERE id = ?");
$sth->execute([$feed_id]);
diff --git a/js/CommonDialogs.js b/js/CommonDialogs.js
index 5477e9ecd..704e797d3 100644
--- a/js/CommonDialogs.js
+++ b/js/CommonDialogs.js
@@ -11,72 +11,6 @@ const CommonDialogs = {
const dialog = dijit.byId("infoBox");
if (dialog) dialog.hide();
},
- removeFeedIcon: function(id) {
- if (confirm(__("Remove stored feed icon?"))) {
- Notify.progress("Removing feed icon...", true);
-
- const query = {op: "pref-feeds", method: "removeicon", feed_id: id};
-
- xhr.post("backend.php", query, () => {
- Notify.info("Feed icon removed.");
-
- if (App.isPrefs())
- dijit.byId("feedTree").reload();
- else
- Feeds.reload();
-
- const icon = App.findAll(".feed-editor-icon")[0];
-
- if (icon)
- icon.src = icon.src.replace(/\?[0-9]+$/, "?" + new Date().getTime());
-
- });
- }
-
- return false;
- },
- uploadFeedIcon: function() {
- const file = App.byId("icon_file");
-
- if (file.value.length == 0) {
- alert(__("Please select an image file to upload."));
- } else if (confirm(__("Upload new icon for this feed?"))) {
- Notify.progress("Uploading, please wait...", true);
-
- const xhr = new XMLHttpRequest();
-
- xhr.open( 'POST', 'backend.php', true );
- xhr.onload = function () {
- switch (parseInt(this.responseText)) {
- case 0:
- {
- Notify.info("Upload complete.");
-
- if (App.isPrefs())
- dijit.byId("feedTree").reload();
- else
- Feeds.reload();
-
- const icon = App.findAll(".feed-editor-icon")[0];
-
- if (icon)
- icon.src = icon.src.replace(/\?[0-9]+$/, "?" + new Date().getTime());
-
- }
- break;
- case 1:
- Notify.error("Upload failed: icon is too big.");
- break;
- case 2:
- Notify.error("Upload failed.");
- break;
- }
- };
- xhr.send(new FormData(App.byId("feed_icon_upload_form")));
- }
-
- return false;
- },
subscribeToFeed: function() {
xhr.json("backend.php",
{op: "feeds", method: "subscribeToFeed"},
@@ -407,6 +341,86 @@ const CommonDialogs = {
CommonDialogs.unsubscribeFeed(feed_id);
}
},
+ uploadIcon: function(input) {
+ if (input.files.length != 0) {
+ const icon_file = input.files[0];
+
+ if (icon_file.type.indexOf("image/") == -1) {
+ alert(__("Please select an image file."));
+ return;
+ }
+
+ const fd = new FormData();
+ fd.append('icon_file', icon_file)
+ fd.append('feed_id', feed_id);
+ fd.append('op', 'pref-feeds');
+ fd.append('method', 'uploadIcon');
+ fd.append('csrf_token', App.getInitParam("csrf_token"));
+
+ const xhr = new XMLHttpRequest();
+
+ xhr.open( 'POST', 'backend.php', true );
+ xhr.onload = function () {
+ console.log(this.responseText);
+
+ // TODO: make a notice box within panel content
+ switch (parseInt(this.responseText)) {
+ case 1:
+ Notify.error("Upload failed: icon is too big.");
+ break;
+ case 2:
+ Notify.error("Upload failed.");
+ break;
+ default:
+ {
+ Notify.info("Upload complete.");
+
+ if (App.isPrefs())
+ dijit.byId("feedTree").reload();
+ else
+ Feeds.reload();
+
+ const icon = dialog.domNode.querySelector(".feedIcon");
+
+ if (icon) {
+ icon.src = this.responseText;
+ icon.show();
+ }
+
+ input.value = "";
+ }
+ }
+ };
+
+ xhr.send(fd);
+
+ }
+ },
+ removeIcon: function(id) {
+ if (confirm(__("Remove stored feed icon?"))) {
+ Notify.progress("Removing feed icon...", true);
+
+ const query = {op: "pref-feeds", method: "removeicon", feed_id: id};
+
+ xhr.post("backend.php", query, () => {
+ Notify.info("Feed icon removed.");
+
+ if (App.isPrefs())
+ dijit.byId("feedTree").reload();
+ else
+ Feeds.reload();
+
+ const icon = dialog.domNode.querySelector(".feedIcon");
+
+ if (icon) {
+ icon.src = "";
+ icon.hide();
+ }
+ });
+ }
+
+ return false;
+ },
execute: function () {
if (this.validate()) {
Notify.progress("Saving data...", true);
@@ -437,205 +451,136 @@ const CommonDialogs = {
// for unsub prompt
dialog.feed_title = feed.title;
+ // options tab
+ const options = {
+ include_in_digest: [ feed.include_in_digest, __('Include in e-mail digest') ],
+ always_display_enclosures: [ feed.always_display_enclosures, __('Always display image attachments') ],
+ hide_images: [ feed.hide_images, __('Do not embed media') ],
+ cache_images: [ feed.cache_images, __('Cache media') ],
+ mark_unread_on_update: [ feed.mark_unread_on_update, __('Mark updated articles as unread') ]
+ };
+
dialog.attr('content',
`
-
-
+
+
+
- ${App.FormFields.hidden_tag("id", feed_id)}
- ${App.FormFields.hidden_tag("op", "pref-feeds")}
- ${App.FormFields.hidden_tag("method", "editSave")}
-
-
-
-
-
-
-
+
+ ${__("Update interval:")}
+ ${App.FormFields.select_hash("update_interval", feed.update_interval, reply.intervals.update)}
+
+
+ ${__('Article purging:')}
-
+ ${App.FormFields.select_hash("purge_interval",
+ feed.purge_interval,
+ reply.intervals.purge,
+ reply.force_purge ? {disabled: 1} : {})}
-
+
+
+
+
+
+
+
+
+ ${Object.keys(options).map((name) =>
+ `
+
+
+ ${App.FormFields.checkbox_tag(name, options[name][0])}
+ ${options[name][1]}
+
+
+ `).join("")}
+
+
+
-
-
- ${reply.plugin_data}
-
-
+ ${App.FormFields.submit_tag(__("Remove"), {class: "alt-danger", onclick: "App.dialogOf(this).removeIcon("+feed_id+")"})}
+
+
+ ${reply.plugin_data}
+
-
-
- ${App.FormFields.button_tag(__("Unsubscribe"), "", {class: "pull-left alt-danger", onclick: "App.dialogOf(this).unsubscribe()"})}
- ${App.FormFields.submit_tag(__("Save"), {onclick: "return App.dialogOf(this).execute()"})}
- ${App.FormFields.cancel_dialog_tag(__("Cancel"))}
-
+
+ ${App.FormFields.button_tag(__("Unsubscribe"), "", {class: "pull-left alt-danger", onclick: "App.dialogOf(this).unsubscribe()"})}
+ ${App.FormFields.submit_tag(__("Save"), {onclick: "App.dialogOf(this).execute()"})}
+ ${App.FormFields.cancel_dialog_tag(__("Cancel"))}
+
+
`);
})
});
--
cgit v1.2.3-54-g00ecf
From 5c7416458f76f83a46e4c39a8697ebaed08bce3d Mon Sep 17 00:00:00 2001
From: Andrew Dolgov
Date: Sat, 20 Feb 2021 13:37:21 +0300
Subject: rpc: disable completeLabels for now
---
classes/rpc.php | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/classes/rpc.php b/classes/rpc.php
index a87f07009..643ad29d8 100755
--- a/classes/rpc.php
+++ b/classes/rpc.php
@@ -1,11 +1,11 @@
pdo->prepare("SELECT DISTINCT caption FROM
@@ -145,7 +145,7 @@ class RPC extends Handler_Protected {
print "" . $line["caption"] . " ";
}
print "";
- }
+ }*/
function catchupFeed() {
$feed_id = clean($_REQUEST['feed_id']);
--
cgit v1.2.3-54-g00ecf
From 39be169f0bb05d73f82e6f98a2e608844fa3f0c1 Mon Sep 17 00:00:00 2001
From: Andrew Dolgov
Date: Sat, 20 Feb 2021 13:39:17 +0300
Subject: also disable Article.completeTags
---
classes/article.php | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/classes/article.php b/classes/article.php
index e64c17a32..dd1470caa 100755
--- a/classes/article.php
+++ b/classes/article.php
@@ -253,7 +253,7 @@ class Article extends Handler_Protected {
}
- function completeTags() {
+ /*function completeTags() {
$search = clean($_REQUEST["search"]);
$sth = $this->pdo->prepare("SELECT DISTINCT tag_name FROM ttrss_tags
@@ -268,7 +268,7 @@ class Article extends Handler_Protected {
print "" . $line["tag_name"] . " ";
}
print "";
- }
+ }*/
function assigntolabel() {
return $this->_label_ops(true);
--
cgit v1.2.3-54-g00ecf
From d6de021ae6eb3e2385630763f2f5daab2566a499 Mon Sep 17 00:00:00 2001
From: Andrew Dolgov
Date: Sat, 20 Feb 2021 13:52:02 +0300
Subject: haven't i fixed this already
---
js/App.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/js/App.js b/js/App.js
index a3618409a..2041a6168 100644
--- a/js/App.js
+++ b/js/App.js
@@ -1222,7 +1222,7 @@ const App = {
}
break;
case "qmcHKhelp":
- this.helpDialog("main");
+ this.hotkeyHelp()
break;
default:
console.log("quickMenuGo: unknown action: " + opid);
--
cgit v1.2.3-54-g00ecf
From be91355c20140c797912247bfbfb45b7dbfd41c9 Mon Sep 17 00:00:00 2001
From: Andrew Dolgov
Date: Sat, 20 Feb 2021 18:15:08 +0300
Subject: first for filter frontend overhaul
---
classes/pref/filters.php | 2 +-
js/CommonFilters.js | 418 +++++++++++++++++++++++------------------------
2 files changed, 208 insertions(+), 212 deletions(-)
diff --git a/classes/pref/filters.php b/classes/pref/filters.php
index f9b3217c9..cfff383d8 100755
--- a/classes/pref/filters.php
+++ b/classes/pref/filters.php
@@ -861,7 +861,7 @@ class Pref_Filters extends Handler_Protected {
print "";
print "";
+ onchange='Filters.hideOrShowActionParam(this)'>";
$res = $this->pdo->query("SELECT id,description FROM ttrss_filter_actions
ORDER BY name");
diff --git a/js/CommonFilters.js b/js/CommonFilters.js
index 0fc8f87ae..222bba4bd 100644
--- a/js/CommonFilters.js
+++ b/js/CommonFilters.js
@@ -5,245 +5,241 @@
/* global __, App, Article, Lists, fox */
/* global xhr, dojo, dijit, Notify, Feeds */
-const Filters = {
- filterDlgCheckAction: function(sender) {
- const action = sender.value;
-
- const action_param = App.byId("filterDlg_paramBox");
-
- if (!action_param) {
- console.log("filterDlgCheckAction: can't find action param box!");
- return;
- }
-
- // if selected action supports parameters, enable params field
- if (action == 4 || action == 6 || action == 7 || action == 9) {
- Element.show(action_param);
-
- Element.hide(dijit.byId("filterDlg_actionParam").domNode);
- Element.hide(dijit.byId("filterDlg_actionParamLabel").domNode);
- Element.hide(dijit.byId("filterDlg_actionParamPlugin").domNode);
-
- if (action == 7) {
- Element.show(dijit.byId("filterDlg_actionParamLabel").domNode);
- } else if (action == 9) {
- Element.show(dijit.byId("filterDlg_actionParamPlugin").domNode);
- } else {
- Element.show(dijit.byId("filterDlg_actionParam").domNode);
- }
+const Filters = {
+ edit: function(id) { // if no id, new filter dialog
+ let query;
+ if (!App.isPrefs()) {
+ query = {
+ op: "pref-filters", method: "edit",
+ feed: Feeds.getActive(), is_cat: Feeds.activeIsCat()
+ };
} else {
- Element.hide(action_param);
- }
- },
- createNewRuleElement: function(parentNode, replaceNode) {
- const rule = dojo.formToJson("filter_new_rule_form");
-
- xhr.post("backend.php", {op: "pref-filters", method: "printrulename", rule: rule}, (reply) => {
- try {
- const li = document.createElement('li');
-
- li.innerHTML = `
- ${reply}
- ${App.FormFields.hidden_tag("rule[]", rule)}`;
-
- dojo.parser.parse(li);
-
- if (replaceNode) {
- parentNode.replaceChild(li, replaceNode);
- } else {
- parentNode.appendChild(li);
- }
- } catch (e) {
- App.Error.report(e);
- }
- });
- },
- createNewActionElement: function(parentNode, replaceNode) {
- const form = document.forms["filter_new_action_form"];
-
- if (form.action_id.value == 7) {
- form.action_param.value = form.action_param_label.value;
- } else if (form.action_id.value == 9) {
- form.action_param.value = form.action_param_plugin.value;
+ query = {op: "pref-filters", method: "edit", id: id};
}
- const action = dojo.formToJson(form);
-
- xhr.post("backend.php", { op: "pref-filters", method: "printactionname", action: action }, (reply) => {
+ xhr.post("backend.php", query, function (reply) {
try {
- const li = document.createElement('li');
-
- li.innerHTML = `
- ${reply}
- ${App.FormFields.hidden_tag("action[]", action)}`;
-
- dojo.parser.parse(li);
-
- if (replaceNode) {
- parentNode.replaceChild(li, replaceNode);
- } else {
- parentNode.appendChild(li);
- }
-
- } catch (e) {
- App.Error.report(e);
- }
- });
- },
- addFilterRule: function(replaceNode, ruleStr) {
- const dialog = new fox.SingleUseDialog({
- id: "filterNewRuleDlg",
- title: ruleStr ? __("Edit rule") : __("Add rule"),
- execute: function () {
- if (this.validate()) {
- Filters.createNewRuleElement(App.byId("filterDlg_Matches"), replaceNode);
- this.hide();
- }
- },
- content: __('Loading, please wait...'),
- });
-
- const tmph = dojo.connect(dialog, "onShow", null, function (/* e */) {
- dojo.disconnect(tmph);
+ const dialog = new fox.SingleUseDialog({
+ id: "filterEditDlg",
+ title: id ? __("Edit Filter") : __("Create Filter"),
+ test: function() {
+ const test_dialog = new fox.SingleUseDialog({
+ title: "Test Filter",
+ results: 0,
+ limit: 100,
+ max_offset: 10000,
+ getTestResults: function (params, offset) {
+ params.method = 'testFilterDo';
+ params.offset = offset;
+ params.limit = test_dialog.limit;
+
+ console.log("getTestResults:" + offset);
+
+ xhr.json("backend.php", params, (result) => {
+ try {
+ if (result && test_dialog && test_dialog.open) {
+ test_dialog.results += result.length;
+
+ console.log("got results:" + result.length);
+
+ App.byId("prefFilterProgressMsg").innerHTML = __("Looking for articles (%d processed, %f found)...")
+ .replace("%f", test_dialog.results)
+ .replace("%d", offset);
+
+ console.log(offset + " " + test_dialog.max_offset);
+
+ for (let i = 0; i < result.length; i++) {
+ const tmp = dojo.create("table", { innerHTML: result[i]});
+
+ App.byId("prefFilterTestResultList").innerHTML += tmp.innerHTML;
+ }
+
+ if (test_dialog.results < 30 && offset < test_dialog.max_offset) {
+
+ // get the next batch
+ window.setTimeout(function () {
+ test_dialog.getTestResults(params, offset + test_dialog.limit);
+ }, 0);
+
+ } else {
+ // all done
+
+ Element.hide("prefFilterLoadingIndicator");
+
+ if (test_dialog.results == 0) {
+ App.byId("prefFilterTestResultList").innerHTML = `
+ ${__('No recent articles matching this filter have been found.')} `;
+ App.byId("prefFilterProgressMsg").innerHTML = "Articles matching this filter:";
+ } else {
+ App.byId("prefFilterProgressMsg").innerHTML = __("Found %d articles matching this filter:")
+ .replace("%d", test_dialog.results);
+ }
+
+ }
+
+ } else if (!result) {
+ console.log("getTestResults: can't parse results object");
+ Element.hide("prefFilterLoadingIndicator");
+ Notify.error("Error while trying to get filter test results.");
+ } else {
+ console.log("getTestResults: dialog closed, bailing out.");
+ }
+ } catch (e) {
+ App.Error.report(e);
+ }
+ });
+ },
+ content: `
+
+
+
Looking for articles...
+
+
+
+
+
+ ${__('Close this window')}
+
+ `
+ });
- xhr.post("backend.php", {op: 'pref-filters', method: 'newrule', rule: ruleStr}, (reply) => {
- dialog.attr('content', reply);
- });
- });
+ const tmph = dojo.connect(test_dialog, "onShow", null, function (/* e */) {
+ dojo.disconnect(tmph);
- dialog.show();
- },
- addFilterAction: function(replaceNode, actionStr) {
- const dialog = new fox.SingleUseDialog({
- title: actionStr ? __("Edit action") : __("Add action"),
- execute: function () {
- if (this.validate()) {
- Filters.createNewActionElement(App.byId("filterDlg_Actions"), replaceNode);
- this.hide();
- }
- }
- });
+ test_dialog.getTestResults(dialog.attr('value'), 0);
+ });
- const tmph = dojo.connect(dialog, "onShow", null, function (/* e */) {
- dojo.disconnect(tmph);
+ test_dialog.show();
+ },
+ hideOrShowActionParam: function(sender) {
+ const action = sender.value;
- xhr.post("backend.php", {op: 'pref-filters', method: 'newaction', action: actionStr}, (reply) => {
- dialog.attr('content', reply);
- });
- });
+ const action_param = App.byId("filterDlg_paramBox");
- dialog.show();
- },
- test: function(params) {
+ if (!action_param) {
+ console.log("hideOrShowActionParam: can't find action param box!");
+ return;
+ }
- const dialog = new fox.SingleUseDialog({
- title: "Test Filter",
- results: 0,
- limit: 100,
- max_offset: 10000,
- getTestResults: function (params, offset) {
- params.method = 'testFilterDo';
- params.offset = offset;
- params.limit = dialog.limit;
+ // if selected action supports parameters, enable params field
+ if (action == 4 || action == 6 || action == 7 || action == 9) {
+ Element.show(action_param);
- console.log("getTestResults:" + offset);
+ Element.hide(dijit.byId("filterDlg_actionParam").domNode);
+ Element.hide(dijit.byId("filterDlg_actionParamLabel").domNode);
+ Element.hide(dijit.byId("filterDlg_actionParamPlugin").domNode);
- xhr.json("backend.php", params, (result) => {
- try {
- if (result && dialog && dialog.open) {
- dialog.results += result.length;
+ if (action == 7) {
+ Element.show(dijit.byId("filterDlg_actionParamLabel").domNode);
+ } else if (action == 9) {
+ Element.show(dijit.byId("filterDlg_actionParamPlugin").domNode);
+ } else {
+ Element.show(dijit.byId("filterDlg_actionParam").domNode);
+ }
- console.log("got results:" + result.length);
+ } else {
+ Element.hide(action_param);
+ }
+ },
+ createNewRuleElement: function(parentNode, replaceNode) {
+ const rule = dojo.formToJson("filter_new_rule_form");
- App.byId("prefFilterProgressMsg").innerHTML = __("Looking for articles (%d processed, %f found)...")
- .replace("%f", dialog.results)
- .replace("%d", offset);
+ xhr.post("backend.php", {op: "pref-filters", method: "printrulename", rule: rule}, (reply) => {
+ try {
+ const li = document.createElement('li');
- console.log(offset + " " + dialog.max_offset);
+ li.innerHTML = `
+ ${reply}
+ ${App.FormFields.hidden_tag("rule[]", rule)}`;
- for (let i = 0; i < result.length; i++) {
- const tmp = dojo.create("table", { innerHTML: result[i]});
+ dojo.parser.parse(li);
- App.byId("prefFilterTestResultList").innerHTML += tmp.innerHTML;
+ if (replaceNode) {
+ parentNode.replaceChild(li, replaceNode);
+ } else {
+ parentNode.appendChild(li);
+ }
+ } catch (e) {
+ App.Error.report(e);
}
+ });
+ },
+ createNewActionElement: function(parentNode, replaceNode) {
+ const form = document.forms["filter_new_action_form"];
- if (dialog.results < 30 && offset < dialog.max_offset) {
+ if (form.action_id.value == 7) {
+ form.action_param.value = form.action_param_label.value;
+ } else if (form.action_id.value == 9) {
+ form.action_param.value = form.action_param_plugin.value;
+ }
- // get the next batch
- window.setTimeout(function () {
- dialog.getTestResults(params, offset + dialog.limit);
- }, 0);
+ const action = dojo.formToJson(form);
- } else {
- // all done
+ xhr.post("backend.php", { op: "pref-filters", method: "printactionname", action: action }, (reply) => {
+ try {
+ const li = document.createElement('li');
- Element.hide("prefFilterLoadingIndicator");
+ li.innerHTML = `
+ ${reply}
+ ${App.FormFields.hidden_tag("action[]", action)}`;
- if (dialog.results == 0) {
- App.byId("prefFilterTestResultList").innerHTML = `
- ${__('No recent articles matching this filter have been found.')} `;
- App.byId("prefFilterProgressMsg").innerHTML = "Articles matching this filter:";
+ dojo.parser.parse(li);
+
+ if (replaceNode) {
+ parentNode.replaceChild(li, replaceNode);
} else {
- App.byId("prefFilterProgressMsg").innerHTML = __("Found %d articles matching this filter:")
- .replace("%d", dialog.results);
+ parentNode.appendChild(li);
}
+ } catch (e) {
+ App.Error.report(e);
}
+ });
+ },
+ addFilterRule: function(replaceNode, ruleStr) {
+ const add_dialog = new fox.SingleUseDialog({
+ id: "filterNewRuleDlg",
+ title: ruleStr ? __("Edit rule") : __("Add rule"),
+ execute: function () {
+ if (this.validate()) {
+ dialog.createNewRuleElement(App.byId("filterDlg_Matches"), replaceNode);
+ this.hide();
+ }
+ },
+ content: __('Loading, please wait...'),
+ });
- } else if (!result) {
- console.log("getTestResults: can't parse results object");
- Element.hide("prefFilterLoadingIndicator");
- Notify.error("Error while trying to get filter test results.");
- } else {
- console.log("getTestResults: dialog closed, bailing out.");
- }
- } catch (e) {
- App.Error.report(e);
- }
- });
- },
- content: `
-
-
-
Looking for articles...
-
-
-
-
-
- ${__('Close this window')}
-
- `
- });
+ const tmph = dojo.connect(add_dialog, "onShow", null, function (/* e */) {
+ dojo.disconnect(tmph);
- dojo.connect(dialog, "onShow", null, function (/* e */) {
- dialog.getTestResults(params, 0);
- });
+ xhr.post("backend.php", {op: 'pref-filters', method: 'newrule', rule: ruleStr}, (reply) => {
+ add_dialog.attr('content', reply);
+ });
+ });
- dialog.show();
- },
- edit: function(id) { // if no id, new filter dialog
- let query;
+ add_dialog.show();
+ },
+ addFilterAction: function(replaceNode, actionStr) {
+ const add_dialog = new fox.SingleUseDialog({
+ title: actionStr ? __("Edit action") : __("Add action"),
+ execute: function () {
+ if (this.validate()) {
+ dialog.createNewActionElement(App.byId("filterDlg_Actions"), replaceNode);
+ this.hide();
+ }
+ }
+ });
- if (!App.isPrefs()) {
- query = {
- op: "pref-filters", method: "edit",
- feed: Feeds.getActive(), is_cat: Feeds.activeIsCat()
- };
- } else {
- query = {op: "pref-filters", method: "edit", id: id};
- }
+ const tmph = dojo.connect(add_dialog, "onShow", null, function (/* e */) {
+ dojo.disconnect(tmph);
- console.log('Filters.edit', query);
+ xhr.post("backend.php", {op: 'pref-filters', method: 'newaction', action: actionStr}, (reply) => {
+ add_dialog.attr('content', reply);
+ });
+ });
- xhr.post("backend.php", query, function (reply) {
- try {
- const dialog = new fox.SingleUseDialog({
- id: "filterEditDlg",
- title: id ? __("Edit Filter") : __("Create Filter"),
- test: function () {
- Filters.test(this.attr('value'));
+ add_dialog.show();
},
selectRules: function (select) {
Lists.select("filterDlg_Matches", select);
@@ -255,13 +251,13 @@ const Filters = {
const li = e.closest('li');
const rule = li.querySelector('input[name="rule[]"]').value
- Filters.addFilterRule(li, rule);
+ this.addFilterRule(li, rule);
},
editAction: function (e) {
const li = e.closest('li');
const action = li.querySelector('input[name="action[]"]').value
- Filters.addFilterAction(li, action);
+ this.addFilterAction(li, action);
},
removeFilter: function () {
const msg = __("Remove filter?");
@@ -281,10 +277,10 @@ const Filters = {
}
},
addAction: function () {
- Filters.addFilterAction();
+ this.addFilterAction();
},
addRule: function () {
- Filters.addFilterRule();
+ this.addFilterRule();
},
deleteAction: function () {
App.findAll("#filterDlg_Actions li[class*=Selected]").forEach(function (e) {
@@ -326,7 +322,7 @@ const Filters = {
const rule = {reg_exp: selectedText, feed_id: [feed_id], filter_type: 1};
- Filters.addFilterRule(null, dojo.toJson(rule));
+ dialog.addFilterRule(null, dojo.toJson(rule));
} else {
@@ -346,7 +342,7 @@ const Filters = {
const rule = {reg_exp: title, feed_id: [feed_id], filter_type: 1};
- Filters.addFilterRule(null, dojo.toJson(rule));
+ dialog.addFilterRule(null, dojo.toJson(rule));
}
});
}
--
cgit v1.2.3-54-g00ecf
From 590b1fc39e104bd41a8ab213b98b38345dba4eac Mon Sep 17 00:00:00 2001
From: Andrew Dolgov
Date: Sat, 20 Feb 2021 18:21:36 +0300
Subject: a few more methods shuffled around
---
classes/pref/filters.php | 6 +--
js/CommonFilters.js | 104 ++++++++++++++++++++++++-----------------------
2 files changed, 56 insertions(+), 54 deletions(-)
diff --git a/classes/pref/filters.php b/classes/pref/filters.php
index cfff383d8..1aeaa8a3f 100755
--- a/classes/pref/filters.php
+++ b/classes/pref/filters.php
@@ -389,7 +389,7 @@ class Pref_Filters extends Handler_Protected {
unset($line["match_on"]);
print "
- ".$this->_get_rule_name($line)." ".
+ ".$this->_get_rule_name($line)." ".
\Controls\hidden_tag("rule[]", (string)json_encode($line))." ";
}
}
@@ -429,7 +429,7 @@ class Pref_Filters extends Handler_Protected {
unset($line["id"]);
print "
- ".$this->_get_action_name($line)." ".
+ ".$this->_get_action_name($line)." ".
\Controls\hidden_tag("action[]", (string)json_encode($line))." ";
}
}
@@ -861,7 +861,7 @@ class Pref_Filters extends Handler_Protected {
print "";
print "";
+ onchange='App.dialogOf(this).hideOrShowActionParam(this)'>";
$res = $this->pdo->query("SELECT id,description FROM ttrss_filter_actions
ORDER BY name");
diff --git a/js/CommonFilters.js b/js/CommonFilters.js
index 222bba4bd..210c63479 100644
--- a/js/CommonFilters.js
+++ b/js/CommonFilters.js
@@ -5,7 +5,8 @@
/* global __, App, Article, Lists, fox */
/* global xhr, dojo, dijit, Notify, Feeds */
-const Filters = {
+/* exported Filters */
+const Filters = {
edit: function(id) { // if no id, new filter dialog
let query;
@@ -112,36 +113,6 @@ const Filters = {
test_dialog.show();
},
- hideOrShowActionParam: function(sender) {
- const action = sender.value;
-
- const action_param = App.byId("filterDlg_paramBox");
-
- if (!action_param) {
- console.log("hideOrShowActionParam: can't find action param box!");
- return;
- }
-
- // if selected action supports parameters, enable params field
- if (action == 4 || action == 6 || action == 7 || action == 9) {
- Element.show(action_param);
-
- Element.hide(dijit.byId("filterDlg_actionParam").domNode);
- Element.hide(dijit.byId("filterDlg_actionParamLabel").domNode);
- Element.hide(dijit.byId("filterDlg_actionParamPlugin").domNode);
-
- if (action == 7) {
- Element.show(dijit.byId("filterDlg_actionParamLabel").domNode);
- } else if (action == 9) {
- Element.show(dijit.byId("filterDlg_actionParamPlugin").domNode);
- } else {
- Element.show(dijit.byId("filterDlg_actionParam").domNode);
- }
-
- } else {
- Element.hide(action_param);
- }
- },
createNewRuleElement: function(parentNode, replaceNode) {
const rule = dojo.formToJson("filter_new_rule_form");
@@ -150,7 +121,7 @@ const Filters = {
const li = document.createElement('li');
li.innerHTML = `
- ${reply}
+ ${reply}
${App.FormFields.hidden_tag("rule[]", rule)}`;
dojo.parser.parse(li);
@@ -181,7 +152,7 @@ const Filters = {
const li = document.createElement('li');
li.innerHTML = `
- ${reply}
+ ${reply}
${App.FormFields.hidden_tag("action[]", action)}`;
dojo.parser.parse(li);
@@ -197,8 +168,8 @@ const Filters = {
}
});
},
- addFilterRule: function(replaceNode, ruleStr) {
- const add_dialog = new fox.SingleUseDialog({
+ editRule: function(replaceNode, ruleStr) {
+ const edit_rule_dialog = new fox.SingleUseDialog({
id: "filterNewRuleDlg",
title: ruleStr ? __("Edit rule") : __("Add rule"),
execute: function () {
@@ -210,19 +181,50 @@ const Filters = {
content: __('Loading, please wait...'),
});
- const tmph = dojo.connect(add_dialog, "onShow", null, function (/* e */) {
+ const tmph = dojo.connect(edit_rule_dialog, "onShow", null, function (/* e */) {
dojo.disconnect(tmph);
xhr.post("backend.php", {op: 'pref-filters', method: 'newrule', rule: ruleStr}, (reply) => {
- add_dialog.attr('content', reply);
+ edit_rule_dialog.attr('content', reply);
});
});
- add_dialog.show();
+ edit_rule_dialog.show();
},
- addFilterAction: function(replaceNode, actionStr) {
- const add_dialog = new fox.SingleUseDialog({
+ editAction: function(replaceNode, actionStr) {
+ const edit_action_dialog = new fox.SingleUseDialog({
title: actionStr ? __("Edit action") : __("Add action"),
+ hideOrShowActionParam: function(sender) {
+ const action = sender.value;
+
+ const action_param = App.byId("filterDlg_paramBox");
+
+ if (!action_param) {
+ console.log("hideOrShowActionParam: can't find action param box!");
+ return;
+ }
+
+ // if selected action supports parameters, enable params field
+ if (action == 4 || action == 6 || action == 7 || action == 9) {
+ Element.show(action_param);
+
+ Element.hide(dijit.byId("filterDlg_actionParam").domNode);
+ Element.hide(dijit.byId("filterDlg_actionParamLabel").domNode);
+ Element.hide(dijit.byId("filterDlg_actionParamPlugin").domNode);
+
+ if (action == 7) {
+ Element.show(dijit.byId("filterDlg_actionParamLabel").domNode);
+ } else if (action == 9) {
+ Element.show(dijit.byId("filterDlg_actionParamPlugin").domNode);
+ } else {
+ Element.show(dijit.byId("filterDlg_actionParam").domNode);
+ }
+
+ } else {
+ Element.hide(action_param);
+ }
+ },
+
execute: function () {
if (this.validate()) {
dialog.createNewActionElement(App.byId("filterDlg_Actions"), replaceNode);
@@ -231,15 +233,15 @@ const Filters = {
}
});
- const tmph = dojo.connect(add_dialog, "onShow", null, function (/* e */) {
+ const tmph = dojo.connect(edit_action_dialog, "onShow", null, function (/* e */) {
dojo.disconnect(tmph);
xhr.post("backend.php", {op: 'pref-filters', method: 'newaction', action: actionStr}, (reply) => {
- add_dialog.attr('content', reply);
+ edit_action_dialog.attr('content', reply);
});
});
- add_dialog.show();
+ edit_action_dialog.show();
},
selectRules: function (select) {
Lists.select("filterDlg_Matches", select);
@@ -247,17 +249,17 @@ const Filters = {
selectActions: function (select) {
Lists.select("filterDlg_Actions", select);
},
- editRule: function (e) {
+ onRuleClicked: function (e) {
const li = e.closest('li');
const rule = li.querySelector('input[name="rule[]"]').value
- this.addFilterRule(li, rule);
+ this.editRule(li, rule);
},
- editAction: function (e) {
+ onActionClicked: function (e) {
const li = e.closest('li');
const action = li.querySelector('input[name="action[]"]').value
- this.addFilterAction(li, action);
+ this.editAction(li, action);
},
removeFilter: function () {
const msg = __("Remove filter?");
@@ -277,10 +279,10 @@ const Filters = {
}
},
addAction: function () {
- this.addFilterAction();
+ this.editAction();
},
addRule: function () {
- this.addFilterRule();
+ this.editRule();
},
deleteAction: function () {
App.findAll("#filterDlg_Actions li[class*=Selected]").forEach(function (e) {
@@ -322,7 +324,7 @@ const Filters = {
const rule = {reg_exp: selectedText, feed_id: [feed_id], filter_type: 1};
- dialog.addFilterRule(null, dojo.toJson(rule));
+ dialog.editRule(null, dojo.toJson(rule));
} else {
@@ -342,7 +344,7 @@ const Filters = {
const rule = {reg_exp: title, feed_id: [feed_id], filter_type: 1};
- dialog.addFilterRule(null, dojo.toJson(rule));
+ dialog.editRule(null, dojo.toJson(rule));
}
});
}
--
cgit v1.2.3-54-g00ecf
From da97b29dbe7ac923fae5a0cddee141716d1da3e5 Mon Sep 17 00:00:00 2001
From: Andrew Dolgov
Date: Sat, 20 Feb 2021 21:07:28 +0300
Subject: prevent filter selected text dialog from opening in wrong order
---
js/App.js | 21 ++
js/CommonFilters.js | 536 ++++++++++++++++++++++++++--------------------------
js/common.js | 22 ---
3 files changed, 284 insertions(+), 295 deletions(-)
diff --git a/js/App.js b/js/App.js
index 2041a6168..68f3740c5 100644
--- a/js/App.js
+++ b/js/App.js
@@ -358,6 +358,27 @@ const App = {
return p;
}
},
+ // http://stackoverflow.com/questions/6251937/how-to-get-selecteduser-highlighted-text-in-contenteditable-element-and-replac
+ getSelectedText: function() {
+ let text = "";
+
+ if (typeof window.getSelection != "undefined") {
+ const sel = window.getSelection();
+ if (sel.rangeCount) {
+ const container = document.createElement("div");
+ for (let i = 0, len = sel.rangeCount; i < len; ++i) {
+ container.appendChild(sel.getRangeAt(i).cloneContents());
+ }
+ text = container.innerHTML;
+ }
+ } else if (typeof document.selection != "undefined") {
+ if (document.selection.type == "Text") {
+ text = document.selection.createRange().textText;
+ }
+ }
+
+ return text.stripTags();
+ },
displayIfChecked: function(checkbox, elemId) {
if (checkbox.checked) {
Element.show(elemId);
diff --git a/js/CommonFilters.js b/js/CommonFilters.js
index 210c63479..88f9c83f5 100644
--- a/js/CommonFilters.js
+++ b/js/CommonFilters.js
@@ -19,342 +19,332 @@ const Filters = {
query = {op: "pref-filters", method: "edit", id: id};
}
- xhr.post("backend.php", query, function (reply) {
- try {
- const dialog = new fox.SingleUseDialog({
- id: "filterEditDlg",
- title: id ? __("Edit Filter") : __("Create Filter"),
- test: function() {
- const test_dialog = new fox.SingleUseDialog({
- title: "Test Filter",
- results: 0,
- limit: 100,
- max_offset: 10000,
- getTestResults: function (params, offset) {
- params.method = 'testFilterDo';
- params.offset = offset;
- params.limit = test_dialog.limit;
-
- console.log("getTestResults:" + offset);
-
- xhr.json("backend.php", params, (result) => {
- try {
- if (result && test_dialog && test_dialog.open) {
- test_dialog.results += result.length;
-
- console.log("got results:" + result.length);
-
- App.byId("prefFilterProgressMsg").innerHTML = __("Looking for articles (%d processed, %f found)...")
- .replace("%f", test_dialog.results)
- .replace("%d", offset);
-
- console.log(offset + " " + test_dialog.max_offset);
-
- for (let i = 0; i < result.length; i++) {
- const tmp = dojo.create("table", { innerHTML: result[i]});
-
- App.byId("prefFilterTestResultList").innerHTML += tmp.innerHTML;
- }
-
- if (test_dialog.results < 30 && offset < test_dialog.max_offset) {
-
- // get the next batch
- window.setTimeout(function () {
- test_dialog.getTestResults(params, offset + test_dialog.limit);
- }, 0);
-
- } else {
- // all done
-
- Element.hide("prefFilterLoadingIndicator");
-
- if (test_dialog.results == 0) {
- App.byId("prefFilterTestResultList").innerHTML = `
- ${__('No recent articles matching this filter have been found.')} `;
- App.byId("prefFilterProgressMsg").innerHTML = "Articles matching this filter:";
- } else {
- App.byId("prefFilterProgressMsg").innerHTML = __("Found %d articles matching this filter:")
- .replace("%d", test_dialog.results);
- }
-
- }
-
- } else if (!result) {
- console.log("getTestResults: can't parse results object");
- Element.hide("prefFilterLoadingIndicator");
- Notify.error("Error while trying to get filter test results.");
- } else {
- console.log("getTestResults: dialog closed, bailing out.");
- }
- } catch (e) {
- App.Error.report(e);
- }
- });
- },
- content: `
-
-
-
Looking for articles...
-
-
-
-
-
- ${__('Close this window')}
-
- `
- });
+ const dialog = new fox.SingleUseDialog({
+ id: "filterEditDlg",
+ title: id ? __("Edit Filter") : __("Create Filter"),
+ test: function() {
+ const test_dialog = new fox.SingleUseDialog({
+ title: "Test Filter",
+ results: 0,
+ limit: 100,
+ max_offset: 10000,
+ getTestResults: function (params, offset) {
+ params.method = 'testFilterDo';
+ params.offset = offset;
+ params.limit = test_dialog.limit;
+
+ console.log("getTestResults:" + offset);
+
+ xhr.json("backend.php", params, (result) => {
+ try {
+ if (result && test_dialog && test_dialog.open) {
+ test_dialog.results += result.length;
- const tmph = dojo.connect(test_dialog, "onShow", null, function (/* e */) {
- dojo.disconnect(tmph);
+ console.log("got results:" + result.length);
- test_dialog.getTestResults(dialog.attr('value'), 0);
- });
+ App.byId("prefFilterProgressMsg").innerHTML = __("Looking for articles (%d processed, %f found)...")
+ .replace("%f", test_dialog.results)
+ .replace("%d", offset);
- test_dialog.show();
- },
- createNewRuleElement: function(parentNode, replaceNode) {
- const rule = dojo.formToJson("filter_new_rule_form");
+ console.log(offset + " " + test_dialog.max_offset);
- xhr.post("backend.php", {op: "pref-filters", method: "printrulename", rule: rule}, (reply) => {
- try {
- const li = document.createElement('li');
+ for (let i = 0; i < result.length; i++) {
+ const tmp = dojo.create("table", { innerHTML: result[i]});
- li.innerHTML = `
- ${reply}
- ${App.FormFields.hidden_tag("rule[]", rule)}`;
+ App.byId("prefFilterTestResultList").innerHTML += tmp.innerHTML;
+ }
- dojo.parser.parse(li);
+ if (test_dialog.results < 30 && offset < test_dialog.max_offset) {
- if (replaceNode) {
- parentNode.replaceChild(li, replaceNode);
- } else {
- parentNode.appendChild(li);
- }
- } catch (e) {
- App.Error.report(e);
- }
- });
- },
- createNewActionElement: function(parentNode, replaceNode) {
- const form = document.forms["filter_new_action_form"];
+ // get the next batch
+ window.setTimeout(function () {
+ test_dialog.getTestResults(params, offset + test_dialog.limit);
+ }, 0);
- if (form.action_id.value == 7) {
- form.action_param.value = form.action_param_label.value;
- } else if (form.action_id.value == 9) {
- form.action_param.value = form.action_param_plugin.value;
- }
-
- const action = dojo.formToJson(form);
+ } else {
+ // all done
- xhr.post("backend.php", { op: "pref-filters", method: "printactionname", action: action }, (reply) => {
- try {
- const li = document.createElement('li');
+ Element.hide("prefFilterLoadingIndicator");
- li.innerHTML = `
- ${reply}
- ${App.FormFields.hidden_tag("action[]", action)}`;
+ if (test_dialog.results == 0) {
+ App.byId("prefFilterTestResultList").innerHTML = `
+ ${__('No recent articles matching this filter have been found.')} `;
+ App.byId("prefFilterProgressMsg").innerHTML = "Articles matching this filter:";
+ } else {
+ App.byId("prefFilterProgressMsg").innerHTML = __("Found %d articles matching this filter:")
+ .replace("%d", test_dialog.results);
+ }
- dojo.parser.parse(li);
+ }
- if (replaceNode) {
- parentNode.replaceChild(li, replaceNode);
+ } else if (!result) {
+ console.log("getTestResults: can't parse results object");
+ Element.hide("prefFilterLoadingIndicator");
+ Notify.error("Error while trying to get filter test results.");
} else {
- parentNode.appendChild(li);
+ console.log("getTestResults: dialog closed, bailing out.");
}
-
} catch (e) {
App.Error.report(e);
}
});
},
- editRule: function(replaceNode, ruleStr) {
- const edit_rule_dialog = new fox.SingleUseDialog({
- id: "filterNewRuleDlg",
- title: ruleStr ? __("Edit rule") : __("Add rule"),
- execute: function () {
- if (this.validate()) {
- dialog.createNewRuleElement(App.byId("filterDlg_Matches"), replaceNode);
- this.hide();
- }
- },
- content: __('Loading, please wait...'),
- });
+ content: `
+
+
+
Looking for articles...
+
+
+
+
+
+ ${__('Close this window')}
+
+ `
+ });
- const tmph = dojo.connect(edit_rule_dialog, "onShow", null, function (/* e */) {
- dojo.disconnect(tmph);
+ const tmph = dojo.connect(test_dialog, "onShow", null, function (/* e */) {
+ dojo.disconnect(tmph);
- xhr.post("backend.php", {op: 'pref-filters', method: 'newrule', rule: ruleStr}, (reply) => {
- edit_rule_dialog.attr('content', reply);
- });
- });
+ test_dialog.getTestResults(dialog.attr('value'), 0);
+ });
- edit_rule_dialog.show();
- },
- editAction: function(replaceNode, actionStr) {
- const edit_action_dialog = new fox.SingleUseDialog({
- title: actionStr ? __("Edit action") : __("Add action"),
- hideOrShowActionParam: function(sender) {
- const action = sender.value;
+ test_dialog.show();
+ },
+ createNewRuleElement: function(parentNode, replaceNode) {
+ const rule = dojo.formToJson("filter_new_rule_form");
- const action_param = App.byId("filterDlg_paramBox");
+ xhr.post("backend.php", {op: "pref-filters", method: "printrulename", rule: rule}, (reply) => {
+ try {
+ const li = document.createElement('li');
- if (!action_param) {
- console.log("hideOrShowActionParam: can't find action param box!");
- return;
- }
+ li.innerHTML = `
+ ${reply}
+ ${App.FormFields.hidden_tag("rule[]", rule)}`;
- // if selected action supports parameters, enable params field
- if (action == 4 || action == 6 || action == 7 || action == 9) {
- Element.show(action_param);
+ dojo.parser.parse(li);
- Element.hide(dijit.byId("filterDlg_actionParam").domNode);
- Element.hide(dijit.byId("filterDlg_actionParamLabel").domNode);
- Element.hide(dijit.byId("filterDlg_actionParamPlugin").domNode);
+ if (replaceNode) {
+ parentNode.replaceChild(li, replaceNode);
+ } else {
+ parentNode.appendChild(li);
+ }
+ } catch (e) {
+ App.Error.report(e);
+ }
+ });
+ },
+ createNewActionElement: function(parentNode, replaceNode) {
+ const form = document.forms["filter_new_action_form"];
+
+ if (form.action_id.value == 7) {
+ form.action_param.value = form.action_param_label.value;
+ } else if (form.action_id.value == 9) {
+ form.action_param.value = form.action_param_plugin.value;
+ }
- if (action == 7) {
- Element.show(dijit.byId("filterDlg_actionParamLabel").domNode);
- } else if (action == 9) {
- Element.show(dijit.byId("filterDlg_actionParamPlugin").domNode);
- } else {
- Element.show(dijit.byId("filterDlg_actionParam").domNode);
- }
+ const action = dojo.formToJson(form);
- } else {
- Element.hide(action_param);
- }
- },
+ xhr.post("backend.php", { op: "pref-filters", method: "printactionname", action: action }, (reply) => {
+ try {
+ const li = document.createElement('li');
- execute: function () {
- if (this.validate()) {
- dialog.createNewActionElement(App.byId("filterDlg_Actions"), replaceNode);
- this.hide();
- }
- }
- });
+ li.innerHTML = `
+ ${reply}
+ ${App.FormFields.hidden_tag("action[]", action)}`;
- const tmph = dojo.connect(edit_action_dialog, "onShow", null, function (/* e */) {
- dojo.disconnect(tmph);
+ dojo.parser.parse(li);
- xhr.post("backend.php", {op: 'pref-filters', method: 'newaction', action: actionStr}, (reply) => {
- edit_action_dialog.attr('content', reply);
- });
- });
+ if (replaceNode) {
+ parentNode.replaceChild(li, replaceNode);
+ } else {
+ parentNode.appendChild(li);
+ }
- edit_action_dialog.show();
- },
- selectRules: function (select) {
- Lists.select("filterDlg_Matches", select);
- },
- selectActions: function (select) {
- Lists.select("filterDlg_Actions", select);
+ } catch (e) {
+ App.Error.report(e);
+ }
+ });
+ },
+ editRule: function(replaceNode, ruleStr) {
+ const edit_rule_dialog = new fox.SingleUseDialog({
+ id: "filterNewRuleDlg",
+ title: ruleStr ? __("Edit rule") : __("Add rule"),
+ execute: function () {
+ if (this.validate()) {
+ dialog.createNewRuleElement(App.byId("filterDlg_Matches"), replaceNode);
+ this.hide();
+ }
},
- onRuleClicked: function (e) {
- const li = e.closest('li');
- const rule = li.querySelector('input[name="rule[]"]').value
+ content: __('Loading, please wait...'),
+ });
- this.editRule(li, rule);
- },
- onActionClicked: function (e) {
- const li = e.closest('li');
- const action = li.querySelector('input[name="action[]"]').value
+ const tmph = dojo.connect(edit_rule_dialog, "onShow", null, function (/* e */) {
+ dojo.disconnect(tmph);
- this.editAction(li, action);
- },
- removeFilter: function () {
- const msg = __("Remove filter?");
+ xhr.post("backend.php", {op: 'pref-filters', method: 'newrule', rule: ruleStr}, (reply) => {
+ edit_rule_dialog.attr('content', reply);
+ });
+ });
- if (confirm(msg)) {
- this.hide();
+ edit_rule_dialog.show();
+ },
+ editAction: function(replaceNode, actionStr) {
+ const edit_action_dialog = new fox.SingleUseDialog({
+ title: actionStr ? __("Edit action") : __("Add action"),
+ hideOrShowActionParam: function(sender) {
+ const action = sender.value;
+
+ const action_param = App.byId("filterDlg_paramBox");
+
+ if (!action_param) {
+ console.log("hideOrShowActionParam: can't find action param box!");
+ return;
+ }
- Notify.progress("Removing filter...");
+ // if selected action supports parameters, enable params field
+ if (action == 4 || action == 6 || action == 7 || action == 9) {
+ Element.show(action_param);
- const query = {op: "pref-filters", method: "remove", ids: this.attr('value').id};
+ Element.hide(dijit.byId("filterDlg_actionParam").domNode);
+ Element.hide(dijit.byId("filterDlg_actionParamLabel").domNode);
+ Element.hide(dijit.byId("filterDlg_actionParamPlugin").domNode);
- xhr.post("backend.php", query, () => {
- const tree = dijit.byId("filterTree");
+ if (action == 7) {
+ Element.show(dijit.byId("filterDlg_actionParamLabel").domNode);
+ } else if (action == 9) {
+ Element.show(dijit.byId("filterDlg_actionParamPlugin").domNode);
+ } else {
+ Element.show(dijit.byId("filterDlg_actionParam").domNode);
+ }
- if (tree) tree.reload();
- });
+ } else {
+ Element.hide(action_param);
}
},
- addAction: function () {
- this.editAction();
- },
- addRule: function () {
- this.editRule();
- },
- deleteAction: function () {
- App.findAll("#filterDlg_Actions li[class*=Selected]").forEach(function (e) {
- e.parentNode.removeChild(e)
- });
- },
- deleteRule: function () {
- App.findAll("#filterDlg_Matches li[class*=Selected]").forEach(function (e) {
- e.parentNode.removeChild(e)
- });
- },
+
execute: function () {
if (this.validate()) {
+ dialog.createNewActionElement(App.byId("filterDlg_Actions"), replaceNode);
+ this.hide();
+ }
+ }
+ });
- Notify.progress("Saving data...", true);
-
- xhr.post("backend.php", this.attr('value'), () => {
- dialog.hide();
+ const tmph = dojo.connect(edit_action_dialog, "onShow", null, function (/* e */) {
+ dojo.disconnect(tmph);
- const tree = dijit.byId("filterTree");
- if (tree) tree.reload();
- });
- }
- },
- content: reply
+ xhr.post("backend.php", {op: 'pref-filters', method: 'newaction', action: actionStr}, (reply) => {
+ edit_action_dialog.attr('content', reply);
+ });
});
- if (!App.isPrefs()) {
- /* global getSelectionText */
- const selectedText = getSelectionText();
+ edit_action_dialog.show();
+ },
+ selectRules: function (select) {
+ Lists.select("filterDlg_Matches", select);
+ },
+ selectActions: function (select) {
+ Lists.select("filterDlg_Actions", select);
+ },
+ onRuleClicked: function (e) {
+ const li = e.closest('li');
+ const rule = li.querySelector('input[name="rule[]"]').value
- const lh = dojo.connect(dialog, "onShow", function () {
- dojo.disconnect(lh);
+ this.editRule(li, rule);
+ },
+ onActionClicked: function (e) {
+ const li = e.closest('li');
+ const action = li.querySelector('input[name="action[]"]').value
- if (selectedText != "") {
+ this.editAction(li, action);
+ },
+ removeFilter: function () {
+ const msg = __("Remove filter?");
- const feed_id = Feeds.activeIsCat() ? 'CAT:' + parseInt(Feeds.getActive()) :
- Feeds.getActive();
+ if (confirm(msg)) {
+ this.hide();
- const rule = {reg_exp: selectedText, feed_id: [feed_id], filter_type: 1};
+ Notify.progress("Removing filter...");
- dialog.editRule(null, dojo.toJson(rule));
+ const query = {op: "pref-filters", method: "remove", ids: this.attr('value').id};
- } else {
+ xhr.post("backend.php", query, () => {
+ const tree = dijit.byId("filterTree");
+
+ if (tree) tree.reload();
+ });
+ }
+ },
+ addAction: function () {
+ this.editAction();
+ },
+ addRule: function () {
+ this.editRule();
+ },
+ deleteAction: function () {
+ App.findAll("#filterDlg_Actions li[class*=Selected]").forEach(function (e) {
+ e.parentNode.removeChild(e)
+ });
+ },
+ deleteRule: function () {
+ App.findAll("#filterDlg_Matches li[class*=Selected]").forEach(function (e) {
+ e.parentNode.removeChild(e)
+ });
+ },
+ execute: function () {
+ if (this.validate()) {
+
+ Notify.progress("Saving data...", true);
+
+ xhr.post("backend.php", this.attr('value'), () => {
+ dialog.hide();
+
+ const tree = dijit.byId("filterTree");
+ if (tree) tree.reload();
+ });
+ }
+ },
+ content: __("Loading, please wait...")
+ });
- const query = {op: "article", method: "getmetadatabyid", id: Article.getActive()};
+ const tmph = dojo.connect(dialog, 'onShow', function () {
+ dojo.disconnect(tmph);
- xhr.json("backend.php", query, (reply) => {
- let title = false;
+ xhr.post("backend.php", query, function (reply) {
+ dialog.attr('content', reply);
- if (reply && reply.title) title = reply.title;
+ if (!App.isPrefs()) {
+ const selectedText = App.getSelectedText();
- if (title || Feeds.getActive() || Feeds.activeIsCat()) {
+ if (selectedText != "") {
+ const feed_id = Feeds.activeIsCat() ? 'CAT:' + parseInt(Feeds.getActive()) :
+ Feeds.getActive();
+ const rule = {reg_exp: selectedText, feed_id: [feed_id], filter_type: 1};
- console.log(title + " " + Feeds.getActive());
+ dialog.editRule(null, dojo.toJson(rule));
+ } else {
+ const query = {op: "article", method: "getmetadatabyid", id: Article.getActive()};
- const feed_id = Feeds.activeIsCat() ? 'CAT:' + parseInt(Feeds.getActive()) :
- Feeds.getActive();
+ xhr.json("backend.php", query, (reply) => {
+ let title;
- const rule = {reg_exp: title, feed_id: [feed_id], filter_type: 1};
+ if (reply && reply.title) title = reply.title;
- dialog.editRule(null, dojo.toJson(rule));
- }
- });
- }
- });
- }
- dialog.show();
+ if (title || Feeds.getActive() || Feeds.activeIsCat()) {
+ console.log(title + " " + Feeds.getActive());
+
+ const feed_id = Feeds.activeIsCat() ? 'CAT:' + parseInt(Feeds.getActive()) :
+ Feeds.getActive();
+ const rule = {reg_exp: title, feed_id: [feed_id], filter_type: 1};
- } catch (e) {
- App.Error.report(e);
- }
+ dialog.editRule(null, dojo.toJson(rule));
+ }
+ });
+ }
+ }
+ });
});
+ dialog.show();
},
};
diff --git a/js/common.js b/js/common.js
index 6e8168357..01fe321f7 100755
--- a/js/common.js
+++ b/js/common.js
@@ -401,25 +401,3 @@ const Notify = {
}
};
-// http://stackoverflow.com/questions/6251937/how-to-get-selecteduser-highlighted-text-in-contenteditable-element-and-replac
-/* exported getSelectionText */
-function getSelectionText() {
- let text = "";
-
- if (typeof window.getSelection != "undefined") {
- const sel = window.getSelection();
- if (sel.rangeCount) {
- const container = document.createElement("div");
- for (let i = 0, len = sel.rangeCount; i < len; ++i) {
- container.appendChild(sel.getRangeAt(i).cloneContents());
- }
- text = container.innerHTML;
- }
- } else if (typeof document.selection != "undefined") {
- if (document.selection.type == "Text") {
- text = document.selection.createRange().textText;
- }
- }
-
- return text.stripTags();
-}
--
cgit v1.2.3-54-g00ecf
From b4e96374bcc14b3be353f87a80f83b34615dec73 Mon Sep 17 00:00:00 2001
From: Andrew Dolgov
Date: Sat, 20 Feb 2021 21:48:05 +0300
Subject: more filter stuff
---
classes/pref/filters.php | 20 ++++++++++----------
js/CommonFilters.js | 47 ++++++++++++++++++++++-------------------------
2 files changed, 32 insertions(+), 35 deletions(-)
diff --git a/classes/pref/filters.php b/classes/pref/filters.php
index 1aeaa8a3f..9c250be19 100755
--- a/classes/pref/filters.php
+++ b/classes/pref/filters.php
@@ -860,7 +860,7 @@ class Pref_Filters extends Handler_Protected {
print "";
- print "";
$res = $this->pdo->query("SELECT id,description FROM ttrss_filter_actions
@@ -873,17 +873,17 @@ class Pref_Filters extends Handler_Protected {
print " ";
- $param_box_hidden = ($action_id == 7 || $action_id == 4 || $action_id == 6 || $action_id == 9) ?
- "" : "display : none";
+ #$param_box_hidden = ($action_id == 7 || $action_id == 4 || $action_id == 6 || $action_id == 9) ?
+ # "" : "display : none";
- $param_hidden = ($action_id == 4 || $action_id == 6) ?
- "" : "display : none";
+ #$param_hidden = ($action_id == 4 || $action_id == 6) ?
+ # "" : "display : none";
- $label_param_hidden = ($action_id == 7) ? "" : "display : none";
- $plugin_param_hidden = ($action_id == 9) ? "" : "display : none";
+ #$label_param_hidden = ($action_id == 7) ? "" : "display : none";
+ #$plugin_param_hidden = ($action_id == 9) ? "" : "display : none";
- print "";
- print " ";
+ #print "";
+ #print " ";
//print " " . __("with parameters:") . " ";
print " $plugin_param_hidden], $filter_plugin_disabled),
"filterDlg_actionParamPlugin");
- print " ";
+ #print " ";
print " "; // tiny layout hack
diff --git a/js/CommonFilters.js b/js/CommonFilters.js
index 88f9c83f5..bd6808f59 100644
--- a/js/CommonFilters.js
+++ b/js/CommonFilters.js
@@ -22,6 +22,11 @@ const Filters = {
const dialog = new fox.SingleUseDialog({
id: "filterEditDlg",
title: id ? __("Edit Filter") : __("Create Filter"),
+ ACTION_TAG: 4,
+ ACTION_SCORE: 6,
+ ACTION_LABEL: 7,
+ ACTION_PLUGIN: 9,
+ PARAM_ACTIONS: [4, 6, 7, 9],
test: function() {
const test_dialog = new fox.SingleUseDialog({
title: "Test Filter",
@@ -193,36 +198,21 @@ const Filters = {
const edit_action_dialog = new fox.SingleUseDialog({
title: actionStr ? __("Edit action") : __("Add action"),
hideOrShowActionParam: function(sender) {
- const action = sender.value;
+ const action = parseInt(sender.value);
- const action_param = App.byId("filterDlg_paramBox");
-
- if (!action_param) {
- console.log("hideOrShowActionParam: can't find action param box!");
- return;
- }
+ dijit.byId("filterDlg_actionParam").domNode.hide();
+ dijit.byId("filterDlg_actionParamLabel").domNode.hide();
+ dijit.byId("filterDlg_actionParamPlugin").domNode.hide();
// if selected action supports parameters, enable params field
- if (action == 4 || action == 6 || action == 7 || action == 9) {
- Element.show(action_param);
-
- Element.hide(dijit.byId("filterDlg_actionParam").domNode);
- Element.hide(dijit.byId("filterDlg_actionParamLabel").domNode);
- Element.hide(dijit.byId("filterDlg_actionParamPlugin").domNode);
-
- if (action == 7) {
- Element.show(dijit.byId("filterDlg_actionParamLabel").domNode);
- } else if (action == 9) {
- Element.show(dijit.byId("filterDlg_actionParamPlugin").domNode);
- } else {
- Element.show(dijit.byId("filterDlg_actionParam").domNode);
- }
-
- } else {
- Element.hide(action_param);
+ if (action == dialog.ACTION_LABEL) {
+ dijit.byId("filterDlg_actionParamLabel").domNode.show();
+ } else if (action == dialog.ACTION_PLUGIN) {
+ dijit.byId("filterDlg_actionParamPlugin").domNode.show();
+ } else if (dialog.PARAM_ACTIONS.indexOf(action) != -1) {
+ dijit.byId("filterDlg_actionParam").domNode.show();
}
},
-
execute: function () {
if (this.validate()) {
dialog.createNewActionElement(App.byId("filterDlg_Actions"), replaceNode);
@@ -236,6 +226,10 @@ const Filters = {
xhr.post("backend.php", {op: 'pref-filters', method: 'newaction', action: actionStr}, (reply) => {
edit_action_dialog.attr('content', reply);
+
+ setTimeout(() => {
+ edit_action_dialog.hideOrShowActionParam(dijit.byId("filterDlg_actionSelect").attr('value'));
+ }, 250);
});
});
@@ -308,6 +302,8 @@ const Filters = {
content: __("Loading, please wait...")
});
+
+
const tmph = dojo.connect(dialog, 'onShow', function () {
dojo.disconnect(tmph);
@@ -345,6 +341,7 @@ const Filters = {
}
});
});
+
dialog.show();
},
};
--
cgit v1.2.3-54-g00ecf
From 94560132ddf45a5a7c68ce520b40ecb10a6f89fe Mon Sep 17 00:00:00 2001
From: Andrew Dolgov
Date: Sun, 21 Feb 2021 09:35:07 +0300
Subject: for the most part, deal with filter rules UI
---
classes/labels.php | 15 +-
classes/pref/filters.php | 231 +++++++++++++++++++---------
classes/rpc.php | 4 +-
include/controls.php | 16 +-
js/CommonFilters.js | 294 +++++++++++++++++++++++++++++++-----
plugins/auto_assign_labels/init.php | 1 +
themes/compact.css | 20 +--
themes/compact_night.css | 20 +--
themes/light.css | 20 +--
themes/light/tt-rss.less | 8 +-
themes/night.css | 20 +--
themes/night_blue.css | 20 +--
12 files changed, 495 insertions(+), 174 deletions(-)
diff --git a/classes/labels.php b/classes/labels.php
index f72d7d84b..570f24f4f 100644
--- a/classes/labels.php
+++ b/classes/labels.php
@@ -37,7 +37,18 @@ class Labels
}
}
- static function get_all_labels($owner_uid) {
+ static function get_as_hash($owner_uid) {
+ $rv = [];
+ $labels = Labels::get_all($owner_uid);
+
+ foreach ($labels as $i => $label) {
+ $rv[$label["id"]] = $labels[$i];
+ }
+
+ return $rv;
+ }
+
+ static function get_all($owner_uid) {
$rv = array();
$pdo = Db::pdo();
@@ -46,7 +57,7 @@ class Labels
WHERE owner_uid = ? ORDER BY caption");
$sth->execute([$owner_uid]);
- while ($line = $sth->fetch()) {
+ while ($line = $sth->fetch(PDO::FETCH_ASSOC)) {
array_push($rv, $line);
}
diff --git a/classes/pref/filters.php b/classes/pref/filters.php
index 9c250be19..4e52260c9 100755
--- a/classes/pref/filters.php
+++ b/classes/pref/filters.php
@@ -318,6 +318,84 @@ class Pref_Filters extends Handler_Protected {
WHERE id = ? AND owner_uid = ?");
$sth->execute([$filter_id, $_SESSION['uid']]);
+ if (empty($filter_id) || $row = $sth->fetch()) {
+ $rv = [
+ "id" => $filter_id,
+ "enabled" => $row["enabled"] ?? true,
+ "match_any_rule" => $row["match_any_rule"] ?? false,
+ "inverse" => $row["inverse"] ?? false,
+ "title" => $row["title"] ?? "",
+ "rules" => [],
+ "actions" => [],
+ "filter_types" => [],
+ "filter_actions" => [],
+ "labels" => Labels::get_all($_SESSION["uid"])
+ ];
+
+ $res = $this->pdo->query("SELECT id,description
+ FROM ttrss_filter_types WHERE id != 5 ORDER BY description");
+
+ while ($line = $res->fetch()) {
+ $rv["filter_types"][$line["id"]] = __($line["description"]);
+ }
+
+ $res = $this->pdo->query("SELECT id,description FROM ttrss_filter_actions
+ ORDER BY name");
+
+ while ($line = $res->fetch()) {
+ $rv["filter_actions"][$line["id"]] = __($line["description"]);
+ }
+
+ if ($filter_id) {
+ $rules_sth = $this->pdo->prepare("SELECT * FROM ttrss_filters2_rules
+ WHERE filter_id = ? ORDER BY reg_exp, id");
+ $rules_sth->execute([$filter_id]);
+
+ while ($rrow = $rules_sth->fetch(PDO::FETCH_ASSOC)) {
+ if ($rrow["match_on"]) {
+ $rrow["feed_id"] = json_decode($rrow["match_on"], true);
+ } else {
+ if ($rrow["cat_filter"]) {
+ $feed_id = "CAT:" . (int)$rrow["cat_id"];
+ } else {
+ $feed_id = (int)$rrow["feed_id"];
+ }
+
+ $rrow["feed_id"] = ["" . $feed_id]; // set item type to string for in_array()
+ }
+
+ unset($rrow["cat_filter"]);
+ unset($rrow["cat_id"]);
+ unset($rrow["filter_id"]);
+ unset($rrow["id"]);
+ if (!$rrow["inverse"]) unset($rrow["inverse"]);
+ unset($rrow["match_on"]);
+
+ $rrow["name"] = $this->_get_rule_name($rrow);
+
+ array_push($rv["rules"], $rrow);
+ }
+
+ $actions_sth = $this->pdo->prepare("SELECT * FROM ttrss_filters2_actions
+ WHERE filter_id = ? ORDER BY id");
+ $actions_sth->execute([$filter_id]);
+
+ while ($arow = $actions_sth->fetch(PDO::FETCH_ASSOC)) {
+ $arow["action_param_label"] = $arow["action_param"];
+
+ unset($arow["filter_id"]);
+ unset($arow["id"]);
+
+ $arow["name"] = $this->_get_action_name($arow);
+
+ array_push($rv["actions"], $arow);
+ }
+ }
+ print json_encode($rv);
+ }
+
+ /*return;
+
if (empty($filter_id) || $row = $sth->fetch()) {
$enabled = $row["enabled"] ?? true;
@@ -475,7 +553,7 @@ class Pref_Filters extends Handler_Protected {
}
print "";
- }
+ } */
}
private function _get_rule_name($rule) {
@@ -592,8 +670,7 @@ class Pref_Filters extends Handler_Protected {
$sth->execute(array_merge($ids, [$_SESSION['uid']]));
}
- private function _save_rules_and_actions($filter_id)
- {
+ private function _save_rules_and_actions($filter_id) {
$sth = $this->pdo->prepare("DELETE FROM ttrss_filters2_rules WHERE filter_id = ?");
$sth->execute([$filter_id]);
@@ -670,7 +747,7 @@ class Pref_Filters extends Handler_Protected {
}
}
- function add() {
+ function add () {
$enabled = checkbox_to_sql_bool(clean($_REQUEST["enabled"] ?? false));
$match_any_rule = checkbox_to_sql_bool(clean($_REQUEST["match_any_rule"] ?? false));
$title = clean($_REQUEST["title"]);
@@ -764,7 +841,15 @@ class Pref_Filters extends Handler_Protected {
$this->feed_multi_select("feed_id", $feed_ids, 'style="width : 500px; height : 300px" dojoType="dijit.form.MultiSelect"')
+ ]);
+
+ /*return;
+
$rule = json_decode(clean($_REQUEST["rule"]), true);
if ($rule) {
@@ -818,7 +903,7 @@ class Pref_Filters extends Handler_Protected {
print "";
print "";
- $this->feed_multi_select("feed_id",
+ print $this->feed_multi_select("feed_id",
$feed_id,
'style="width : 500px; height : 300px" dojoType="dijit.form.MultiSelect"');
print " ";
@@ -840,7 +925,7 @@ class Pref_Filters extends Handler_Protected {
print "";
- print "";
+ print "";*/
}
function newaction() {
@@ -1071,102 +1156,106 @@ class Pref_Filters extends Handler_Protected {
$attributes = "", $include_all_feeds = true,
$root_id = null, $nest_level = 0) {
- $pdo = Db::pdo();
+ $pdo = Db::pdo();
- // print_r(in_array("CAT:6",$default_ids));
+ $rv = "";
- if (!$root_id) {
- print "";
- if ($include_all_feeds) {
- $is_selected = (in_array("0", $default_ids)) ? "selected=\"1\"" : "";
- print "".__('All feeds')." ";
- }
- }
+ // print_r(in_array("CAT:6",$default_ids));
- if (get_pref('ENABLE_FEED_CATS')) {
+ if (!$root_id) {
+ $rv .= "";
+ if ($include_all_feeds) {
+ $is_selected = (in_array("0", $default_ids)) ? "selected=\"1\"" : "";
+ $rv .= "".__('All feeds')." ";
+ }
+ }
- if (!$root_id) $root_id = null;
+ if (get_pref('ENABLE_FEED_CATS')) {
- $sth = $pdo->prepare("SELECT id,title,
- (SELECT COUNT(id) FROM ttrss_feed_categories AS c2 WHERE
- c2.parent_cat = ttrss_feed_categories.id) AS num_children
- FROM ttrss_feed_categories
- WHERE owner_uid = :uid AND
- (parent_cat = :root_id OR (:root_id IS NULL AND parent_cat IS NULL)) ORDER BY title");
+ if (!$root_id) $root_id = null;
- $sth->execute([":uid" => $_SESSION['uid'], ":root_id" => $root_id]);
+ $sth = $pdo->prepare("SELECT id,title,
+ (SELECT COUNT(id) FROM ttrss_feed_categories AS c2 WHERE
+ c2.parent_cat = ttrss_feed_categories.id) AS num_children
+ FROM ttrss_feed_categories
+ WHERE owner_uid = :uid AND
+ (parent_cat = :root_id OR (:root_id IS NULL AND parent_cat IS NULL)) ORDER BY title");
- while ($line = $sth->fetch()) {
+ $sth->execute([":uid" => $_SESSION['uid'], ":root_id" => $root_id]);
- for ($i = 0; $i < $nest_level; $i++)
- $line["title"] = " " . $line["title"];
+ while ($line = $sth->fetch()) {
- $is_selected = in_array("CAT:".$line["id"], $default_ids) ? "selected=\"1\"" : "";
+ for ($i = 0; $i < $nest_level; $i++)
+ $line["title"] = " " . $line["title"];
- printf("%s ",
- $line["id"], htmlspecialchars($line["title"]));
+ $is_selected = in_array("CAT:".$line["id"], $default_ids) ? "selected=\"1\"" : "";
- if ($line["num_children"] > 0)
- $this->feed_multi_select($id, $default_ids, $attributes,
- $include_all_feeds, $line["id"], $nest_level+1);
+ $rv .= sprintf("%s ",
+ $line["id"], htmlspecialchars($line["title"]));
- $f_sth = $pdo->prepare("SELECT id,title FROM ttrss_feeds
- WHERE cat_id = ? AND owner_uid = ? ORDER BY title");
+ if ($line["num_children"] > 0)
+ $rv .= $this->feed_multi_select($id, $default_ids, $attributes,
+ $include_all_feeds, $line["id"], $nest_level+1);
- $f_sth->execute([$line['id'], $_SESSION['uid']]);
+ $f_sth = $pdo->prepare("SELECT id,title FROM ttrss_feeds
+ WHERE cat_id = ? AND owner_uid = ? ORDER BY title");
- while ($fline = $f_sth->fetch()) {
- $is_selected = (in_array($fline["id"], $default_ids)) ? "selected=\"1\"" : "";
+ $f_sth->execute([$line['id'], $_SESSION['uid']]);
- $fline["title"] = " " . $fline["title"];
+ while ($fline = $f_sth->fetch()) {
+ $is_selected = (in_array($fline["id"], $default_ids)) ? "selected=\"1\"" : "";
- for ($i = 0; $i < $nest_level; $i++)
$fline["title"] = " " . $fline["title"];
- printf("%s ",
- $fline["id"], htmlspecialchars($fline["title"]));
- }
- }
+ for ($i = 0; $i < $nest_level; $i++)
+ $fline["title"] = " " . $fline["title"];
- if (!$root_id) {
- $is_selected = in_array("CAT:0", $default_ids) ? "selected=\"1\"" : "";
+ $rv .= sprintf("%s ",
+ $fline["id"], htmlspecialchars($fline["title"]));
+ }
+ }
- printf("%s ",
- __("Uncategorized"));
+ if (!$root_id) {
+ $is_selected = in_array("CAT:0", $default_ids) ? "selected=\"1\"" : "";
- $f_sth = $pdo->prepare("SELECT id,title FROM ttrss_feeds
- WHERE cat_id IS NULL AND owner_uid = ? ORDER BY title");
- $f_sth->execute([$_SESSION['uid']]);
+ $rv .= sprintf("%s ",
+ __("Uncategorized"));
- while ($fline = $f_sth->fetch()) {
- $is_selected = in_array($fline["id"], $default_ids) ? "selected=\"1\"" : "";
+ $f_sth = $pdo->prepare("SELECT id,title FROM ttrss_feeds
+ WHERE cat_id IS NULL AND owner_uid = ? ORDER BY title");
+ $f_sth->execute([$_SESSION['uid']]);
- $fline["title"] = " " . $fline["title"];
+ while ($fline = $f_sth->fetch()) {
+ $is_selected = in_array($fline["id"], $default_ids) ? "selected=\"1\"" : "";
- for ($i = 0; $i < $nest_level; $i++)
$fline["title"] = " " . $fline["title"];
- printf("%s ",
- $fline["id"], htmlspecialchars($fline["title"]));
+ for ($i = 0; $i < $nest_level; $i++)
+ $fline["title"] = " " . $fline["title"];
+
+ $rv .= sprintf("%s ",
+ $fline["id"], htmlspecialchars($fline["title"]));
+ }
}
- }
- } else {
- $sth = $pdo->prepare("SELECT id,title FROM ttrss_feeds
- WHERE owner_uid = ? ORDER BY title");
- $sth->execute([$_SESSION['uid']]);
+ } else {
+ $sth = $pdo->prepare("SELECT id,title FROM ttrss_feeds
+ WHERE owner_uid = ? ORDER BY title");
+ $sth->execute([$_SESSION['uid']]);
- while ($line = $sth->fetch()) {
+ while ($line = $sth->fetch()) {
- $is_selected = (in_array($line["id"], $default_ids)) ? "selected=\"1\"" : "";
+ $is_selected = (in_array($line["id"], $default_ids)) ? "selected=\"1\"" : "";
- printf("%s ",
- $line["id"], htmlspecialchars($line["title"]));
+ $rv .= sprintf("%s ",
+ $line["id"], htmlspecialchars($line["title"]));
+ }
}
- }
- if (!$root_id) {
- print " ";
+ if (!$root_id) {
+ $rv .= " ";
+ }
+
+ return $rv;
}
}
-}
diff --git a/classes/rpc.php b/classes/rpc.php
index 643ad29d8..20a11b994 100755
--- a/classes/rpc.php
+++ b/classes/rpc.php
@@ -399,7 +399,7 @@ class RPC extends Handler_Protected {
$params["icon_indicator_white"] = $this->image_to_base64("images/indicator_white.gif");
- $params["labels"] = Labels::get_all_labels($_SESSION["uid"]);
+ $params["labels"] = Labels::get_all($_SESSION["uid"]);
return $params;
}
@@ -430,7 +430,7 @@ class RPC extends Handler_Protected {
$data["max_feed_id"] = (int) $max_feed_id;
$data["num_feeds"] = (int) $num_feeds;
$data['cdm_expanded'] = get_pref('CDM_EXPANDED');
- $data["labels"] = Labels::get_all_labels($_SESSION["uid"]);
+ $data["labels"] = Labels::get_all($_SESSION["uid"]);
if (LOG_DESTINATION == 'sql' && $_SESSION['access_level'] >= 10) {
if (DB_TYPE == 'pgsql') {
diff --git a/include/controls.php b/include/controls.php
index ae5fba739..e3349d31b 100755
--- a/include/controls.php
+++ b/include/controls.php
@@ -60,21 +60,11 @@
return $rv;
}
- function select_labels(string $name, string $value, array $attributes = [], string $id = "") {
- $pdo = \Db::pdo();
-
- $sth = $pdo->prepare("SELECT caption FROM ttrss_labels2
- WHERE owner_uid = ? ORDER BY caption");
- $sth->execute([$_SESSION['uid']]);
-
- $values = [];
-
- while ($row = $sth->fetch()) {
- array_push($values, $row["caption"]);
- }
+ /*function select_labels(string $name, string $value, array $attributes = [], string $id = "") {
+ $values = \Labels::get_as_hash($_SESSION["uid"]);
return select_tag($name, $value, $values, $attributes, $id);
- }
+ }*/
function select_hash(string $name, $value, array $values, array $attributes = [], string $id = "") {
$attributes_str = attributes_to_string($attributes);
diff --git a/js/CommonFilters.js b/js/CommonFilters.js
index bd6808f59..75e1fa8af 100644
--- a/js/CommonFilters.js
+++ b/js/CommonFilters.js
@@ -7,26 +7,17 @@
/* exported Filters */
const Filters = {
- edit: function(id) { // if no id, new filter dialog
- let query;
-
- if (!App.isPrefs()) {
- query = {
- op: "pref-filters", method: "edit",
- feed: Feeds.getActive(), is_cat: Feeds.activeIsCat()
- };
- } else {
- query = {op: "pref-filters", method: "edit", id: id};
- }
+ edit: function(filter_id = null) { // if no id, new filter dialog
const dialog = new fox.SingleUseDialog({
id: "filterEditDlg",
- title: id ? __("Edit Filter") : __("Create Filter"),
+ title: filter_id ? __("Edit Filter") : __("Create Filter"),
ACTION_TAG: 4,
ACTION_SCORE: 6,
ACTION_LABEL: 7,
ACTION_PLUGIN: 9,
PARAM_ACTIONS: [4, 6, 7, 9],
+ filter_info: {},
test: function() {
const test_dialog = new fox.SingleUseDialog({
title: "Test Filter",
@@ -116,16 +107,17 @@ const Filters = {
test_dialog.show();
},
- createNewRuleElement: function(parentNode, replaceNode) {
+ insertRule: function(parentNode, replaceNode) {
const rule = dojo.formToJson("filter_new_rule_form");
xhr.post("backend.php", {op: "pref-filters", method: "printrulename", rule: rule}, (reply) => {
try {
const li = document.createElement('li');
+ li.addClassName("rule");
- li.innerHTML = `
- ${reply}
- ${App.FormFields.hidden_tag("rule[]", rule)}`;
+ li.innerHTML = `${App.FormFields.checkbox_tag("", false, {onclick: 'Lists.onRowChecked(this)'})}
+ ${reply}
+ ${App.FormFields.hidden_tag("rule[]", rule)} `;
dojo.parser.parse(li);
@@ -139,7 +131,7 @@ const Filters = {
}
});
},
- createNewActionElement: function(parentNode, replaceNode) {
+ insertAction: function(parentNode, replaceNode) {
const form = document.forms["filter_new_action_form"];
if (form.action_id.value == 7) {
@@ -153,10 +145,11 @@ const Filters = {
xhr.post("backend.php", { op: "pref-filters", method: "printactionname", action: action }, (reply) => {
try {
const li = document.createElement('li');
+ li.addClassName("action");
- li.innerHTML = `
- ${reply}
- ${App.FormFields.hidden_tag("action[]", action)}`;
+ li.innerHTML = `${App.FormFields.checkbox_tag("", false, {onclick: 'Lists.onRowChecked(this)'})}
+ ${reply}
+ ${App.FormFields.hidden_tag("action[]", action)} `;
dojo.parser.parse(li);
@@ -171,30 +164,84 @@ const Filters = {
}
});
},
- editRule: function(replaceNode, ruleStr) {
+ editRule: function(replaceNode, ruleStr = null) {
const edit_rule_dialog = new fox.SingleUseDialog({
id: "filterNewRuleDlg",
title: ruleStr ? __("Edit rule") : __("Add rule"),
execute: function () {
if (this.validate()) {
- dialog.createNewRuleElement(App.byId("filterDlg_Matches"), replaceNode);
+ dialog.insertRule(App.byId("filterDlg_Matches"), replaceNode);
this.hide();
}
},
content: __('Loading, please wait...'),
});
- const tmph = dojo.connect(edit_rule_dialog, "onShow", null, function (/* e */) {
+ const tmph = dojo.connect(edit_rule_dialog, "onShow", null, function () {
dojo.disconnect(tmph);
- xhr.post("backend.php", {op: 'pref-filters', method: 'newrule', rule: ruleStr}, (reply) => {
- edit_rule_dialog.attr('content', reply);
+ let rule;
+
+ if (ruleStr) {
+ rule = JSON.parse(ruleStr);
+ } else {
+ rule = {
+ reg_exp: "",
+ filter_type: 1,
+ feed_id: ["0"],
+ inverse: false,
+ };
+ }
+
+ console.log(rule, dialog.filter_info);
+
+ xhr.json("backend.php", {op: "pref-filters", method: "editrule", ids: rule.feed_id.join(",")}, function (editrule) {
+ edit_rule_dialog.attr('content',
+ `
+
+
+
+ ${rule.reg_exp}
+
+
+
+
+ ".
+ ${App.FormFields.checkbox_tag("inverse", rule.inverse)}
+ ${__("Inverse regular expression matching")}
+
+
+
+ ${__("on field")}
+ ${App.FormFields.select_hash("filter_type", rule.filter_type, dialog.filter_info.filter_types)}
+ ${__("in")}
+
+
+
+ ${editrule.multiselect}
+
+
+
+
+
+ ${App.FormFields.button_tag(App.FormFields.icon("help") + " " + __("More info"), "", {class: 'pull-left alt-info',
+ onclick: "window.open('https://tt-rss.org/wiki/ContentFilters')"})}
+ ${App.FormFields.submit_tag(__("Save rule"), {onclick: "App.dialogOf(this).execute()"})}
+ ${App.FormFields.cancel_dialog_tag(__("Cancel"))}
+
+
+
+ `);
});
+
});
edit_rule_dialog.show();
},
- editAction: function(replaceNode, actionStr) {
+ /*editAction: function(replaceNode, actionStr) {
const edit_action_dialog = new fox.SingleUseDialog({
title: actionStr ? __("Edit action") : __("Add action"),
hideOrShowActionParam: function(sender) {
@@ -221,7 +268,7 @@ const Filters = {
}
});
- const tmph = dojo.connect(edit_action_dialog, "onShow", null, function (/* e */) {
+ const tmph = dojo.connect(edit_action_dialog, "onShow", null, function () {
dojo.disconnect(tmph);
xhr.post("backend.php", {op: 'pref-filters', method: 'newaction', action: actionStr}, (reply) => {
@@ -234,22 +281,65 @@ const Filters = {
});
edit_action_dialog.show();
- },
+ }, */
+ /*editAction: function(replaceNode, actionStr) {
+ const edit_action_dialog = new fox.SingleUseDialog({
+ title: actionStr ? __("Edit action") : __("Add action"),
+ hideOrShowActionParam: function(sender) {
+ const action = parseInt(sender.value);
+
+ dijit.byId("filterDlg_actionParam").domNode.hide();
+ dijit.byId("filterDlg_actionParamLabel").domNode.hide();
+ dijit.byId("filterDlg_actionParamPlugin").domNode.hide();
+
+ // if selected action supports parameters, enable params field
+ if (action == dialog.ACTION_LABEL) {
+ dijit.byId("filterDlg_actionParamLabel").domNode.show();
+ } else if (action == dialog.ACTION_PLUGIN) {
+ dijit.byId("filterDlg_actionParamPlugin").domNode.show();
+ } else if (dialog.PARAM_ACTIONS.indexOf(action) != -1) {
+ dijit.byId("filterDlg_actionParam").domNode.show();
+ }
+ },
+ execute: function () {
+ if (this.validate()) {
+ dialog.createNewActionElement(App.byId("filterDlg_Actions"), replaceNode);
+ this.hide();
+ }
+ }
+ });
+
+ const tmph = dojo.connect(edit_action_dialog, "onShow", null, function () {
+ dojo.disconnect(tmph);
+
+ xhr.post("backend.php", {op: 'pref-filters', method: 'newaction', action: actionStr}, (reply) => {
+ edit_action_dialog.attr('content', reply);
+
+ setTimeout(() => {
+ edit_action_dialog.hideOrShowActionParam(dijit.byId("filterDlg_actionSelect").attr('value'));
+ }, 250);
+ });
+ });
+
+ edit_action_dialog.show();
+ },*/
selectRules: function (select) {
Lists.select("filterDlg_Matches", select);
},
selectActions: function (select) {
Lists.select("filterDlg_Actions", select);
},
- onRuleClicked: function (e) {
- const li = e.closest('li');
- const rule = li.querySelector('input[name="rule[]"]').value
+ onRuleClicked: function (elem) {
+
+ const li = elem.closest('li');
+ const rule = li.querySelector('input[name="rule[]"]').value;
this.editRule(li, rule);
},
- onActionClicked: function (e) {
- const li = e.closest('li');
- const action = li.querySelector('input[name="action[]"]').value
+ onActionClicked: function (elem) {
+
+ const li = elem.closest('li');
+ const action = li.querySelector('input[name="action[]"]').value;
this.editAction(li, action);
},
@@ -302,13 +392,141 @@ const Filters = {
content: __("Loading, please wait...")
});
-
-
const tmph = dojo.connect(dialog, 'onShow', function () {
dojo.disconnect(tmph);
- xhr.post("backend.php", query, function (reply) {
- dialog.attr('content', reply);
+ const query = {op: "pref-filters", method: "edit", id: filter_id};
+
+ /*if (!App.isPrefs()) {
+ query = {
+ op: "pref-filters", method: "edit",
+ feed: Feeds.getActive(), is_cat: Feeds.activeIsCat()
+ };
+ } else {
+ query = {op: "pref-filters", method: "edit", id: id};
+ }*/
+
+ xhr.json("backend.php", query, function (filter) {
+
+ dialog.filter_info = filter;
+
+ const options = {
+ enabled: [ filter.enabled, __('Enabled') ],
+ match_any_rule: [ filter.match_any_rule, __('Match any rule') ],
+ inverse: [ filter.inverse, __('Inverse matching') ],
+ };
+
+ dialog.attr('content',
+ `
+
+
+ ${App.FormFields.hidden_tag("op", "pref-filters")}
+ ${App.FormFields.hidden_tag("id", filter_id)}
+ ${App.FormFields.hidden_tag("method", filter_id ? "editSave" : "add")}
+ ${App.FormFields.hidden_tag("csrf_token", App.getInitParam('csrf_token'))}
+
+
+
+
+
+
+
+
+
${__("Select")}
+
+
+
${__("All")}
+
${__("None")}
+
+
+
+ ${__("Add")}
+
+
+ ${__("Delete")}
+
+
+
+
+ ${filter.rules.map((rule) => `
+
+ ${App.FormFields.checkbox_tag("", false, "", {onclick: 'Lists.onRowChecked(this)'})}
+ ${rule.name}
+ ${App.FormFields.hidden_tag("rule[]", JSON.stringify(rule))}
+
+ `).join("")}
+
+
+
+
+
+
+
+
+
${__("Select")}
+
+
${__("All")}
+
${__("None")}
+
+
+
".
+ ${__("Add")}
+
+
".
+ ${__("Delete")}
+
+
+
+
+ ${filter.actions.map((action) => `
+
+ ${App.FormFields.checkbox_tag("", false, "", {onclick: 'Lists.onRowChecked(this)'})}
+ ${App.escapeHtml(action.name)}
+ ${App.FormFields.hidden_tag("action[]", JSON.stringify(action))}
+
+ `).join("")}
+
+
+
+
+
+
+
+
+
+ ${Object.keys(options).map((name) =>
+ `
+
+
+ ${App.FormFields.checkbox_tag(name, options[name][0])}
+ ${options[name][1]}
+
+
+ `).join("")}
+
+
+
+ ${filter_id ?
+ `
+ ${App.FormFields.button_tag(__("Remove"), "", {class: "pull-left alt-danger", onclick: "App.dialogOf(this).removeFilter()"})}
+ ${App.FormFields.button_tag(__("Test"), "", {class: "alt-info", onclick: "App.dialogOf(this).test()"})}
+ ${App.FormFields.submit_tag(__("Save"), {onclick: "App.dialogOf(this).execute()"})}
+ ${App.FormFields.cancel_dialog_tag(__("Cancel"))}
+ ` : `
+ ${App.FormFields.button_tag(__("Test"), "", {class: "alt-info", onclick: "App.dialogOf(this).test()"})}
+ ${App.FormFields.submit_tag(__("Create"), {onclick: "App.dialogOf(this).execute()"})}
+ ${App.FormFields.cancel_dialog_tag(__("Cancel"))}
+ `}
+
+
+ `);
if (!App.isPrefs()) {
const selectedText = App.getSelectedText();
diff --git a/plugins/auto_assign_labels/init.php b/plugins/auto_assign_labels/init.php
index 3fa4ad8c0..341895cef 100755
--- a/plugins/auto_assign_labels/init.php
+++ b/plugins/auto_assign_labels/init.php
@@ -19,6 +19,7 @@ class Auto_Assign_Labels extends Plugin {
function get_all_labels_filter_format($owner_uid) {
$rv = array();
+ // TODO: use Labels::get_all()
$sth = $this->pdo->prepare("SELECT id, fg_color, bg_color, caption FROM ttrss_labels2 WHERE owner_uid = ?");
$sth->execute([$owner_uid]);
diff --git a/themes/compact.css b/themes/compact.css
index 92e9928c8..16bdcf1f0 100644
--- a/themes/compact.css
+++ b/themes/compact.css
@@ -822,16 +822,18 @@ body.ttrss_main #headlines-spacer a:hover {
}
body.ttrss_main ul#filterDlg_Matches,
body.ttrss_main ul#filterDlg_Actions {
- max-height: 100px;
- overflow: auto;
list-style-type: none;
- border-style: solid;
- border-color: #ddd;
- border-width: 1px 1px 1px 1px;
- background-color: white;
- margin: 0px 0px 5px 0px;
- padding: 4px;
- min-height: 16px;
+ margin: 0;
+ padding: 0;
+ /*max-height : 100px;
+ overflow : auto;
+ border-style : solid;
+ border-color : @border-default;
+ border-width : 1px 1px 1px 1px;
+ background-color : @default-bg;
+ margin : 0px 0px 5px 0px;
+ padding : 4px;
+ min-height : 16px;*/
}
body.ttrss_main ul#filterDlg_Matches li,
body.ttrss_main ul#filterDlg_Actions li {
diff --git a/themes/compact_night.css b/themes/compact_night.css
index 29eff9cb9..37adf3fda 100644
--- a/themes/compact_night.css
+++ b/themes/compact_night.css
@@ -822,16 +822,18 @@ body.ttrss_main #headlines-spacer a:hover {
}
body.ttrss_main ul#filterDlg_Matches,
body.ttrss_main ul#filterDlg_Actions {
- max-height: 100px;
- overflow: auto;
list-style-type: none;
- border-style: solid;
- border-color: #222;
- border-width: 1px 1px 1px 1px;
- background-color: #333;
- margin: 0px 0px 5px 0px;
- padding: 4px;
- min-height: 16px;
+ margin: 0;
+ padding: 0;
+ /*max-height : 100px;
+ overflow : auto;
+ border-style : solid;
+ border-color : @border-default;
+ border-width : 1px 1px 1px 1px;
+ background-color : @default-bg;
+ margin : 0px 0px 5px 0px;
+ padding : 4px;
+ min-height : 16px;*/
}
body.ttrss_main ul#filterDlg_Matches li,
body.ttrss_main ul#filterDlg_Actions li {
diff --git a/themes/light.css b/themes/light.css
index 583f9cabb..0f2ffc1b6 100644
--- a/themes/light.css
+++ b/themes/light.css
@@ -822,16 +822,18 @@ body.ttrss_main #headlines-spacer a:hover {
}
body.ttrss_main ul#filterDlg_Matches,
body.ttrss_main ul#filterDlg_Actions {
- max-height: 100px;
- overflow: auto;
list-style-type: none;
- border-style: solid;
- border-color: #ddd;
- border-width: 1px 1px 1px 1px;
- background-color: white;
- margin: 0px 0px 5px 0px;
- padding: 4px;
- min-height: 16px;
+ margin: 0;
+ padding: 0;
+ /*max-height : 100px;
+ overflow : auto;
+ border-style : solid;
+ border-color : @border-default;
+ border-width : 1px 1px 1px 1px;
+ background-color : @default-bg;
+ margin : 0px 0px 5px 0px;
+ padding : 4px;
+ min-height : 16px;*/
}
body.ttrss_main ul#filterDlg_Matches li,
body.ttrss_main ul#filterDlg_Actions li {
diff --git a/themes/light/tt-rss.less b/themes/light/tt-rss.less
index b1895f318..2794d8177 100644
--- a/themes/light/tt-rss.less
+++ b/themes/light/tt-rss.less
@@ -955,16 +955,18 @@ body.ttrss_main {
}
ul#filterDlg_Matches, ul#filterDlg_Actions {
- max-height : 100px;
- overflow : auto;
list-style-type : none;
+ margin : 0;
+ padding: 0;
+ /*max-height : 100px;
+ overflow : auto;
border-style : solid;
border-color : @border-default;
border-width : 1px 1px 1px 1px;
background-color : @default-bg;
margin : 0px 0px 5px 0px;
padding : 4px;
- min-height : 16px;
+ min-height : 16px;*/
}
ul#filterDlg_Matches li, ul#filterDlg_Actions li {
diff --git a/themes/night.css b/themes/night.css
index e428d8aa7..e012c92b2 100644
--- a/themes/night.css
+++ b/themes/night.css
@@ -823,16 +823,18 @@ body.ttrss_main #headlines-spacer a:hover {
}
body.ttrss_main ul#filterDlg_Matches,
body.ttrss_main ul#filterDlg_Actions {
- max-height: 100px;
- overflow: auto;
list-style-type: none;
- border-style: solid;
- border-color: #222;
- border-width: 1px 1px 1px 1px;
- background-color: #333;
- margin: 0px 0px 5px 0px;
- padding: 4px;
- min-height: 16px;
+ margin: 0;
+ padding: 0;
+ /*max-height : 100px;
+ overflow : auto;
+ border-style : solid;
+ border-color : @border-default;
+ border-width : 1px 1px 1px 1px;
+ background-color : @default-bg;
+ margin : 0px 0px 5px 0px;
+ padding : 4px;
+ min-height : 16px;*/
}
body.ttrss_main ul#filterDlg_Matches li,
body.ttrss_main ul#filterDlg_Actions li {
diff --git a/themes/night_blue.css b/themes/night_blue.css
index c9ccaf737..b49a496e3 100644
--- a/themes/night_blue.css
+++ b/themes/night_blue.css
@@ -823,16 +823,18 @@ body.ttrss_main #headlines-spacer a:hover {
}
body.ttrss_main ul#filterDlg_Matches,
body.ttrss_main ul#filterDlg_Actions {
- max-height: 100px;
- overflow: auto;
list-style-type: none;
- border-style: solid;
- border-color: #222;
- border-width: 1px 1px 1px 1px;
- background-color: #333;
- margin: 0px 0px 5px 0px;
- padding: 4px;
- min-height: 16px;
+ margin: 0;
+ padding: 0;
+ /*max-height : 100px;
+ overflow : auto;
+ border-style : solid;
+ border-color : @border-default;
+ border-width : 1px 1px 1px 1px;
+ background-color : @default-bg;
+ margin : 0px 0px 5px 0px;
+ padding : 4px;
+ min-height : 16px;*/
}
body.ttrss_main ul#filterDlg_Matches li,
body.ttrss_main ul#filterDlg_Actions li {
--
cgit v1.2.3-54-g00ecf
From 3b8d69206ccc24b41b45acd55f0c63681e749fd1 Mon Sep 17 00:00:00 2001
From: Andrew Dolgov
Date: Sun, 21 Feb 2021 10:28:59 +0300
Subject: deal with filter actions UI
---
classes/pref/filters.php | 354 +++--------------------------------------------
js/CommonFilters.js | 118 ++++++++--------
2 files changed, 74 insertions(+), 398 deletions(-)
diff --git a/classes/pref/filters.php b/classes/pref/filters.php
index 4e52260c9..c00e52bde 100755
--- a/classes/pref/filters.php
+++ b/classes/pref/filters.php
@@ -328,7 +328,8 @@ class Pref_Filters extends Handler_Protected {
"rules" => [],
"actions" => [],
"filter_types" => [],
- "filter_actions" => [],
+ "action_types" => [],
+ "plugin_actions" => [],
"labels" => Labels::get_all($_SESSION["uid"])
];
@@ -343,7 +344,17 @@ class Pref_Filters extends Handler_Protected {
ORDER BY name");
while ($line = $res->fetch()) {
- $rv["filter_actions"][$line["id"]] = __($line["description"]);
+ $rv["action_types"][$line["id"]] = __($line["description"]);
+ }
+
+ $filter_actions = PluginHost::getInstance()->get_filter_actions();
+
+ foreach ($filter_actions as $fclass => $factions) {
+ foreach ($factions as $faction) {
+
+ $rv["plugin_actions"][$fclass . ":" . $faction["action"]] =
+ $fclass . ": " . $faction["description"];
+ }
}
if ($filter_id) {
@@ -393,167 +404,6 @@ class Pref_Filters extends Handler_Protected {
}
print json_encode($rv);
}
-
- /*return;
-
- if (empty($filter_id) || $row = $sth->fetch()) {
-
- $enabled = $row["enabled"] ?? true;
- $match_any_rule = $row["match_any_rule"] ?? false;
- $inverse = $row["inverse"] ?? false;
- $title = htmlspecialchars($row["title"] ?? "");
-
- print "";
-
- print \Controls\hidden_tag("op", "pref-filters");
-
- if ($filter_id) {
- print \Controls\hidden_tag("id", "$filter_id");
- print \Controls\hidden_tag("method", "editSave");
- } else {
- print \Controls\hidden_tag("method", "add");
- }
-
- print \Controls\hidden_tag("csrf_token", $_SESSION['csrf_token']);
-
- print "
-
-
-
-
-
-
" . __('Select')."
-
-
-
".__('All')."
-
".__('None')."
-
-
-
".
- __('Add')."
-
".
- __('Delete')."
-
";
-
- print "
- ";
-
- print "
-
-
-
-
".__('Select')."
-
-
".__('All')."
-
".__('None')."
-
-
-
".
- __('Add')."
-
".
- __('Delete')."
-
";
-
- print "";
-
- print " ";
-
- print "
- ";
-
- print "
- ".\Controls\checkbox_tag('enabled', $enabled)." ".__('Enabled')." ";
-
- print "
- ".\Controls\checkbox_tag('match_any_rule', $match_any_rule)." ".__('Match any rule')."
- ";
-
- print "".\Controls\checkbox_tag('inverse', $inverse)." ".__('Inverse matching')."
- ";
-
- print "
- ";
-
- if ($filter_id) {
- print "
- ".
- __('Remove')."
-
- ".
- __('Test')."
- ".
- __('Save')."
- ".
- __('Cancel')." ";
- } else {
- print "".
- __('Test')."
- ".
- __('Create')."
- ".
- __('Cancel')." ";
- }
-
- print " ";
- } */
}
private function _get_rule_name($rule) {
@@ -845,180 +695,8 @@ class Pref_Filters extends Handler_Protected {
$feed_ids = explode(",", clean($_REQUEST["ids"]));
print json_encode([
- "multiselect" => $this->feed_multi_select("feed_id", $feed_ids, 'style="width : 500px; height : 300px" dojoType="dijit.form.MultiSelect"')
+ "multiselect" => $this->_feed_multi_select("feed_id", $feed_ids, 'style="width : 540px; height : 300px" dojoType="dijit.form.MultiSelect"')
]);
-
- /*return;
-
- $rule = json_decode(clean($_REQUEST["rule"]), true);
-
- if ($rule) {
- $reg_exp = htmlspecialchars($rule["reg_exp"]);
- $filter_type = $rule["filter_type"];
- $feed_id = $rule["feed_id"];
- $inverse_checked = !empty($rule["inverse"]);
- } else {
- $reg_exp = "";
- $filter_type = 1;
- $feed_id = ["0"];
- $inverse_checked = false;
- }
-
- print "";
-
- $res = $this->pdo->query("SELECT id,description
- FROM ttrss_filter_types WHERE id != 5 ORDER BY description");
-
- $filter_types = array();
-
- while ($line = $res->fetch()) {
- $filter_types[$line["id"]] = __($line["description"]);
- }
-
- print "";
-
- print "";
-
- print "$reg_exp ";
-
- print "
";
-
- print "";
- print "".
- \Controls\checkbox_tag("inverse", $inverse_checked) .
- __("Inverse regular expression matching")." ";
- print " ";
-
- print "";
- print "". __("on field") . " ";
- print \Controls\select_hash("filter_type", $filter_type, $filter_types);
- print "" . __("in") . " ";
-
- print " ";
-
- print "";
- print "";
- print $this->feed_multi_select("feed_id",
- $feed_id,
- 'style="width : 500px; height : 300px" dojoType="dijit.form.MultiSelect"');
- print " ";
-
- print " ";
-
- print " ";
-
- print "";
-
- print "
- help ".__("More info...")." ";
-
- print "".
- ($rule ? __("Save rule") : __('Add rule'))." ";
-
- print "".
- __('Cancel')." ";
-
- print " ";
-
- print " ";*/
- }
-
- function newaction() {
- $action = json_decode(clean($_REQUEST["action"]), true);
-
- if ($action) {
- $action_param = $action["action_param"];
- $action_id = (int)$action["action_id"];
- } else {
- $action_param = "";
- $action_id = 0;
- }
-
- print "";
-
- print "";
-
- print "";
-
- print "";
-
- $res = $this->pdo->query("SELECT id,description FROM ttrss_filter_actions
- ORDER BY name");
-
- while ($line = $res->fetch()) {
- $is_selected = ($line["id"] == $action_id) ? "selected='1'" : "";
- printf("%s ", $line["id"], __($line["description"]));
- }
-
- print " ";
-
- #$param_box_hidden = ($action_id == 7 || $action_id == 4 || $action_id == 6 || $action_id == 9) ?
- # "" : "display : none";
-
- #$param_hidden = ($action_id == 4 || $action_id == 6) ?
- # "" : "display : none";
-
- #$label_param_hidden = ($action_id == 7) ? "" : "display : none";
- #$plugin_param_hidden = ($action_id == 9) ? "" : "display : none";
-
- #print "";
- #print " ";
- //print " " . __("with parameters:") . " ";
- print " ";
-
- print \Controls\select_labels("action_param_label", $action_param,
- ["style" => $label_param_hidden],
- "filterDlg_actionParamLabel");
-
- $filter_actions = PluginHost::getInstance()->get_filter_actions();
- $filter_action_hash = array();
-
- foreach ($filter_actions as $fclass => $factions) {
- foreach ($factions as $faction) {
-
- $filter_action_hash[$fclass . ":" . $faction["action"]] =
- $fclass . ": " . $faction["description"];
- }
- }
-
- if (count($filter_action_hash) == 0) {
- $filter_plugin_disabled = ["disabled" => "1"];
-
- $filter_action_hash["no-data"] = __("No actions available");
-
- } else {
- $filter_plugin_disabled = [];
- }
-
- print \Controls\select_hash("action_param_plugin", $action_param, $filter_action_hash,
- array_merge(["style" => $plugin_param_hidden], $filter_plugin_disabled),
- "filterDlg_actionParamPlugin");
-
- #print " ";
-
- print " "; // tiny layout hack
-
- print " ";
-
- print "";
-
- print "".
- ($action ? __("Save action") : __('Add action'))." ";
-
- print "".
- __('Cancel')." ";
-
- print " ";
-
- print " ";
}
private function _get_name($id) {
@@ -1152,7 +830,7 @@ class Pref_Filters extends Handler_Protected {
$this->pdo->commit();
}
- private function feed_multi_select($id, $default_ids = [],
+ private function _feed_multi_select($id, $default_ids = [],
$attributes = "", $include_all_feeds = true,
$root_id = null, $nest_level = 0) {
@@ -1194,7 +872,7 @@ class Pref_Filters extends Handler_Protected {
$line["id"], htmlspecialchars($line["title"]));
if ($line["num_children"] > 0)
- $rv .= $this->feed_multi_select($id, $default_ids, $attributes,
+ $rv .= $this->_feed_multi_select($id, $default_ids, $attributes,
$include_all_feeds, $line["id"], $nest_level+1);
$f_sth = $pdo->prepare("SELECT id,title FROM ttrss_feeds
diff --git a/js/CommonFilters.js b/js/CommonFilters.js
index 75e1fa8af..5874170b8 100644
--- a/js/CommonFilters.js
+++ b/js/CommonFilters.js
@@ -209,13 +209,13 @@ const Filters = {
- ".
+
${App.FormFields.checkbox_tag("inverse", rule.inverse)}
${__("Inverse regular expression matching")}
- ${__("on field")}
+ ${__("on")}
${App.FormFields.select_hash("filter_type", rule.filter_type, dialog.filter_info.filter_types)}
${__("in")}
@@ -241,10 +241,14 @@ const Filters = {
edit_rule_dialog.show();
},
- /*editAction: function(replaceNode, actionStr) {
+ editAction: function(replaceNode, actionStr) {
const edit_action_dialog = new fox.SingleUseDialog({
title: actionStr ? __("Edit action") : __("Add action"),
- hideOrShowActionParam: function(sender) {
+ select_labels: function(name, value, labels, attributes = {}, id = "") {
+ const values = Object.values(labels).map((label) => label.caption);
+ return App.FormFields.select_tag(name, value, values, attributes, id);
+ },
+ toggleParam: function(sender) {
const action = parseInt(sender.value);
dijit.byId("filterDlg_actionParam").domNode.hide();
@@ -262,67 +266,72 @@ const Filters = {
},
execute: function () {
if (this.validate()) {
- dialog.createNewActionElement(App.byId("filterDlg_Actions"), replaceNode);
+ dialog.insertAction(App.byId("filterDlg_Actions"), replaceNode);
this.hide();
}
- }
+ },
+ content: __("Loading, please wait...")
});
const tmph = dojo.connect(edit_action_dialog, "onShow", null, function () {
dojo.disconnect(tmph);
- xhr.post("backend.php", {op: 'pref-filters', method: 'newaction', action: actionStr}, (reply) => {
- edit_action_dialog.attr('content', reply);
+ let action;
- setTimeout(() => {
- edit_action_dialog.hideOrShowActionParam(dijit.byId("filterDlg_actionSelect").attr('value'));
- }, 250);
- });
- });
-
- edit_action_dialog.show();
- }, */
- /*editAction: function(replaceNode, actionStr) {
- const edit_action_dialog = new fox.SingleUseDialog({
- title: actionStr ? __("Edit action") : __("Add action"),
- hideOrShowActionParam: function(sender) {
- const action = parseInt(sender.value);
+ if (actionStr) {
+ action = JSON.parse(actionStr);
+ } else {
+ action = {
+ action_id: 2,
+ action_param: ""
+ };
+ }
- dijit.byId("filterDlg_actionParam").domNode.hide();
- dijit.byId("filterDlg_actionParamLabel").domNode.hide();
- dijit.byId("filterDlg_actionParamPlugin").domNode.hide();
+ console.log(action);
- // if selected action supports parameters, enable params field
- if (action == dialog.ACTION_LABEL) {
- dijit.byId("filterDlg_actionParamLabel").domNode.show();
- } else if (action == dialog.ACTION_PLUGIN) {
- dijit.byId("filterDlg_actionParamPlugin").domNode.show();
- } else if (dialog.PARAM_ACTIONS.indexOf(action) != -1) {
- dijit.byId("filterDlg_actionParam").domNode.show();
- }
- },
- execute: function () {
- if (this.validate()) {
- dialog.createNewActionElement(App.byId("filterDlg_Actions"), replaceNode);
- this.hide();
- }
- }
- });
+ edit_action_dialog.attr('content',
+ `
+
+
+ ${App.FormFields.select_hash("action_id", -1,
+ dialog.filter_info.action_types,
+ {onchange: "App.dialogOf(this).toggleParam(this)"},
+ "filterDlg_actionSelect")}
+
+
+
+ ${edit_action_dialog.select_labels("action_param_label", action.action_param,
+ dialog.filter_info.labels,
+ {},
+ "filterDlg_actionParamLabel")}
+
+ ${App.FormFields.select_hash("action_param_plugin", action.action_param,
+ dialog.filter_info.plugin_actions,
+ {},
+ "filterDlg_actionParamPlugin")}
+
+
+ ${App.FormFields.submit_tag(__("Save action"), {onclick: "App.dialogOf(this).execute()"})}
+ ${App.FormFields.cancel_dialog_tag(__("Cancel"))}
+
+
+ `);
- const tmph = dojo.connect(edit_action_dialog, "onShow", null, function () {
- dojo.disconnect(tmph);
+ dijit.byId("filterDlg_actionSelect").attr('value', action.action_id);
- xhr.post("backend.php", {op: 'pref-filters', method: 'newaction', action: actionStr}, (reply) => {
+ /*xhr.post("backend.php", {op: 'pref-filters', method: 'newaction', action: actionStr}, (reply) => {
edit_action_dialog.attr('content', reply);
setTimeout(() => {
edit_action_dialog.hideOrShowActionParam(dijit.byId("filterDlg_actionSelect").attr('value'));
}, 250);
- });
+ });*/
});
edit_action_dialog.show();
- },*/
+ },
selectRules: function (select) {
Lists.select("filterDlg_Matches", select);
},
@@ -395,18 +404,7 @@ const Filters = {
const tmph = dojo.connect(dialog, 'onShow', function () {
dojo.disconnect(tmph);
- const query = {op: "pref-filters", method: "edit", id: filter_id};
-
- /*if (!App.isPrefs()) {
- query = {
- op: "pref-filters", method: "edit",
- feed: Feeds.getActive(), is_cat: Feeds.activeIsCat()
- };
- } else {
- query = {op: "pref-filters", method: "edit", id: id};
- }*/
-
- xhr.json("backend.php", query, function (filter) {
+ xhr.json("backend.php", {op: "pref-filters", method: "edit", id: filter_id}, function (filter) {
dialog.filter_info = filter;
@@ -476,10 +474,10 @@ const Filters = {
dojoType="dijit.MenuItem">${__("None")}
-
".
+
${__("Add")}
- ".
+
${__("Delete")}
@@ -488,7 +486,7 @@ const Filters = {
${filter.actions.map((action) => `
${App.FormFields.checkbox_tag("", false, "", {onclick: 'Lists.onRowChecked(this)'})}
- ${App.escapeHtml(action.name)}
+ ${App.escapeHtml(action.name)}
${App.FormFields.hidden_tag("action[]", JSON.stringify(action))}
`).join("")}
--
cgit v1.2.3-54-g00ecf
From 9e56896bd428114ff9bfd979c2d4ff8d93f99485 Mon Sep 17 00:00:00 2001
From: Andrew Dolgov
Date: Sun, 21 Feb 2021 10:34:28 +0300
Subject: Element visible: check for offsetHeight/offsetWidth
---
js/common.js | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/js/common.js b/js/common.js
index 6e8168357..e85862990 100755
--- a/js/common.js
+++ b/js/common.js
@@ -86,8 +86,7 @@ Element.prototype.fadeIn = function(display = undefined){
};
Element.prototype.visible = function() {
- // TODO: should we actually check for offsetWidth/offsetHeight == 0?
- return this.style.display != "none";
+ return this.style.display != "none" && this.offsetHeight != 0 && this.offsetWidth != 0;
}
Element.visible = function(elem) {
--
cgit v1.2.3-54-g00ecf
From 810afdaf5a429468d31b09ae5a7f995dd11568f8 Mon Sep 17 00:00:00 2001
From: Andrew Dolgov
Date: Sun, 21 Feb 2021 12:28:25 +0300
Subject: prevent creation of filter rules matching no feeds
---
classes/pref/filters.php | 2 +-
js/form/ValidationMultiSelect.js | 20 ++++++++++++++++++++
js/prefs.js | 1 +
js/tt-rss.js | 1 +
4 files changed, 23 insertions(+), 1 deletion(-)
create mode 100644 js/form/ValidationMultiSelect.js
diff --git a/classes/pref/filters.php b/classes/pref/filters.php
index c00e52bde..9388cc8d7 100755
--- a/classes/pref/filters.php
+++ b/classes/pref/filters.php
@@ -695,7 +695,7 @@ class Pref_Filters extends Handler_Protected {
$feed_ids = explode(",", clean($_REQUEST["ids"]));
print json_encode([
- "multiselect" => $this->_feed_multi_select("feed_id", $feed_ids, 'style="width : 540px; height : 300px" dojoType="dijit.form.MultiSelect"')
+ "multiselect" => $this->_feed_multi_select("feed_id", $feed_ids, 'required="1" style="width : 540px; height : 300px" dojoType="fox.form.ValidationMultiSelect"')
]);
}
diff --git a/js/form/ValidationMultiSelect.js b/js/form/ValidationMultiSelect.js
new file mode 100644
index 000000000..4e7263c61
--- /dev/null
+++ b/js/form/ValidationMultiSelect.js
@@ -0,0 +1,20 @@
+/* global define */
+
+// only supports required for the time being
+// TODO: maybe show dojo native error message? i dunno
+define(["dojo/_base/declare", "dojo/_base/lang", "dijit/form/MultiSelect", ],
+ function(declare, lang, MultiSelect) {
+
+ return declare('fox.form.ValidationMultiSelect', [MultiSelect], {
+ constructor: function(params){
+ this.constraints = {};
+ this.baseClass += ' dijitValidationMultiSelect';
+ },
+ validate: function(/*Boolean*/ isFocused){
+ if (this.required && this.attr('value').length == 0)
+ return false;
+
+ return true;
+ },
+ })
+ });
diff --git a/js/prefs.js b/js/prefs.js
index a23a74856..8f4f45700 100755
--- a/js/prefs.js
+++ b/js/prefs.js
@@ -53,6 +53,7 @@ require(["dojo/_base/kernel",
"fox/PrefLabelTree",
"fox/Toolbar",
"fox/SingleUseDialog",
+ "fox/form/ValidationMultiSelect",
"fox/form/ValidationTextArea",
"fox/form/Select",
"fox/form/ComboButton",
diff --git a/js/tt-rss.js b/js/tt-rss.js
index 8d7dd00a6..4a7f2e643 100644
--- a/js/tt-rss.js
+++ b/js/tt-rss.js
@@ -51,6 +51,7 @@ require(["dojo/_base/kernel",
"fox/FeedTree",
"fox/Toolbar",
"fox/SingleUseDialog",
+ "fox/form/ValidationMultiSelect",
"fox/form/ValidationTextArea",
"fox/form/Select",
"fox/form/ComboButton",
--
cgit v1.2.3-54-g00ecf
From 2843b9917133e5ed8e1adf4ffd12356459fc16e4 Mon Sep 17 00:00:00 2001
From: Andrew Dolgov
Date: Sun, 21 Feb 2021 13:08:34 +0300
Subject: minor filter UI layout fix
---
classes/pref/filters.php | 2 +-
js/CommonFilters.js | 8 +++-----
themes/compact.css | 1 +
themes/compact_night.css | 1 +
themes/light.css | 1 +
themes/light/tt-rss.less | 1 +
themes/night.css | 1 +
themes/night_blue.css | 1 +
8 files changed, 10 insertions(+), 6 deletions(-)
diff --git a/classes/pref/filters.php b/classes/pref/filters.php
index 9388cc8d7..fda4a6513 100755
--- a/classes/pref/filters.php
+++ b/classes/pref/filters.php
@@ -695,7 +695,7 @@ class Pref_Filters extends Handler_Protected {
$feed_ids = explode(",", clean($_REQUEST["ids"]));
print json_encode([
- "multiselect" => $this->_feed_multi_select("feed_id", $feed_ids, 'required="1" style="width : 540px; height : 300px" dojoType="fox.form.ValidationMultiSelect"')
+ "multiselect" => $this->_feed_multi_select("feed_id", $feed_ids, 'required="1" style="width : 100%; height : 300px" dojoType="fox.form.ValidationMultiSelect"')
]);
}
diff --git a/js/CommonFilters.js b/js/CommonFilters.js
index 5874170b8..0c138760d 100644
--- a/js/CommonFilters.js
+++ b/js/CommonFilters.js
@@ -423,8 +423,8 @@ const Filters = {
${App.FormFields.hidden_tag("method", filter_id ? "editSave" : "add")}
${App.FormFields.hidden_tag("csrf_token", App.getInitParam('csrf_token'))}
-
@@ -496,9 +496,7 @@ const Filters = {
-
-
-
+
${Object.keys(options).map((name) =>
`
diff --git a/themes/compact.css b/themes/compact.css
index 16bdcf1f0..9baf14227 100644
--- a/themes/compact.css
+++ b/themes/compact.css
@@ -456,6 +456,7 @@ body.ttrss_main .dijitDialog .dlgSecCont {
margin: 10px 20px;
}
body.ttrss_main .dijitDialog header.horizontal + section,
+body.ttrss_main .dijitDialog section.horizontal,
body.ttrss_main .dijitDialog .dlgSecHoriz + .dlgSecCont {
margin: 10px 0;
}
diff --git a/themes/compact_night.css b/themes/compact_night.css
index 37adf3fda..4d57208d0 100644
--- a/themes/compact_night.css
+++ b/themes/compact_night.css
@@ -456,6 +456,7 @@ body.ttrss_main .dijitDialog .dlgSecCont {
margin: 10px 20px;
}
body.ttrss_main .dijitDialog header.horizontal + section,
+body.ttrss_main .dijitDialog section.horizontal,
body.ttrss_main .dijitDialog .dlgSecHoriz + .dlgSecCont {
margin: 10px 0;
}
diff --git a/themes/light.css b/themes/light.css
index 0f2ffc1b6..e47ee5adf 100644
--- a/themes/light.css
+++ b/themes/light.css
@@ -456,6 +456,7 @@ body.ttrss_main .dijitDialog .dlgSecCont {
margin: 10px 20px;
}
body.ttrss_main .dijitDialog header.horizontal + section,
+body.ttrss_main .dijitDialog section.horizontal,
body.ttrss_main .dijitDialog .dlgSecHoriz + .dlgSecCont {
margin: 10px 0;
}
diff --git a/themes/light/tt-rss.less b/themes/light/tt-rss.less
index 2794d8177..7b24c7701 100644
--- a/themes/light/tt-rss.less
+++ b/themes/light/tt-rss.less
@@ -530,6 +530,7 @@ body.ttrss_main {
}
header.horizontal + section,
+ section.horizontal,
.dlgSecHoriz + .dlgSecCont {
margin : 10px 0;
}
diff --git a/themes/night.css b/themes/night.css
index e012c92b2..8ca622d8d 100644
--- a/themes/night.css
+++ b/themes/night.css
@@ -457,6 +457,7 @@ body.ttrss_main .dijitDialog .dlgSecCont {
margin: 10px 20px;
}
body.ttrss_main .dijitDialog header.horizontal + section,
+body.ttrss_main .dijitDialog section.horizontal,
body.ttrss_main .dijitDialog .dlgSecHoriz + .dlgSecCont {
margin: 10px 0;
}
diff --git a/themes/night_blue.css b/themes/night_blue.css
index b49a496e3..6d98bbb26 100644
--- a/themes/night_blue.css
+++ b/themes/night_blue.css
@@ -457,6 +457,7 @@ body.ttrss_main .dijitDialog .dlgSecCont {
margin: 10px 20px;
}
body.ttrss_main .dijitDialog header.horizontal + section,
+body.ttrss_main .dijitDialog section.horizontal,
body.ttrss_main .dijitDialog .dlgSecHoriz + .dlgSecCont {
margin: 10px 0;
}
--
cgit v1.2.3-54-g00ecf
From d1328321bebadcf8a530d3c05f52a8f3c58bb969 Mon Sep 17 00:00:00 2001
From: Andrew Dolgov
Date: Sun, 21 Feb 2021 15:16:39 +0300
Subject: move published OPML endpoint to public.php
---
classes/handler/public.php | 21 +++++++++++++++++++++
classes/opml.php | 9 +++------
classes/pref/feeds.php | 4 ++--
classes/rpc.php | 13 +++++--------
opml.php | 36 ------------------------------------
themes/compact.css | 26 +++++++++++++++-----------
themes/compact_night.css | 26 +++++++++++++++-----------
themes/light.css | 26 +++++++++++++++-----------
themes/light/prefs.less | 4 ++--
themes/light/tt-rss.less | 4 ++--
themes/night.css | 26 +++++++++++++++-----------
themes/night_blue.css | 26 +++++++++++++++-----------
12 files changed, 110 insertions(+), 111 deletions(-)
delete mode 100644 opml.php
diff --git a/classes/handler/public.php b/classes/handler/public.php
index 8076bb303..b0ce2306d 100755
--- a/classes/handler/public.php
+++ b/classes/handler/public.php
@@ -737,6 +737,27 @@ class Handler_Public extends Handler {
prepare( "SELECT owner_uid
+ FROM ttrss_access_keys WHERE
+ access_key = ? AND feed_id = 'OPML:Publish'");
+ $sth->execute([$key]);
+
+ if ($row = $sth->fetch()) {
+ $owner_uid = $row['owner_uid'];
+
+ $opml = new OPML($_REQUEST);
+ $opml->opml_export("published.opml", $owner_uid, true, false);
+
+ } else {
+ header($_SERVER["SERVER_PROTOCOL"]." 404 Not Found");
+ echo "File not found.";
+ }
+ }
+
function cached() {
list ($cache_dir, $filename) = explode("/", $_GET["file"], 2);
diff --git a/classes/opml.php b/classes/opml.php
index 78ddb2842..04d287125 100644
--- a/classes/opml.php
+++ b/classes/opml.php
@@ -634,13 +634,10 @@ class OPML extends Handler_Protected {
print "$msg ";
}
- static function opml_publish_url(){
-
- $url_path = get_self_url_prefix();
- $url_path .= "/opml.php?op=publish&key=" .
+ static function get_publish_url(){
+ return get_self_url_prefix() .
+ "/public.php?op=publishOpml&key=" .
Feeds::_get_access_key('OPML:Publish', false, $_SESSION["uid"]);
-
- return $url_path;
}
function get_feed_category($feed_cat, $parent_cat_id = false) {
diff --git a/classes/pref/feeds.php b/classes/pref/feeds.php
index cf9e7c95e..8d3f84a03 100755
--- a/classes/pref/feeds.php
+++ b/classes/pref/feeds.php
@@ -1329,14 +1329,14 @@ class Pref_Feeds extends Handler_Protected {
}
function getOPMLKey() {
- print json_encode(["link" => OPML::opml_publish_url()]);
+ print json_encode(["link" => OPML::get_publish_url()]);
}
function regenOPMLKey() {
$this->update_feed_access_key('OPML:Publish',
false, $_SESSION["uid"]);
- print json_encode(["link" => OPML::opml_publish_url()]);
+ print json_encode(["link" => OPML::get_publish_url()]);
}
function regenFeedKey() {
diff --git a/classes/rpc.php b/classes/rpc.php
index 20a11b994..95fd0f5ae 100755
--- a/classes/rpc.php
+++ b/classes/rpc.php
@@ -656,12 +656,10 @@ class RPC extends Handler_Protected {
";
-
- ?>
+ ?>
+
= \Controls\submit_tag(__('Close this window')) ?>
diff --git a/opml.php b/opml.php
deleted file mode 100644
index 6f13a6f3c..000000000
--- a/opml.php
+++ /dev/null
@@ -1,36 +0,0 @@
-prepare( "SELECT owner_uid
- FROM ttrss_access_keys WHERE
- access_key = ? AND feed_id = 'OPML:Publish'");
- $sth->execute([$key]);
-
- if ($row = $sth->fetch()) {
- $owner_uid = $row['owner_uid'];
-
- $opml = new OPML($_REQUEST);
- $opml->opml_export("", $owner_uid, true, false);
-
- } else {
- print "User not found ";
- }
- }
-
-?>
diff --git a/themes/compact.css b/themes/compact.css
index 9baf14227..64f60641c 100644
--- a/themes/compact.css
+++ b/themes/compact.css
@@ -898,12 +898,14 @@ body.ttrss_main .dijitTooltipBelow .dijitTooltipConnector {
body.ttrss_main .dijitTooltipAbove .dijitTooltipConnector {
border-top-color: #1c5c7d;
}
-body.ttrss_main .dijitDialog h1:first-of-type,
-body.ttrss_main .dijitDialog h2:first-of-type,
-body.ttrss_main .dijitDialog h3:first-of-type,
-body.ttrss_main .dijitDialog h4:first-of-type {
- margin-top: 0px;
-}
+/*body.ttrss_main .dijitDialog {
+ h1:first-of-type,
+ h2:first-of-type,
+ h3:first-of-type,
+ h4:first-of-type {
+ margin-top: 0px;
+ }
+}*/
body.ttrss_main[view-mode="marked"] #feeds-holder #feedTree .dijitTreeRow.Has_Marked .dijitTreeLabel {
color: #257aa7;
}
@@ -1413,6 +1415,13 @@ body.ttrss_prefs {
background-color: #f5f5f5;
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
font-size: 14px;
+ /*.dijitContentPane {
+ h1:first-of-type,
+ h2:first-of-type,
+ h3:first-of-type {
+ margin-top: 0px;
+ }
+ }*/
}
body.ttrss_prefs h1,
body.ttrss_prefs h2,
@@ -1422,11 +1431,6 @@ body.ttrss_prefs h4 {
font-weight: 600;
color: #555;
}
-body.ttrss_prefs .dijitContentPane h1:first-of-type,
-body.ttrss_prefs .dijitContentPane h2:first-of-type,
-body.ttrss_prefs .dijitContentPane h3:first-of-type {
- margin-top: 0px;
-}
body.ttrss_prefs #footer,
body.ttrss_prefs #header {
padding: 8px;
diff --git a/themes/compact_night.css b/themes/compact_night.css
index 4d57208d0..a5acb9c86 100644
--- a/themes/compact_night.css
+++ b/themes/compact_night.css
@@ -898,12 +898,14 @@ body.ttrss_main .dijitTooltipBelow .dijitTooltipConnector {
body.ttrss_main .dijitTooltipAbove .dijitTooltipConnector {
border-top-color: #d29745;
}
-body.ttrss_main .dijitDialog h1:first-of-type,
-body.ttrss_main .dijitDialog h2:first-of-type,
-body.ttrss_main .dijitDialog h3:first-of-type,
-body.ttrss_main .dijitDialog h4:first-of-type {
- margin-top: 0px;
-}
+/*body.ttrss_main .dijitDialog {
+ h1:first-of-type,
+ h2:first-of-type,
+ h3:first-of-type,
+ h4:first-of-type {
+ margin-top: 0px;
+ }
+}*/
body.ttrss_main[view-mode="marked"] #feeds-holder #feedTree .dijitTreeRow.Has_Marked .dijitTreeLabel {
color: #b87d2c;
}
@@ -1413,6 +1415,13 @@ body.ttrss_prefs {
background-color: #222;
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
font-size: 14px;
+ /*.dijitContentPane {
+ h1:first-of-type,
+ h2:first-of-type,
+ h3:first-of-type {
+ margin-top: 0px;
+ }
+ }*/
}
body.ttrss_prefs h1,
body.ttrss_prefs h2,
@@ -1422,11 +1431,6 @@ body.ttrss_prefs h4 {
font-weight: 600;
color: #ccc;
}
-body.ttrss_prefs .dijitContentPane h1:first-of-type,
-body.ttrss_prefs .dijitContentPane h2:first-of-type,
-body.ttrss_prefs .dijitContentPane h3:first-of-type {
- margin-top: 0px;
-}
body.ttrss_prefs #footer,
body.ttrss_prefs #header {
padding: 8px;
diff --git a/themes/light.css b/themes/light.css
index e47ee5adf..7030e5182 100644
--- a/themes/light.css
+++ b/themes/light.css
@@ -898,12 +898,14 @@ body.ttrss_main .dijitTooltipBelow .dijitTooltipConnector {
body.ttrss_main .dijitTooltipAbove .dijitTooltipConnector {
border-top-color: #1c5c7d;
}
-body.ttrss_main .dijitDialog h1:first-of-type,
-body.ttrss_main .dijitDialog h2:first-of-type,
-body.ttrss_main .dijitDialog h3:first-of-type,
-body.ttrss_main .dijitDialog h4:first-of-type {
- margin-top: 0px;
-}
+/*body.ttrss_main .dijitDialog {
+ h1:first-of-type,
+ h2:first-of-type,
+ h3:first-of-type,
+ h4:first-of-type {
+ margin-top: 0px;
+ }
+}*/
body.ttrss_main[view-mode="marked"] #feeds-holder #feedTree .dijitTreeRow.Has_Marked .dijitTreeLabel {
color: #257aa7;
}
@@ -1413,6 +1415,13 @@ body.ttrss_prefs {
background-color: #f5f5f5;
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
font-size: 14px;
+ /*.dijitContentPane {
+ h1:first-of-type,
+ h2:first-of-type,
+ h3:first-of-type {
+ margin-top: 0px;
+ }
+ }*/
}
body.ttrss_prefs h1,
body.ttrss_prefs h2,
@@ -1422,11 +1431,6 @@ body.ttrss_prefs h4 {
font-weight: 600;
color: #555;
}
-body.ttrss_prefs .dijitContentPane h1:first-of-type,
-body.ttrss_prefs .dijitContentPane h2:first-of-type,
-body.ttrss_prefs .dijitContentPane h3:first-of-type {
- margin-top: 0px;
-}
body.ttrss_prefs #footer,
body.ttrss_prefs #header {
padding: 8px;
diff --git a/themes/light/prefs.less b/themes/light/prefs.less
index ec3006ce5..510388391 100644
--- a/themes/light/prefs.less
+++ b/themes/light/prefs.less
@@ -9,13 +9,13 @@ body.ttrss_prefs {
color : @default-text;
}
- .dijitContentPane {
+ /*.dijitContentPane {
h1:first-of-type,
h2:first-of-type,
h3:first-of-type {
margin-top: 0px;
}
- }
+ }*/
#footer, #header {
padding : 8px;
diff --git a/themes/light/tt-rss.less b/themes/light/tt-rss.less
index 7b24c7701..35eec3e48 100644
--- a/themes/light/tt-rss.less
+++ b/themes/light/tt-rss.less
@@ -1049,14 +1049,14 @@ body.ttrss_main {
}
}
-body.ttrss_main .dijitDialog {
+/*body.ttrss_main .dijitDialog {
h1:first-of-type,
h2:first-of-type,
h3:first-of-type,
h4:first-of-type {
margin-top: 0px;
}
-}
+}*/
body.ttrss_main[view-mode="marked"] #feeds-holder #feedTree {
.dijitTreeRow.Has_Marked .dijitTreeLabel {
diff --git a/themes/night.css b/themes/night.css
index 8ca622d8d..73f1ec96d 100644
--- a/themes/night.css
+++ b/themes/night.css
@@ -899,12 +899,14 @@ body.ttrss_main .dijitTooltipBelow .dijitTooltipConnector {
body.ttrss_main .dijitTooltipAbove .dijitTooltipConnector {
border-top-color: #d29745;
}
-body.ttrss_main .dijitDialog h1:first-of-type,
-body.ttrss_main .dijitDialog h2:first-of-type,
-body.ttrss_main .dijitDialog h3:first-of-type,
-body.ttrss_main .dijitDialog h4:first-of-type {
- margin-top: 0px;
-}
+/*body.ttrss_main .dijitDialog {
+ h1:first-of-type,
+ h2:first-of-type,
+ h3:first-of-type,
+ h4:first-of-type {
+ margin-top: 0px;
+ }
+}*/
body.ttrss_main[view-mode="marked"] #feeds-holder #feedTree .dijitTreeRow.Has_Marked .dijitTreeLabel {
color: #b87d2c;
}
@@ -1414,6 +1416,13 @@ body.ttrss_prefs {
background-color: #222;
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
font-size: 14px;
+ /*.dijitContentPane {
+ h1:first-of-type,
+ h2:first-of-type,
+ h3:first-of-type {
+ margin-top: 0px;
+ }
+ }*/
}
body.ttrss_prefs h1,
body.ttrss_prefs h2,
@@ -1423,11 +1432,6 @@ body.ttrss_prefs h4 {
font-weight: 600;
color: #ccc;
}
-body.ttrss_prefs .dijitContentPane h1:first-of-type,
-body.ttrss_prefs .dijitContentPane h2:first-of-type,
-body.ttrss_prefs .dijitContentPane h3:first-of-type {
- margin-top: 0px;
-}
body.ttrss_prefs #footer,
body.ttrss_prefs #header {
padding: 8px;
diff --git a/themes/night_blue.css b/themes/night_blue.css
index 6d98bbb26..aa3ead557 100644
--- a/themes/night_blue.css
+++ b/themes/night_blue.css
@@ -899,12 +899,14 @@ body.ttrss_main .dijitTooltipBelow .dijitTooltipConnector {
body.ttrss_main .dijitTooltipAbove .dijitTooltipConnector {
border-top-color: #2e99d1;
}
-body.ttrss_main .dijitDialog h1:first-of-type,
-body.ttrss_main .dijitDialog h2:first-of-type,
-body.ttrss_main .dijitDialog h3:first-of-type,
-body.ttrss_main .dijitDialog h4:first-of-type {
- margin-top: 0px;
-}
+/*body.ttrss_main .dijitDialog {
+ h1:first-of-type,
+ h2:first-of-type,
+ h3:first-of-type,
+ h4:first-of-type {
+ margin-top: 0px;
+ }
+}*/
body.ttrss_main[view-mode="marked"] #feeds-holder #feedTree .dijitTreeRow.Has_Marked .dijitTreeLabel {
color: #257aa7;
}
@@ -1414,6 +1416,13 @@ body.ttrss_prefs {
background-color: #222;
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
font-size: 14px;
+ /*.dijitContentPane {
+ h1:first-of-type,
+ h2:first-of-type,
+ h3:first-of-type {
+ margin-top: 0px;
+ }
+ }*/
}
body.ttrss_prefs h1,
body.ttrss_prefs h2,
@@ -1423,11 +1432,6 @@ body.ttrss_prefs h4 {
font-weight: 600;
color: #ccc;
}
-body.ttrss_prefs .dijitContentPane h1:first-of-type,
-body.ttrss_prefs .dijitContentPane h2:first-of-type,
-body.ttrss_prefs .dijitContentPane h3:first-of-type {
- margin-top: 0px;
-}
body.ttrss_prefs #footer,
body.ttrss_prefs #header {
padding: 8px;
--
cgit v1.2.3-54-g00ecf
From 1bd5152c8016c6019a647bf995d29d81c6b731ed Mon Sep 17 00:00:00 2001
From: wn_
Date: Sat, 20 Feb 2021 13:44:42 +0000
Subject: Open the default feed after unsubscribing.
Previously the UI appeared to hang, even though the backend request had already completed successfully.
---
js/CommonDialogs.js | 2 +-
js/Feeds.js | 6 +++++-
2 files changed, 6 insertions(+), 2 deletions(-)
diff --git a/js/CommonDialogs.js b/js/CommonDialogs.js
index 704e797d3..a100a546d 100644
--- a/js/CommonDialogs.js
+++ b/js/CommonDialogs.js
@@ -312,7 +312,7 @@ const CommonDialogs = {
} else {
if (feed_id == Feeds.getActive())
setTimeout(() => {
- Feeds.open({feed: -5})
+ Feeds.openDefaultFeed();
},
100);
diff --git a/js/Feeds.js b/js/Feeds.js
index e9ac5328d..4841fd0df 100644
--- a/js/Feeds.js
+++ b/js/Feeds.js
@@ -3,6 +3,7 @@
/* global __, App, Headlines, xhrPost, xhr, dojo, dijit, fox, PluginHost, Notify, fox */
const Feeds = {
+ _default_feed_id: -3,
counters_last_request: 0,
_active_feed_id: undefined,
_active_feed_is_cat: false,
@@ -109,6 +110,9 @@ const Feeds = {
}
return false; // block unneeded form submits
},
+ openDefaultFeed: function() {
+ this.open({feed: this._default_feed_id});
+ },
openNextUnread: function() {
const is_cat = this.activeIsCat();
const nuf = this.getNextUnread(this.getActive(), is_cat);
@@ -215,7 +219,7 @@ const Feeds = {
if (hash_feed_id != undefined) {
this.open({feed: hash_feed_id, is_cat: hash_feed_is_cat});
} else {
- this.open({feed: -3});
+ this.openDefaultFeed();
}
this.hideOrShowFeeds(App.getInitParam("hide_read_feeds"));
--
cgit v1.2.3-54-g00ecf
From 521d0b65c73f90d6e86c1a38dcab492b5a23982b Mon Sep 17 00:00:00 2001
From: Andrew Dolgov
Date: Sun, 21 Feb 2021 16:02:57 +0300
Subject: batch feed editor: use tab layout, cleanup
---
classes/pref/feeds.php | 243 +++++++++++++++++++------------------------------
js/PrefFeedTree.js | 21 +++--
2 files changed, 108 insertions(+), 156 deletions(-)
diff --git a/classes/pref/feeds.php b/classes/pref/feeds.php
index 8d3f84a03..c901bc96e 100755
--- a/classes/pref/feeds.php
+++ b/classes/pref/feeds.php
@@ -22,11 +22,6 @@ class Pref_Feeds extends Handler_Protected {
return $rv;
}
- function batch_edit_cbox($elem, $label = false) {
- print " ";
- }
-
function renamecat() {
$title = clean($_REQUEST['title']);
$id = clean($_REQUEST['id']);
@@ -571,165 +566,117 @@ class Pref_Feeds extends Handler_Protected {
}
}
+ private function _batch_toggle_checkbox($name) {
+ return \Controls\checkbox_tag("", false, "",
+ ["data-control-for" => $name, "title" => __("Check to enable field"), "onchange" => "App.dialogOf(this).toggleField(this)"]);
+ }
+
function editfeeds() {
global $purge_intervals;
global $update_intervals;
$feed_ids = clean($_REQUEST["ids"]);
- print_notice("Enable the options you wish to apply using checkboxes on the right:");
-
- print \Controls\hidden_tag("ids", "$feed_ids");
- print \Controls\hidden_tag("op", "pref-feeds");
- print \Controls\hidden_tag("method", "batchEditSave");
-
- print "";
- print "";
-
- /* Category */
-
- if (get_pref('ENABLE_FEED_CATS')) {
-
- print "";
-
- print "" . __('Place in category:') . " ";
-
- print \Controls\select_feeds_cats("cat_id", null, ['disabled' => '1']);
-
- $this->batch_edit_cbox("cat_id");
-
- print " ";
- }
-
- /* FTS Stemming Language */
-
- if (DB_TYPE == "pgsql") {
- print "";
-
- print "" . __('Language:') . " ";
- print \Controls\select_tag("feed_language", "", $this::get_ts_languages(), ["disabled"=> 1]);
-
- $this->batch_edit_cbox("feed_language");
-
- print " ";
- }
-
- print " ";
-
- print "";
- print "";
-
- /* Update Interval */
-
- print "";
-
- print "".__("Interval:")." ";
-
$local_update_intervals = $update_intervals;
$local_update_intervals[0] .= sprintf(" (%s)", $update_intervals[get_pref("DEFAULT_UPDATE_INTERVAL")]);
- print \Controls\select_hash("update_interval", "", $local_update_intervals, ["disabled" => 1]);
-
- $this->batch_edit_cbox("update_interval");
-
- print " ";
-
- /* Purge intl */
-
- if (FORCE_ARTICLE_PURGE == 0) {
-
- print "";
-
- print "" . __('Article purging:') . " ";
-
- $local_purge_intervals = $purge_intervals;
- $default_purge_interval = get_pref("PURGE_OLD_DAYS");
-
- if ($default_purge_interval > 0)
- $local_purge_intervals[0] .= " " . T_sprintf("(%d days)", $default_purge_interval);
- else
- $local_purge_intervals[0] .= " " . sprintf("(%s)", __("Disabled"));
+ $local_purge_intervals = $purge_intervals;
+ $default_purge_interval = get_pref("PURGE_OLD_DAYS");
- print \Controls\select_hash("purge_interval", "", $local_purge_intervals, ["disabled" => 1]);
-
- $this->batch_edit_cbox("purge_interval");
-
- print " ";
- }
-
- print " ";
- print "";
- print "";
- print "";
- print "";
-
- print "";
- print " ".__('Include in e-mail digest')." ";
-
- print " "; $this->batch_edit_cbox("include_in_digest", "include_in_digest_l");
-
- print " ";
-
- print " ".__('Always display image attachments')." ";
-
- print " "; $this->batch_edit_cbox("always_display_enclosures", "always_display_enclosures_l");
-
- print " ";
-
- print " ". __('Do not embed media')." ";
-
- print " "; $this->batch_edit_cbox("hide_images", "hide_images_l");
-
- print " ";
-
- print " ".__('Cache media')." ";
-
- print " "; $this->batch_edit_cbox("cache_images", "cache_images_l");
-
- print " ";
+ if ($default_purge_interval > 0)
+ $local_purge_intervals[0] .= " " . T_sprintf("(%d days)", $default_purge_interval);
+ else
+ $local_purge_intervals[0] .= " " . sprintf("(%s)", __("Disabled"));
- print " ".__('Mark updated articles as unread')." ";
+ $options = [
+ "include_in_digest" => __('Include in e-mail digest'),
+ "always_display_enclosures" => __('Always display image attachments'),
+ "hide_images" => __('Do not embed media'),
+ "cache_images" => __('Cache media'),
+ "mark_unread_on_update" => __('Mark updated articles as unread')
+ ];
- print " "; $this->batch_edit_cbox("mark_unread_on_update", "mark_unread_on_update_l");
+ print_notice("Enable the options you wish to apply using checkboxes on the right.");
+ ?>
- print " ";
+ = \Controls\hidden_tag("ids", $feed_ids) ?>
+ = \Controls\hidden_tag("op", "pref-feeds") ?>
+ = \Controls\hidden_tag("method", "batchEditSave") ?>
- print " ";
+
+
+
+
+
+ = __('Place in category:') ?>
+ = \Controls\select_feeds_cats("cat_id", null, ['disabled' => '1']) ?>
+ = $this->_batch_toggle_checkbox("cat_id") ?>
+
+
- print "
- ".
- __('Save')."
- ".
- __('Cancel')."
- ";
+
+
+ = __('Language:') ?>
+ = \Controls\select_tag("feed_language", "", $this::get_ts_languages(), ["disabled"=> 1]) ?>
+ = $this->_batch_toggle_checkbox("feed_language") ?>
+
+
+
+
+
+
+
+
+ = __("Update interval:") ?>
+ = \Controls\select_hash("update_interval", "", $local_update_intervals, ["disabled" => 1]) ?>
+ = $this->_batch_toggle_checkbox("update_interval") ?>
+
+
+
+
+ = __('Article purging:') ?>
+ = \Controls\select_hash("purge_interval", "", $local_purge_intervals, ["disabled" => 1]) ?>
+ = $this->_batch_toggle_checkbox("purge_interval") ?>
+
+
+
+
+
+
+
+
+ $caption) {
+ ?>
+
+
+ = \Controls\checkbox_tag($name, false, "", ["disabled" => "1"]) ?>
+ = $caption ?>
+ = $this->_batch_toggle_checkbox($name) ?>
+
+
+
+
+
- return;
+
+ = \Controls\submit_tag(__("Save")) ?>
+ = \Controls\cancel_dialog_tag(__("Cancel")) ?>
+
+
Date: Sun, 21 Feb 2021 16:06:46 +0300
Subject: batch editor: comment out getChildByName
---
js/PrefFeedTree.js | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/js/PrefFeedTree.js b/js/PrefFeedTree.js
index 468e2025c..bb5d25e67 100644
--- a/js/PrefFeedTree.js
+++ b/js/PrefFeedTree.js
@@ -301,7 +301,7 @@ define(["dojo/_base/declare", "dojo/dom-construct", "lib/CheckBoxTree", "dojo/_b
try {
const dialog = new fox.SingleUseDialog({
title: __("Edit Multiple Feeds"),
- getChildByName: function (name) {
+ /*getChildByName: function (name) {
let rv = null;
this.getChildren().forEach(
function (child) {
@@ -311,7 +311,7 @@ define(["dojo/_base/declare", "dojo/dom-construct", "lib/CheckBoxTree", "dojo/_b
}
});
return rv;
- },
+ },*/
toggleField: function (checkbox) {
const name = checkbox.attr("data-control-for");
const target = dijit.getEnclosingWidget(dialog.domNode.querySelector(`input[name="${name}"]`));
--
cgit v1.2.3-54-g00ecf
From 861a632ac7c283c55dfd947ed0152d9846fa2ac0 Mon Sep 17 00:00:00 2001
From: Andrew Dolgov
Date: Sun, 21 Feb 2021 18:04:44 +0300
Subject: move published opml JS code to pref helpers
---
classes/pref/feeds.php | 2 +-
js/CommonDialogs.js | 58 --------------------------------------------------
js/PrefHelpers.js | 57 +++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 58 insertions(+), 59 deletions(-)
diff --git a/classes/pref/feeds.php b/classes/pref/feeds.php
index c901bc96e..e583a5f51 100755
--- a/classes/pref/feeds.php
+++ b/classes/pref/feeds.php
@@ -1043,7 +1043,7 @@ class Pref_Feeds extends Handler_Protected {
= __("Published OPML does not include your Tiny Tiny RSS settings, feeds that require authentication or feeds hidden from Popular feeds.") ?>
-
+
= __('Display published OPML URL') ?>
diff --git a/js/CommonDialogs.js b/js/CommonDialogs.js
index a100a546d..321ddf6d3 100644
--- a/js/CommonDialogs.js
+++ b/js/CommonDialogs.js
@@ -587,64 +587,6 @@ const CommonDialogs = {
dialog.show();
},
- publishedOPML: function() {
-
- Notify.progress("Loading, please wait...", true);
-
- xhr.json("backend.php", {op: "pref-feeds", method: "getOPMLKey"}, (reply) => {
- try {
- const dialog = new fox.SingleUseDialog({
- title: __("Public OPML URL"),
- regenOPMLKey: function() {
- if (confirm(__("Replace current OPML publishing address with a new one?"))) {
- Notify.progress("Trying to change address...", true);
-
- xhr.json("backend.php", {op: "pref-feeds", method: "regenOPMLKey"}, (reply) => {
- if (reply) {
- const new_link = reply.link;
- const target = this.domNode.querySelector('.generated_url');
-
- if (new_link && target) {
- target.href = new_link;
- target.innerHTML = new_link;
-
- Notify.close();
-
- } else {
- Notify.error("Could not change feed URL.");
- }
- }
- });
- }
- return false;
- },
- content: `
- ${__("Your Public OPML URL is:")}
-
-
-
- ${__('Generate new URL')}
-
-
- ${__('Close this window')}
-
-
- `
- });
-
- dialog.show();
-
- Notify.close();
-
- } catch (e) {
- App.Error.report(e);
- }
- });
- },
generatedFeed: function(feed, is_cat, search = "") {
Notify.progress("Loading, please wait...", true);
diff --git a/js/PrefHelpers.js b/js/PrefHelpers.js
index d27e0e071..62f6d91b1 100644
--- a/js/PrefHelpers.js
+++ b/js/PrefHelpers.js
@@ -347,5 +347,62 @@ const Helpers = {
console.log("export");
window.open("backend.php?op=opml&method=export&" + dojo.formToQuery("opmlExportForm"));
},
+ publish: function() {
+ Notify.progress("Loading, please wait...", true);
+
+ xhr.json("backend.php", {op: "pref-feeds", method: "getOPMLKey"}, (reply) => {
+ try {
+ const dialog = new fox.SingleUseDialog({
+ title: __("Public OPML URL"),
+ regenOPMLKey: function() {
+ if (confirm(__("Replace current OPML publishing address with a new one?"))) {
+ Notify.progress("Trying to change address...", true);
+
+ xhr.json("backend.php", {op: "pref-feeds", method: "regenOPMLKey"}, (reply) => {
+ if (reply) {
+ const new_link = reply.link;
+ const target = this.domNode.querySelector('.generated_url');
+
+ if (new_link && target) {
+ target.href = new_link;
+ target.innerHTML = new_link;
+
+ Notify.close();
+
+ } else {
+ Notify.error("Could not change feed URL.");
+ }
+ }
+ });
+ }
+ return false;
+ },
+ content: `
+ ${__("Your Public OPML URL is:")}
+
+
+
+ ${__('Generate new URL')}
+
+
+ ${__('Close this window')}
+
+
+ `
+ });
+
+ dialog.show();
+
+ Notify.close();
+
+ } catch (e) {
+ App.Error.report(e);
+ }
+ });
+ },
}
};
--
cgit v1.2.3-54-g00ecf
From cb401af6f6f278b94b664569796c49f045e3ffde Mon Sep 17 00:00:00 2001
From: wn_
Date: Sun, 21 Feb 2021 18:40:43 +0000
Subject: Let 'RSSUtils::check_feed_favicon' update existing favicons.
---
classes/rssutils.php | 106 +++++++++++++++++++++++++++++----------------------
1 file changed, 60 insertions(+), 46 deletions(-)
diff --git a/classes/rssutils.php b/classes/rssutils.php
index 5fb2e7712..13f63bc7a 100755
--- a/classes/rssutils.php
+++ b/classes/rssutils.php
@@ -594,7 +594,7 @@ class RSSUtils {
$favicon_file = ICONS_DIR . "/$feed.ico";
$favicon_modified = file_exists($favicon_file) ? filemtime($favicon_file) : -1;
- Debug::log("checking favicon...", Debug::$LOG_VERBOSE);
+ Debug::log("checking favicon for feed $feed...", Debug::$LOG_VERBOSE);
self::check_feed_favicon($site_url, $feed);
$favicon_modified_new = file_exists($favicon_file) ? filemtime($favicon_file) : -1;
@@ -1643,58 +1643,72 @@ class RSSUtils {
}
static function check_feed_favicon($site_url, $feed) {
- # print "FAVICON [$site_url]: $favicon_url\n";
-
$icon_file = ICONS_DIR . "/$feed.ico";
- if (!file_exists($icon_file)) {
- $favicon_url = self::get_favicon_url($site_url);
+ $favicon_url = self::get_favicon_url($site_url);
+ if (!$favicon_url) {
+ Debug::log("couldn't find favicon URL in $site_url", Debug::$LOG_VERBOSE);
+ return false;
+ }
- if ($favicon_url) {
- // Limiting to "image" type misses those served with text/plain
- $contents = UrlHelper::fetch($favicon_url); // , "image");
+ // Limiting to "image" type misses those served with text/plain
+ $contents = UrlHelper::fetch(['url' => $favicon_url]); // , "image");
+ if (!$contents) {
+ Debug::log("fetching favicon $favicon_url failed", Debug::$LOG_VERBOSE);
+ return false;
+ }
- if ($contents) {
- // Crude image type matching.
- // Patterns gleaned from the file(1) source code.
- if (preg_match('/^\x00\x00\x01\x00/', $contents)) {
- // 0 string \000\000\001\000 MS Windows icon resource
- //error_log("check_feed_favicon: favicon_url=$favicon_url isa MS Windows icon resource");
- }
- elseif (preg_match('/^GIF8/', $contents)) {
- // 0 string GIF8 GIF image data
- //error_log("check_feed_favicon: favicon_url=$favicon_url isa GIF image");
- }
- elseif (preg_match('/^\x89PNG\x0d\x0a\x1a\x0a/', $contents)) {
- // 0 string \x89PNG\x0d\x0a\x1a\x0a PNG image data
- //error_log("check_feed_favicon: favicon_url=$favicon_url isa PNG image");
- }
- elseif (preg_match('/^\xff\xd8/', $contents)) {
- // 0 beshort 0xffd8 JPEG image data
- //error_log("check_feed_favicon: favicon_url=$favicon_url isa JPG image");
- }
- elseif (preg_match('/^BM/', $contents)) {
- // 0 string BM PC bitmap (OS2, Windows BMP files)
- //error_log("check_feed_favicon, favicon_url=$favicon_url isa BMP image");
- }
- else {
- //error_log("check_feed_favicon: favicon_url=$favicon_url isa UNKNOWN type");
- $contents = "";
- }
- }
+ $original_contents = file_exists($icon_file) ? file_get_contents($icon_file) : null;
+ if ($original_contents) {
+ if (strcmp($contents, $original_contents) === 0) {
+ Debug::log("favicon content has not changed", Debug::$LOG_VERBOSE);
+ return $icon_file;
+ }
+ Debug::log("favicon content has changed", Debug::$LOG_VERBOSE);
+ }
- if ($contents) {
- $fp = @fopen($icon_file, "w");
+ // Crude image type matching.
+ // Patterns gleaned from the file(1) source code.
+ if (preg_match('/^\x00\x00\x01\x00/', $contents)) {
+ // 0 string \000\000\001\000 MS Windows icon resource
+ //error_log("check_feed_favicon: favicon_url=$favicon_url isa MS Windows icon resource");
+ }
+ elseif (preg_match('/^GIF8/', $contents)) {
+ // 0 string GIF8 GIF image data
+ //error_log("check_feed_favicon: favicon_url=$favicon_url isa GIF image");
+ }
+ elseif (preg_match('/^\x89PNG\x0d\x0a\x1a\x0a/', $contents)) {
+ // 0 string \x89PNG\x0d\x0a\x1a\x0a PNG image data
+ //error_log("check_feed_favicon: favicon_url=$favicon_url isa PNG image");
+ }
+ elseif (preg_match('/^\xff\xd8/', $contents)) {
+ // 0 beshort 0xffd8 JPEG image data
+ //error_log("check_feed_favicon: favicon_url=$favicon_url isa JPG image");
+ }
+ elseif (preg_match('/^BM/', $contents)) {
+ // 0 string BM PC bitmap (OS2, Windows BMP files)
+ //error_log("check_feed_favicon, favicon_url=$favicon_url isa BMP image");
+ }
+ else {
+ //error_log("check_feed_favicon: favicon_url=$favicon_url isa UNKNOWN type");
+ Debug::log("favicon $favicon_url type is unknown (not updating)", Debug::$LOG_VERBOSE);
+ return false;
+ }
- if ($fp) {
- fwrite($fp, $contents);
- fclose($fp);
- chmod($icon_file, 0644);
- }
- }
- }
- return $icon_file;
+ Debug::log("setting contents of $icon_file", Debug::$LOG_VERBOSE);
+
+ $fp = @fopen($icon_file, "w");
+ if (!$fp) {
+ Debug::log("failed to open $icon_file for writing", Debug::$LOG_VERBOSE);
+ return false;
}
+
+ fwrite($fp, $contents);
+ fclose($fp);
+ chmod($icon_file, 0644);
+ clearstatcache();
+
+ return $icon_file;
}
static function is_gzipped($feed_data) {
--
cgit v1.2.3-54-g00ecf
From f6bfb89b2912933f638416135dff7bb8cb28890d Mon Sep 17 00:00:00 2001
From: Andrew Dolgov
Date: Sun, 21 Feb 2021 23:18:32 +0300
Subject: pref-prefs: switch to new control shorthand in a few places
---
classes/pref/prefs.php | 51 +++++++++++++++++++++-----------------------------
include/controls.php | 17 +++++++++++++++++
2 files changed, 38 insertions(+), 30 deletions(-)
diff --git a/classes/pref/prefs.php b/classes/pref/prefs.php
index 2ea2e9f01..a26281fee 100644
--- a/classes/pref/prefs.php
+++ b/classes/pref/prefs.php
@@ -712,59 +712,50 @@ class Pref_Prefs extends Handler_Protected {
array_push($listed_boolean_prefs, $pref_name);
- $is_checked = ($value == "true") ? "checked=\"checked\"" : "";
-
if ($pref_name == "PURGE_UNREAD_ARTICLES" && FORCE_ARTICLE_PURGE != 0) {
- $is_disabled = "disabled=\"1\"";
- $is_checked = "checked=\"checked\"";
+ $is_disabled = true;
+ $is_checked = true;
} else {
- $is_disabled = "";
+ $is_disabled = false;
+ $is_checked = ($value == "true");
}
- print " ";
+ print \Controls\checkbox_tag($pref_name, $is_checked, "true",
+ ["disabled" => $is_disabled], "CB_$pref_name");
} else if (in_array($pref_name, ['FRESH_ARTICLE_MAX_AGE',
'PURGE_OLD_DAYS', 'LONG_DATE_FORMAT', 'SHORT_DATE_FORMAT'])) {
- $regexp = ($type_name == 'integer') ? 'regexp="^\d*$"' : '';
-
if ($pref_name == "PURGE_OLD_DAYS" && FORCE_ARTICLE_PURGE != 0) {
- $is_disabled = "disabled='1'";
+ $attributes = ["disabled" => true, "required" => true];
$value = FORCE_ARTICLE_PURGE;
} else {
- $is_disabled = "";
+ $attributes = ["required" => true];
}
if ($type_name == 'integer')
- print " ";
+ print \Controls\number_spinner_tag($pref_name, $value, $attributes);
else
- print " ";
+ print \Controls\input_tag($pref_name, $value, "text", $attributes);
} else if ($pref_name == "SSL_CERT_SERIAL") {
- print " ";
+ print \Controls\input_tag($pref_name, $value, "text", ["readonly" => true], "SSL_CERT_SERIAL");
$cert_serial = htmlspecialchars(get_ssl_certificate_id());
- $has_serial = ($cert_serial) ? "false" : "true";
+ $has_serial = ($cert_serial) ? true : false;
- print "" .
- __('Register') . " ";
+ print \Controls\button_tag(__('Register'), "", [
+ "disabled" => !$has_serial,
+ "onclick" => "dijit.byId('SSL_CERT_SERIAL').attr('value', '$cert_serial')"]);
- print "" .
- __('Clear') . " ";
+ print \Controls\button_tag(__('Clear'), "", [
+ "class" => "alt-danger",
+ "onclick" => "dijit.byId('SSL_CERT_SERIAL').attr('value', '')"]);
- print "
- help ".__("More info...")." ";
+ print \Controls\button_tag(\Controls\icon("help") . " " . __("More info..."), "", [
+ "class" => "alt-info",
+ "onclick" => "window.open('https://tt-rss.org/wiki/SSL%20Certificate%20Authentication')"]);
} else if ($pref_name == 'DIGEST_PREFERRED_TIME') {
print " $v) {
+
+ // special handling for "disabled"
+ if ($k === "disabled" && !sql_bool_to_bool($v))
+ continue;
+
$rv .= "$k=\"" . htmlspecialchars($v) . "\"";
}
@@ -30,6 +35,18 @@
return "$value ";
}
+ function input_tag(string $name, string $value, string $type = "text", array $attributes = [], string $id = "") {
+ $attributes_str = attributes_to_string($attributes);
+ $dojo_type = strpos($attributes_str, "dojoType") === false ? "dojoType='dijit.form.TextBox'" : "";
+
+ return " ";
+ }
+
+ function number_spinner_tag(string $name, string $value, array $attributes = [], string $id = "") {
+ return input_tag($name, $value, "text", array_merge(["dojoType" => "dijit.form.NumberSpinner"], $attributes), $id);
+ }
+
function submit_tag(string $value, array $attributes = []) {
return button_tag($value, "submit", array_merge(["class" => "alt-primary"], $attributes));
}
--
cgit v1.2.3-54-g00ecf
From 6f29ecbbb96440552f434f5f487b96753bdb02df Mon Sep 17 00:00:00 2001
From: Andrew Dolgov
Date: Sun, 21 Feb 2021 23:19:58 +0300
Subject: add phpstan config
---
phpstan.neon | 17 +++++++++++++++++
1 file changed, 17 insertions(+)
create mode 100644 phpstan.neon
diff --git a/phpstan.neon b/phpstan.neon
new file mode 100644
index 000000000..0703e0d15
--- /dev/null
+++ b/phpstan.neon
@@ -0,0 +1,17 @@
+parameters:
+ level: 5
+ ignoreErrors:
+ - '#Constant.*not found#'
+ - '#Call to an undefined method DOMNode::getAttribute\(\).#'
+ - '#PHPDoc tag @param has invalid value#'
+ - message: '##'
+ paths:
+ - lib/*
+ - vendor/*
+ - plugins/*/vendor/*
+ - plugins.local/*/vendor/*
+
+ excludePaths:
+ - node_modules/*
+ paths:
+ - .
\ No newline at end of file
--
cgit v1.2.3-54-g00ecf
From 02a9485966dbbac1ed52ecbfb29fcc15125cba43 Mon Sep 17 00:00:00 2001
From: wn_
Date: Sun, 21 Feb 2021 23:30:31 +0000
Subject: Try to limit max favicon size, don't store current/old in a var.
---
classes/rssutils.php | 12 ++++++++----
include/functions.php | 2 ++
utils/phpstan_tunables.php | 2 ++
3 files changed, 12 insertions(+), 4 deletions(-)
diff --git a/classes/rssutils.php b/classes/rssutils.php
index 13f63bc7a..6785ab3f5 100755
--- a/classes/rssutils.php
+++ b/classes/rssutils.php
@@ -1652,15 +1652,19 @@ class RSSUtils {
}
// Limiting to "image" type misses those served with text/plain
- $contents = UrlHelper::fetch(['url' => $favicon_url]); // , "image");
+ $contents = UrlHelper::fetch([
+ 'url' => $favicon_url,
+ 'max_size' => MAX_FAVICON_FILE_SIZE,
+ //'type' => 'image',
+ ]);
if (!$contents) {
Debug::log("fetching favicon $favicon_url failed", Debug::$LOG_VERBOSE);
return false;
}
- $original_contents = file_exists($icon_file) ? file_get_contents($icon_file) : null;
- if ($original_contents) {
- if (strcmp($contents, $original_contents) === 0) {
+ $original_contents_md5 = file_exists($icon_file) ? md5_file($icon_file) : null;
+ if ($original_contents_md5) {
+ if (md5($contents) == $original_contents_md5) {
Debug::log("favicon content has not changed", Debug::$LOG_VERBOSE);
return $icon_file;
}
diff --git a/include/functions.php b/include/functions.php
index 174ef39f0..df8730aca 100644
--- a/include/functions.php
+++ b/include/functions.php
@@ -68,6 +68,8 @@
// do not cache files larger than that (bytes)
define_default('MAX_DOWNLOAD_FILE_SIZE', 16*1024*1024);
// do not download general files larger than that (bytes)
+ define_default('MAX_FAVICON_FILE_SIZE', 1*1024*1024);
+ // do not download favicon files larger than that (bytes)
define_default('CACHE_MAX_DAYS', 7);
// max age in days for various automatically cached (temporary) files
define_default('MAX_CONDITIONAL_INTERVAL', 3600*12);
diff --git a/utils/phpstan_tunables.php b/utils/phpstan_tunables.php
index 7d5d8f03a..e192bcdba 100644
--- a/utils/phpstan_tunables.php
+++ b/utils/phpstan_tunables.php
@@ -27,6 +27,8 @@
// do not cache files larger than that (bytes)
define('MAX_DOWNLOAD_FILE_SIZE', 16*1024*1024);
// do not download general files larger than that (bytes)
+ define('MAX_FAVICON_FILE_SIZE', 1*1024*1024);
+ // do not download favicon files larger than that (bytes)
define('CACHE_MAX_DAYS', 7);
// max age in days for various automatically cached (temporary) files
define('MAX_CONDITIONAL_INTERVAL', 3600*12);
--
cgit v1.2.3-54-g00ecf
From 33fff2686946021314a24feef61032beaf48e7a4 Mon Sep 17 00:00:00 2001
From: Andrew Dolgov
Date: Mon, 22 Feb 2021 10:00:50 +0300
Subject: reinstate HOOK_RENDER_ENCLOSURE
---
classes/article.php | 23 ++++++++++++++++++-----
classes/pluginhost.php | 4 ++--
js/Article.js | 6 +-----
plugins/af_youtube_embed/init.php | 6 +++---
4 files changed, 24 insertions(+), 15 deletions(-)
diff --git a/classes/article.php b/classes/article.php
index dd1470caa..acd83694c 100755
--- a/classes/article.php
+++ b/classes/article.php
@@ -343,6 +343,7 @@ class Article extends Handler_Protected {
}
$rv = [
+ 'formatted' => '',
'entries' => []
];
@@ -358,12 +359,24 @@ class Article extends Handler_Protected {
// this is highly approximate
$enc["filename"] = basename($enc["content_url"]);
- PluginHost::getInstance()->chain_hooks_callback(PluginHost::HOOK_ENCLOSURE_ENTRY,
- function ($result) use (&$enc) {
- $enc = $result;
+ $rendered_enc = "";
+ PluginHost::getInstance()->chain_hooks_callback(PluginHost::HOOK_RENDER_ENCLOSURE,
+ function ($result) use (&$rendered_enc) {
+ $rendered_enc = $result;
},
- $enc, $id);
- array_push($rv['entries'], $enc);
+ $enc, $id, $rv);
+
+ if ($rendered_enc) {
+ $rv['formatted'] .= $rendered_enc;
+ } else {
+ PluginHost::getInstance()->chain_hooks_callback(PluginHost::HOOK_ENCLOSURE_ENTRY,
+ function ($result) use (&$enc) {
+ $enc = $result;
+ },
+ $enc, $id, $rv);
+
+ array_push($rv['entries'], $enc);
+ }
}
return $rv;
diff --git a/classes/pluginhost.php b/classes/pluginhost.php
index d50c5a706..a05938111 100755
--- a/classes/pluginhost.php
+++ b/classes/pluginhost.php
@@ -51,11 +51,11 @@ class PluginHost {
const HOOK_FORMAT_ENCLOSURES = "hook_format_enclosures"; // hook__format_enclosures($rv, $result, $id, $always_display_enclosures, $article_content, $hide_images) (byref)
const HOOK_SUBSCRIBE_FEED = "hook_subscribe_feed"; // hook_subscribe_feed($contents, $url, $auth_login, $auth_pass) (byref)
const HOOK_HEADLINES_BEFORE = "hook_headlines_before"; // hook_headlines_before($feed, $is_cat, $qfh_ret)
- const HOOK_RENDER_ENCLOSURE = "hook_render_enclosure"; // hook_render_enclosure($entry, $hide_images)
+ const HOOK_RENDER_ENCLOSURE = "hook_render_enclosure"; // hook_render_enclosure($entry, $id, $rv)
const HOOK_ARTICLE_FILTER_ACTION = "hook_article_filter_action"; // hook_article_filter_action($article, $action)
const HOOK_ARTICLE_EXPORT_FEED = "hook_article_export_feed"; // hook_article_export_feed($line, $feed, $is_cat, $owner_uid) (byref)
const HOOK_MAIN_TOOLBAR_BUTTON = "hook_main_toolbar_button"; // hook_main_toolbar_button()
- const HOOK_ENCLOSURE_ENTRY = "hook_enclosure_entry"; // hook_enclosure_entry($row, $id) (byref)
+ const HOOK_ENCLOSURE_ENTRY = "hook_enclosure_entry"; // hook_enclosure_entry($entry, $id, $rv) (byref)
const HOOK_FORMAT_ARTICLE = "hook_format_article"; // hook_format_article($html, $row)
const HOOK_FORMAT_ARTICLE_CDM = "hook_format_article_cdm"; /* RIP */
const HOOK_FEED_BASIC_INFO = "hook_feed_basic_info"; // hook_feed_basic_info($basic_info, $fetch_url, $owner_uid, $feed_id, $auth_login, $auth_pass) (byref)
diff --git a/js/Article.js b/js/Article.js
index d039882ec..5f695561c 100644
--- a/js/Article.js
+++ b/js/Article.js
@@ -150,12 +150,8 @@ const Article = {
).join("")}`;
},
renderEnclosures: function (enclosures) {
-
- // enclosure list was handled by backend (HOOK_FORMAT_ENCLOSURES)
- if (enclosures.formatted)
- return enclosures.formatted;
-
return `
+ ${enclosures.formatted}
${enclosures.can_inline ?
`
${enclosures.entries.map((enc) => {
diff --git a/plugins/af_youtube_embed/init.php b/plugins/af_youtube_embed/init.php
index db82dc9f5..6309aac02 100644
--- a/plugins/af_youtube_embed/init.php
+++ b/plugins/af_youtube_embed/init.php
@@ -23,9 +23,9 @@ class Af_Youtube_Embed extends Plugin {
$matches = array();
- if (preg_match("/\/\/www\.youtube\.com\/v\/([\w-]+)/", $entry["url"], $matches) ||
- preg_match("/\/\/www\.youtube\.com\/watch?v=([\w-]+)/", $entry["url"], $matches) ||
- preg_match("/\/\/youtu.be\/([\w-]+)/", $entry["url"], $matches)) {
+ if (preg_match("/\/\/www\.youtube\.com\/v\/([\w-]+)/", $entry["content_url"], $matches) ||
+ preg_match("/\/\/www\.youtube\.com\/watch?v=([\w-]+)/", $entry["content_url"], $matches) ||
+ preg_match("/\/\/youtu.be\/([\w-]+)/", $entry["content_url"], $matches)) {
$vid_id = $matches[1];
--
cgit v1.2.3-54-g00ecf
From 167ed87684e7eb392d2f762d7294acf4b261c5da Mon Sep 17 00:00:00 2001
From: Andrew Dolgov
Date: Mon, 22 Feb 2021 11:40:31 +0300
Subject: add launch.json for xdebug
---
.vscode/launch.json | 13 +++++++++++++
1 file changed, 13 insertions(+)
create mode 100644 .vscode/launch.json
diff --git a/.vscode/launch.json b/.vscode/launch.json
new file mode 100644
index 000000000..d8aee785f
--- /dev/null
+++ b/.vscode/launch.json
@@ -0,0 +1,13 @@
+{
+ "version": "0.2.0",
+ "configurations": [
+ {
+ "name": "Listen for XDebug",
+ "type": "php",
+ "request": "launch",
+ "pathMappings": {
+ "/var/www/html/tt-rss": "${workspaceRoot}",
+ },
+ "port": 9000
+ }]
+}
\ No newline at end of file
--
cgit v1.2.3-54-g00ecf
From 043ef3dad68f774598e1b172ecb0f5ea75f112af Mon Sep 17 00:00:00 2001
From: Andrew Dolgov
Date: Mon, 22 Feb 2021 13:44:25 +0300
Subject: add chrome configuration for debugging
---
.vscode/launch.json | 12 +++++++++++-
1 file changed, 11 insertions(+), 1 deletion(-)
diff --git a/.vscode/launch.json b/.vscode/launch.json
index d8aee785f..0e10b4b23 100644
--- a/.vscode/launch.json
+++ b/.vscode/launch.json
@@ -1,7 +1,17 @@
{
"version": "0.2.0",
"configurations": [
- {
+ {
+ "name": "Launch Chrome",
+ "request": "launch",
+ "type": "chrome",
+ "pathMapping": {
+ "/tt-rss/": "${workspaceFolder}"
+ },
+ "urlFilter": "*/tt-rss/*",
+ "runtimeExecutable": "chrome.exe",
+ },
+ {
"name": "Listen for XDebug",
"type": "php",
"request": "launch",
--
cgit v1.2.3-54-g00ecf
From be4e7b13403666fc477d4b563ea8c075d0fd2022 Mon Sep 17 00:00:00 2001
From: Andrew Dolgov
Date: Mon, 22 Feb 2021 14:41:09 +0300
Subject: fix several issues reported by phpstan
---
api/index.php | 4 ++--
classes/api.php | 2 +-
classes/digest.php | 9 ---------
classes/feeds.php | 6 ------
classes/handler/public.php | 10 +++++-----
classes/pluginhost.php | 3 ++-
classes/pref/prefs.php | 7 -------
include/functions.php | 8 ++++----
include/sanity_check.php | 6 +++---
include/sanity_config.php | 4 ++--
include/sessions.php | 8 ++++----
phpstan.neon | 4 +++-
plugins/af_fsckportal/init.php | 5 +----
plugins/af_redditimgur/init.php | 5 ++++-
update.php | 4 ++--
utils/regen_config_checks.sh | 4 ++--
16 files changed, 35 insertions(+), 54 deletions(-)
diff --git a/api/index.php b/api/index.php
index eb79422f9..1b713d561 100644
--- a/api/index.php
+++ b/api/index.php
@@ -18,8 +18,8 @@
require_once "functions.php";
require_once "sessions.php";
- ini_set('session.use_cookies', 0);
- ini_set("session.gc_maxlifetime", 86400);
+ ini_set('session.use_cookies', "0");
+ ini_set("session.gc_maxlifetime", "86400");
ob_start();
diff --git a/classes/api.php b/classes/api.php
index 03eea1927..5677cb908 100755
--- a/classes/api.php
+++ b/classes/api.php
@@ -292,7 +292,7 @@ class API extends Handler {
$sanitize_content = !isset($_REQUEST["sanitize"]) ||
self::_param_to_bool($_REQUEST["sanitize"]);
- if ($article_ids) {
+ if (count($article_ids) > 0) {
$article_qmarks = arr_qmarks($article_ids);
diff --git a/classes/digest.php b/classes/digest.php
index 77eb92c54..e0c23d705 100644
--- a/classes/digest.php
+++ b/classes/digest.php
@@ -1,12 +1,6 @@
addBlock('enclosure');
}
} else {
- $tpl->setVariable('ARTICLE_ENCLOSURE_URL', null, true);
- $tpl->setVariable('ARTICLE_ENCLOSURE_TYPE', null, true);
- $tpl->setVariable('ARTICLE_ENCLOSURE_LENGTH', null, true);
+ $tpl->setVariable('ARTICLE_ENCLOSURE_URL', "", true);
+ $tpl->setVariable('ARTICLE_ENCLOSURE_TYPE', "", true);
+ $tpl->setVariable('ARTICLE_ENCLOSURE_LENGTH', "", true);
}
list ($og_image, $og_stream) = Article::_get_image($enclosures, $line['content'], $feed_site_url);
@@ -207,8 +207,8 @@ class Handler_Public extends Handler {
$article['content'] = Sanitizer::sanitize($line["content"], false, $owner_uid, $feed_site_url, false, $line["id"]);
$article['updated'] = date('c', strtotime($line["updated"]));
- if ($line['note']) $article['note'] = $line['note'];
- if ($article['author']) $article['author'] = $line['author'];
+ if (!empty($line['note'])) $article['note'] = $line['note'];
+ if (!empty($line['author'])) $article['author'] = $line['author'];
if (count($line["tags"]) > 0) {
$article['tags'] = array();
diff --git a/classes/pluginhost.php b/classes/pluginhost.php
index a05938111..5121c8491 100755
--- a/classes/pluginhost.php
+++ b/classes/pluginhost.php
@@ -108,8 +108,9 @@ class PluginHost {
return false;
}
+ // needed for compatibility with API 2 (?)
function get_dbh() {
- return Db::get();
+ return false;
}
function get_pdo(): PDO {
diff --git a/classes/pref/prefs.php b/classes/pref/prefs.php
index a26281fee..adb249dac 100644
--- a/classes/pref/prefs.php
+++ b/classes/pref/prefs.php
@@ -311,13 +311,6 @@ class Pref_Prefs extends Handler_Protected {
-
-
- = __('Access level:') ?>
- = $access_level_names[$row["access_level"]] ?>
-
-
-
diff --git a/include/functions.php b/include/functions.php
index 174ef39f0..bf9b374a2 100644
--- a/include/functions.php
+++ b/include/functions.php
@@ -34,8 +34,8 @@
error_reporting(E_ALL & ~E_NOTICE);
}
- ini_set('display_errors', 0);
- ini_set('display_startup_errors', 0);
+ ini_set('display_errors', "false");
+ ini_set('display_startup_errors', "false");
require_once 'config.php';
@@ -281,7 +281,7 @@
} else if (is_string($param)) {
return trim(strip_tags($param));
} else {
- return trim($param);
+ return $param;
}
}
@@ -430,7 +430,7 @@
}
function uniqid_short() {
- return uniqid(base_convert(rand(), 10, 36));
+ return uniqid(base_convert((string)rand(), 10, 36));
}
function T_sprintf() {
diff --git a/include/sanity_check.php b/include/sanity_check.php
index 9407b606f..2786f012f 100755
--- a/include/sanity_check.php
+++ b/include/sanity_check.php
@@ -40,8 +40,6 @@
array_push($errors, "Configuration file not found. Looks like you forgot to copy config.php-dist to config.php and edit it.");
} else {
- require_once "sanity_config.php";
-
if (!file_exists("config.php")) {
array_push($errors, "Please copy config.php-dist to config.php");
}
@@ -78,12 +76,14 @@
array_push($errors, "Data export cache is not writable (chmod -R 777 ".CACHE_DIR."/export)");
}
+ require_once "sanity_config.php";
+
if (GENERATED_CONFIG_CHECK != EXPECTED_CONFIG_VERSION) {
array_push($errors,
"Configuration option checker sanity_config.php is outdated, please recreate it using ./utils/regen_config_checks.sh");
}
- foreach ($required_defines as $d) {
+ foreach (get_required_defines() as $d) {
if (!defined($d)) {
array_push($errors,
"Required configuration file parameter $d is not defined in config.php. You might need to copy it from config.php-dist.");
diff --git a/include/sanity_config.php b/include/sanity_config.php
index 5059ee83b..b304adf54 100644
--- a/include/sanity_config.php
+++ b/include/sanity_config.php
@@ -1,3 +1,3 @@
-
+function get_required_defines() { return [ 'DB_TYPE', 'DB_HOST', 'DB_USER', 'DB_NAME', 'DB_PASS', 'MYSQL_CHARSET', 'SELF_URL_PATH', 'SINGLE_USER_MODE', 'SIMPLE_UPDATE_MODE', 'PHP_EXECUTABLE', 'LOCK_DIRECTORY', 'CACHE_DIR', 'ICONS_DIR', 'ICONS_URL', 'AUTH_AUTO_CREATE', 'AUTH_AUTO_LOGIN', 'FORCE_ARTICLE_PURGE', 'SESSION_COOKIE_LIFETIME', 'SMTP_FROM_NAME', 'SMTP_FROM_ADDRESS', 'DIGEST_SUBJECT', 'CHECK_FOR_UPDATES', 'PLUGINS', 'LOG_DESTINATION', 'CONFIG_VERSION']; }
diff --git a/include/sessions.php b/include/sessions.php
index 16de53ab2..5b372612b 100644
--- a/include/sessions.php
+++ b/include/sessions.php
@@ -12,14 +12,14 @@
$session_name = (!defined('TTRSS_SESSION_NAME')) ? "ttrss_sid" : TTRSS_SESSION_NAME;
if (is_server_https()) {
- ini_set("session.cookie_secure", true);
+ ini_set("session.cookie_secure", "true");
}
- ini_set("session.gc_probability", 75);
+ ini_set("session.gc_probability", "75");
ini_set("session.name", $session_name);
- ini_set("session.use_only_cookies", true);
+ ini_set("session.use_only_cookies", "true");
ini_set("session.gc_maxlifetime", $session_expire);
- ini_set("session.cookie_lifetime", 0);
+ ini_set("session.cookie_lifetime", "0");
function session_get_schema_version() {
global $schema_version;
diff --git a/phpstan.neon b/phpstan.neon
index 0703e0d15..b2cd978d8 100644
--- a/phpstan.neon
+++ b/phpstan.neon
@@ -2,7 +2,9 @@ parameters:
level: 5
ignoreErrors:
- '#Constant.*not found#'
- - '#Call to an undefined method DOMNode::getAttribute\(\).#'
+ - '#Comparison operation ">" between int<1, max> and 0 is always true.#'
+ - '#Access to an undefined property DOMNode::\$tagName.#'
+ - '#Call to an undefined method DOMNode::(get|remove|set)Attribute\(\).#'
- '#PHPDoc tag @param has invalid value#'
- message: '##'
paths:
diff --git a/plugins/af_fsckportal/init.php b/plugins/af_fsckportal/init.php
index 04b77a15a..8caa617c6 100644
--- a/plugins/af_fsckportal/init.php
+++ b/plugins/af_fsckportal/init.php
@@ -19,9 +19,7 @@ class Af_Fsckportal extends Plugin {
$doc = new DOMDocument();
- @$doc->loadHTML('' . $article["content"]);
-
- if ($doc) {
+ if (@$doc->loadHTML('' . $article["content"])) {
$xpath = new DOMXPath($doc);
$entries = $xpath->query('(//img[@src]|//a[@href])');
@@ -34,7 +32,6 @@ class Af_Fsckportal extends Plugin {
}
$article["content"] = $doc->saveHTML();
-
}
return $article;
diff --git a/plugins/af_redditimgur/init.php b/plugins/af_redditimgur/init.php
index 2677fdd90..713eaea5c 100755
--- a/plugins/af_redditimgur/init.php
+++ b/plugins/af_redditimgur/init.php
@@ -207,7 +207,7 @@ class Af_RedditImgur extends Plugin {
$found = false;
// embed before reddit post layout
- $anchor = $xpath->query('//body/*')->item(0);
+ $anchor = $xpath->query('//_body/*')->item(0);
// deal with json-provided media content first
if ($article["link"] && $anchor) {
@@ -217,6 +217,7 @@ class Af_RedditImgur extends Plugin {
$this->fallback_preview_urls = [];
+ // @phpstan-ignore-next-line
if ($tmp && $anchor) {
$json = json_decode($tmp, true);
@@ -346,6 +347,8 @@ class Af_RedditImgur extends Plugin {
if (strpos($source_stream, "imgur.com") !== false)
$poster_url = str_replace(".mp4", "h.jpg", $source_stream);
+ else
+ $poster_url = false;
$this->handle_as_video($doc, $entry, $source_stream, $poster_url);
diff --git a/update.php b/update.php
index 1f79dccf0..71b8cf76c 100755
--- a/update.php
+++ b/update.php
@@ -32,7 +32,7 @@
if (DB_TYPE == "pgsql") {
$interval_query = "date_updated < NOW() - INTERVAL '$days days'";
- } else if (DB_TYPE == "mysql") {
+ } else /*if (DB_TYPE == "mysql") */ {
$interval_query = "date_updated < DATE_SUB(NOW(), INTERVAL $days DAY)";
}
@@ -459,7 +459,7 @@
if (isset($options["list-plugins"])) {
$tmppluginhost = new PluginHost();
- $tmppluginhost->load_all($tmppluginhost::KIND_ALL, false);
+ $tmppluginhost->load_all($tmppluginhost::KIND_ALL);
$enabled = array_map("trim", explode(",", PLUGINS));
echo "List of all available plugins:\n";
diff --git a/utils/regen_config_checks.sh b/utils/regen_config_checks.sh
index e8b1ed830..b20ce0480 100755
--- a/utils/regen_config_checks.sh
+++ b/utils/regen_config_checks.sh
@@ -8,10 +8,10 @@ echo -n "define('GENERATED_CONFIG_CHECK', " >> $DESTINATION
grep CONFIG_VERSION config.php-dist | awk -F ' |\)' '{ print $2 }' | xargs echo -n >> $DESTINATION
echo ");" >> $DESTINATION
-echo -n "\$required_defines = array( " >> $DESTINATION
+echo -n "function get_required_defines() { return [ " >> $DESTINATION
grep define\( config.php-dist | awk -F\' '{ print "*" $2 "*," }' | grep -v DB_PORT | xargs echo -n | sed -e s/,$// -e s/*/\'/g >> $DESTINATION
-echo "); ?>" >> $DESTINATION
+echo "]; }" >> $DESTINATION
--
cgit v1.2.3-54-g00ecf
From 6fbf7ef368520f8f4d2c07c153d1429b2f4ff5e3 Mon Sep 17 00:00:00 2001
From: wn_
Date: Mon, 22 Feb 2021 12:06:27 +0000
Subject: Remove check against the old file in 'RSSUtils::check_feed_favicon'.
---
classes/rssutils.php | 9 ---------
1 file changed, 9 deletions(-)
diff --git a/classes/rssutils.php b/classes/rssutils.php
index 6785ab3f5..30d08328f 100755
--- a/classes/rssutils.php
+++ b/classes/rssutils.php
@@ -1662,15 +1662,6 @@ class RSSUtils {
return false;
}
- $original_contents_md5 = file_exists($icon_file) ? md5_file($icon_file) : null;
- if ($original_contents_md5) {
- if (md5($contents) == $original_contents_md5) {
- Debug::log("favicon content has not changed", Debug::$LOG_VERBOSE);
- return $icon_file;
- }
- Debug::log("favicon content has changed", Debug::$LOG_VERBOSE);
- }
-
// Crude image type matching.
// Patterns gleaned from the file(1) source code.
if (preg_match('/^\x00\x00\x01\x00/', $contents)) {
--
cgit v1.2.3-54-g00ecf
From add6242e5148d29be506d753ca4123b900427b7f Mon Sep 17 00:00:00 2001
From: Andrew Dolgov
Date: Mon, 22 Feb 2021 17:35:52 +0300
Subject: do not use define_default() because it screws with static analyzers
---
include/functions.php | 35 ++++++++++++++---------------------
update_daemon2.php | 8 ++++----
utils/phpstan_tunables.php | 46 ----------------------------------------------
3 files changed, 18 insertions(+), 71 deletions(-)
delete mode 100644 utils/phpstan_tunables.php
diff --git a/include/functions.php b/include/functions.php
index 21459da9c..1f25f6947 100644
--- a/include/functions.php
+++ b/include/functions.php
@@ -39,49 +39,42 @@
require_once 'config.php';
- /**
- * Define a constant if not already defined
- */
- function define_default($name, $value) {
- defined($name) or define($name, $value);
- }
-
/* Some tunables you can override in config.php using define(): */
- define_default('FEED_FETCH_TIMEOUT', 45);
+ if (!defined('FEED_FETCH_TIMEOUT')) define('FEED_FETCH_TIMEOUT', 45);
// How may seconds to wait for response when requesting feed from a site
- define_default('FEED_FETCH_NO_CACHE_TIMEOUT', 15);
+ if (!defined('FEED_FETCH_NO_CACHE_TIMEOUT')) define('FEED_FETCH_NO_CACHE_TIMEOUT', 15);
// How may seconds to wait for response when requesting feed from a
// site when that feed wasn't cached before
- define_default('FILE_FETCH_TIMEOUT', 45);
+ if (!defined('FILE_FETCH_TIMEOUT')) define('FILE_FETCH_TIMEOUT', 45);
// Default timeout when fetching files from remote sites
- define_default('FILE_FETCH_CONNECT_TIMEOUT', 15);
+ if (!defined('FILE_FETCH_CONNECT_TIMEOUT')) define('FILE_FETCH_CONNECT_TIMEOUT', 15);
// How many seconds to wait for initial response from website when
// fetching files from remote sites
- define_default('DAEMON_UPDATE_LOGIN_LIMIT', 30);
+ if (!defined('DAEMON_UPDATE_LOGIN_LIMIT')) define('DAEMON_UPDATE_LOGIN_LIMIT', 30);
// stop updating feeds if users haven't logged in for X days
- define_default('DAEMON_FEED_LIMIT', 500);
+ if (!defined('DAEMON_FEED_LIMIT')) define('DAEMON_FEED_LIMIT', 500);
// feed limit for one update batch
- define_default('DAEMON_SLEEP_INTERVAL', 120);
+ if (!defined('DAEMON_SLEEP_INTERVAL')) define('DAEMON_SLEEP_INTERVAL', 120);
// default sleep interval between feed updates (sec)
- define_default('MAX_CACHE_FILE_SIZE', 64*1024*1024);
+ if (!defined('MAX_CACHE_FILE_SIZE')) define('MAX_CACHE_FILE_SIZE', 64*1024*1024);
// do not cache files larger than that (bytes)
- define_default('MAX_DOWNLOAD_FILE_SIZE', 16*1024*1024);
+ if (!defined('MAX_DOWNLOAD_FILE_SIZE')) define('MAX_DOWNLOAD_FILE_SIZE', 16*1024*1024);
// do not download general files larger than that (bytes)
- define_default('MAX_FAVICON_FILE_SIZE', 1*1024*1024);
+ if (!defined('MAX_FAVICON_FILE_SIZE')) define('MAX_FAVICON_FILE_SIZE', 1*1024*1024);
// do not download favicon files larger than that (bytes)
- define_default('CACHE_MAX_DAYS', 7);
+ if (!defined('CACHE_MAX_DAYS')) define('CACHE_MAX_DAYS', 7);
// max age in days for various automatically cached (temporary) files
- define_default('MAX_CONDITIONAL_INTERVAL', 3600*12);
+ if (!defined('MAX_CONDITIONAL_INTERVAL')) define('MAX_CONDITIONAL_INTERVAL', 3600*12);
// max interval between forced unconditional updates for servers
// not complying with http if-modified-since (seconds)
- // define_default('MAX_FETCH_REQUESTS_PER_HOST', 25);
+ // if (!defined('MAX_FETCH_REQUESTS_PER_HOST')) define('MAX_FETCH_REQUESTS_PER_HOST', 25);
// a maximum amount of allowed HTTP requests per destination host
// during a single update (i.e. within PHP process lifetime)
// this is used to not cause excessive load on the origin server on
// e.g. feed subscription when all articles are being processes
// (not implemented)
- define_default('DAEMON_UNSUCCESSFUL_DAYS_LIMIT', 30);
+ if (!defined('DAEMON_UNSUCCESSFUL_DAYS_LIMIT')) define('DAEMON_UNSUCCESSFUL_DAYS_LIMIT', 30);
// automatically disable updates for feeds which failed to
// update for this amount of days; 0 disables
diff --git a/update_daemon2.php b/update_daemon2.php
index 2a016df48..af4cdedc9 100755
--- a/update_daemon2.php
+++ b/update_daemon2.php
@@ -13,10 +13,10 @@
require_once "config.php";
// defaults
- define_default('PURGE_INTERVAL', 3600); // seconds
- define_default('MAX_CHILD_RUNTIME', 1800); // seconds
- define_default('MAX_JOBS', 2);
- define_default('SPAWN_INTERVAL', DAEMON_SLEEP_INTERVAL); // seconds
+ if (!defined('PURGE_INTERVAL')) define('PURGE_INTERVAL', 3600); // seconds
+ if (!defined('MAX_CHILD_RUNTIME')) define('MAX_CHILD_RUNTIME', 1800); // seconds
+ if (!defined('MAX_JOBS')) define('MAX_JOBS', 2);
+ if (!defined('SPAWN_INTERVAL')) define('SPAWN_INTERVAL', DAEMON_SLEEP_INTERVAL); // seconds
require_once "sanity_check.php";
require_once "db-prefs.php";
diff --git a/utils/phpstan_tunables.php b/utils/phpstan_tunables.php
deleted file mode 100644
index e192bcdba..000000000
--- a/utils/phpstan_tunables.php
+++ /dev/null
@@ -1,46 +0,0 @@
-
Date: Mon, 22 Feb 2021 17:38:46 +0300
Subject: dirname(__FILE__) -> __DIR__
---
api/index.php | 6 +++---
backend.php | 2 +-
classes/pluginhost.php | 4 ++--
errors.php | 2 +-
include/errorhandler.php | 4 ++--
include/functions.php | 2 +-
index.php | 2 +-
plugins/note/init.php | 2 +-
plugins/nsfw/init.php | 2 +-
prefs.php | 2 +-
public.php | 2 +-
update.php | 4 ++--
update_daemon2.php | 4 ++--
13 files changed, 19 insertions(+), 19 deletions(-)
diff --git a/api/index.php b/api/index.php
index 1b713d561..6b0071141 100644
--- a/api/index.php
+++ b/api/index.php
@@ -3,9 +3,9 @@
require_once "../config.php";
- set_include_path(dirname(__FILE__) . PATH_SEPARATOR .
- dirname(dirname(__FILE__)) . PATH_SEPARATOR .
- dirname(dirname(__FILE__)) . "/include" . PATH_SEPARATOR .
+ set_include_path(__DIR__ . PATH_SEPARATOR .
+ dirname(__DIR__) . PATH_SEPARATOR .
+ dirname(__DIR__) . "/include" . PATH_SEPARATOR .
get_include_path());
chdir("..");
diff --git a/backend.php b/backend.php
index e64c6561f..b6b3e0030 100644
--- a/backend.php
+++ b/backend.php
@@ -1,5 +1,5 @@
Date: Mon, 22 Feb 2021 18:03:36 +0000
Subject: Check whether data is parsable by 'imagecreatefromstring' in jimIcon.
---
lib/jimIcon.php | 17 ++++++++++++-----
1 file changed, 12 insertions(+), 5 deletions(-)
diff --git a/lib/jimIcon.php b/lib/jimIcon.php
index f8e533f90..eaa768272 100644
--- a/lib/jimIcon.php
+++ b/lib/jimIcon.php
@@ -104,11 +104,11 @@ class jimIcon {
}
// See if we can parse it (might be PNG format here)
- $i = @imagecreatefromstring($data);
-
- if ($i) {
- imagesavealpha($i, true);
- return $i;
+ if (self::has_parsable_image_type($data)) {
+ if ($i = @imagecreatefromstring($data)) {
+ imagesavealpha($i, true);
+ return $i;
+ }
}
// Must be a BMP. Parse it ourselves.
@@ -267,5 +267,12 @@ class jimIcon {
}
return $img;
}
+
+ // Checks whether the data is a type parsable by imagecreatefromstring()
+ private function has_parsable_image_type($image_data) {
+ $size = getimagesizefromstring($image_data);
+ return $size && in_array($size[2],
+ [IMAGETYPE_JPEG, IMAGETYPE_PNG, IMAGETYPE_GIF, IMAGETYPE_BMP, IMAGETYPE_WBMP, IMAGETYPE_WEBP]);
+ }
}
?>
--
cgit v1.2.3-54-g00ecf
From e4107ac9520ca404d4ab49ef79ca74430e8fd772 Mon Sep 17 00:00:00 2001
From: Andrew Dolgov
Date: Mon, 22 Feb 2021 21:47:48 +0300
Subject: wip: initial for config object
---
backend.php | 2 +-
classes/api.php | 9 ++++---
classes/article.php | 6 ++---
classes/db.php | 12 ++++-----
classes/digest.php | 12 ++++-----
classes/diskcache.php | 6 ++---
classes/feeditem/common.php | 2 +-
classes/feeds.php | 36 +++++++++++++--------------
classes/handler/public.php | 18 +++++++-------
classes/opml.php | 2 +-
classes/pref/feeds.php | 18 +++++++-------
classes/pref/prefs.php | 16 ++++++------
classes/rpc.php | 12 ++++-----
classes/rssutils.php | 40 +++++++++++++++---------------
classes/userhelper.php | 6 ++---
include/autoload.php | 2 --
include/functions.php | 24 +++++++++---------
include/login_form.php | 6 ++---
include/sanity_check.php | 54 ++++++++++++++---------------------------
include/sanity_config.php | 3 ---
include/sessions.php | 7 +++---
index.php | 2 ++
phpstan.neon | 2 +-
plugins/af_psql_trgm/init.php | 4 +--
plugins/af_redditimgur/init.php | 2 +-
plugins/auth_internal/init.php | 2 +-
plugins/bookmarklets/init.php | 4 +--
update.php | 28 ++++++++++-----------
update_daemon2.php | 10 ++++----
utils/regen_config_checks.sh | 17 -------------
30 files changed, 165 insertions(+), 199 deletions(-)
delete mode 100644 include/sanity_config.php
delete mode 100755 utils/regen_config_checks.sh
diff --git a/backend.php b/backend.php
index b6b3e0030..2237c06b3 100644
--- a/backend.php
+++ b/backend.php
@@ -40,7 +40,7 @@
header("Content-Type: text/json; charset=utf-8");
- if (SINGLE_USER_MODE) {
+ if (Config::get(Config::SINGLE_USER_MODE)) {
UserHelper::authenticate( "admin", null);
}
diff --git a/classes/api.php b/classes/api.php
index 5677cb908..6f3ee77db 100755
--- a/classes/api.php
+++ b/classes/api.php
@@ -57,7 +57,7 @@ class API extends Handler {
$password = clean($_REQUEST["password"]);
$password_base64 = base64_decode(clean($_REQUEST["password"]));
- if (SINGLE_USER_MODE) $login = "admin";
+ if (Config::get(Config::SINGLE_USER_MODE)) $login = "admin";
if ($uid = UserHelper::find_user_by_login($login)) {
if (get_pref("ENABLE_API_ACCESS", $uid)) {
@@ -361,9 +361,10 @@ class API extends Handler {
}
function getConfig() {
- $config = array(
- "icons_dir" => ICONS_DIR,
- "icons_url" => ICONS_URL);
+ $config = [
+ "icons_dir" => Config::get(Config::ICONS_DIR),
+ "icons_url" => Config::get(Config::ICONS_URL)
+ ];
$config["daemon_is_running"] = file_is_locked("update_daemon.lock");
diff --git a/classes/article.php b/classes/article.php
index acd83694c..a2a38118b 100755
--- a/classes/article.php
+++ b/classes/article.php
@@ -85,7 +85,7 @@ class Article extends Handler_Protected {
content = ?, content_hash = ? WHERE id = ?");
$sth->execute([$content, $content_hash, $ref_id]);
- if (DB_TYPE == "pgsql"){
+ if (Config::get(Config::DB_TYPE) == "pgsql") {
$sth = $pdo->prepare("UPDATE ttrss_entries
SET tsvector_combined = to_tsvector( :ts_content)
WHERE id = :id");
@@ -130,7 +130,7 @@ class Article extends Handler_Protected {
if ($row = $sth->fetch()) {
$ref_id = $row["id"];
- if (DB_TYPE == "pgsql"){
+ if (Config::get(Config::DB_TYPE) == "pgsql"){
$sth = $pdo->prepare("UPDATE ttrss_entries
SET tsvector_combined = to_tsvector( :ts_content)
WHERE id = :id");
@@ -475,7 +475,7 @@ class Article extends Handler_Protected {
// purge orphaned posts in main content table
- if (DB_TYPE == "mysql")
+ if (Config::get(Config::DB_TYPE) == "mysql")
$limit_qpart = "LIMIT 5000";
else
$limit_qpart = "";
diff --git a/classes/db.php b/classes/db.php
index 490cecd57..1ccaa3533 100755
--- a/classes/db.php
+++ b/classes/db.php
@@ -21,9 +21,9 @@ class Db
$db_host = defined('DB_HOST') && DB_HOST ? ';host=' . DB_HOST : '';
try {
- $pdo = new PDO(DB_TYPE . ':dbname=' . DB_NAME . $db_host . $db_port,
- DB_USER,
- DB_PASS);
+ $pdo = new PDO(Config::get(Config::DB_TYPE) . ':dbname=' . Config::get(Config::DB_NAME) . $db_host . $db_port,
+ Config::get(Config::DB_USER),
+ Config::get(Config::DB_PASS));
} catch (Exception $e) {
print "Exception while creating PDO object:" . $e->getMessage() . " ";
exit(101);
@@ -31,14 +31,14 @@ class Db
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
- if (DB_TYPE == "pgsql") {
+ if (Config::get(Config::DB_TYPE) == "pgsql") {
$pdo->query("set client_encoding = 'UTF-8'");
$pdo->query("set datestyle = 'ISO, european'");
$pdo->query("set TIME ZONE 0");
$pdo->query("set cpu_tuple_cost = 0.5");
- } else if (DB_TYPE == "mysql") {
+ } else if (Config::get(Config::DB_TYPE) == "mysql") {
$pdo->query("SET time_zone = '+0:0'");
if (defined('MYSQL_CHARSET') && MYSQL_CHARSET) {
@@ -68,7 +68,7 @@ class Db
}
public static function sql_random_function() {
- if (DB_TYPE == "mysql") {
+ if (Config::get(Config::DB_TYPE) == "mysql") {
return "RAND()";
} else {
return "RANDOM()";
diff --git a/classes/digest.php b/classes/digest.php
index e0c23d705..9ac3f6a17 100644
--- a/classes/digest.php
+++ b/classes/digest.php
@@ -8,9 +8,9 @@ class Digest
Debug::log("Sending digests, batch of max $user_limit users, headline limit = $limit");
- if (DB_TYPE == "pgsql") {
+ if (Config::get(Config::DB_TYPE) == "pgsql") {
$interval_qpart = "last_digest_sent < NOW() - INTERVAL '1 days'";
- } else /* if (DB_TYPE == "mysql") */ {
+ } else /* if (Config::get(Config::DB_TYPE) == "mysql") */ {
$interval_qpart = "last_digest_sent < DATE_SUB(NOW(), INTERVAL 1 DAY)";
}
@@ -91,19 +91,19 @@ class Digest
$tpl->setVariable('CUR_DATE', date('Y/m/d', $local_ts));
$tpl->setVariable('CUR_TIME', date('G:i', $local_ts));
- $tpl->setVariable('TTRSS_HOST', SELF_URL_PATH);
+ $tpl->setVariable('TTRSS_HOST', Config::get(Config.Config::get(Config::SELF_URL_PATH)));
$tpl_t->setVariable('CUR_DATE', date('Y/m/d', $local_ts));
$tpl_t->setVariable('CUR_TIME', date('G:i', $local_ts));
- $tpl_t->setVariable('TTRSS_HOST', SELF_URL_PATH);
+ $tpl_t->setVariable('TTRSS_HOST', Config::get(Config.Config::get(Config::SELF_URL_PATH)));
$affected_ids = array();
$days = (int) $days;
- if (DB_TYPE == "pgsql") {
+ if (Config::get(Config::DB_TYPE) == "pgsql") {
$interval_qpart = "ttrss_entries.date_updated > NOW() - INTERVAL '$days days'";
- } else /* if (DB_TYPE == "mysql") */ {
+ } else /* if (Config::get(Config::DB_TYPE) == "mysql") */ {
$interval_qpart = "ttrss_entries.date_updated > DATE_SUB(NOW(), INTERVAL $days DAY)";
}
diff --git a/classes/diskcache.php b/classes/diskcache.php
index 94f645f32..063a3847c 100644
--- a/classes/diskcache.php
+++ b/classes/diskcache.php
@@ -191,7 +191,7 @@ class DiskCache {
];
public function __construct($dir) {
- $this->dir = CACHE_DIR . "/" . basename(clean($dir));
+ $this->dir = Config::get(Config::CACHE_DIR) . "/" . basename(clean($dir));
}
public function get_dir() {
@@ -339,7 +339,7 @@ class DiskCache {
}
static function expire() {
- $dirs = array_filter(glob(CACHE_DIR . "/*"), "is_dir");
+ $dirs = array_filter(glob(Config::get(Config::CACHE_DIR) . "/*"), "is_dir");
foreach ($dirs as $cache_dir) {
$num_deleted = 0;
@@ -396,7 +396,7 @@ class DiskCache {
$tmppluginhost = new PluginHost();
- $tmppluginhost->load(PLUGINS, PluginHost::KIND_SYSTEM);
+ $tmppluginhost->load(Config::get(Config::PLUGINS), PluginHost::KIND_SYSTEM);
//$tmppluginhost->load_data();
if ($tmppluginhost->run_hooks_until(PluginHost::HOOK_SEND_LOCAL_FILE, true, $filename))
diff --git a/classes/feeditem/common.php b/classes/feeditem/common.php
index f387e0779..8f2b9188b 100755
--- a/classes/feeditem/common.php
+++ b/classes/feeditem/common.php
@@ -179,7 +179,7 @@ abstract class FeedItem_Common extends FeedItem {
$cat = preg_replace('/[,\'\"]/', "", $cat);
- if (DB_TYPE == "mysql") {
+ if (Config::get(Config::DB_TYPE) == "mysql") {
$cat = preg_replace('/[\x{10000}-\x{10FFFF}]/u', "\xEF\xBF\xBD", $cat);
}
diff --git a/classes/feeds.php b/classes/feeds.php
index b59504c03..274cb22d0 100755
--- a/classes/feeds.php
+++ b/classes/feeds.php
@@ -186,7 +186,7 @@ class Feeds extends Handler_Protected {
$id = $line["id"];
// frontend doesn't expect pdo returning booleans as strings on mysql
- if (DB_TYPE == "mysql") {
+ if (Config::get(Config::DB_TYPE) == "mysql") {
foreach (["unread", "marked", "published"] as $k) {
$line[$k] = $line[$k] === "1";
}
@@ -576,7 +576,7 @@ class Feeds extends Handler_Protected {
function search() {
print json_encode([
- "show_language" => DB_TYPE == "pgsql",
+ "show_language" => Config::get(Config::DB_TYPE) == "pgsql",
"show_syntax_help" => count(PluginHost::getInstance()->get_hooks(PluginHost::HOOK_SEARCH)) == 0,
"all_languages" => Pref_Feeds::get_ts_languages(),
"default_language" => get_pref('DEFAULT_SEARCH_LANGUAGE')
@@ -716,21 +716,21 @@ class Feeds extends Handler_Protected {
switch ($mode) {
case "1day":
- if (DB_TYPE == "pgsql") {
+ if (Config::get(Config::DB_TYPE) == "pgsql") {
$date_qpart = "date_entered < NOW() - INTERVAL '1 day' ";
} else {
$date_qpart = "date_entered < DATE_SUB(NOW(), INTERVAL 1 DAY) ";
}
break;
case "1week":
- if (DB_TYPE == "pgsql") {
+ if (Config::get(Config::DB_TYPE) == "pgsql") {
$date_qpart = "date_entered < NOW() - INTERVAL '1 week' ";
} else {
$date_qpart = "date_entered < DATE_SUB(NOW(), INTERVAL 1 WEEK) ";
}
break;
case "2week":
- if (DB_TYPE == "pgsql") {
+ if (Config::get(Config::DB_TYPE) == "pgsql") {
$date_qpart = "date_entered < NOW() - INTERVAL '2 week' ";
} else {
$date_qpart = "date_entered < DATE_SUB(NOW(), INTERVAL 2 WEEK) ";
@@ -807,7 +807,7 @@ class Feeds extends Handler_Protected {
$intl = (int) get_pref("FRESH_ARTICLE_MAX_AGE");
- if (DB_TYPE == "pgsql") {
+ if (Config::get(Config::DB_TYPE) == "pgsql") {
$match_part = "date_entered > NOW() - INTERVAL '$intl hour' ";
} else {
$match_part = "date_entered > DATE_SUB(NOW(),
@@ -900,7 +900,7 @@ class Feeds extends Handler_Protected {
$intl = (int) get_pref("FRESH_ARTICLE_MAX_AGE", $owner_uid);
- if (DB_TYPE == "pgsql") {
+ if (Config::get(Config::DB_TYPE) == "pgsql") {
$match_part .= " AND date_entered > NOW() - INTERVAL '$intl hour' ";
} else {
$match_part .= " AND date_entered > DATE_SUB(NOW(), INTERVAL $intl HOUR) ";
@@ -1332,7 +1332,7 @@ class Feeds extends Handler_Protected {
list($search_query_part, $search_words) = self::_search_to_sql($search, $search_language, $owner_uid);
}
- if (DB_TYPE == "pgsql") {
+ if (Config::get(Config::DB_TYPE) == "pgsql") {
$test_sth = $pdo->prepare("select $search_query_part
FROM ttrss_entries, ttrss_user_entries WHERE id = ref_id limit 1");
@@ -1469,7 +1469,7 @@ class Feeds extends Handler_Protected {
} else if ($feed == -6) { // recently read
$query_strategy_part = "unread = false AND last_read IS NOT NULL";
- if (DB_TYPE == "pgsql") {
+ if (Config::get(Config::DB_TYPE) == "pgsql") {
$query_strategy_part .= " AND last_read > NOW() - INTERVAL '1 DAY' ";
} else {
$query_strategy_part .= " AND last_read > DATE_SUB(NOW(), INTERVAL 1 DAY) ";
@@ -1486,7 +1486,7 @@ class Feeds extends Handler_Protected {
$intl = (int) get_pref("FRESH_ARTICLE_MAX_AGE", $owner_uid);
- if (DB_TYPE == "pgsql") {
+ if (Config::get(Config::DB_TYPE) == "pgsql") {
$query_strategy_part .= " AND date_entered > NOW() - INTERVAL '$intl hour' ";
} else {
$query_strategy_part .= " AND date_entered > DATE_SUB(NOW(), INTERVAL $intl HOUR) ";
@@ -1605,7 +1605,7 @@ class Feeds extends Handler_Protected {
if ($feed == -3)
$first_id_query_strategy_part = "true";
- if (DB_TYPE == "pgsql") {
+ if (Config::get(Config::DB_TYPE) == "pgsql") {
$sanity_interval_qpart = "date_entered >= NOW() - INTERVAL '1 hour' AND";
$yyiw_qpart = "to_char(date_entered, 'IYYY-IW') AS yyiw";
@@ -1705,7 +1705,7 @@ class Feeds extends Handler_Protected {
} else {
// browsing by tag
- if (DB_TYPE == "pgsql") {
+ if (Config::get(Config::DB_TYPE) == "pgsql") {
$distinct_columns = str_replace("desc", "", strtolower($order_by));
$distinct_qpart = "DISTINCT ON (id, $distinct_columns)";
} else {
@@ -1948,10 +1948,10 @@ class Feeds extends Handler_Protected {
if ($row = $sth->fetch()) {
$owner_uid = $row["owner_uid"];
- if (FORCE_ARTICLE_PURGE != 0) {
- Debug::log("purge_feed: FORCE_ARTICLE_PURGE is set, overriding interval to " . FORCE_ARTICLE_PURGE, Debug::$LOG_VERBOSE);
+ if (Config::get(Config::FORCE_ARTICLE_PURGE) != 0) {
+ Debug::log("purge_feed: FORCE_ARTICLE_PURGE is set, overriding interval to " . Config::get(Config::FORCE_ARTICLE_PURGE), Debug::$LOG_VERBOSE);
$purge_unread = true;
- $purge_interval = FORCE_ARTICLE_PURGE;
+ $purge_interval = Config::get(Config::FORCE_ARTICLE_PURGE);
} else {
$purge_unread = get_pref("PURGE_UNREAD_ARTICLES", $owner_uid, false);
}
@@ -1970,7 +1970,7 @@ class Feeds extends Handler_Protected {
else
$query_limit = "";
- if (DB_TYPE == "pgsql") {
+ if (Config::get(Config::DB_TYPE) == "pgsql") {
$sth = $pdo->prepare("DELETE FROM ttrss_user_entries
USING ttrss_entries
WHERE ttrss_entries.id = ref_id AND
@@ -2153,7 +2153,7 @@ class Feeds extends Handler_Protected {
array_push($query_keywords, "(".SUBSTRING_FOR_DATE."(updated,1,LENGTH('$k')) $not = '$k')");
} else {
- if (DB_TYPE == "pgsql") {
+ if (Config::get(Config::DB_TYPE) == "pgsql") {
$k = mb_strtolower($k);
array_push($search_query_leftover, $not ? "!$k" : $k);
} else {
@@ -2168,7 +2168,7 @@ class Feeds extends Handler_Protected {
if (count($search_query_leftover) > 0) {
- if (DB_TYPE == "pgsql") {
+ if (Config::get(Config::DB_TYPE) == "pgsql") {
// if there's no joiners consider this a "simple" search and
// concatenate everything with &, otherwise don't try to mess with tsquery syntax
diff --git a/classes/handler/public.php b/classes/handler/public.php
index 3910cf7c1..79dff37b5 100755
--- a/classes/handler/public.php
+++ b/classes/handler/public.php
@@ -43,7 +43,7 @@ class Handler_Public extends Handler {
$user_plugins = get_pref("_ENABLED_PLUGINS", $owner_uid);
$tmppluginhost = new PluginHost();
- $tmppluginhost->load(PLUGINS, PluginHost::KIND_ALL);
+ $tmppluginhost->load(Config::get(Config::PLUGINS), PluginHost::KIND_ALL);
$tmppluginhost->load((string)$user_plugins, PluginHost::KIND_USER, $owner_uid);
//$tmppluginhost->load_data();
@@ -309,7 +309,7 @@ class Handler_Public extends Handler {
$format = clean($_REQUEST['format'] ?? "atom");
$orig_guid = clean($_REQUEST["orig_guid"] ?? false);
- if (SINGLE_USER_MODE) {
+ if (Config::get(Config::SINGLE_USER_MODE)) {
UserHelper::authenticate("admin", null);
}
@@ -347,7 +347,7 @@ class Handler_Public extends Handler {
}
function login() {
- if (!SINGLE_USER_MODE) {
+ if (!Config::get(Config::SINGLE_USER_MODE)) {
$login = clean($_POST["login"]);
$password = clean($_POST["password"]);
@@ -355,7 +355,7 @@ class Handler_Public extends Handler {
$safe_mode = checkbox_to_sql_bool(clean($_POST["safe_mode"] ?? false));
if ($remember_me) {
- @session_set_cookie_params(SESSION_COOKIE_LIFETIME);
+ @session_set_cookie_params(Config::get(Config::SESSION_COOKIE_LIFETIME));
} else {
@session_set_cookie_params(0);
}
@@ -398,7 +398,7 @@ class Handler_Public extends Handler {
$return = clean($_REQUEST['return']);
- if ($_REQUEST['return'] && mb_strpos($return, SELF_URL_PATH) === 0) {
+ if ($_REQUEST['return'] && mb_strpos($return, Config::get(Config::SELF_URL_PATH)) === 0) {
header("Location: " . clean($_REQUEST['return']));
} else {
header("Location: " . get_self_url_prefix());
@@ -559,7 +559,7 @@ class Handler_Public extends Handler {
$tpl->setVariable('LOGIN', $login);
$tpl->setVariable('RESETPASS_LINK', $resetpass_link);
- $tpl->setVariable('TTRSS_HOST', SELF_URL_PATH);
+ $tpl->setVariable('TTRSS_HOST', Config::get(Config::SELF_URL_PATH));
$tpl->addBlock('message');
@@ -613,7 +613,7 @@ class Handler_Public extends Handler {
function dbupdate() {
startup_gettext();
- if (!SINGLE_USER_MODE && $_SESSION["access_level"] < 10) {
+ if (!Config::get(Config::SINGLE_USER_MODE) && $_SESSION["access_level"] < 10) {
$_SESSION["login_error_msg"] = __("Your access level is insufficient to run this script.");
$this->_render_login_form();
exit;
@@ -660,7 +660,7 @@ class Handler_Public extends Handler {
is_update_required()) {
@@ -709,7 +709,7 @@ class Handler_Public extends Handler {
print "".T_sprintf("Tiny Tiny RSS database needs update to the latest version (%d to %d).",
$updater->get_schema_version(), SCHEMA_VERSION)." ";
- if (DB_TYPE == "mysql") {
+ if (Config::get(Config::DB_TYPE) == "mysql") {
print_error("READ THIS: Due to MySQL limitations, your database is not completely protected while updating. ".
"Errors may put it in an inconsistent state requiring manual rollback. BACKUP YOUR DATABASE BEFORE CONTINUING. ");
} else {
diff --git a/classes/opml.php b/classes/opml.php
index 04d287125..cbc1269e3 100644
--- a/classes/opml.php
+++ b/classes/opml.php
@@ -594,7 +594,7 @@ class OPML extends Handler_Protected {
}
if (is_uploaded_file($_FILES['opml_file']['tmp_name'])) {
- $tmp_file = (string)tempnam(CACHE_DIR . '/upload', 'opml');
+ $tmp_file = (string)tempnam(Config::get(Config::CACHE_DIR) . '/upload', 'opml');
$result = move_uploaded_file($_FILES['opml_file']['tmp_name'],
$tmp_file);
diff --git a/classes/pref/feeds.php b/classes/pref/feeds.php
index e583a5f51..229effeb3 100755
--- a/classes/pref/feeds.php
+++ b/classes/pref/feeds.php
@@ -9,7 +9,7 @@ class Pref_Feeds extends Handler_Protected {
public static function get_ts_languages() {
$rv = [];
- if (DB_TYPE == "pgsql") {
+ if (Config::get(Config::DB_TYPE) == "pgsql") {
$dbh = Db::pdo();
$res = $dbh->query("SELECT cfgname FROM pg_ts_config");
@@ -453,7 +453,7 @@ class Pref_Feeds extends Handler_Protected {
header("Content-type: text/html");
if (is_uploaded_file($_FILES['icon_file']['tmp_name'])) {
- $tmp_file = tempnam(CACHE_DIR . '/upload', 'icon');
+ $tmp_file = tempnam(Config::get(Config::CACHE_DIR) . '/upload', 'icon');
if (!$tmp_file)
return;
@@ -529,7 +529,7 @@ class Pref_Feeds extends Handler_Protected {
$local_update_intervals = $update_intervals;
$local_update_intervals[0] .= sprintf(" (%s)", $update_intervals[get_pref("DEFAULT_UPDATE_INTERVAL")]);
- if (FORCE_ARTICLE_PURGE == 0) {
+ if (Config::get(Config::FORCE_ARTICLE_PURGE) == 0) {
$local_purge_intervals = $purge_intervals;
$default_purge_interval = get_pref("PURGE_OLD_DAYS");
@@ -539,7 +539,7 @@ class Pref_Feeds extends Handler_Protected {
$local_purge_intervals[0] .= " " . sprintf("(%s)", __("Disabled"));
} else {
- $purge_interval = FORCE_ARTICLE_PURGE;
+ $purge_interval = Config::get(Config::FORCE_ARTICLE_PURGE);
$local_purge_intervals = [ T_nsprintf('%d day', '%d days', $purge_interval, $purge_interval) ];
}
@@ -550,13 +550,13 @@ class Pref_Feeds extends Handler_Protected {
"select" => \Controls\select_feeds_cats("cat_id", $row["cat_id"]),
],
"plugin_data" => $plugin_data,
- "force_purge" => (int)FORCE_ARTICLE_PURGE,
+ "force_purge" => (int)Config::get(Config::FORCE_ARTICLE_PURGE),
"intervals" => [
"update" => $local_update_intervals,
"purge" => $local_purge_intervals,
],
"lang" => [
- "enabled" => DB_TYPE == "pgsql",
+ "enabled" => Config::get(Config::DB_TYPE) == "pgsql",
"default" => get_pref('DEFAULT_SEARCH_LANGUAGE'),
"all" => $this::get_ts_languages(),
]
@@ -614,7 +614,7 @@ class Pref_Feeds extends Handler_Protected {
-
+
= __('Language:') ?>
= \Controls\select_tag("feed_language", "", $this::get_ts_languages(), ["disabled"=> 1]) ?>
@@ -632,7 +632,7 @@ class Pref_Feeds extends Handler_Protected {
= $this->_batch_toggle_checkbox("update_interval") ?>
-
+
= __('Article purging:') ?>
= \Controls\select_hash("purge_interval", "", $local_purge_intervals, ["disabled" => 1]) ?>
@@ -1147,7 +1147,7 @@ class Pref_Feeds extends Handler_Protected {
function inactiveFeeds() {
- if (DB_TYPE == "pgsql") {
+ if (Config::get(Config::DB_TYPE) == "pgsql") {
$interval_qpart = "NOW() - INTERVAL '3 months'";
} else {
$interval_qpart = "DATE_SUB(NOW(), INTERVAL 3 MONTH)";
diff --git a/classes/pref/prefs.php b/classes/pref/prefs.php
index adb249dac..1ca5b28be 100644
--- a/classes/pref/prefs.php
+++ b/classes/pref/prefs.php
@@ -236,7 +236,7 @@ class Pref_Prefs extends Handler_Protected {
$tpl->setVariable('LOGIN', $row["login"]);
$tpl->setVariable('NEWMAIL', $email);
- $tpl->setVariable('TTRSS_HOST', SELF_URL_PATH);
+ $tpl->setVariable('TTRSS_HOST', Config::get(Config::SELF_URL_PATH));
$tpl->addBlock('message');
@@ -625,7 +625,7 @@ class Pref_Prefs extends Handler_Protected {
continue;
}
- if ($pref_name == "DEFAULT_SEARCH_LANGUAGE" && DB_TYPE != "pgsql") {
+ if ($pref_name == "DEFAULT_SEARCH_LANGUAGE" && Config::get(Config::DB_TYPE) != "pgsql") {
continue;
}
@@ -705,7 +705,7 @@ class Pref_Prefs extends Handler_Protected {
array_push($listed_boolean_prefs, $pref_name);
- if ($pref_name == "PURGE_UNREAD_ARTICLES" && FORCE_ARTICLE_PURGE != 0) {
+ if ($pref_name == "PURGE_UNREAD_ARTICLES" && Config::get(Config::FORCE_ARTICLE_PURGE) != 0) {
$is_disabled = true;
$is_checked = true;
} else {
@@ -719,9 +719,9 @@ class Pref_Prefs extends Handler_Protected {
} else if (in_array($pref_name, ['FRESH_ARTICLE_MAX_AGE',
'PURGE_OLD_DAYS', 'LONG_DATE_FORMAT', 'SHORT_DATE_FORMAT'])) {
- if ($pref_name == "PURGE_OLD_DAYS" && FORCE_ARTICLE_PURGE != 0) {
+ if ($pref_name == "PURGE_OLD_DAYS" && Config::get(Config::FORCE_ARTICLE_PURGE) != 0) {
$attributes = ["disabled" => true, "required" => true];
- $value = FORCE_ARTICLE_PURGE;
+ $value = Config::get(Config::FORCE_ARTICLE_PURGE);
} else {
$attributes = ["required" => true];
}
@@ -829,7 +829,7 @@ class Pref_Prefs extends Handler_Protected {
private function index_plugins_system() {
print_notice("System plugins are enabled in config.php for all users.");
- $system_enabled = array_map("trim", explode(",", (string)PLUGINS));
+ $system_enabled = array_map("trim", explode(",", (string)Config::get(Config::PLUGINS)));
$tmppluginhost = new PluginHost();
$tmppluginhost->load_all($tmppluginhost::KIND_ALL, $_SESSION["uid"], true);
@@ -862,7 +862,7 @@ class Pref_Prefs extends Handler_Protected {
}
private function index_plugins_user() {
- $system_enabled = array_map("trim", explode(",", (string)PLUGINS));
+ $system_enabled = array_map("trim", explode(",", (string)Config::get(Config::PLUGINS)));
$user_enabled = array_map("trim", explode(",", get_pref("_ENABLED_PLUGINS")));
$tmppluginhost = new PluginHost();
@@ -1135,7 +1135,7 @@ class Pref_Prefs extends Handler_Protected {
$tpl->readTemplateFromFile("otp_disabled_template.txt");
$tpl->setVariable('LOGIN', $row["login"]);
- $tpl->setVariable('TTRSS_HOST', SELF_URL_PATH);
+ $tpl->setVariable('TTRSS_HOST', Config::get(Config::SELF_URL_PATH));
$tpl->addBlock('message');
diff --git a/classes/rpc.php b/classes/rpc.php
index 95fd0f5ae..bf24132b0 100755
--- a/classes/rpc.php
+++ b/classes/rpc.php
@@ -174,7 +174,7 @@ class RPC extends Handler_Protected {
static function updaterandomfeed_real() {
// Test if the feed need a update (update interval exceded).
- if (DB_TYPE == "pgsql") {
+ if (Config::get(Config::DB_TYPE) == "pgsql") {
$update_limit_qpart = "AND ((
ttrss_feeds.update_interval = 0
AND ttrss_feeds.last_updated < NOW() - CAST((ttrss_user_prefs.value || ' minutes') AS INTERVAL)
@@ -199,7 +199,7 @@ class RPC extends Handler_Protected {
}
// Test if feed is currently being updated by another process.
- if (DB_TYPE == "pgsql") {
+ if (Config::get(Config::DB_TYPE) == "pgsql") {
$updstart_thresh_qpart = "AND (ttrss_feeds.last_update_started IS NULL OR ttrss_feeds.last_update_started < NOW() - INTERVAL '5 minutes')";
} else {
$updstart_thresh_qpart = "AND (ttrss_feeds.last_update_started IS NULL OR ttrss_feeds.last_update_started < DATE_SUB(NOW(), INTERVAL 5 MINUTE))";
@@ -361,7 +361,7 @@ class RPC extends Handler_Protected {
$params["safe_mode"] = !empty($_SESSION["safe_mode"]);
$params["check_for_updates"] = CHECK_FOR_UPDATES;
$params["icons_url"] = ICONS_URL;
- $params["cookie_lifetime"] = SESSION_COOKIE_LIFETIME;
+ $params["cookie_lifetime"] = Config::get(Config::SESSION_COOKIE_LIFETIME);
$params["default_view_mode"] = get_pref("_DEFAULT_VIEW_MODE");
$params["default_view_limit"] = (int) get_pref("_DEFAULT_VIEW_LIMIT");
$params["default_view_order_by"] = get_pref("_DEFAULT_VIEW_ORDER_BY");
@@ -433,7 +433,7 @@ class RPC extends Handler_Protected {
$data["labels"] = Labels::get_all($_SESSION["uid"]);
if (LOG_DESTINATION == 'sql' && $_SESSION['access_level'] >= 10) {
- if (DB_TYPE == 'pgsql') {
+ if (Config::get(Config::DB_TYPE) == 'pgsql') {
$log_interval = "created_at > NOW() - interval '1 hour'";
} else {
$log_interval = "created_at > DATE_SUB(NOW(), INTERVAL 1 HOUR)";
@@ -452,13 +452,13 @@ class RPC extends Handler_Protected {
}
}
- if (file_exists(LOCK_DIRECTORY . "/update_daemon.lock")) {
+ if (file_exists(Config::get(Config::LOCK_DIRECTORY) . "/update_daemon.lock")) {
$data['daemon_is_running'] = (int) file_is_locked("update_daemon.lock");
if (time() - ($_SESSION["daemon_stamp_check"] ?? 0) > 30) {
- $stamp = (int) @file_get_contents(LOCK_DIRECTORY . "/update_daemon.stamp");
+ $stamp = (int) @file_get_contents(Config::get(Config::LOCK_DIRECTORY) . "/update_daemon.stamp");
if ($stamp) {
$stamp_delta = time() - $stamp;
diff --git a/classes/rssutils.php b/classes/rssutils.php
index 30d08328f..c951003f0 100755
--- a/classes/rssutils.php
+++ b/classes/rssutils.php
@@ -61,8 +61,8 @@ class RSSUtils {
$pdo = Db::pdo();
- if (!SINGLE_USER_MODE && DAEMON_UPDATE_LOGIN_LIMIT > 0) {
- if (DB_TYPE == "pgsql") {
+ if (!Config::get(Config::SINGLE_USER_MODE) && DAEMON_UPDATE_LOGIN_LIMIT > 0) {
+ if (Config::get(Config::DB_TYPE) == "pgsql") {
$login_thresh_qpart = "AND ttrss_users.last_login >= NOW() - INTERVAL '".DAEMON_UPDATE_LOGIN_LIMIT." days'";
} else {
$login_thresh_qpart = "AND ttrss_users.last_login >= DATE_SUB(NOW(), INTERVAL ".DAEMON_UPDATE_LOGIN_LIMIT." DAY)";
@@ -71,7 +71,7 @@ class RSSUtils {
$login_thresh_qpart = "";
}
- if (DB_TYPE == "pgsql") {
+ if (Config::get(Config::DB_TYPE) == "pgsql") {
$update_limit_qpart = "AND ((
ttrss_feeds.update_interval = 0
AND ttrss_user_prefs.value != '-1'
@@ -96,7 +96,7 @@ class RSSUtils {
}
// Test if feed is currently being updated by another process.
- if (DB_TYPE == "pgsql") {
+ if (Config::get(Config::DB_TYPE) == "pgsql") {
$updstart_thresh_qpart = "AND (last_update_started IS NULL OR last_update_started < NOW() - INTERVAL '10 minutes')";
} else {
$updstart_thresh_qpart = "AND (last_update_started IS NULL OR last_update_started < DATE_SUB(NOW(), INTERVAL 10 MINUTE))";
@@ -106,7 +106,7 @@ class RSSUtils {
// Update the least recently updated feeds first
$query_order = "ORDER BY last_updated";
- if (DB_TYPE == "pgsql") $query_order .= " NULLS FIRST";
+ if (Config::get(Config::DB_TYPE) == "pgsql") $query_order .= " NULLS FIRST";
$query = "SELECT DISTINCT ttrss_feeds.feed_url, ttrss_feeds.last_updated
FROM
@@ -182,7 +182,7 @@ class RSSUtils {
if (self::function_enabled('passthru')) {
$exit_code = 0;
- passthru(PHP_EXECUTABLE . " update.php --update-feed " . $tline["id"] . " --pidlock feed-" . $tline["id"] . " $quiet $log $log_level", $exit_code);
+ passthru(Config::get(Config::PHP_EXECUTABLE) . " update.php --update-feed " . $tline["id"] . " --pidlock feed-" . $tline["id"] . " $quiet $log $log_level", $exit_code);
Debug::log(sprintf("<= %.4f (sec) exit code: %d", microtime(true) - $fstarted, $exit_code));
@@ -275,7 +275,7 @@ class RSSUtils {
$pluginhost = new PluginHost();
$user_plugins = get_pref("_ENABLED_PLUGINS", $owner_uid);
- $pluginhost->load(PLUGINS, PluginHost::KIND_ALL);
+ $pluginhost->load(Config::get(Config::PLUGINS), PluginHost::KIND_ALL);
$pluginhost->load((string)$user_plugins, PluginHost::KIND_USER, $owner_uid);
//$pluginhost->load_data();
@@ -395,12 +395,12 @@ class RSSUtils {
$date_feed_processed = date('Y-m-d H:i');
- $cache_filename = CACHE_DIR . "/feeds/" . sha1($fetch_url) . ".xml";
+ $cache_filename = Config::get(Config::CACHE_DIR) . "/feeds/" . sha1($fetch_url) . ".xml";
$pluginhost = new PluginHost();
$user_plugins = get_pref("_ENABLED_PLUGINS", $owner_uid);
- $pluginhost->load(PLUGINS, PluginHost::KIND_ALL);
+ $pluginhost->load(Config::get(Config::PLUGINS), PluginHost::KIND_ALL);
$pluginhost->load((string)$user_plugins, PluginHost::KIND_USER, $owner_uid);
//$pluginhost->load_data();
@@ -488,7 +488,7 @@ class RSSUtils {
}
// cache vanilla feed data for re-use
- if ($feed_data && !$auth_pass && !$auth_login && is_writable(CACHE_DIR . "/feeds")) {
+ if ($feed_data && !$auth_pass && !$auth_login && is_writable(Config::get(Config::CACHE_DIR) . "/feeds")) {
$new_rss_hash = sha1($feed_data);
if ($new_rss_hash != $rss_hash) {
@@ -561,7 +561,7 @@ class RSSUtils {
Debug::log("language: $feed_language", Debug::$LOG_VERBOSE);
Debug::log("processing feed data...", Debug::$LOG_VERBOSE);
- if (DB_TYPE == "pgsql") {
+ if (Config::get(Config::DB_TYPE) == "pgsql") {
$favicon_interval_qpart = "favicon_last_checked < NOW() - INTERVAL '12 hour'";
} else {
$favicon_interval_qpart = "favicon_last_checked < DATE_SUB(NOW(), INTERVAL 12 HOUR)";
@@ -755,7 +755,7 @@ class RSSUtils {
$e->type, $e->length, $e->title, $e->width, $e->height);
// Yet another episode of "mysql utf8_general_ci is gimped"
- if (DB_TYPE == "mysql" && MYSQL_CHARSET != "UTF8MB4") {
+ if (Config::get(Config::DB_TYPE) == "mysql" && MYSQL_CHARSET != "UTF8MB4") {
for ($i = 0; $i < count($e_item); $i++) {
if (is_string($e_item[$i])) {
$e_item[$i] = self::strip_utf8mb4($e_item[$i]);
@@ -833,7 +833,7 @@ class RSSUtils {
Debug::log("plugin data: $entry_plugin_data", Debug::$LOG_VERBOSE);
// Workaround: 4-byte unicode requires utf8mb4 in MySQL. See https://tt-rss.org/forum/viewtopic.php?f=1&t=3377&p=20077#p20077
- if (DB_TYPE == "mysql" && MYSQL_CHARSET != "UTF8MB4") {
+ if (Config::get(Config::DB_TYPE) == "mysql" && MYSQL_CHARSET != "UTF8MB4") {
foreach ($article as $k => $v) {
// i guess we'll have to take the risk of 4byte unicode labels & tags here
if (is_string($article[$k])) {
@@ -1079,7 +1079,7 @@ class RSSUtils {
Debug::log("resulting RID: $entry_ref_id, IID: $entry_int_id", Debug::$LOG_VERBOSE);
- if (DB_TYPE == "pgsql")
+ if (Config::get(Config::DB_TYPE) == "pgsql")
$tsvector_qpart = "tsvector_combined = to_tsvector(:ts_lang, :ts_content),";
else
$tsvector_qpart = "";
@@ -1107,7 +1107,7 @@ class RSSUtils {
":lang" => $entry_language,
":id" => $ref_id];
- if (DB_TYPE == "pgsql") {
+ if (Config::get(Config::DB_TYPE) == "pgsql") {
$params[":ts_lang"] = $feed_language;
$params[":ts_content"] = mb_substr(strip_tags($entry_title . " " . $entry_content), 0, 900000);
}
@@ -1375,7 +1375,7 @@ class RSSUtils {
$pdo = Db::pdo();
- if (DB_TYPE == "pgsql") {
+ if (Config::get(Config::DB_TYPE) == "pgsql") {
$pdo->query("DELETE FROM ttrss_error_log
WHERE created_at < NOW() - INTERVAL '7 days'");
} else {
@@ -1396,8 +1396,8 @@ class RSSUtils {
$num_deleted = 0;
- if (is_writable(LOCK_DIRECTORY)) {
- $files = glob(LOCK_DIRECTORY . "/*.lock");
+ if (is_writable(Config::get(Config::LOCK_DIRECTORY))) {
+ $files = glob(Config::get(Config::LOCK_DIRECTORY) . "/*.lock");
if ($files) {
foreach ($files as $file) {
@@ -1589,9 +1589,9 @@ class RSSUtils {
$days = DAEMON_UNSUCCESSFUL_DAYS_LIMIT;
- if (DB_TYPE == "pgsql") {
+ if (Config::get(Config::DB_TYPE) == "pgsql") {
$interval_query = "last_successful_update < NOW() - INTERVAL '$days days' AND last_updated > NOW() - INTERVAL '1 days'";
- } else /* if (DB_TYPE == "mysql") */ {
+ } else /* if (Config::get(Config::DB_TYPE) == "mysql") */ {
$interval_query = "last_successful_update < DATE_SUB(NOW(), INTERVAL $days DAY) AND last_updated > DATE_SUB(NOW(), INTERVAL 1 DAY)";
}
diff --git a/classes/userhelper.php b/classes/userhelper.php
index 7fe1e5557..82a2fe05f 100644
--- a/classes/userhelper.php
+++ b/classes/userhelper.php
@@ -2,7 +2,7 @@
class UserHelper {
static function authenticate(string $login = null, string $password = null, bool $check_only = false, string $service = null) {
- if (!SINGLE_USER_MODE) {
+ if (!Config::get(Config::SINGLE_USER_MODE)) {
$user_id = false;
$auth_module = false;
@@ -88,7 +88,7 @@ class UserHelper {
static function login_sequence() {
$pdo = Db::pdo();
- if (SINGLE_USER_MODE) {
+ if (Config::get(Config::SINGLE_USER_MODE)) {
@session_start();
self::authenticate("admin", null);
startup_gettext();
@@ -98,7 +98,7 @@ class UserHelper {
if (empty($_SESSION["uid"])) {
- if (AUTH_AUTO_LOGIN && self::authenticate(null, null)) {
+ if (Config::get(Config::AUTH_AUTO_LOGIN) && self::authenticate(null, null)) {
$_SESSION["ref_schema_version"] = get_schema_version(true);
} else {
self::authenticate(null, null, true);
diff --git a/include/autoload.php b/include/autoload.php
index c02923dba..19e00b9ea 100644
--- a/include/autoload.php
+++ b/include/autoload.php
@@ -1,6 +1,4 @@
load(PLUGINS, PluginHost::KIND_ALL);
+ PluginHost::getInstance()->load(Config::get(Config::PLUGINS), PluginHost::KIND_ALL);
return true;
}
diff --git a/include/login_form.php b/include/login_form.php
index 211302a87..537c7f994 100755
--- a/include/login_form.php
+++ b/include/login_form.php
@@ -79,7 +79,7 @@
},
bwLimitChange: function(elem) {
Cookie.set("ttrss_bwlimit", elem.checked,
- );
+ );
}
};
@@ -122,7 +122,7 @@
onblur="UtilityApp.fetchProfiles()"
value="= $_SESSION["fake_password"] ?? "" ?>"/>
-
+
= __("I forgot my password") ?>
@@ -161,7 +161,7 @@
= __("Uses default theme and prevents all plugins from loading."); ?>
- 0) { ?>
+ 0) { ?>
diff --git a/include/sanity_check.php b/include/sanity_check.php
index 2786f012f..5efd23d98 100755
--- a/include/sanity_check.php
+++ b/include/sanity_check.php
@@ -21,7 +21,7 @@
$sth = $pdo->prepare("SELECT engine, table_name FROM information_schema.tables WHERE
table_schema = ? AND table_name LIKE 'ttrss_%' AND engine != 'InnoDB'");
- $sth->execute([DB_NAME]);
+ $sth->execute([Config::get(Config::DB_NAME)]);
$bad_tables = [];
@@ -44,8 +44,8 @@
array_push($errors, "Please copy config.php-dist to config.php");
}
- if (strpos(PLUGINS, "auth_") === false) {
- array_push($errors, "Please enable at least one authentication module via PLUGINS constant in config.php");
+ if (strpos(Config::get(Config::PLUGINS), "auth_") === false) {
+ array_push($errors, "Please enable at least one authentication module via Config::get(Config::PLUGINS) constant in config.php");
}
if (function_exists('posix_getuid') && posix_getuid() == 0) {
@@ -60,43 +60,25 @@
array_push($errors, "PHP UConverter class is missing, it's provided by the Internationalization (intl) module.");
}
- if (CONFIG_VERSION != EXPECTED_CONFIG_VERSION) {
- array_push($errors, "Configuration file (config.php) has incorrect version. Update it with new options from config.php-dist and set CONFIG_VERSION to the correct value.");
+ if (!is_writable(Config::get(Config::CACHE_DIR) . "/images")) {
+ array_push($errors, "Image cache is not writable (chmod -R 777 ".Config::get(Config::CACHE_DIR)."/images)");
}
- if (!is_writable(CACHE_DIR . "/images")) {
- array_push($errors, "Image cache is not writable (chmod -R 777 ".CACHE_DIR."/images)");
+ if (!is_writable(Config::get(Config::CACHE_DIR) . "/upload")) {
+ array_push($errors, "Upload cache is not writable (chmod -R 777 ".Config::get(Config::CACHE_DIR)."/upload)");
}
- if (!is_writable(CACHE_DIR . "/upload")) {
- array_push($errors, "Upload cache is not writable (chmod -R 777 ".CACHE_DIR."/upload)");
+ if (!is_writable(Config::get(Config::CACHE_DIR) . "/export")) {
+ array_push($errors, "Data export cache is not writable (chmod -R 777 ".Config::get(Config::CACHE_DIR)."/export)");
}
- if (!is_writable(CACHE_DIR . "/export")) {
- array_push($errors, "Data export cache is not writable (chmod -R 777 ".CACHE_DIR."/export)");
- }
-
- require_once "sanity_config.php";
-
- if (GENERATED_CONFIG_CHECK != EXPECTED_CONFIG_VERSION) {
- array_push($errors,
- "Configuration option checker sanity_config.php is outdated, please recreate it using ./utils/regen_config_checks.sh");
- }
-
- foreach (get_required_defines() as $d) {
- if (!defined($d)) {
- array_push($errors,
- "Required configuration file parameter $d is not defined in config.php. You might need to copy it from config.php-dist.");
- }
- }
-
- if (SINGLE_USER_MODE && class_exists("PDO")) {
+ if (Config::get(Config::SINGLE_USER_MODE) && class_exists("PDO")) {
$pdo = Db::pdo();
$res = $pdo->query("SELECT id FROM ttrss_users WHERE id = 1");
if (!$res->fetch()) {
- array_push($errors, "SINGLE_USER_MODE is enabled in config.php but default admin account is not found.");
+ array_push($errors, "Config::get(Config::SINGLE_USER_MODE) is enabled in config.php but default admin account is not found.");
}
}
@@ -107,17 +89,17 @@
$ref_self_url_path = preg_replace("/\w+\.php$/", "", $ref_self_url_path);
}
- if (SELF_URL_PATH == "http://example.org/tt-rss/") {
+ if (Config::get(Config::SELF_URL_PATH) == "http://example.org/tt-rss/") {
$hint = $ref_self_url_path ? "(possible value: $ref_self_url_path )" : "";
array_push($errors,
- "Please set SELF_URL_PATH to the correct value for your server: $hint");
+ "Please set Config::get(Config::SELF_URL_PATH) to the correct value for your server: $hint");
}
if ($ref_self_url_path &&
(!defined('_SKIP_SELF_URL_PATH_CHECKS') || !_SKIP_SELF_URL_PATH_CHECKS) &&
- SELF_URL_PATH != $ref_self_url_path && SELF_URL_PATH != mb_substr($ref_self_url_path, 0, mb_strlen($ref_self_url_path)-1)) {
+ Config::get(Config::SELF_URL_PATH) != $ref_self_url_path && Config::get(Config::SELF_URL_PATH) != mb_substr($ref_self_url_path, 0, mb_strlen($ref_self_url_path)-1)) {
array_push($errors,
- "Please set SELF_URL_PATH to the correct value detected for your server: $ref_self_url_path (you're using: " . SELF_URL_PATH . " )");
+ "Please set Config::get(Config::SELF_URL_PATH) to the correct value detected for your server: $ref_self_url_path (you're using: " . Config::get(Config::SELF_URL_PATH) . " )");
}
}
@@ -125,8 +107,8 @@
array_push($errors, "ICONS_DIR defined in config.php is not writable (chmod -R 777 ".ICONS_DIR.").\n");
}
- if (!is_writable(LOCK_DIRECTORY)) {
- array_push($errors, "LOCK_DIRECTORY defined in config.php is not writable (chmod -R 777 ".LOCK_DIRECTORY.").\n");
+ if (!is_writable(Config::get(Config::LOCK_DIRECTORY))) {
+ array_push($errors, "Config::get(Config::LOCK_DIRECTORY) defined in config.php is not writable (chmod -R 777 ".Config::get(Config::LOCK_DIRECTORY).").\n");
}
if (!function_exists("curl_init") && !ini_get("allow_url_fopen")) {
@@ -161,7 +143,7 @@
array_push($errors, "PHP support for DOMDocument is required, but was not found.");
}
- if (DB_TYPE == "mysql") {
+ if (Config::get(Config::DB_TYPE) == "mysql") {
$bad_tables = check_mysql_tables();
if (count($bad_tables) > 0) {
diff --git a/include/sanity_config.php b/include/sanity_config.php
deleted file mode 100644
index b304adf54..000000000
--- a/include/sanity_config.php
+++ /dev/null
@@ -1,3 +0,0 @@
-Fatal Error: You forgot to copy
config.php-dist to config.php and edit it.\n";
@@ -16,6 +17,7 @@
get_include_path());
require_once "autoload.php";
+
require_once "sessions.php";
require_once "functions.php";
require_once "sanity_check.php";
diff --git a/phpstan.neon b/phpstan.neon
index b2cd978d8..ba425e3d9 100644
--- a/phpstan.neon
+++ b/phpstan.neon
@@ -1,7 +1,7 @@
parameters:
level: 5
ignoreErrors:
- - '#Constant.*not found#'
+# - '#Constant.*not found#'
- '#Comparison operation ">" between int<1, max> and 0 is always true.#'
- '#Access to an undefined property DOMNode::\$tagName.#'
- '#Call to an undefined method DOMNode::(get|remove|set)Attribute\(\).#'
diff --git a/plugins/af_psql_trgm/init.php b/plugins/af_psql_trgm/init.php
index 3b7ed6b14..5611d8998 100644
--- a/plugins/af_psql_trgm/init.php
+++ b/plugins/af_psql_trgm/init.php
@@ -134,7 +134,7 @@ class Af_Psql_Trgm extends Plugin {
title="extension = __('Mark similar articles as read (af_psql_trgm)') ?>">
pdo->query("select 'similarity'::regproc");
@@ -258,7 +258,7 @@ class Af_Psql_Trgm extends Plugin {
function hook_article_filter($article) {
- if (DB_TYPE != "pgsql") return $article;
+ if (Config::get(Config::DB_TYPE) != "pgsql") return $article;
$res = $this->pdo->query("select 'similarity'::regproc");
if (!$res || !$res->fetch()) return $article;
diff --git a/plugins/af_redditimgur/init.php b/plugins/af_redditimgur/init.php
index 713eaea5c..9cd046ba4 100755
--- a/plugins/af_redditimgur/init.php
+++ b/plugins/af_redditimgur/init.php
@@ -530,7 +530,7 @@ class Af_RedditImgur extends Plugin {
$entry_guid = $article["guid_hashed"];
$owner_uid = $article["owner_uid"];
- if (DB_TYPE == "pgsql") {
+ if (Config::get(Config::DB_TYPE) == "pgsql") {
$interval_qpart = "date_entered < NOW() - INTERVAL '1 day'";
} else {
$interval_qpart = "date_entered < DATE_SUB(NOW(), INTERVAL 1 DAY)";
diff --git a/plugins/auth_internal/init.php b/plugins/auth_internal/init.php
index 6a68534ea..13a7bc969 100644
--- a/plugins/auth_internal/init.php
+++ b/plugins/auth_internal/init.php
@@ -244,7 +244,7 @@ class Auth_Internal extends Auth_Base {
$tpl->readTemplateFromFile("password_change_template.txt");
$tpl->setVariable('LOGIN', $row["login"]);
- $tpl->setVariable('TTRSS_HOST', SELF_URL_PATH);
+ $tpl->setVariable('TTRSS_HOST', Config::get(Config::SELF_URL_PATH));
$tpl->addBlock('message');
diff --git a/plugins/bookmarklets/init.php b/plugins/bookmarklets/init.php
index caa8b39df..967918823 100644
--- a/plugins/bookmarklets/init.php
+++ b/plugins/bookmarklets/init.php
@@ -21,7 +21,7 @@ class Bookmarklets extends Plugin {
}
function subscribe() {
- if (SINGLE_USER_MODE) {
+ if (Config::get(Config::SINGLE_USER_MODE)) {
UserHelper::login_sequence();
}
@@ -172,7 +172,7 @@ class Bookmarklets extends Plugin {
}
function sharepopup() {
- if (SINGLE_USER_MODE) {
+ if (Config::get(Config::SINGLE_USER_MODE)) {
UserHelper::login_sequence();
}
diff --git a/update.php b/update.php
index ab6272c83..4aff4a774 100755
--- a/update.php
+++ b/update.php
@@ -14,7 +14,7 @@
require_once "db-prefs.php";
function make_stampfile($filename) {
- $fp = fopen(LOCK_DIRECTORY . "/$filename", "w");
+ $fp = fopen(Config::get(Config::LOCK_DIRECTORY) . "/$filename", "w");
if (flock($fp, LOCK_EX | LOCK_NB)) {
fwrite($fp, time() . "\n");
@@ -30,9 +30,9 @@
$days = (int) $days;
- if (DB_TYPE == "pgsql") {
+ if (Config::get(Config::DB_TYPE) == "pgsql") {
$interval_query = "date_updated < NOW() - INTERVAL '$days days'";
- } else /*if (DB_TYPE == "mysql") */ {
+ } else /*if (Config::get(Config::DB_TYPE) == "mysql") */ {
$interval_query = "date_updated < DATE_SUB(NOW(), INTERVAL $days DAY)";
}
@@ -224,7 +224,7 @@
$log = isset($options['log']) ? '--log '.$options['log'] : '';
$log_level = isset($options['log-level']) ? '--log-level '.$options['log-level'] : '';
- passthru(PHP_EXECUTABLE . " " . $argv[0] ." --daemon-loop $quiet $log $log_level");
+ passthru(Config::get(Config::PHP_EXECUTABLE) . " " . $argv[0] ." --daemon-loop $quiet $log $log_level");
// let's enforce a minimum spawn interval as to not forkbomb the host
$spawn_interval = max(60, DAEMON_SLEEP_INTERVAL);
@@ -277,7 +277,7 @@
Debug::log("clearing existing indexes...");
- if (DB_TYPE == "pgsql") {
+ if (Config::get(Config::DB_TYPE) == "pgsql") {
$sth = $pdo->query( "SELECT relname FROM
pg_catalog.pg_class WHERE relname LIKE 'ttrss_%'
AND relname NOT LIKE '%_pkey'
@@ -288,7 +288,7 @@
}
while ($line = $sth->fetch()) {
- if (DB_TYPE == "pgsql") {
+ if (Config::get(Config::DB_TYPE) == "pgsql") {
$statement = "DROP INDEX " . $line["relname"];
Debug::log($statement);
} else {
@@ -299,9 +299,9 @@
$pdo->query($statement);
}
- Debug::log("reading indexes from schema for: " . DB_TYPE);
+ Debug::log("reading indexes from schema for: " . Config::get(Config::DB_TYPE));
- $fp = fopen("schema/ttrss_schema_" . DB_TYPE . ".sql", "r");
+ $fp = fopen("schema/ttrss_schema_" . Config::get(Config::DB_TYPE) . ".sql", "r");
if ($fp) {
while ($line = fgets($fp)) {
$matches = array();
@@ -375,14 +375,14 @@
}
if (isset($options["update-schema"])) {
- Debug::log("Checking for updates (" . DB_TYPE . ")...");
+ Debug::log("Checking for updates (" . Config::get(Config::DB_TYPE) . ")...");
- $updater = new DbUpdater(Db::pdo(), DB_TYPE, SCHEMA_VERSION);
+ $updater = new DbUpdater(Db::pdo(), Config::get(Config::DB_TYPE), SCHEMA_VERSION);
if ($updater->is_update_required()) {
Debug::log("Schema update required, version " . $updater->get_schema_version() . " to " . SCHEMA_VERSION);
- if (DB_TYPE == "mysql")
+ if (Config::get(Config::DB_TYPE) == "mysql")
Debug::Log("READ THIS: Due to MySQL limitations, your database is not completely protected while updating.\n".
"Errors may put it in an inconsistent state requiring manual rollback.\nBACKUP YOUR DATABASE BEFORE CONTINUING.");
else
@@ -460,7 +460,7 @@
if (isset($options["list-plugins"])) {
$tmppluginhost = new PluginHost();
$tmppluginhost->load_all($tmppluginhost::KIND_ALL);
- $enabled = array_map("trim", explode(",", PLUGINS));
+ $enabled = array_map("trim", explode(",", Config::get(Config::PLUGINS)));
echo "List of all available plugins:\n";
@@ -515,8 +515,8 @@
PluginHost::getInstance()->run_commands($options);
- if (file_exists(LOCK_DIRECTORY . "/$lock_filename"))
+ if (file_exists(Config::get(Config::LOCK_DIRECTORY) . "/$lock_filename"))
if (strtoupper(substr(PHP_OS, 0, 3)) == 'WIN')
fclose($lock_handle);
- unlink(LOCK_DIRECTORY . "/$lock_filename");
+ unlink(Config::get(Config::LOCK_DIRECTORY) . "/$lock_filename");
?>
diff --git a/update_daemon2.php b/update_daemon2.php
index 5d4d3759c..b67fba37d 100755
--- a/update_daemon2.php
+++ b/update_daemon2.php
@@ -98,9 +98,9 @@
function shutdown($caller_pid) {
if ($caller_pid == posix_getpid()) {
- if (file_exists(LOCK_DIRECTORY . "/update_daemon.lock")) {
+ if (file_exists(Config::get(Config::LOCK_DIRECTORY) . "/update_daemon.lock")) {
Debug::log("Removing lockfile (master)...");
- unlink(LOCK_DIRECTORY . "/update_daemon.lock");
+ unlink(Config::get(Config::LOCK_DIRECTORY) . "/update_daemon.lock");
}
}
}
@@ -108,9 +108,9 @@
function task_shutdown() {
$pid = posix_getpid();
- if (file_exists(LOCK_DIRECTORY . "/update_daemon-$pid.lock")) {
+ if (file_exists(Config::get(Config::LOCK_DIRECTORY) . "/update_daemon-$pid.lock")) {
Debug::log("Removing task lockfile for PID $pid...");
- unlink(LOCK_DIRECTORY . "/update_daemon-$pid.lock");
+ unlink(Config::get(Config::LOCK_DIRECTORY) . "/update_daemon-$pid.lock");
}
}
@@ -249,7 +249,7 @@
$my_pid = posix_getpid();
- passthru(PHP_EXECUTABLE . " update.php --daemon-loop $quiet $log --task $j --pidlock $my_pid");
+ passthru(Config::get(Config::PHP_EXECUTABLE) . " update.php --daemon-loop $quiet $log --task $j --pidlock $my_pid");
sleep(1);
diff --git a/utils/regen_config_checks.sh b/utils/regen_config_checks.sh
deleted file mode 100755
index b20ce0480..000000000
--- a/utils/regen_config_checks.sh
+++ /dev/null
@@ -1,17 +0,0 @@
-#!/bin/sh
-
-DESTINATION="include/sanity_config.php"
-
-echo " $DESTINATION
-
-echo -n "define('GENERATED_CONFIG_CHECK', " >> $DESTINATION
-grep CONFIG_VERSION config.php-dist | awk -F ' |\)' '{ print $2 }' | xargs echo -n >> $DESTINATION
-echo ");" >> $DESTINATION
-
-echo -n "function get_required_defines() { return [ " >> $DESTINATION
-
-grep define\( config.php-dist | awk -F\' '{ print "*" $2 "*," }' | grep -v DB_PORT | xargs echo -n | sed -e s/,$// -e s/*/\'/g >> $DESTINATION
-
-echo "]; }" >> $DESTINATION
-
-
--
cgit v1.2.3-54-g00ecf
From 383f4ca04af8c7a1ff4f8be5a488f6799e0e0d37 Mon Sep 17 00:00:00 2001
From: Andrew Dolgov
Date: Mon, 22 Feb 2021 21:49:09 +0300
Subject: add config.php
---
.gitignore | 2 +-
classes/config.php | 98 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 99 insertions(+), 1 deletion(-)
create mode 100644 classes/config.php
diff --git a/.gitignore b/.gitignore
index eaf169cb8..9a3d01c23 100644
--- a/.gitignore
+++ b/.gitignore
@@ -11,7 +11,7 @@ Thumbs.db
.idea/*
plugins.local/*
themes.local/*
-config.php
+/config.php
feed-icons/*
cache/*/*
lock/*
diff --git a/classes/config.php b/classes/config.php
new file mode 100644
index 000000000..8a7470135
--- /dev/null
+++ b/classes/config.php
@@ -0,0 +1,98 @@
+ "pgsql",
+ Config::DB_HOST => "db",
+ Config::DB_USER => "",
+ Config::DB_NAME => "",
+ Config::DB_PASS => "",
+ Config::DB_PORT => "5432",
+ Config::MYSQL_CHARSET => "UTF8",
+ Config::SELF_URL_PATH => "",
+ Config::SINGLE_USER_MODE => "",
+ Config::SIMPLE_UPDATE_MODE => "",
+ Config::PHP_EXECUTABLE => "/usr/bin/php",
+ Config::LOCK_DIRECTORY => "lock",
+ Config::CACHE_DIR => "cache",
+ Config::ICONS_DIR => "feed-icons",
+ Config::ICONS_URL => "feed-icons",
+ Config::AUTH_AUTO_CREATE => "true",
+ Config::AUTH_AUTO_LOGIN => "true",
+ Config::FORCE_ARTICLE_PURGE => 0,
+ Config::ENABLE_REGISTRATION => "",
+ Config::SESSION_COOKIE_LIFETIME => 86400,
+ Config::SMTP_FROM_NAME => "Tiny Tiny RSS",
+ Config::SMTP_FROM_ADDRESS => "noreply@localhost",
+ Config::DIGEST_SUBJECT => "[tt-rss] New headlines for last 24 hours",
+ Config::CHECK_FOR_UPDATES => "true",
+ Config::PLUGINS => "auth_internal",
+ Config::LOG_DESTINATION => "sql",
+ ];
+
+ private const _ENVVAR_PREFIX = "TTRSS_";
+ private static $instance;
+
+ private $params = [];
+
+ public static function get_instance() {
+ if (self::$instance == null)
+ self::$instance = new self();
+
+ return self::$instance;
+ }
+
+ function __construct() {
+ $ref = new ReflectionClass(get_class($this));
+
+ foreach ($ref->getConstants() as $const => $cvalue) {
+ if (strpos($const, "_") !== 0) {
+ $override = getenv($this::_ENVVAR_PREFIX . $const);
+
+ if (!empty($override)) {
+ $this->params[$cvalue] = $override;
+ } else {
+ $this->params[$cvalue] = $this::_DEFAULTS[$const];
+ }
+ }
+ }
+ }
+
+ private function _get($param) {
+ return $this->params[$param];
+ }
+
+ static function get($param) {
+ $instance = self::get_instance();
+
+ return $instance->_get($param);
+ }
+
+}
\ No newline at end of file
--
cgit v1.2.3-54-g00ecf
From 211f699aa0c4211e4ee8a02446d51b9811d0c28c Mon Sep 17 00:00:00 2001
From: Andrew Dolgov
Date: Mon, 22 Feb 2021 22:35:27 +0300
Subject: migrate the rest into Config::
---
classes/config.php | 192 ++++++++++++++++++++--------------
classes/db.php | 4 +-
classes/digest.php | 8 +-
classes/diskcache.php | 2 +-
classes/feeds.php | 6 +-
classes/logger.php | 2 +-
classes/mailer.php | 6 +-
classes/pref/feeds.php | 8 +-
classes/pref/system.php | 4 +-
classes/pref/users.php | 2 +-
classes/rpc.php | 18 ++--
classes/rssutils.php | 36 ++++---
classes/urlhelper.php | 10 +-
config.php-dist | 2 +-
include/functions.php | 50 +--------
include/login_form.php | 4 +-
include/sanity_check.php | 4 +-
index.php | 5 +-
phpstan.neon | 1 +
plugins/af_proxy_http/init.php | 2 +-
plugins/cache_starred_images/init.php | 2 +-
prefs.php | 4 +-
update.php | 6 +-
update_daemon2.php | 17 +--
24 files changed, 187 insertions(+), 208 deletions(-)
diff --git a/classes/config.php b/classes/config.php
index 8a7470135..349706390 100644
--- a/classes/config.php
+++ b/classes/config.php
@@ -1,98 +1,134 @@
"pgsql",
- Config::DB_HOST => "db",
- Config::DB_USER => "",
- Config::DB_NAME => "",
- Config::DB_PASS => "",
- Config::DB_PORT => "5432",
- Config::MYSQL_CHARSET => "UTF8",
- Config::SELF_URL_PATH => "",
- Config::SINGLE_USER_MODE => "",
- Config::SIMPLE_UPDATE_MODE => "",
- Config::PHP_EXECUTABLE => "/usr/bin/php",
- Config::LOCK_DIRECTORY => "lock",
- Config::CACHE_DIR => "cache",
- Config::ICONS_DIR => "feed-icons",
- Config::ICONS_URL => "feed-icons",
- Config::AUTH_AUTO_CREATE => "true",
- Config::AUTH_AUTO_LOGIN => "true",
- Config::FORCE_ARTICLE_PURGE => 0,
- Config::ENABLE_REGISTRATION => "",
- Config::SESSION_COOKIE_LIFETIME => 86400,
- Config::SMTP_FROM_NAME => "Tiny Tiny RSS",
- Config::SMTP_FROM_ADDRESS => "noreply@localhost",
- Config::DIGEST_SUBJECT => "[tt-rss] New headlines for last 24 hours",
- Config::CHECK_FOR_UPDATES => "true",
- Config::PLUGINS => "auth_internal",
- Config::LOG_DESTINATION => "sql",
- ];
+ const DB_TYPE = "DB_TYPE";
+ const DB_HOST = "DB_HOST";
+ const DB_USER = "DB_USER";
+ const DB_NAME = "DB_NAME";
+ const DB_PASS = "DB_PASS";
+ const DB_PORT = "DB_PORT";
+ const MYSQL_CHARSET = "MYSQL_CHARSET";
+ const SELF_URL_PATH = "SELF_URL_PATH";
+ const SINGLE_USER_MODE = "SINGLE_USER_MODE";
+ const SIMPLE_UPDATE_MODE = "SIMPLE_UPDATE_MODE";
+ const PHP_EXECUTABLE = "PHP_EXECUTABLE";
+ const LOCK_DIRECTORY = "LOCK_DIRECTORY";
+ const CACHE_DIR = "CACHE_DIR";
+ const ICONS_DIR = "ICONS_DIR";
+ const ICONS_URL = "ICONS_URL";
+ const AUTH_AUTO_CREATE = "AUTH_AUTO_CREATE";
+ const AUTH_AUTO_LOGIN = "AUTH_AUTO_LOGIN";
+ const FORCE_ARTICLE_PURGE = "FORCE_ARTICLE_PURGE";
+ const ENABLE_REGISTRATION = "ENABLE_REGISTRATION";
+ const SESSION_COOKIE_LIFETIME = "SESSION_COOKIE_LIFETIME";
+ const SMTP_FROM_NAME = "SMTP_FROM_NAME";
+ const SMTP_FROM_ADDRESS = "SMTP_FROM_ADDRESS";
+ const DIGEST_SUBJECT = "DIGEST_SUBJECT";
+ const CHECK_FOR_UPDATES = "CHECK_FOR_UPDATES";
+ const PLUGINS = "PLUGINS";
+ const LOG_DESTINATION = "LOG_DESTINATION";
+ const LOCAL_OVERRIDE_STYLESHEET = "LOCAL_OVERRIDE_STYLESHEET";
+ const DAEMON_MAX_CHILD_RUNTIME = "DAEMON_MAX_CHILD_RUNTIME";
+ const DAEMON_MAX_JOBS = "DAEMON_MAX_JOBS";
+ const FEED_FETCH_TIMEOUT = "FEED_FETCH_TIMEOUT";
+ const FEED_FETCH_NO_CACHE_TIMEOUT = "FEED_FETCH_NO_CACHE_TIMEOUT";
+ const FILE_FETCH_TIMEOUT = "FILE_FETCH_TIMEOUT";
+ const FILE_FETCH_CONNECT_TIMEOUT = "FILE_FETCH_CONNECT_TIMEOUT";
+ const DAEMON_UPDATE_LOGIN_LIMIT = "DAEMON_UPDATE_LOGIN_LIMIT";
+ const DAEMON_FEED_LIMIT = "DAEMON_FEED_LIMIT";
+ const DAEMON_SLEEP_INTERVAL = "DAEMON_SLEEP_INTERVAL";
+ const MAX_CACHE_FILE_SIZE = "MAX_CACHE_FILE_SIZE";
+ const MAX_DOWNLOAD_FILE_SIZE = "MAX_DOWNLOAD_FILE_SIZE";
+ const MAX_FAVICON_FILE_SIZE = "MAX_FAVICON_FILE_SIZE";
+ const CACHE_MAX_DAYS = "CACHE_MAX_DAYS";
+ const MAX_CONDITIONAL_INTERVAL = "MAX_CONDITIONAL_INTERVAL";
+ const DAEMON_UNSUCCESSFUL_DAYS_LIMIT = "DAEMON_UNSUCCESSFUL_DAYS_LIMIT";
+ const LOG_SENT_MAIL = "LOG_SENT_MAIL";
- private const _ENVVAR_PREFIX = "TTRSS_";
- private static $instance;
+ private const _DEFAULTS = [
+ Config::DB_TYPE => "pgsql",
+ Config::DB_HOST => "db",
+ Config::DB_USER => "",
+ Config::DB_NAME => "",
+ Config::DB_PASS => "",
+ Config::DB_PORT => "5432",
+ Config::MYSQL_CHARSET => "UTF8",
+ Config::SELF_URL_PATH => "",
+ Config::SINGLE_USER_MODE => "",
+ Config::SIMPLE_UPDATE_MODE => "",
+ Config::PHP_EXECUTABLE => "/usr/bin/php",
+ Config::LOCK_DIRECTORY => "lock",
+ Config::CACHE_DIR => "cache",
+ Config::ICONS_DIR => "feed-icons",
+ Config::ICONS_URL => "feed-icons",
+ Config::AUTH_AUTO_CREATE => "true",
+ Config::AUTH_AUTO_LOGIN => "true",
+ Config::FORCE_ARTICLE_PURGE => 0,
+ Config::ENABLE_REGISTRATION => "",
+ Config::SESSION_COOKIE_LIFETIME => 86400,
+ Config::SMTP_FROM_NAME => "Tiny Tiny RSS",
+ Config::SMTP_FROM_ADDRESS => "noreply@localhost",
+ Config::DIGEST_SUBJECT => "[tt-rss] New headlines for last 24 hours",
+ Config::CHECK_FOR_UPDATES => "true",
+ Config::PLUGINS => "auth_internal",
+ Config::LOG_DESTINATION => "sql",
+ Config::LOCAL_OVERRIDE_STYLESHEET => "local-overrides.css",
+ Config::DAEMON_MAX_CHILD_RUNTIME => 1800,
+ Config::DAEMON_MAX_JOBS => 2,
+ Config::FEED_FETCH_TIMEOUT => 45,
+ Config::FEED_FETCH_NO_CACHE_TIMEOUT => 15,
+ Config::FILE_FETCH_TIMEOUT => 45,
+ Config::FILE_FETCH_CONNECT_TIMEOUT => 15,
+ Config::DAEMON_UPDATE_LOGIN_LIMIT => 30,
+ Config::DAEMON_FEED_LIMIT => 500,
+ Config::DAEMON_SLEEP_INTERVAL => 120,
+ Config::MAX_CACHE_FILE_SIZE => 64*1024*1024,
+ Config::MAX_DOWNLOAD_FILE_SIZE => 16*1024*1024,
+ Config::MAX_FAVICON_FILE_SIZE => 1*1024*1024,
+ Config::CACHE_MAX_DAYS => 7,
+ Config::MAX_CONDITIONAL_INTERVAL => 3600*12,
+ Config::DAEMON_UNSUCCESSFUL_DAYS_LIMIT => 30,
+ Config::LOG_SENT_MAIL => "",
+ ];
- private $params = [];
+ private static $instance;
- public static function get_instance() {
+ private $params = [];
+
+ public static function get_instance() {
if (self::$instance == null)
self::$instance = new self();
return self::$instance;
}
- function __construct() {
- $ref = new ReflectionClass(get_class($this));
+ function __construct() {
+ $ref = new ReflectionClass(get_class($this));
- foreach ($ref->getConstants() as $const => $cvalue) {
- if (strpos($const, "_") !== 0) {
- $override = getenv($this::_ENVVAR_PREFIX . $const);
+ foreach ($ref->getConstants() as $const => $cvalue) {
+ if (strpos($const, "_") !== 0) {
+ $override = getenv($this::_ENVVAR_PREFIX . $const);
- if (!empty($override)) {
- $this->params[$cvalue] = $override;
- } else {
- $this->params[$cvalue] = $this::_DEFAULTS[$const];
- }
- }
- }
- }
+ if (!empty($override)) {
+ $this->params[$cvalue] = $override;
+ } else {
+ $this->params[$cvalue] = $this::_DEFAULTS[$const];
+ }
+ }
+ }
+ }
- private function _get($param) {
- return $this->params[$param];
- }
+ private function _get($param) {
+ return $this->params[$param];
+ }
- static function get($param) {
- $instance = self::get_instance();
+ static function get($param) {
+ $instance = self::get_instance();
- return $instance->_get($param);
- }
+ return $instance->_get($param);
+ }
}
\ No newline at end of file
diff --git a/classes/db.php b/classes/db.php
index 1ccaa3533..5196e7c7d 100755
--- a/classes/db.php
+++ b/classes/db.php
@@ -41,8 +41,8 @@ class Db
} else if (Config::get(Config::DB_TYPE) == "mysql") {
$pdo->query("SET time_zone = '+0:0'");
- if (defined('MYSQL_CHARSET') && MYSQL_CHARSET) {
- $pdo->query("SET NAMES " . MYSQL_CHARSET);
+ if (defined('Config::get(Config::MYSQL_CHARSET)') && Config::get(Config::MYSQL_CHARSET)) {
+ $pdo->query("SET NAMES " . Config::get(Config::MYSQL_CHARSET));
}
}
diff --git a/classes/digest.php b/classes/digest.php
index 9ac3f6a17..a6a0c47de 100644
--- a/classes/digest.php
+++ b/classes/digest.php
@@ -48,11 +48,11 @@ class Digest
$mailer = new Mailer();
- //$rc = $mail->quickMail($line["email"], $line["login"], DIGEST_SUBJECT, $digest, $digest_text);
+ //$rc = $mail->quickMail($line["email"], $line["login"], Config::get(Config::DIGEST_SUBJECT), $digest, $digest_text);
$rc = $mailer->mail(["to_name" => $line["login"],
"to_address" => $line["email"],
- "subject" => DIGEST_SUBJECT,
+ "subject" => Config::get(Config::DIGEST_SUBJECT),
"message" => $digest_text,
"message_html" => $digest]);
@@ -91,11 +91,11 @@ class Digest
$tpl->setVariable('CUR_DATE', date('Y/m/d', $local_ts));
$tpl->setVariable('CUR_TIME', date('G:i', $local_ts));
- $tpl->setVariable('TTRSS_HOST', Config::get(Config.Config::get(Config::SELF_URL_PATH)));
+ $tpl->setVariable('TTRSS_HOST', Config::get(Config::get(Config::SELF_URL_PATH)));
$tpl_t->setVariable('CUR_DATE', date('Y/m/d', $local_ts));
$tpl_t->setVariable('CUR_TIME', date('G:i', $local_ts));
- $tpl_t->setVariable('TTRSS_HOST', Config::get(Config.Config::get(Config::SELF_URL_PATH)));
+ $tpl_t->setVariable('TTRSS_HOST', Config::get(Config::get(Config::SELF_URL_PATH)));
$affected_ids = array();
diff --git a/classes/diskcache.php b/classes/diskcache.php
index 063a3847c..9c594acc5 100644
--- a/classes/diskcache.php
+++ b/classes/diskcache.php
@@ -349,7 +349,7 @@ class DiskCache {
if ($files) {
foreach ($files as $file) {
- if (time() - filemtime($file) > 86400*CACHE_MAX_DAYS) {
+ if (time() - filemtime($file) > 86400*Config::get(Config::CACHE_MAX_DAYS)) {
unlink($file);
++$num_deleted;
diff --git a/classes/feeds.php b/classes/feeds.php
index 274cb22d0..eaedc1aee 100755
--- a/classes/feeds.php
+++ b/classes/feeds.php
@@ -1056,11 +1056,11 @@ class Feeds extends Handler_Protected {
}
static function _get_icon_file($feed_id) {
- return ICONS_DIR . "/$feed_id.ico";
+ return Config::get(Config::ICONS_DIR) . "/$feed_id.ico";
}
static function _has_icon($id) {
- return is_file(ICONS_DIR . "/$id.ico") && filesize(ICONS_DIR . "/$id.ico") > 0;
+ return is_file(Config::get(Config::ICONS_DIR) . "/$id.ico") && filesize(Config::get(Config::ICONS_DIR) . "/$id.ico") > 0;
}
static function _get_icon($id) {
@@ -1084,7 +1084,7 @@ class Feeds extends Handler_Protected {
$icon = self::_get_icon_file($id);
if ($icon && file_exists($icon)) {
- return ICONS_URL . "/" . basename($icon) . "?" . filemtime($icon);
+ return Config::get(Config::ICONS_URL) . "/" . basename($icon) . "?" . filemtime($icon);
}
}
break;
diff --git a/classes/logger.php b/classes/logger.php
index cdc6b240a..6cc33314d 100755
--- a/classes/logger.php
+++ b/classes/logger.php
@@ -42,7 +42,7 @@ class Logger {
}
function __construct() {
- switch (LOG_DESTINATION) {
+ switch (Config::get(Config::LOG_DESTINATION)) {
case "sql":
$this->adapter = new Logger_SQL();
break;
diff --git a/classes/mailer.php b/classes/mailer.php
index 16be16523..93f778210 100644
--- a/classes/mailer.php
+++ b/classes/mailer.php
@@ -11,15 +11,15 @@ class Mailer {
$subject = $params["subject"];
$message = $params["message"];
$message_html = $params["message_html"];
- $from_name = $params["from_name"] ? $params["from_name"] : SMTP_FROM_NAME;
- $from_address = $params["from_address"] ? $params["from_address"] : SMTP_FROM_ADDRESS;
+ $from_name = $params["from_name"] ? $params["from_name"] : Config::get(Config::SMTP_FROM_NAME);
+ $from_address = $params["from_address"] ? $params["from_address"] : Config::get(Config::SMTP_FROM_ADDRESS);
$additional_headers = $params["headers"] ? $params["headers"] : [];
$from_combined = $from_name ? "$from_name <$from_address>" : $from_address;
$to_combined = $to_name ? "$to_name <$to_address>" : $to_address;
- if (defined('_LOG_SENT_MAIL') && _LOG_SENT_MAIL)
+ if (Config::get(Config::LOG_SENT_MAIL))
Logger::get()->log(E_USER_NOTICE, "Sending mail from $from_combined to $to_combined [$subject]: $message");
// HOOK_SEND_MAIL plugin instructions:
diff --git a/classes/pref/feeds.php b/classes/pref/feeds.php
index 229effeb3..7c3a40647 100755
--- a/classes/pref/feeds.php
+++ b/classes/pref/feeds.php
@@ -441,7 +441,7 @@ class Pref_Feeds extends Handler_Protected {
$sth->execute([$feed_id, $_SESSION['uid']]);
if ($row = $sth->fetch()) {
- @unlink(ICONS_DIR . "/$feed_id.ico");
+ @unlink(Config::get(Config::ICONS_DIR) . "/$feed_id.ico");
$sth = $this->pdo->prepare("UPDATE ttrss_feeds SET favicon_avg_color = NULL, favicon_last_checked = '1970-01-01'
where id = ?");
@@ -479,7 +479,7 @@ class Pref_Feeds extends Handler_Protected {
$sth->execute([$feed_id, $_SESSION['uid']]);
if ($row = $sth->fetch()) {
- $new_filename = ICONS_DIR . "/$feed_id.ico";
+ $new_filename = Config::get(Config::ICONS_DIR) . "/$feed_id.ico";
if (file_exists($new_filename)) unlink($new_filename);
@@ -1228,8 +1228,8 @@ class Pref_Feeds extends Handler_Protected {
$pdo->commit();
- if (file_exists(ICONS_DIR . "/$id.ico")) {
- unlink(ICONS_DIR . "/$id.ico");
+ if (file_exists(Config::get(Config::ICONS_DIR) . "/$id.ico")) {
+ unlink(Config::get(Config::ICONS_DIR) . "/$id.ico");
}
} else {
diff --git a/classes/pref/system.php b/classes/pref/system.php
index bc519a321..35c776463 100644
--- a/classes/pref/system.php
+++ b/classes/pref/system.php
@@ -153,10 +153,10 @@ class Pref_System extends Handler_Administrative {
'>
_log_viewer($page, $severity);
} else {
- print_notice("Please set LOG_DESTINATION to 'sql' in config.php to enable database logging.");
+ print_notice("Please set Config::get(Config::LOG_DESTINATION) to 'sql' in config.php to enable database logging.");
}
?>
diff --git a/classes/pref/users.php b/classes/pref/users.php
index 5ac6a7990..f30abe001 100644
--- a/classes/pref/users.php
+++ b/classes/pref/users.php
@@ -86,7 +86,7 @@ class Pref_Users extends Handler_Administrative {
fetch()) { ?>
diff --git a/classes/rpc.php b/classes/rpc.php
index bf24132b0..4aa3f69d5 100755
--- a/classes/rpc.php
+++ b/classes/rpc.php
@@ -165,8 +165,9 @@ class RPC extends Handler_Protected {
function setpanelmode() {
$wide = (int) clean($_REQUEST["wide"]);
+ // FIXME should this use SESSION_COOKIE_LIFETIME and be renewed periodically?
setcookie("ttrss_widescreen", (string)$wide,
- time() + COOKIE_LIFETIME_LONG);
+ time() + 86400*365);
print json_encode(array("wide" => $wide));
}
@@ -328,7 +329,7 @@ class RPC extends Handler_Protected {
get_version($git_commit, $git_timestamp);
- if (defined('CHECK_FOR_UPDATES') && CHECK_FOR_UPDATES && $_SESSION["access_level"] >= 10 && $git_timestamp) {
+ if (defined('Config::get(Config::CHECK_FOR_UPDATES)') && Config::get(Config::CHECK_FOR_UPDATES) && $_SESSION["access_level"] >= 10 && $git_timestamp) {
$content = @UrlHelper::fetch(["url" => "https://tt-rss.org/version.json"]);
if ($content) {
@@ -359,8 +360,8 @@ class RPC extends Handler_Protected {
}
$params["safe_mode"] = !empty($_SESSION["safe_mode"]);
- $params["check_for_updates"] = CHECK_FOR_UPDATES;
- $params["icons_url"] = ICONS_URL;
+ $params["check_for_updates"] = Config::get(Config::CHECK_FOR_UPDATES);
+ $params["icons_url"] = Config::get(Config::ICONS_URL);
$params["cookie_lifetime"] = Config::get(Config::SESSION_COOKIE_LIFETIME);
$params["default_view_mode"] = get_pref("_DEFAULT_VIEW_MODE");
$params["default_view_limit"] = (int) get_pref("_DEFAULT_VIEW_LIMIT");
@@ -390,15 +391,10 @@ class RPC extends Handler_Protected {
$params["self_url_prefix"] = get_self_url_prefix();
$params["max_feed_id"] = (int) $max_feed_id;
$params["num_feeds"] = (int) $num_feeds;
-
$params["hotkeys"] = $this->get_hotkeys_map();
-
$params["widescreen"] = (int) ($_COOKIE["ttrss_widescreen"] ?? 0);
-
- $params['simple_update'] = SIMPLE_UPDATE_MODE;
-
+ $params['simple_update'] = Config::get(Config::SIMPLE_UPDATE_MODE);
$params["icon_indicator_white"] = $this->image_to_base64("images/indicator_white.gif");
-
$params["labels"] = Labels::get_all($_SESSION["uid"]);
return $params;
@@ -432,7 +428,7 @@ class RPC extends Handler_Protected {
$data['cdm_expanded'] = get_pref('CDM_EXPANDED');
$data["labels"] = Labels::get_all($_SESSION["uid"]);
- if (LOG_DESTINATION == 'sql' && $_SESSION['access_level'] >= 10) {
+ if (Config::get(Config::LOG_DESTINATION) == 'sql' && $_SESSION['access_level'] >= 10) {
if (Config::get(Config::DB_TYPE) == 'pgsql') {
$log_interval = "created_at > NOW() - interval '1 hour'";
} else {
diff --git a/classes/rssutils.php b/classes/rssutils.php
index c951003f0..5dcbb48d6 100755
--- a/classes/rssutils.php
+++ b/classes/rssutils.php
@@ -34,9 +34,9 @@ class RSSUtils {
$pdo = Db::pdo();
$sth = $pdo->prepare("SELECT id FROM ttrss_feeds WHERE id = ?");
- // check icon files once every CACHE_MAX_DAYS days
- $icon_files = array_filter(glob(ICONS_DIR . "/*.ico"),
- function($f) { return filemtime($f) < time() - 86400*CACHE_MAX_DAYS; });
+ // check icon files once every Config::get(Config::CACHE_MAX_DAYS) days
+ $icon_files = array_filter(glob(Config::get(Config::ICONS_DIR) . "/*.ico"),
+ function($f) { return filemtime($f) < time() - 86400 * Config::get(Config::CACHE_MAX_DAYS); });
foreach ($icon_files as $icon) {
$feed_id = basename($icon, ".ico");
@@ -52,20 +52,22 @@ class RSSUtils {
}
}
- static function update_daemon_common($limit = DAEMON_FEED_LIMIT, $options = []) {
+ static function update_daemon_common($limit = null, $options = []) {
$schema_version = get_schema_version();
+ if (!$limit) $limit = Config::get(Config::DAEMON_FEED_LIMIT);
+
if ($schema_version != SCHEMA_VERSION) {
die("Schema version is wrong, please upgrade the database.\n");
}
$pdo = Db::pdo();
- if (!Config::get(Config::SINGLE_USER_MODE) && DAEMON_UPDATE_LOGIN_LIMIT > 0) {
+ if (!Config::get(Config::SINGLE_USER_MODE) && Config::get(Config::DAEMON_UPDATE_LOGIN_LIMIT) > 0) {
if (Config::get(Config::DB_TYPE) == "pgsql") {
- $login_thresh_qpart = "AND ttrss_users.last_login >= NOW() - INTERVAL '".DAEMON_UPDATE_LOGIN_LIMIT." days'";
+ $login_thresh_qpart = "AND ttrss_users.last_login >= NOW() - INTERVAL '".Config::get(Config::DAEMON_UPDATE_LOGIN_LIMIT)." days'";
} else {
- $login_thresh_qpart = "AND ttrss_users.last_login >= DATE_SUB(NOW(), INTERVAL ".DAEMON_UPDATE_LOGIN_LIMIT." DAY)";
+ $login_thresh_qpart = "AND ttrss_users.last_login >= DATE_SUB(NOW(), INTERVAL ".Config::get(Config::DAEMON_UPDATE_LOGIN_LIMIT)." DAY)";
}
} else {
$login_thresh_qpart = "";
@@ -288,7 +290,7 @@ class RSSUtils {
if (!$basic_info) {
$feed_data = UrlHelper::fetch($fetch_url, false,
$auth_login, $auth_pass, false,
- FEED_FETCH_TIMEOUT,
+ Config::get(Config::FEED_FETCH_TIMEOUT),
0);
$feed_data = trim($feed_data);
@@ -455,7 +457,7 @@ class RSSUtils {
Debug::log("not using CURL due to open_basedir restrictions", Debug::$LOG_VERBOSE);
}
- if (time() - strtotime($last_unconditional) > MAX_CONDITIONAL_INTERVAL) {
+ if (time() - strtotime($last_unconditional) > Config::get(Config::MAX_CONDITIONAL_INTERVAL)) {
Debug::log("maximum allowed interval for conditional requests exceeded, forcing refetch", Debug::$LOG_VERBOSE);
$force_refetch = true;
@@ -469,7 +471,7 @@ class RSSUtils {
"url" => $fetch_url,
"login" => $auth_login,
"pass" => $auth_pass,
- "timeout" => $no_cache ? FEED_FETCH_NO_CACHE_TIMEOUT : FEED_FETCH_TIMEOUT,
+ "timeout" => $no_cache ? Config::get(Config::FEED_FETCH_NO_CACHE_TIMEOUT) : Config::get(Config::FEED_FETCH_TIMEOUT),
"last_modified" => $force_refetch ? "" : $stored_last_modified
]);
@@ -591,7 +593,7 @@ class RSSUtils {
/* terrible hack: if we crash on floicon shit here, we won't check
* the icon avgcolor again (unless the icon got updated) */
- $favicon_file = ICONS_DIR . "/$feed.ico";
+ $favicon_file = Config::get(Config::ICONS_DIR) . "/$feed.ico";
$favicon_modified = file_exists($favicon_file) ? filemtime($favicon_file) : -1;
Debug::log("checking favicon for feed $feed...", Debug::$LOG_VERBOSE);
@@ -755,7 +757,7 @@ class RSSUtils {
$e->type, $e->length, $e->title, $e->width, $e->height);
// Yet another episode of "mysql utf8_general_ci is gimped"
- if (Config::get(Config::DB_TYPE) == "mysql" && MYSQL_CHARSET != "UTF8MB4") {
+ if (Config::get(Config::DB_TYPE) == "mysql" && Config::get(Config::MYSQL_CHARSET) != "UTF8MB4") {
for ($i = 0; $i < count($e_item); $i++) {
if (is_string($e_item[$i])) {
$e_item[$i] = self::strip_utf8mb4($e_item[$i]);
@@ -833,7 +835,7 @@ class RSSUtils {
Debug::log("plugin data: $entry_plugin_data", Debug::$LOG_VERBOSE);
// Workaround: 4-byte unicode requires utf8mb4 in MySQL. See https://tt-rss.org/forum/viewtopic.php?f=1&t=3377&p=20077#p20077
- if (Config::get(Config::DB_TYPE) == "mysql" && MYSQL_CHARSET != "UTF8MB4") {
+ if (Config::get(Config::DB_TYPE) == "mysql" && Config::get(Config::MYSQL_CHARSET) != "UTF8MB4") {
foreach ($article as $k => $v) {
// i guess we'll have to take the risk of 4byte unicode labels & tags here
if (is_string($article[$k])) {
@@ -1298,7 +1300,7 @@ class RSSUtils {
$file_content = UrlHelper::fetch(array("url" => $src,
"http_referrer" => $src,
- "max_size" => MAX_CACHE_FILE_SIZE));
+ "max_size" => Config::get(Config::MAX_CACHE_FILE_SIZE)));
if ($file_content) {
$cache->put($local_filename, $file_content);
@@ -1328,7 +1330,7 @@ class RSSUtils {
$file_content = UrlHelper::fetch(array("url" => $url,
"http_referrer" => $url,
- "max_size" => MAX_CACHE_FILE_SIZE));
+ "max_size" => Config::get(Config::MAX_CACHE_FILE_SIZE)));
if ($file_content) {
$cache->put($local_filename, $file_content);
@@ -1643,7 +1645,7 @@ class RSSUtils {
}
static function check_feed_favicon($site_url, $feed) {
- $icon_file = ICONS_DIR . "/$feed.ico";
+ $icon_file = Config::get(Config::ICONS_DIR) . "/$feed.ico";
$favicon_url = self::get_favicon_url($site_url);
if (!$favicon_url) {
@@ -1654,7 +1656,7 @@ class RSSUtils {
// Limiting to "image" type misses those served with text/plain
$contents = UrlHelper::fetch([
'url' => $favicon_url,
- 'max_size' => MAX_FAVICON_FILE_SIZE,
+ 'max_size' => Config::get(Config::MAX_FAVICON_FILE_SIZE),
//'type' => 'image',
]);
if (!$contents) {
diff --git a/classes/urlhelper.php b/classes/urlhelper.php
index 8717d02c3..42aa069e6 100644
--- a/classes/urlhelper.php
+++ b/classes/urlhelper.php
@@ -209,7 +209,7 @@ class UrlHelper {
$last_modified = isset($options["last_modified"]) ? $options["last_modified"] : "";
$useragent = isset($options["useragent"]) ? $options["useragent"] : false;
$followlocation = isset($options["followlocation"]) ? $options["followlocation"] : true;
- $max_size = isset($options["max_size"]) ? $options["max_size"] : MAX_DOWNLOAD_FILE_SIZE; // in bytes
+ $max_size = isset($options["max_size"]) ? $options["max_size"] : Config::get(Config::MAX_DOWNLOAD_FILE_SIZE); // in bytes
$http_accept = isset($options["http_accept"]) ? $options["http_accept"] : false;
$http_referrer = isset($options["http_referrer"]) ? $options["http_referrer"] : false;
@@ -250,8 +250,8 @@ class UrlHelper {
if (count($curl_http_headers) > 0)
curl_setopt($ch, CURLOPT_HTTPHEADER, $curl_http_headers);
- curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout ? $timeout : FILE_FETCH_CONNECT_TIMEOUT);
- curl_setopt($ch, CURLOPT_TIMEOUT, $timeout ? $timeout : FILE_FETCH_TIMEOUT);
+ curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout ? $timeout : Config::get(Config::FILE_FETCH_CONNECT_TIMEOUT));
+ curl_setopt($ch, CURLOPT_TIMEOUT, $timeout ? $timeout : Config::get(Config::FILE_FETCH_TIMEOUT));
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, !ini_get("open_basedir") && $followlocation);
curl_setopt($ch, CURLOPT_MAXREDIRS, 20);
curl_setopt($ch, CURLOPT_BINARYTRANSFER, true);
@@ -395,7 +395,7 @@ class UrlHelper {
),
'method' => 'GET',
'ignore_errors' => true,
- 'timeout' => $timeout ? $timeout : FILE_FETCH_TIMEOUT,
+ 'timeout' => $timeout ? $timeout : Config::get(Config::FILE_FETCH_TIMEOUT),
'protocol_version'=> 1.1)
);
@@ -417,7 +417,7 @@ class UrlHelper {
$old_error = error_get_last();
- $fetch_effective_url = self::resolve_redirects($url, $timeout ? $timeout : FILE_FETCH_CONNECT_TIMEOUT);
+ $fetch_effective_url = self::resolve_redirects($url, $timeout ? $timeout : Config::get(Config::FILE_FETCH_CONNECT_TIMEOUT));
if (!self::validate($fetch_effective_url, true)) {
$fetch_last_error = "URL received after redirection failed extended validation.";
diff --git a/config.php-dist b/config.php-dist
index 2ee1c719d..840880ad9 100644
--- a/config.php-dist
+++ b/config.php-dist
@@ -131,7 +131,7 @@
// Disabling auth_internal in this list would automatically disable
// reset password link on the login form.
- define('LOG_DESTINATION', 'sql');
+ define('Config::get(Config::LOG_DESTINATION)', 'sql');
// Error log destination to use. Possible values: sql (uses internal logging
// you can read in Preferences -> System), syslog - logs to system log.
// Setting this to blank uses PHP logging (usually to http server
diff --git a/include/functions.php b/include/functions.php
index 526c6058a..59c824e43 100644
--- a/include/functions.php
+++ b/include/functions.php
@@ -5,12 +5,6 @@
define('LABEL_BASE_INDEX', -1024);
define('PLUGIN_FEED_BASE_INDEX', -128);
- define('COOKIE_LIFETIME_LONG', 86400*365);
-
- // this CSS file is included for everyone (if it exists in themes.local)
- // on login, registration, and main (index and prefs) pages
- define('LOCAL_OVERRIDE_STYLESHEET', '.local-overrides.css');
-
$fetch_last_error = false;
$fetch_last_error_code = false;
$fetch_last_content_type = false;
@@ -37,49 +31,7 @@
ini_set('display_errors', "false");
ini_set('display_startup_errors', "false");
- require_once 'config.php';
-
- /* Some tunables you can override in config.php using define(): */
-
- if (!defined('FEED_FETCH_TIMEOUT')) define('FEED_FETCH_TIMEOUT', 45);
- // How may seconds to wait for response when requesting feed from a site
- if (!defined('FEED_FETCH_NO_CACHE_TIMEOUT')) define('FEED_FETCH_NO_CACHE_TIMEOUT', 15);
- // How may seconds to wait for response when requesting feed from a
- // site when that feed wasn't cached before
- if (!defined('FILE_FETCH_TIMEOUT')) define('FILE_FETCH_TIMEOUT', 45);
- // Default timeout when fetching files from remote sites
- if (!defined('FILE_FETCH_CONNECT_TIMEOUT')) define('FILE_FETCH_CONNECT_TIMEOUT', 15);
- // How many seconds to wait for initial response from website when
- // fetching files from remote sites
- if (!defined('DAEMON_UPDATE_LOGIN_LIMIT')) define('DAEMON_UPDATE_LOGIN_LIMIT', 30);
- // stop updating feeds if users haven't logged in for X days
- if (!defined('DAEMON_FEED_LIMIT')) define('DAEMON_FEED_LIMIT', 500);
- // feed limit for one update batch
- if (!defined('DAEMON_SLEEP_INTERVAL')) define('DAEMON_SLEEP_INTERVAL', 120);
- // default sleep interval between feed updates (sec)
- if (!defined('MAX_CACHE_FILE_SIZE')) define('MAX_CACHE_FILE_SIZE', 64*1024*1024);
- // do not cache files larger than that (bytes)
- if (!defined('MAX_DOWNLOAD_FILE_SIZE')) define('MAX_DOWNLOAD_FILE_SIZE', 16*1024*1024);
- // do not download general files larger than that (bytes)
- if (!defined('MAX_FAVICON_FILE_SIZE')) define('MAX_FAVICON_FILE_SIZE', 1*1024*1024);
- // do not download favicon files larger than that (bytes)
- if (!defined('CACHE_MAX_DAYS')) define('CACHE_MAX_DAYS', 7);
- // max age in days for various automatically cached (temporary) files
- if (!defined('MAX_CONDITIONAL_INTERVAL')) define('MAX_CONDITIONAL_INTERVAL', 3600*12);
- // max interval between forced unconditional updates for servers
- // not complying with http if-modified-since (seconds)
- // if (!defined('MAX_FETCH_REQUESTS_PER_HOST')) define('MAX_FETCH_REQUESTS_PER_HOST', 25);
- // a maximum amount of allowed HTTP requests per destination host
- // during a single update (i.e. within PHP process lifetime)
- // this is used to not cause excessive load on the origin server on
- // e.g. feed subscription when all articles are being processes
- // (not implemented)
- if (!defined('DAEMON_UNSUCCESSFUL_DAYS_LIMIT')) define('DAEMON_UNSUCCESSFUL_DAYS_LIMIT', 30);
- // automatically disable updates for feeds which failed to
- // update for this amount of days; 0 disables
-
- /* tunables end here */
-
+ require_once "config.php";
require_once "autoload.php";
if (Config::get(Config::DB_TYPE) == "pgsql") {
diff --git a/include/login_form.php b/include/login_form.php
index 537c7f994..168fe50aa 100755
--- a/include/login_form.php
+++ b/include/login_form.php
@@ -16,8 +16,8 @@
} ?>
-