1
0
mirror of https://git.tt-rss.org/git/tt-rss.git synced 2025-12-13 19:05:55 +00:00

rework class system to use subdirectories

add placeholder plugin/hook system
This commit is contained in:
Andrew Dolgov
2012-08-17 14:20:55 +04:00
parent 3d2c9f5adf
commit 369dbc19d6
29 changed files with 131 additions and 22 deletions

1681
classes/pref/feeds.php Normal file

File diff suppressed because it is too large Load Diff

657
classes/pref/filters.php Normal file
View File

@@ -0,0 +1,657 @@
<?php
class Pref_Filters extends Handler_Protected {
function csrf_ignore($method) {
$csrf_ignored = array("index", "getfiltertree", "edit");
return array_search($method, $csrf_ignored) !== false;
}
function filter_test($filter_type, $reg_exp,
$action_id, $action_param, $filter_param, $inverse, $feed_id, $cat_id,
$cat_filter) {
$result = db_query($this->link, "SELECT name FROM ttrss_filter_types WHERE
id = " . $filter_type);
$type_name = db_fetch_result($result, 0, "name");
$result = db_query($this->link, "SELECT name FROM ttrss_filter_actions WHERE
id = " . $action_id);
$action_name = db_fetch_result($result, 0, "name");
$filter["reg_exp"] = $reg_exp;
$filter["action"] = $action_name;
$filter["type"] = $type_name;
$filter["action_param"] = $action_param;
$filter["filter_param"] = $filter_param;
$filter["inverse"] = $inverse;
$filters[$type_name] = array($filter);
if ($feed_id)
$feed = $feed_id;
else
$feed = -4;
$regexp_valid = preg_match('/' . $filter['reg_exp'] . '/',
$filter['reg_exp']) !== FALSE;
print __("Articles matching this filter:");
print "<div class=\"filterTestHolder\">";
print "<table width=\"100%\" cellspacing=\"0\" id=\"prefErrorFeedList\">";
if ($regexp_valid) {
$feed_title = getFeedTitle($this->link, $feed);
$qfh_ret = queryFeedHeadlines($this->link, $cat_filter ? $cat_id : $feed,
30, "", $cat_filter, false, false,
false, "date_entered DESC", 0, $_SESSION["uid"], $filter);
$result = $qfh_ret[0];
$articles = array();
$found = 0;
while ($line = db_fetch_assoc($result)) {
$entry_timestamp = strtotime($line["updated"]);
$entry_tags = get_article_tags($this->link, $line["id"], $_SESSION["uid"]);
$content_preview = truncate_string(
strip_tags($line["content_preview"]), 100, '...');
if ($line["feed_title"])
$feed_title = $line["feed_title"];
print "<tr>";
print "<td width='5%' align='center'><input
dojoType=\"dijit.form.CheckBox\" checked=\"1\"
disabled=\"1\" type=\"checkbox\"></td>";
print "<td>";
print $line["title"];
print "&nbsp;(";
print "<b>" . $feed_title . "</b>";
print "):&nbsp;";
print "<span class=\"insensitive\">" . $content_preview . "</span>";
print " " . mb_substr($line["date_entered"], 0, 16);
print "</td></tr>";
$found++;
}
if ($found == 0) {
print "<tr><td align='center'>" .
__("No articles matching this filter has been found.") . "</td></tr>";
}
} else {
print "<tr><td align='center' class='error'>" .
__("Invalid regular expression.") . "</td></tr>";
}
print "</table>";
print "</div>";
}
function getfiltertree() {
$root = array();
$root['id'] = 'root';
$root['name'] = __('Filters');
$root['items'] = array();
$search = $_SESSION["prefs_filter_search"];
if ($search) $search_qpart = " (LOWER(reg_exp) LIKE LOWER('%$search%')
OR LOWER(ttrss_feeds.title) LIKE LOWER('%$search%')
OR LOWER(COALESCE(ttrss_feed_categories.title, '".__('Uncategorized')."'))
LIKE LOWER('%$search%') AND cat_filter = true) AND ";
$result = db_query($this->link, "SELECT
ttrss_filters.id AS id,reg_exp,
ttrss_filter_types.name AS filter_type_name,
ttrss_filter_types.description AS filter_type_descr,
enabled,
inverse,
cat_filter,
feed_id,
ttrss_filters.cat_id,
action_id,
filter_param,
filter_type,
ttrss_filter_actions.description AS action_description,
ttrss_feeds.title AS feed_title,
COALESCE(ttrss_feed_categories.title, '".__('Uncategorized')."') AS cat_title,
ttrss_filter_actions.name AS action_name,
ttrss_filters.action_param AS action_param
FROM
ttrss_filter_types,ttrss_filter_actions,ttrss_filters LEFT JOIN
ttrss_feeds ON (ttrss_filters.feed_id = ttrss_feeds.id) LEFT JOIN
ttrss_feed_categories ON (ttrss_filters.cat_id = ttrss_feed_categories.id)
WHERE
filter_type = ttrss_filter_types.id AND
ttrss_filter_actions.id = action_id AND
$search_qpart
ttrss_filters.owner_uid = ".$_SESSION["uid"]."
ORDER by action_description, reg_exp");
$cat = false;
$cur_action_description = "";
if (db_num_rows($result) > 0) {
while ($line = db_fetch_assoc($result)) {
if ($cur_action_description != $line['action_description']) {
if ($cat)
array_push($root['items'], $cat);
$cat = array();
$cat['id'] = 'ACTION:' . $line['action_id'];
$cat['name'] = $line['action_description'];
$cat['items'] = array();
$cur_action_description = $line['action_description'];
}
if (array_search($line["action_name"],
array("score", "tag", "label")) === false) {
$line["action_param"] = '';
} else {
if ($line['action_name'] == 'label') {
$tmp_result = db_query($this->link, "SELECT fg_color, bg_color
FROM ttrss_labels2 WHERE caption = '".
db_escape_string($line["action_param"])."' AND
owner_uid = " . $_SESSION["uid"]);
if (db_num_rows($tmp_result) != 0) {
$fg_color = db_fetch_result($tmp_result, 0, "fg_color");
$bg_color = db_fetch_result($tmp_result, 0, "bg_color");
$tmp = "<span class=\"labelColorIndicator\" style='color : $fg_color; background-color : $bg_color'>&alpha;</span> " . $line['action_param'];
$line['action_param'] = $tmp;
}
}
}
$filter = array();
$filter['id'] = 'FILTER:' . $line['id'];
$filter['bare_id'] = $line['id'];
$filter['name'] = $line['reg_exp'];
$filter['type'] = $line['filter_type'];
$filter['enabled'] = sql_bool_to_bool($line['enabled']);
$filter['param'] = $line['action_param'];
$filter['inverse'] = sql_bool_to_bool($line['inverse']);
$filter['checkbox'] = false;
if (sql_bool_to_bool($line['cat_filter']))
if ($line['cat_id'] != 0) {
$filter['feed'] = $line['cat_title'];
} else {
$filter['feed'] = __('Uncategorized');
}
else if ($line['feed_id'])
$filter['feed'] = $line['feed_title'];
array_push($cat['items'], $filter);
}
array_push($root['items'], $cat);
}
$fl = array();
$fl['identifier'] = 'id';
$fl['label'] = 'name';
$fl['items'] = array($root);
print json_encode($fl);
return;
}
function edit() {
$filter_id = db_escape_string($_REQUEST["id"]);
$result = db_query($this->link,
"SELECT * FROM ttrss_filters WHERE id = '$filter_id' AND owner_uid = " . $_SESSION["uid"]);
$reg_exp = htmlspecialchars(db_fetch_result($result, 0, "reg_exp"));
$filter_type = db_fetch_result($result, 0, "filter_type");
$feed_id = db_fetch_result($result, 0, "feed_id");
$cat_id = db_fetch_result($result, 0, "cat_id");
$action_id = db_fetch_result($result, 0, "action_id");
$action_param = db_fetch_result($result, 0, "action_param");
$filter_param = db_fetch_result($result, 0, "filter_param");
$enabled = sql_bool_to_bool(db_fetch_result($result, 0, "enabled"));
$inverse = sql_bool_to_bool(db_fetch_result($result, 0, "inverse"));
$cat_filter = sql_bool_to_bool(db_fetch_result($result, 0, "cat_filter"));
print "<form id=\"filter_edit_form\" onsubmit='return false'>";
print "<input dojoType=\"dijit.form.TextBox\" style=\"display : none\" name=\"op\" value=\"pref-filters\">";
print "<input dojoType=\"dijit.form.TextBox\" style=\"display : none\" name=\"id\" value=\"$filter_id\">";
print "<input dojoType=\"dijit.form.TextBox\" style=\"display : none\" name=\"method\" value=\"editSave\">";
print "<input dojoType=\"dijit.form.TextBox\" style=\"display : none\" name=\"csrf_token\" value=\"".$_SESSION['csrf_token']."\">";
$result = db_query($this->link, "SELECT id,description
FROM ttrss_filter_types ORDER BY description");
$filter_types = array();
while ($line = db_fetch_assoc($result)) {
//array_push($filter_types, $line["description"]);
$filter_types[$line["id"]] = __($line["description"]);
}
print "<div class=\"dlgSec\">".__("Match")."</div>";
print "<div class=\"dlgSecCont\">";
if ($filter_type != 5) {
$date_ops_invisible = 'style="display : none"';
}
print "<span id=\"filterDlg_dateModBox\" $date_ops_invisible>";
print __("Date") . " ";
$filter_params = array(
"before" => __("before"),
"after" => __("after"));
print_select_hash("filter_date_modifier", $filter_param,
$filter_params, 'dojoType="dijit.form.Select"');
print "&nbsp;</span>";
print "<input dojoType=\"dijit.form.ValidationTextBox\"
required=\"1\"
name=\"reg_exp\" style=\"font-size : 16px;\" value=\"$reg_exp\">";
print "<span id=\"filterDlg_dateChkBox\" $date_ops_invisible>";
print "&nbsp;<button dojoType=\"dijit.form.Button\" onclick=\"return filterDlgCheckDate()\">".
__('Check it')."</button>";
print "</span>";
print "<hr/> " . __("on field") . " ";
print_select_hash("filter_type", $filter_type, $filter_types,
'onchange="filterDlgCheckType(this)" dojoType="dijit.form.Select"');
print "<hr/>";
print __("in") . " ";
$hidden = $cat_filter ? "style='display:none'" : "";
print "<span id='filterDlg_feeds' $hidden>";
print_feed_select($this->link, "feed_id", $feed_id,
'dojoType="dijit.form.FilteringSelect"');
print "</span>";
$hidden = $cat_filter ? "" : "style='display:none'";
print "<span id='filterDlg_cats' $hidden>";
print_feed_cat_select($this->link, "cat_id", $cat_id,
'dojoType="dijit.form.FilteringSelect"');
print "</span>";
print "</div>";
print "<div class=\"dlgSec\">".__("Perform Action")."</div>";
print "<div class=\"dlgSecCont\">";
print "<select name=\"action_id\" dojoType=\"dijit.form.Select\"
onchange=\"filterDlgCheckAction(this)\">";
$result = db_query($this->link, "SELECT id,description FROM ttrss_filter_actions
ORDER BY name");
while ($line = db_fetch_assoc($result)) {
$is_sel = ($line["id"] == $action_id) ? "selected=\"1\"" : "";
printf("<option value='%d' $is_sel>%s</option>", $line["id"], __($line["description"]));
}
print "</select>";
$param_hidden = ($action_id == 4 || $action_id == 6 || $action_id == 7) ? "" : "display : none";
print "<span id=\"filterDlg_paramBox\" style=\"$param_hidden\">";
print " " . __("with parameters:") . " ";
$param_int_hidden = ($action_id != 7) ? "" : "display : none";
print "<input style=\"$param_int_hidden\"
dojoType=\"dijit.form.TextBox\" id=\"filterDlg_actionParam\"
name=\"action_param\" value=\"$action_param\">";
$param_int_hidden = ($action_id == 7) ? "" : "display : none";
print_label_select($this->link, "action_param_label", $action_param,
"style=\"$param_int_hidden\"" .
'id="filterDlg_actionParamLabel" dojoType="dijit.form.Select"');
print "</span>";
print "&nbsp;"; // tiny layout hack
print "</div>";
print "<div class=\"dlgSec\">".__("Options")."</div>";
print "<div class=\"dlgSecCont\">";
print "<div style=\"line-height : 100%\">";
if ($enabled) {
$checked = "checked=\"1\"";
} else {
$checked = "";
}
print "<input dojoType=\"dijit.form.CheckBox\" type=\"checkbox\" name=\"enabled\" id=\"enabled\" $checked>
<label for=\"enabled\">".__('Enabled')."</label><hr/>";
if ($inverse) {
$checked = "checked=\"1\"";
} else {
$checked = "";
}
print "<input dojoType=\"dijit.form.CheckBox\" type=\"checkbox\" name=\"inverse\" id=\"inverse\" $checked>
<label for=\"inverse\">".__('Inverse match')."</label><hr/>";
if ($cat_filter) {
$checked = "checked=\"1\"";
} else {
$checked = "";
}
print "<input dojoType=\"dijit.form.CheckBox\" type=\"checkbox\" name=\"cat_filter\" id=\"cat_filter\" onchange=\"filterDlgCheckCat(this)\" $checked>
<label for=\"cat_filter\">".__('Apply to category')."</label><hr/>";
print "</div>";
print "</div>";
print "<div class=\"dlgButtons\">";
print "<div style=\"float : left\">";
print "<button dojoType=\"dijit.form.Button\" onclick=\"return dijit.byId('filterEditDlg').removeFilter()\">".
__('Remove')."</button>";
print "</div>";
print "<button dojoType=\"dijit.form.Button\" onclick=\"return dijit.byId('filterEditDlg').test()\">".
__('Test')."</button> ";
print "<button dojoType=\"dijit.form.Button\" onclick=\"return dijit.byId('filterEditDlg').execute()\">".
__('Save')."</button> ";
print "<button dojoType=\"dijit.form.Button\" onclick=\"return dijit.byId('filterEditDlg').hide()\">".
__('Cancel')."</button>";
print "</div>";
}
function editSave() {
$savemode = db_escape_string($_REQUEST["savemode"]);
$reg_exp = db_escape_string(trim($_REQUEST["reg_exp"]));
$filter_type = db_escape_string(trim($_REQUEST["filter_type"]));
$filter_id = db_escape_string($_REQUEST["id"]);
$feed_id = db_escape_string($_REQUEST["feed_id"]);
$action_id = db_escape_string($_REQUEST["action_id"]);
$action_param = db_escape_string($_REQUEST["action_param"]);
$action_param_label = db_escape_string($_REQUEST["action_param_label"]);
$enabled = checkbox_to_sql_bool(db_escape_string($_REQUEST["enabled"]));
$inverse = checkbox_to_sql_bool(db_escape_string($_REQUEST["inverse"]));
$cat_filter = checkbox_to_sql_bool(db_escape_string($_REQUEST["cat_filter"]));
$cat_id = db_escape_string($_REQUEST['cat_id']);
# for the time being, no other filters use params anyway...
$filter_param = db_escape_string($_REQUEST["filter_date_modifier"]);
if (!$feed_id) {
$feed_id = 'NULL';
} else {
$feed_id = sprintf("'%s'", db_escape_string($feed_id));
}
if (!$cat_id) {
$cat_id = 'NULL';
} else {
$cat_id = sprintf("'%d'", db_escape_string($cat_id));
}
/* When processing 'assign label' filters, action_param_label dropbox
* overrides action_param */
if ($action_id == 7) {
$action_param = $action_param_label;
}
if ($action_id == 6) {
$action_param = (int) str_replace("+", "", $action_param);
}
if ($savemode != "test") {
$result = db_query($this->link, "UPDATE ttrss_filters SET
reg_exp = '$reg_exp',
feed_id = $feed_id,
cat_id = $cat_id,
action_id = '$action_id',
filter_type = '$filter_type',
enabled = $enabled,
inverse = $inverse,
cat_filter = $cat_filter,
action_param = '$action_param',
filter_param = '$filter_param'
WHERE id = '$filter_id' AND owner_uid = " . $_SESSION["uid"]);
} else {
$this->filter_test($filter_type, $reg_exp,
$action_id, $action_param, $filter_param, sql_bool_to_bool($inverse),
(int) $_REQUEST["feed_id"], (int) $_REQUEST['cat_id'],
sql_bool_to_bool($cat_filter));
print "<div align='center'>";
print "<button dojoType=\"dijit.form.Button\"
onclick=\"return dijit.byId('filterTestDlg').hide()\">".
__('Close this window')."</button>";
print "</div>";
}
}
function remove() {
$ids = split(",", db_escape_string($_REQUEST["ids"]));
foreach ($ids as $id) {
db_query($this->link, "DELETE FROM ttrss_filters WHERE id = '$id' AND owner_uid = ". $_SESSION["uid"]);
}
}
function add() {
$savemode = db_escape_string($_REQUEST["savemode"]);
$regexp = db_escape_string(trim($_REQUEST["reg_exp"]));
$filter_type = db_escape_string(trim($_REQUEST["filter_type"]));
$feed_id = db_escape_string($_REQUEST["feed_id"]);
$cat_id = db_escape_string($_REQUEST["cat_id"]);
$action_id = db_escape_string($_REQUEST["action_id"]);
$action_param = db_escape_string($_REQUEST["action_param"]);
$action_param_label = db_escape_string($_REQUEST["action_param_label"]);
$inverse = checkbox_to_sql_bool(db_escape_string($_REQUEST["inverse"]));
$cat_filter = checkbox_to_sql_bool(db_escape_string($_REQUEST["cat_filter"]));
# for the time being, no other filters use params anyway...
$filter_param = db_escape_string($_REQUEST["filter_date_modifier"]);
if (!$regexp) return;
if (!$feed_id) {
$feed_id = 'NULL';
} else {
$feed_id = sprintf("'%s'", db_escape_string($feed_id));
}
if (!$cat_id) {
$cat_id = 'NULL';
} else {
$cat_id = sprintf("'%d'", db_escape_string($cat_id));
}
/* When processing 'assign label' filters, action_param_label dropbox
* overrides action_param */
if ($action_id == 7) {
$action_param = $action_param_label;
}
if ($action_id == 6) {
$action_param = (int) str_replace("+", "", $action_param);
}
if ($savemode != "test") {
$result = db_query($this->link,
"INSERT INTO ttrss_filters (reg_exp,filter_type,owner_uid,feed_id,
action_id, action_param, inverse, filter_param, cat_id, cat_filter)
VALUES
('$regexp', '$filter_type','".$_SESSION["uid"]."',
$feed_id, '$action_id', '$action_param', $inverse,
'$filter_param', $cat_id, $cat_filter)");
if (db_affected_rows($this->link, $result) != 0) {
print T_sprintf("Created filter <b>%s</b>", htmlspecialchars($regexp));
}
} else {
$this->filter_test($filter_type, $regexp,
$action_id, $action_param, $filter_param, sql_bool_to_bool($inverse),
(int) $_REQUEST["feed_id"], (int) $_REQUEST['cat_id'],
sql_bool_to_bool($cat_filter));
print "<div align='center'>";
print "<button dojoType=\"dijit.form.Button\"
onclick=\"return dijit.byId('filterTestDlg').hide()\">".
__('Close this window')."</button>";
print "</div>";
}
}
function index() {
$sort = db_escape_string($_REQUEST["sort"]);
if (!$sort || $sort == "undefined") {
$sort = "reg_exp";
}
$result = db_query($this->link, "SELECT id,description
FROM ttrss_filter_types ORDER BY description");
$filter_types = array();
while ($line = db_fetch_assoc($result)) {
//array_push($filter_types, $line["description"]);
$filter_types[$line["id"]] = $line["description"];
}
$filter_search = db_escape_string($_REQUEST["search"]);
if (array_key_exists("search", $_REQUEST)) {
$_SESSION["prefs_filter_search"] = $filter_search;
} else {
$filter_search = $_SESSION["prefs_filter_search"];
}
print "<div id=\"pref-filter-wrap\" dojoType=\"dijit.layout.BorderContainer\" gutters=\"false\">";
print "<div id=\"pref-filter-header\" dojoType=\"dijit.layout.ContentPane\" region=\"top\">";
print "<div id=\"pref-filter-toolbar\" dojoType=\"dijit.Toolbar\">";
$filter_search = db_escape_string($_REQUEST["search"]);
if (array_key_exists("search", $_REQUEST)) {
$_SESSION["prefs_filter_search"] = $filter_search;
} else {
$filter_search = $_SESSION["prefs_filter_search"];
}
print "<div style='float : right; padding-right : 4px;'>
<input dojoType=\"dijit.form.TextBox\" id=\"filter_search\" size=\"20\" type=\"search\"
value=\"$filter_search\">
<button dojoType=\"dijit.form.Button\" onclick=\"updateFilterList()\">".
__('Search')."</button>
</div>";
print "<div dojoType=\"dijit.form.DropDownButton\">".
"<span>" . __('Select')."</span>";
print "<div dojoType=\"dijit.Menu\" style=\"display: none;\">";
print "<div onclick=\"dijit.byId('filterTree').model.setAllChecked(true)\"
dojoType=\"dijit.MenuItem\">".__('All')."</div>";
print "<div onclick=\"dijit.byId('filterTree').model.setAllChecked(false)\"
dojoType=\"dijit.MenuItem\">".__('None')."</div>";
print "</div></div>";
print "<button dojoType=\"dijit.form.Button\" onclick=\"return quickAddFilter()\">".
__('Create filter')."</button> ";
print "<button dojoType=\"dijit.form.Button\" onclick=\"return editSelectedFilter()\">".
__('Edit')."</button> ";
print "<button dojoType=\"dijit.form.Button\" onclick=\"return removeSelectedFilters()\">".
__('Remove')."</button> ";
if (defined('_ENABLE_FEED_DEBUGGING')) {
print "<button dojoType=\"dijit.form.Button\" onclick=\"rescore_all_feeds()\">".
__('Rescore articles')."</button> ";
}
print "</div>"; # toolbar
print "</div>"; # toolbar-frame
print "<div id=\"pref-filter-content\" dojoType=\"dijit.layout.ContentPane\" region=\"center\">";
print "<div id=\"filterlistLoading\">
<img src='images/indicator_tiny.gif'>".
__("Loading, please wait...")."</div>";
print "<div dojoType=\"dojo.data.ItemFileWriteStore\" jsId=\"filterStore\"
url=\"backend.php?op=pref-filters&method=getfiltertree\">
</div>
<div dojoType=\"lib.CheckBoxStoreModel\" jsId=\"filterModel\" store=\"filterStore\"
query=\"{id:'root'}\" rootId=\"root\" rootLabel=\"Feeds\"
childrenAttrs=\"items\" checkboxStrict=\"false\" checkboxAll=\"false\">
</div>
<div dojoType=\"fox.PrefFilterTree\" id=\"filterTree\"
model=\"filterModel\" openOnClick=\"true\">
<script type=\"dojo/method\" event=\"onLoad\" args=\"item\">
Element.hide(\"filterlistLoading\");
</script>
<script type=\"dojo/method\" event=\"onClick\" args=\"item\">
var id = String(item.id);
var bare_id = id.substr(id.indexOf(':')+1);
if (id.match('FILTER:')) {
editFilter(bare_id);
}
</script>
</div>";
print "</div>"; #pane
print "</div>"; #container
}
}
?>

210
classes/pref/instances.php Normal file
View File

@@ -0,0 +1,210 @@
<?php
class Pref_Instances extends Handler_Protected {
function csrf_ignore($method) {
$csrf_ignored = array("index", "edit");
return array_search($method, $csrf_ignored) !== false;
}
function before($method) {
if (parent::before($method)) {
if ($_SESSION["access_level"] < 10) {
print __("Your access level is insufficient to open this tab.");
return false;
}
return true;
}
return false;
}
function remove() {
$ids = db_escape_string($_REQUEST['ids']);
db_query($this->link, "DELETE FROM ttrss_linked_instances WHERE
id IN ($ids)");
}
function add() {
$id = db_escape_string($_REQUEST["id"]);
$access_url = db_escape_string($_REQUEST["access_url"]);
$access_key = db_escape_string($_REQUEST["access_key"]);
db_query($this->link, "BEGIN");
$result = db_query($this->link, "SELECT id FROM ttrss_linked_instances
WHERE access_url = '$access_url'");
if (db_num_rows($result) == 0) {
db_query($this->link, "INSERT INTO ttrss_linked_instances
(access_url, access_key, last_connected, last_status_in, last_status_out)
VALUES
('$access_url', '$access_key', '1970-01-01', -1, -1)");
}
db_query($this->link, "COMMIT");
}
function edit() {
$id = db_escape_string($_REQUEST["id"]);
$result = db_query($this->link, "SELECT * FROM ttrss_linked_instances WHERE
id = '$id'");
print "<input dojoType=\"dijit.form.TextBox\" style=\"display : none\" name=\"id\" value=\"$id\">";
print "<input dojoType=\"dijit.form.TextBox\" style=\"display : none\" name=\"op\" value=\"pref-instances\">";
print "<input dojoType=\"dijit.form.TextBox\" style=\"display : none\" name=\"method\" value=\"editSave\">";
print "<div class=\"dlgSec\">".__("Instance")."</div>";
print "<div class=\"dlgSecCont\">";
/* URL */
$access_url = htmlspecialchars(db_fetch_result($result, 0, "access_url"));
print __("URL:") . " ";
print "<input dojoType=\"dijit.form.ValidationTextBox\" required=\"1\"
placeHolder=\"".__("Instance URL")."\"
regExp='^(http|https)://.*'
style=\"font-size : 16px; width: 20em\" name=\"access_url\"
value=\"$access_url\">";
print "<hr/>";
$access_key = htmlspecialchars(db_fetch_result($result, 0, "access_key"));
/* Access key */
print __("Access key:") . " ";
print "<input dojoType=\"dijit.form.ValidationTextBox\" required=\"1\"
placeHolder=\"".__("Access key")."\" regExp='\w{40}'
style=\"width: 20em\" name=\"access_key\" id=\"instance_edit_key\"
value=\"$access_key\">";
print "<p class='insensitive'>" . __("Use one access key for both linked instances.");
print "</div>";
print "<div class=\"dlgButtons\">
<div style='float : left'>
<button dojoType=\"dijit.form.Button\"
onclick=\"return dijit.byId('instanceEditDlg').regenKey()\">".
__('Generate new key')."</button>
</div>
<button dojoType=\"dijit.form.Button\"
onclick=\"return dijit.byId('instanceEditDlg').execute()\">".
__('Save')."</button>
<button dojoType=\"dijit.form.Button\"
onclick=\"return dijit.byId('instanceEditDlg').hide()\"\">".
__('Cancel')."</button></div>";
}
function editSave() {
$id = db_escape_string($_REQUEST["id"]);
$access_url = db_escape_string($_REQUEST["access_url"]);
$access_key = db_escape_string($_REQUEST["access_key"]);
db_query($this->link, "UPDATE ttrss_linked_instances SET
access_key = '$access_key', access_url = '$access_url',
last_connected = '1970-01-01'
WHERE id = '$id'");
}
function index() {
if (!function_exists('curl_init')) {
print "<div style='padding : 1em'>";
print_error("This functionality requires CURL functions. Please enable CURL in your PHP configuration (you might also want to disable open_basedir in php.ini) and reload this page.");
print "</div>";
}
print "<div id=\"pref-instance-wrap\" dojoType=\"dijit.layout.BorderContainer\" gutters=\"false\">";
print "<div id=\"pref-instance-header\" dojoType=\"dijit.layout.ContentPane\" region=\"top\">";
print "<div id=\"pref-instance-toolbar\" dojoType=\"dijit.Toolbar\">";
$sort = db_escape_string($_REQUEST["sort"]);
if (!$sort || $sort == "undefined") {
$sort = "access_url";
}
print "<div dojoType=\"dijit.form.DropDownButton\">".
"<span>" . __('Select')."</span>";
print "<div dojoType=\"dijit.Menu\" style=\"display: none;\">";
print "<div onclick=\"selectTableRows('prefInstanceList', 'all')\"
dojoType=\"dijit.MenuItem\">".__('All')."</div>";
print "<div onclick=\"selectTableRows('prefInstanceList', 'none')\"
dojoType=\"dijit.MenuItem\">".__('None')."</div>";
print "</div></div>";
print "<button dojoType=\"dijit.form.Button\" onclick=\"addInstance()\">".__('Link instance')."</button>";
print "<button dojoType=\"dijit.form.Button\" onclick=\"editSelectedInstance()\">".__('Edit')."</button>";
print "<button dojoType=\"dijit.form.Button\" onclick=\"removeSelectedInstances()\">".__('Remove')."</button>";
print "</div>"; #toolbar
$result = db_query($this->link, "SELECT *,
(SELECT COUNT(*) FROM ttrss_linked_feeds
WHERE instance_id = ttrss_linked_instances.id) AS num_feeds
FROM ttrss_linked_instances
ORDER BY $sort");
print "<p class=\"insensitive\" style='margin-left : 1em;'>" . __("You can connect other instances of Tiny Tiny RSS to this one to share Popular feeds. Link to this instance of Tiny Tiny RSS by using this URL:");
print " <a href=\"#\" onclick=\"alert('".htmlspecialchars(get_self_url_prefix())."')\">(display url)</a>";
print "<p><table width='100%' id='prefInstanceList' class='prefInstanceList' cellspacing='0'>";
print "<tr class=\"title\">
<td align='center' width=\"5%\">&nbsp;</td>
<td width=''><a href=\"#\" onclick=\"updateInstanceList('access_url')\">".__('Instance URL')."</a></td>
<td width='20%'><a href=\"#\" onclick=\"updateInstanceList('access_key')\">".__('Access key')."</a></td>
<td width='10%'><a href=\"#\" onclick=\"updateUsersList('last_connected')\">".__('Last connected')."</a></td>
<td width='10%'><a href=\"#\" onclick=\"updateUsersList('num_feeds')\">".__('Stored feeds')."</a></td>
</tr>";
$lnum = 0;
while ($line = db_fetch_assoc($result)) {
$class = ($lnum % 2) ? "even" : "odd";
$id = $line['id'];
$this_row_id = "id=\"LIRR-$id\"";
$line["last_connected"] = make_local_datetime($this->link, $line["last_connected"], false);
print "<tr class=\"$class\" $this_row_id>";
print "<td align='center'><input onclick='toggleSelectRow(this);'
type=\"checkbox\" id=\"LICHK-$id\"></td>";
$onclick = "onclick='editInstance($id, event)' title='".__('Click to edit')."'";
$access_key = mb_substr($line['access_key'], 0, 4) . '...' .
mb_substr($line['access_key'], -4);
print "<td $onclick>" . htmlspecialchars($line['access_url']) . "</td>";
print "<td $onclick>" . htmlspecialchars($access_key) . "</td>";
print "<td $onclick>" . htmlspecialchars($line['last_connected']) . "</td>";
print "<td $onclick>" . htmlspecialchars($line['num_feeds']) . "</td>";
print "</tr>";
++$lnum;
}
print "</table>";
print "</div>"; #pane
print "</div>"; #container
}
}
?>

326
classes/pref/labels.php Normal file
View File

@@ -0,0 +1,326 @@
<?php
class Pref_Labels extends Handler_Protected {
function csrf_ignore($method) {
$csrf_ignored = array("index", "getlabeltree", "edit");
return array_search($method, $csrf_ignored) !== false;
}
function edit() {
$label_id = db_escape_string($_REQUEST['id']);
$result = db_query($this->link, "SELECT * FROM ttrss_labels2 WHERE
id = '$label_id' AND owner_uid = " . $_SESSION["uid"]);
$line = db_fetch_assoc($result);
print "<input dojoType=\"dijit.form.TextBox\" style=\"display : none\" name=\"id\" value=\"$label_id\">";
print "<input dojoType=\"dijit.form.TextBox\" style=\"display : none\" name=\"op\" value=\"pref-labels\">";
print "<input dojoType=\"dijit.form.TextBox\" style=\"display : none\" name=\"method\" value=\"save\">";
print "<div class=\"dlgSec\">".__("Caption")."</div>";
print "<div class=\"dlgSecCont\">";
$fg_color = $line['fg_color'];
$bg_color = $line['bg_color'];
print "<span class=\"labelColorIndicator\" id=\"label-editor-indicator\" style='color : $fg_color; background-color : $bg_color; margin-bottom : 4px; margin-right : 4px'>&alpha;</span>";
print "<input style=\"font-size : 16px\" name=\"caption\"
dojoType=\"dijit.form.ValidationTextBox\"
required=\"true\"
value=\"".htmlspecialchars($line['caption'])."\">";
print "</div>";
print "<div class=\"dlgSec\">" . __("Colors") . "</div>";
print "<div class=\"dlgSecCont\">";
print "<table cellspacing=\"0\">";
print "<tr><td>".__("Foreground:")."</td><td>".__("Background:").
"</td></tr>";
print "<tr><td style='padding-right : 10px'>";
print "<input dojoType=\"dijit.form.TextBox\"
style=\"display : none\" id=\"labelEdit_fgColor\"
name=\"fg_color\" value=\"$fg_color\">";
print "<input dojoType=\"dijit.form.TextBox\"
style=\"display : none\" id=\"labelEdit_bgColor\"
name=\"bg_color\" value=\"$bg_color\">";
print "<div dojoType=\"dijit.ColorPalette\">
<script type=\"dojo/method\" event=\"onChange\" args=\"fg_color\">
dijit.byId(\"labelEdit_fgColor\").attr('value', fg_color);
$('label-editor-indicator').setStyle({color: fg_color});
</script>
</div>";
print "</div>";
print "</td><td>";
print "<div dojoType=\"dijit.ColorPalette\">
<script type=\"dojo/method\" event=\"onChange\" args=\"bg_color\">
dijit.byId(\"labelEdit_bgColor\").attr('value', bg_color);
$('label-editor-indicator').setStyle({backgroundColor: bg_color});
</script>
</div>";
print "</div>";
print "</td></tr></table>";
print "</div>";
# print "</form>";
print "<div class=\"dlgButtons\">";
print "<button dojoType=\"dijit.form.Button\" onclick=\"dijit.byId('labelEditDlg').execute()\">".
__('Save')."</button>";
print "<button dojoType=\"dijit.form.Button\" onclick=\"dijit.byId('labelEditDlg').hide()\">".
__('Cancel')."</button>";
print "</div>";
return;
}
function getlabeltree() {
$root = array();
$root['id'] = 'root';
$root['name'] = __('Labels');
$root['items'] = array();
$result = db_query($this->link, "SELECT *
FROM ttrss_labels2
WHERE owner_uid = ".$_SESSION["uid"]."
ORDER BY caption");
while ($line = db_fetch_assoc($result)) {
$label = array();
$label['id'] = 'LABEL:' . $line['id'];
$label['bare_id'] = $line['id'];
$label['name'] = $line['caption'];
$label['fg_color'] = $line['fg_color'];
$label['bg_color'] = $line['bg_color'];
$label['type'] = 'label';
$label['checkbox'] = false;
array_push($root['items'], $label);
}
$fl = array();
$fl['identifier'] = 'id';
$fl['label'] = 'name';
$fl['items'] = array($root);
print json_encode($fl);
return;
}
function colorset() {
$kind = db_escape_string($_REQUEST["kind"]);
$ids = split(',', db_escape_string($_REQUEST["ids"]));
$color = db_escape_string($_REQUEST["color"]);
$fg = db_escape_string($_REQUEST["fg"]);
$bg = db_escape_string($_REQUEST["bg"]);
foreach ($ids as $id) {
if ($kind == "fg" || $kind == "bg") {
db_query($this->link, "UPDATE ttrss_labels2 SET
${kind}_color = '$color' WHERE id = '$id'
AND owner_uid = " . $_SESSION["uid"]);
} else {
db_query($this->link, "UPDATE ttrss_labels2 SET
fg_color = '$fg', bg_color = '$bg' WHERE id = '$id'
AND owner_uid = " . $_SESSION["uid"]);
}
$caption = db_escape_string(label_find_caption($this->link, $id, $_SESSION["uid"]));
/* Remove cached data */
db_query($this->link, "UPDATE ttrss_user_entries SET label_cache = ''
WHERE label_cache LIKE '%$caption%' AND owner_uid = " . $_SESSION["uid"]);
}
return;
}
function colorreset() {
$ids = split(',', db_escape_string($_REQUEST["ids"]));
foreach ($ids as $id) {
db_query($this->link, "UPDATE ttrss_labels2 SET
fg_color = '', bg_color = '' WHERE id = '$id'
AND owner_uid = " . $_SESSION["uid"]);
$caption = db_escape_string(label_find_caption($this->link, $id, $_SESSION["uid"]));
/* Remove cached data */
db_query($this->link, "UPDATE ttrss_user_entries SET label_cache = ''
WHERE label_cache LIKE '%$caption%' AND owner_uid = " . $_SESSION["uid"]);
}
}
function save() {
$id = db_escape_string($_REQUEST["id"]);
$caption = db_escape_string(trim($_REQUEST["caption"]));
db_query($this->link, "BEGIN");
$result = db_query($this->link, "SELECT caption FROM ttrss_labels2
WHERE id = '$id' AND owner_uid = ". $_SESSION["uid"]);
if (db_num_rows($result) != 0) {
$old_caption = db_fetch_result($result, 0, "caption");
$result = db_query($this->link, "SELECT id FROM ttrss_labels2
WHERE caption = '$caption' AND owner_uid = ". $_SESSION["uid"]);
if (db_num_rows($result) == 0) {
if ($caption) {
$result = db_query($this->link, "UPDATE ttrss_labels2 SET
caption = '$caption' WHERE id = '$id' AND
owner_uid = " . $_SESSION["uid"]);
/* Update filters that reference label being renamed */
$old_caption = db_escape_string($old_caption);
db_query($this->link, "UPDATE ttrss_filters SET
action_param = '$caption' WHERE action_param = '$old_caption'
AND action_id = 7
AND owner_uid = " . $_SESSION["uid"]);
print $_REQUEST["value"];
} else {
print $old_caption;
}
} else {
print $old_caption;
}
}
db_query($this->link, "COMMIT");
return;
}
function remove() {
$ids = split(",", db_escape_string($_REQUEST["ids"]));
foreach ($ids as $id) {
label_remove($this->link, $id, $_SESSION["uid"]);
}
}
function add() {
$caption = db_escape_string($_REQUEST["caption"]);
$output = db_escape_string($_REQUEST["output"]);
if ($caption) {
if (label_create($this->link, $caption)) {
if (!$output) {
print T_sprintf("Created label <b>%s</b>", htmlspecialchars($caption));
}
}
if ($output == "select") {
header("Content-Type: text/xml");
print "<rpc-reply><payload>";
print_label_select($this->link, "select_label",
$caption, "");
print "</payload></rpc-reply>";
}
}
return;
}
function index() {
$sort = db_escape_string($_REQUEST["sort"]);
if (!$sort || $sort == "undefined") {
$sort = "caption";
}
$label_search = db_escape_string($_REQUEST["search"]);
if (array_key_exists("search", $_REQUEST)) {
$_SESSION["prefs_label_search"] = $label_search;
} else {
$label_search = $_SESSION["prefs_label_search"];
}
print "<div id=\"pref-label-wrap\" dojoType=\"dijit.layout.BorderContainer\" gutters=\"false\">";
print "<div id=\"pref-label-header\" dojoType=\"dijit.layout.ContentPane\" region=\"top\">";
print "<div id=\"pref-label-toolbar\" dojoType=\"dijit.Toolbar\">";
print "<div dojoType=\"dijit.form.DropDownButton\">".
"<span>" . __('Select')."</span>";
print "<div dojoType=\"dijit.Menu\" style=\"display: none;\">";
print "<div onclick=\"dijit.byId('labelTree').model.setAllChecked(true)\"
dojoType=\"dijit.MenuItem\">".__('All')."</div>";
print "<div onclick=\"dijit.byId('labelTree').model.setAllChecked(false)\"
dojoType=\"dijit.MenuItem\">".__('None')."</div>";
print "</div></div>";
print"<button dojoType=\"dijit.form.Button\" onclick=\"return addLabel()\">".
__('Create label')."</button dojoType=\"dijit.form.Button\"> ";
print "<button dojoType=\"dijit.form.Button\" onclick=\"removeSelectedLabels()\">".
__('Remove')."</button dojoType=\"dijit.form.Button\"> ";
print "<button dojoType=\"dijit.form.Button\" onclick=\"labelColorReset()\">".
__('Clear colors')."</button dojoType=\"dijit.form.Button\">";
print "</div>"; #toolbar
print "</div>"; #pane
print "<div id=\"pref-label-content\" dojoType=\"dijit.layout.ContentPane\" region=\"center\">";
print "<div id=\"labellistLoading\">
<img src='images/indicator_tiny.gif'>".
__("Loading, please wait...")."</div>";
print "<div dojoType=\"dojo.data.ItemFileWriteStore\" jsId=\"labelStore\"
url=\"backend.php?op=pref-labels&method=getlabeltree\">
</div>
<div dojoType=\"lib.CheckBoxStoreModel\" jsId=\"labelModel\" store=\"labelStore\"
query=\"{id:'root'}\" rootId=\"root\"
childrenAttrs=\"items\" checkboxStrict=\"false\" checkboxAll=\"false\">
</div>
<div dojoType=\"fox.PrefLabelTree\" id=\"labelTree\"
model=\"labelModel\" openOnClick=\"true\">
<script type=\"dojo/method\" event=\"onLoad\" args=\"item\">
Element.hide(\"labellistLoading\");
</script>
<script type=\"dojo/method\" event=\"onClick\" args=\"item\">
var id = String(item.id);
var bare_id = id.substr(id.indexOf(':')+1);
if (id.match('LABEL:')) {
editLabel(bare_id);
}
</script>
</div>";
print "</div>"; #pane
print "</div>"; #container
}
}
?>

499
classes/pref/prefs.php Normal file
View File

@@ -0,0 +1,499 @@
<?php
class Pref_Prefs extends Handler_Protected {
function csrf_ignore($method) {
$csrf_ignored = array("index");
return array_search($method, $csrf_ignored) !== false;
}
function changepassword() {
$old_pw = $_POST["old_password"];
$new_pw = $_POST["new_password"];
$con_pw = $_POST["confirm_password"];
if ($old_pw == "") {
print "ERROR: ".__("Old password cannot be blank.");
return;
}
if ($new_pw == "") {
print "ERROR: ".__("New password cannot be blank.");
return;
}
if ($new_pw != $con_pw) {
print "ERROR: ".__("Entered passwords do not match.");
return;
}
$module_class = "auth_" . $_SESSION["auth_module"];
$authenticator = new $module_class($this->link);
if (method_exists($authenticator, "change_password")) {
print $authenticator->change_password($_SESSION["uid"], $old_pw, $new_pw);
} else {
print "ERROR: ".__("Function not supported by authentication module.");
}
}
function saveconfig() {
$_SESSION["prefs_cache"] = false;
$orig_theme = get_pref($this->link, "_THEME_ID");
foreach (array_keys($_POST) as $pref_name) {
$pref_name = db_escape_string($pref_name);
$value = db_escape_string($_POST[$pref_name]);
if ($pref_name == 'DIGEST_PREFERRED_TIME') {
if (get_pref($this->link, 'DIGEST_PREFERRED_TIME') != $value) {
db_query($this->link, "UPDATE ttrss_users SET
last_digest_sent = NULL WHERE id = " . $_SESSION['uid']);
}
}
set_pref($this->link, $pref_name, $value);
}
if ($orig_theme != get_pref($this->link, "_THEME_ID")) {
print "PREFS_THEME_CHANGED";
} else {
print __("The configuration was saved.");
}
}
function getHelp() {
$pref_name = db_escape_string($_REQUEST["pn"]);
$result = db_query($this->link, "SELECT help_text FROM ttrss_prefs
WHERE pref_name = '$pref_name'");
if (db_num_rows($result) > 0) {
$help_text = db_fetch_result($result, 0, "help_text");
print $help_text;
} else {
printf(__("Unknown option: %s"), $pref_name);
}
}
function changeemail() {
$email = db_escape_string($_POST["email"]);
$full_name = db_escape_string($_POST["full_name"]);
$active_uid = $_SESSION["uid"];
db_query($this->link, "UPDATE ttrss_users SET email = '$email',
full_name = '$full_name' WHERE id = '$active_uid'");
print __("Your personal data has been saved.");
return;
}
function resetconfig() {
$_SESSION["prefs_op_result"] = "reset-to-defaults";
if ($_SESSION["profile"]) {
$profile_qpart = "profile = '" . $_SESSION["profile"] . "'";
} else {
$profile_qpart = "profile IS NULL";
}
db_query($this->link, "DELETE FROM ttrss_user_prefs
WHERE $profile_qpart AND owner_uid = ".$_SESSION["uid"]);
initialize_user_prefs($this->link, $_SESSION["uid"], $_SESSION["profile"]);
print "PREFS_THEME_CHANGED";
}
function index() {
global $access_level_names;
$prefs_blacklist = array("HIDE_READ_FEEDS", "FEEDS_SORT_BY_UNREAD",
"STRIP_UNSAFE_TAGS");
$profile_blacklist = array("ALLOW_DUPLICATE_POSTS", "PURGE_OLD_DAYS",
"PURGE_UNREAD_ARTICLES", "DIGEST_ENABLE", "DIGEST_CATCHUP",
"BLACKLISTED_TAGS", "ENABLE_API_ACCESS", "UPDATE_POST_ON_CHECKSUM_CHANGE",
"DEFAULT_UPDATE_INTERVAL", "USER_TIMEZONE", "SORT_HEADLINES_BY_FEED_DATE",
"SSL_CERT_SERIAL", "DIGEST_PREFERRED_TIME");
$_SESSION["prefs_op_result"] = "";
print "<div dojoType=\"dijit.layout.AccordionContainer\" region=\"center\">";
print "<div dojoType=\"dijit.layout.AccordionPane\" title=\"".__('Personal data / Authentication')."\">";
print "<form dojoType=\"dijit.form.Form\" id=\"changeUserdataForm\">";
print "<script type=\"dojo/method\" event=\"onSubmit\" args=\"evt\">
evt.preventDefault();
if (this.validate()) {
notify_progress('Saving data...', true);
new Ajax.Request('backend.php', {
parameters: dojo.objectToQuery(this.getValues()),
onComplete: function(transport) {
notify_callback2(transport);
} });
}
</script>";
print "<table width=\"100%\" class=\"prefPrefsList\">";
$result = db_query($this->link, "SELECT email,full_name,
access_level FROM ttrss_users
WHERE id = ".$_SESSION["uid"]);
$email = htmlspecialchars(db_fetch_result($result, 0, "email"));
$full_name = htmlspecialchars(db_fetch_result($result, 0, "full_name"));
print "<tr><td width=\"40%\">".__('Full name')."</td>";
print "<td class=\"prefValue\"><input dojoType=\"dijit.form.ValidationTextBox\" name=\"full_name\" required=\"1\"
value=\"$full_name\"></td></tr>";
print "<tr><td width=\"40%\">".__('E-mail')."</td>";
print "<td class=\"prefValue\"><input dojoType=\"dijit.form.ValidationTextBox\" name=\"email\" required=\"1\" value=\"$email\"></td></tr>";
if (!SINGLE_USER_MODE && !$_SESSION["hide_hello"]) {
$access_level = db_fetch_result($result, 0, "access_level");
print "<tr><td width=\"40%\">".__('Access level')."</td>";
print "<td>" . $access_level_names[$access_level] . "</td></tr>";
}
print "</table>";
print "<input dojoType=\"dijit.form.TextBox\" style=\"display : none\" name=\"op\" value=\"pref-prefs\">";
print "<input dojoType=\"dijit.form.TextBox\" style=\"display : none\" name=\"method\" value=\"changeemail\">";
print "<p><button dojoType=\"dijit.form.Button\" type=\"submit\">".
__("Save data")."</button>";
print "</form>";
if ($_SESSION["auth_module"]) {
$module_class = "auth_" . $_SESSION["auth_module"];
$authenticator = new $module_class($this->link);
} else {
$authenticator = false;
}
if ($authenticator && method_exists($authenticator, "change_password")) {
$result = db_query($this->link, "SELECT id FROM ttrss_users
WHERE id = ".$_SESSION["uid"]." AND pwd_hash
= 'SHA1:5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8'");
if (db_num_rows($result) != 0) {
print format_warning(__("Your password is at default value, please change it."), "default_pass_warning");
}
print "<form dojoType=\"dijit.form.Form\">";
print "<script type=\"dojo/method\" event=\"onSubmit\" args=\"evt\">
evt.preventDefault();
if (this.validate()) {
notify_progress('Changing password...', true);
new Ajax.Request('backend.php', {
parameters: dojo.objectToQuery(this.getValues()),
onComplete: function(transport) {
notify('');
if (transport.responseText.indexOf('ERROR: ') == 0) {
notify_error(transport.responseText.replace('ERROR: ', ''));
} else {
notify_info(transport.responseText);
var warn = $('default_pass_warning');
if (warn) Element.hide(warn);
}
}});
this.reset();
}
</script>";
print "<table width=\"100%\" class=\"prefPrefsList\">";
print "<tr><td width=\"40%\">".__("Old password")."</td>";
print "<td class=\"prefValue\"><input dojoType=\"dijit.form.ValidationTextBox\" type=\"password\" required=\"1\" name=\"old_password\"></td></tr>";
print "<tr><td width=\"40%\">".__("New password")."</td>";
print "<td class=\"prefValue\"><input dojoType=\"dijit.form.ValidationTextBox\" type=\"password\" required=\"1\"
name=\"new_password\"></td></tr>";
print "<tr><td width=\"40%\">".__("Confirm password")."</td>";
print "<td class=\"prefValue\"><input dojoType=\"dijit.form.ValidationTextBox\" type=\"password\" required=\"1\" name=\"confirm_password\"></td></tr>";
print "</table>";
print "<input dojoType=\"dijit.form.TextBox\" style=\"display : none\" name=\"op\" value=\"pref-prefs\">";
print "<input dojoType=\"dijit.form.TextBox\" style=\"display : none\" name=\"method\" value=\"changepassword\">";
print "<p><button dojoType=\"dijit.form.Button\" type=\"submit\">".
__("Change password")."</button>";
print "</form>";
}
print "</div>"; #pane
print "<div dojoType=\"dijit.layout.AccordionPane\" selected=\"true\" title=\"".__('Preferences')."\">";
print "<form dojoType=\"dijit.form.Form\" id=\"changeSettingsForm\">";
print "<script type=\"dojo/method\" event=\"onSubmit\" args=\"evt\">
evt.preventDefault();
if (this.validate()) {
console.log(dojo.objectToQuery(this.getValues()));
new Ajax.Request('backend.php', {
parameters: dojo.objectToQuery(this.getValues()),
onComplete: function(transport) {
var msg = transport.responseText;
if (msg.match('PREFS_THEME_CHANGED')) {
window.location.reload();
} else {
notify_info(msg);
}
} });
}
</script>";
print '<div dojoType="dijit.layout.BorderContainer" gutters="false">';
print '<div dojoType="dijit.layout.ContentPane" region="center" style="overflow-y : auto">';
if ($_SESSION["profile"]) {
print_notice("Some preferences are only available in default profile.");
}
if ($_SESSION["profile"]) {
initialize_user_prefs($this->link, $_SESSION["uid"], $_SESSION["profile"]);
$profile_qpart = "profile = '" . $_SESSION["profile"] . "'";
} else {
initialize_user_prefs($this->link, $_SESSION["uid"]);
$profile_qpart = "profile IS NULL";
}
$result = db_query($this->link, "SELECT DISTINCT
ttrss_user_prefs.pref_name,short_desc,help_text,value,type_name,
section_name,def_value,section_id
FROM ttrss_prefs,ttrss_prefs_types,ttrss_prefs_sections,ttrss_user_prefs
WHERE type_id = ttrss_prefs_types.id AND
$profile_qpart AND
section_id = ttrss_prefs_sections.id AND
ttrss_user_prefs.pref_name = ttrss_prefs.pref_name AND
short_desc != '' AND
owner_uid = ".$_SESSION["uid"]."
ORDER BY section_id,short_desc");
$lnum = 0;
$active_section = "";
while ($line = db_fetch_assoc($result)) {
if (in_array($line["pref_name"], $prefs_blacklist)) {
continue;
}
if ($_SESSION["profile"] && in_array($line["pref_name"],
$profile_blacklist)) {
continue;
}
if ($active_section != $line["section_name"]) {
if ($active_section != "") {
print "</table>";
}
print "<table width=\"100%\" class=\"prefPrefsList\">";
$active_section = $line["section_name"];
print "<tr><td colspan=\"3\"><h3>".__($active_section)."</h3></td></tr>";
if ($line["section_id"] == 2) {
print "<tr><td width=\"40%\">".__("Select theme")."</td>";
$user_theme = get_pref($this->link, "_THEME_ID");
$themes = get_all_themes();
print "<td><select name=\"_THEME_ID\" dojoType=\"dijit.form.Select\">";
print "<option value='Default'>".__('Default')."</option>";
print "<option value='----------------' disabled=\"1\">--------</option>";
foreach ($themes as $t) {
$base = $t['base'];
$name = $t['name'];
if ($base == $user_theme) {
$selected = "selected=\"1\"";
} else {
$selected = "";
}
print "<option $selected value='$base'>$name</option>";
}
print "</select></td></tr>";
}
$lnum = 0;
}
print "<tr>";
$type_name = $line["type_name"];
$pref_name = $line["pref_name"];
$value = $line["value"];
$def_value = $line["def_value"];
$help_text = $line["help_text"];
print "<td width=\"40%\" class=\"prefName\" id=\"$pref_name\">" . __($line["short_desc"]);
if ($help_text) print "<div class=\"prefHelp\">".__($help_text)."</div>";
print "</td>";
print "<td class=\"prefValue\">";
if ($pref_name == "USER_TIMEZONE") {
$timezones = explode("\n", file_get_contents("lib/timezones.txt"));
print_select($pref_name, $value, $timezones, 'dojoType="dijit.form.FilteringSelect"');
} else if ($pref_name == "USER_STYLESHEET") {
print "<button dojoType=\"dijit.form.Button\"
onclick=\"customizeCSS()\">" . __('Customize') . "</button>";
} else if ($pref_name == "DEFAULT_ARTICLE_LIMIT") {
$limits = array(15, 30, 45, 60);
print_select($pref_name, $value, $limits,
'dojoType="dijit.form.Select"');
} else if ($pref_name == "DEFAULT_UPDATE_INTERVAL") {
global $update_intervals_nodefault;
print_select_hash($pref_name, $value, $update_intervals_nodefault,
'dojoType="dijit.form.Select"');
} else if ($type_name == "bool") {
if ($value == "true") {
$value = __("Yes");
} else {
$value = __("No");
}
if ($pref_name == "PURGE_UNREAD_ARTICLES" && FORCE_ARTICLE_PURGE != 0) {
$disabled = "disabled=\"1\"";
$value = __("Yes");
} else {
$disabled = "";
}
print_radio($pref_name, $value, __("Yes"), array(__("Yes"), __("No")),
$disabled);
} else if (array_search($pref_name, array('FRESH_ARTICLE_MAX_AGE', 'DEFAULT_ARTICLE_LIMIT',
'PURGE_OLD_DAYS', 'LONG_DATE_FORMAT', 'SHORT_DATE_FORMAT')) !== false) {
$regexp = ($type_name == 'integer') ? 'regexp="^\d*$"' : '';
if ($pref_name == "PURGE_OLD_DAYS" && FORCE_ARTICLE_PURGE != 0) {
$disabled = "disabled=\"1\"";
$value = FORCE_ARTICLE_PURGE;
} else {
$disabled = "";
}
print "<input dojoType=\"dijit.form.ValidationTextBox\"
required=\"1\" $regexp $disabled
name=\"$pref_name\" value=\"$value\">";
} else if ($pref_name == "SSL_CERT_SERIAL") {
print "<input dojoType=\"dijit.form.ValidationTextBox\"
id=\"SSL_CERT_SERIAL\" readonly=\"1\"
name=\"$pref_name\" value=\"$value\">";
$cert_serial = htmlspecialchars(get_ssl_certificate_id());
$has_serial = ($cert_serial) ? "false" : "true";
print " <button dojoType=\"dijit.form.Button\" disabled=\"$has_serial\"
onclick=\"insertSSLserial('$cert_serial')\">" .
__('Register') . "</button>";
print " <button dojoType=\"dijit.form.Button\"
onclick=\"insertSSLserial('')\">" .
__('Clear') . "</button>";
} else if ($pref_name == 'DIGEST_PREFERRED_TIME') {
print "<input dojoType=\"dijit.form.ValidationTextBox\"
id=\"$pref_name\" regexp=\"[012]?\d:\d\d\" placeHolder=\"12:00\"
name=\"$pref_name\" value=\"$value\"><div class=\"insensitive\">".
T_sprintf("Current server time: %s (UTC)", date("H:i")) . "</div>";
} else {
$regexp = ($type_name == 'integer') ? 'regexp="^\d*$"' : '';
print "<input dojoType=\"dijit.form.ValidationTextBox\"
$regexp
name=\"$pref_name\" value=\"$value\">";
}
print "</td>";
print "</tr>";
$lnum++;
}
print "</table>";
print '</div>'; # inside pane
print '<div dojoType="dijit.layout.ContentPane" region="bottom">';
print "<input dojoType=\"dijit.form.TextBox\" style=\"display : none\" name=\"op\" value=\"pref-prefs\">";
print "<input dojoType=\"dijit.form.TextBox\" style=\"display : none\" name=\"method\" value=\"saveconfig\">";
print "<button dojoType=\"dijit.form.Button\" type=\"submit\">".
__('Save configuration')."</button> ";
print "<button dojoType=\"dijit.form.Button\" onclick=\"return editProfiles()\">".
__('Manage profiles')."</button> ";
print "<button dojoType=\"dijit.form.Button\" onclick=\"return validatePrefsReset()\">".
__('Reset to defaults')."</button>";
print '</div>'; # inner pane
print '</div>'; # border container
print "</form>";
print "</div>"; #pane
print "</div>"; #container
}
}
?>

494
classes/pref/users.php Normal file
View File

@@ -0,0 +1,494 @@
<?php
class Pref_Users extends Handler_Protected {
function before($method) {
if (parent::before($method)) {
if ($_SESSION["access_level"] < 10) {
print __("Your access level is insufficient to open this tab.");
return false;
}
return true;
}
return false;
}
function csrf_ignore($method) {
$csrf_ignored = array("index");
return array_search($method, $csrf_ignored) !== false;
}
function userdetails() {
header("Content-Type: text/xml");
print "<dlg>";
$uid = sprintf("%d", $_REQUEST["id"]);
print "<title>".__('User details')."</title>";
print "<content><![CDATA[";
$result = db_query($this->link, "SELECT login,
".SUBSTRING_FOR_DATE."(last_login,1,16) AS last_login,
access_level,
(SELECT COUNT(int_id) FROM ttrss_user_entries
WHERE owner_uid = id) AS stored_articles,
".SUBSTRING_FOR_DATE."(created,1,16) AS created
FROM ttrss_users
WHERE id = '$uid'");
if (db_num_rows($result) == 0) {
print "<h1>".__('User not found')."</h1>";
return;
}
// print "<h1>User Details</h1>";
$login = db_fetch_result($result, 0, "login");
print "<table width='100%'>";
$last_login = make_local_datetime($this->link,
db_fetch_result($result, 0, "last_login"), true);
$created = make_local_datetime($this->link,
db_fetch_result($result, 0, "created"), true);
$access_level = db_fetch_result($result, 0, "access_level");
$stored_articles = db_fetch_result($result, 0, "stored_articles");
print "<tr><td>".__('Registered')."</td><td>$created</td></tr>";
print "<tr><td>".__('Last logged in')."</td><td>$last_login</td></tr>";
$result = db_query($this->link, "SELECT COUNT(id) as num_feeds FROM ttrss_feeds
WHERE owner_uid = '$uid'");
$num_feeds = db_fetch_result($result, 0, "num_feeds");
print "<tr><td>".__('Subscribed feeds count')."</td><td>$num_feeds</td></tr>";
print "</table>";
print "<h1>".__('Subscribed feeds')."</h1>";
$result = db_query($this->link, "SELECT id,title,site_url FROM ttrss_feeds
WHERE owner_uid = '$uid' ORDER BY title");
print "<ul class=\"userFeedList\">";
$row_class = "odd";
while ($line = db_fetch_assoc($result)) {
$icon_file = ICONS_URL."/".$line["id"].".ico";
if (file_exists($icon_file) && filesize($icon_file) > 0) {
$feed_icon = "<img class=\"tinyFeedIcon\" src=\"$icon_file\">";
} else {
$feed_icon = "<img class=\"tinyFeedIcon\" src=\"images/blank_icon.gif\">";
}
print "<li class=\"$row_class\">$feed_icon&nbsp;<a href=\"".$line["site_url"]."\">".$line["title"]."</a></li>";
$row_class = $row_class == "even" ? "odd" : "even";
}
if (db_num_rows($result) < $num_feeds) {
// FIXME - add link to show ALL subscribed feeds here somewhere
print "<li><img
class=\"tinyFeedIcon\" src=\"images/blank_icon.gif\">&nbsp;...</li>";
}
print "</ul>";
print "<div align='center'>
<button onclick=\"closeInfoBox()\">".__("Close this window").
"</button></div>";
print "]]></content></dlg>";
return;
}
function edit() {
global $access_level_names;
header("Content-Type: text/xml");
$id = db_escape_string($_REQUEST["id"]);
print "<dlg id=\"$method\">";
print "<title>".__('User Editor')."</title>";
print "<content><![CDATA[";
print "<form id=\"user_edit_form\" onsubmit='return false'>";
print "<input type=\"hidden\" name=\"id\" value=\"$id\">";
print "<input type=\"hidden\" name=\"op\" value=\"pref-users\">";
print "<input type=\"hidden\" name=\"method\" value=\"editSave\">";
$result = db_query($this->link, "SELECT * FROM ttrss_users WHERE id = '$id'");
$login = db_fetch_result($result, 0, "login");
$access_level = db_fetch_result($result, 0, "access_level");
$email = db_fetch_result($result, 0, "email");
$sel_disabled = ($id == $_SESSION["uid"]) ? "disabled" : "";
print "<div class=\"dlgSec\">".__("User")."</div>";
print "<div class=\"dlgSecCont\">";
if ($sel_disabled) {
print "<input type=\"hidden\" name=\"login\" value=\"$login\">";
print "<input size=\"30\" style=\"font-size : 16px\"
onkeypress=\"return filterCR(event, userEditSave)\" $sel_disabled
value=\"$login\">";
} else {
print "<input size=\"30\" style=\"font-size : 16px\"
onkeypress=\"return filterCR(event, userEditSave)\" $sel_disabled
name=\"login\" value=\"$login\">";
}
print "</div>";
print "<div class=\"dlgSec\">".__("Authentication")."</div>";
print "<div class=\"dlgSecCont\">";
print __('Access level: ') . " ";
if (!$sel_disabled) {
print_select_hash("access_level", $access_level, $access_level_names,
$sel_disabled);
} else {
print_select_hash("", $access_level, $access_level_names,
$sel_disabled);
print "<input type=\"hidden\" name=\"access_level\" value=\"$access_level\">";
}
print "<br/>";
print __('Change password to') .
" <input size=\"20\" onkeypress=\"return filterCR(event, userEditSave)\"
name=\"password\">";
print "</div>";
print "<div class=\"dlgSec\">".__("Options")."</div>";
print "<div class=\"dlgSecCont\">";
print __('E-mail: ').
" <input size=\"30\" name=\"email\" onkeypress=\"return filterCR(event, userEditSave)\"
value=\"$email\">";
print "</div>";
print "</table>";
print "</form>";
print "<div class=\"dlgButtons\">
<button onclick=\"return userEditSave()\">".
__('Save')."</button>
<button onclick=\"return userEditCancel()\">".
__('Cancel')."</button></div>";
print "]]></content></dlg>";
return;
}
function editSave() {
$login = db_escape_string(trim($_REQUEST["login"]));
$uid = db_escape_string($_REQUEST["id"]);
$access_level = (int) $_REQUEST["access_level"];
$email = db_escape_string(trim($_REQUEST["email"]));
$password = db_escape_string(trim($_REQUEST["password"]));
if ($password) {
$salt = substr(bin2hex(get_random_bytes(125)), 0, 250);
$pwd_hash = encrypt_password($password, $salt, true);
$pass_query_part = "pwd_hash = '$pwd_hash', salt = '$salt',";
} else {
$pass_query_part = "";
}
db_query($this->link, "UPDATE ttrss_users SET $pass_query_part login = '$login',
access_level = '$access_level', email = '$email' WHERE id = '$uid'");
}
function remove() {
$ids = split(",", db_escape_string($_REQUEST["ids"]));
foreach ($ids as $id) {
if ($id != $_SESSION["uid"] && $id != 1) {
db_query($this->link, "DELETE FROM ttrss_tags WHERE owner_uid = '$id'");
db_query($this->link, "DELETE FROM ttrss_feeds WHERE owner_uid = '$id'");
db_query($this->link, "DELETE FROM ttrss_users WHERE id = '$id'");
}
}
}
function add() {
$login = db_escape_string(trim($_REQUEST["login"]));
$tmp_user_pwd = make_password(8);
$salt = substr(bin2hex(get_random_bytes(125)), 0, 250);
$pwd_hash = encrypt_password($tmp_user_pwd, $salt, true);
$result = db_query($this->link, "SELECT id FROM ttrss_users WHERE
login = '$login'");
if (db_num_rows($result) == 0) {
db_query($this->link, "INSERT INTO ttrss_users
(login,pwd_hash,access_level,last_login,created, salt)
VALUES ('$login', '$pwd_hash', 0, null, NOW(), '$salt')");
$result = db_query($this->link, "SELECT id FROM ttrss_users WHERE
login = '$login' AND pwd_hash = '$pwd_hash'");
if (db_num_rows($result) == 1) {
$new_uid = db_fetch_result($result, 0, "id");
print format_notice(T_sprintf("Added user <b>%s</b> with password <b>%s</b>",
$login, $tmp_user_pwd));
initialize_user($this->link, $new_uid);
} else {
print format_warning(T_sprintf("Could not create user <b>%s</b>", $login));
}
} else {
print format_warning(T_sprintf("User <b>%s</b> already exists.", $login));
}
}
function resetPass() {
$uid = db_escape_string($_REQUEST["id"]);
$result = db_query($this->link, "SELECT login,email
FROM ttrss_users WHERE id = '$uid'");
$login = db_fetch_result($result, 0, "login");
$email = db_fetch_result($result, 0, "email");
$salt = db_fetch_result($result, 0, "salt");
$new_salt = substr(bin2hex(get_random_bytes(125)), 0, 250);
$tmp_user_pwd = make_password(8);
$pwd_hash = encrypt_password($tmp_user_pwd, $new_salt, true);
db_query($this->link, "UPDATE ttrss_users SET pwd_hash = '$pwd_hash', salt = '$new_salt'
WHERE id = '$uid'");
print T_sprintf("Changed password of user <b>%s</b>
to <b>%s</b>", $login, $tmp_user_pwd);
require_once 'lib/phpmailer/class.phpmailer.php';
if ($email) {
print " ";
print T_sprintf("Notifying <b>%s</b>.", $email);
require_once "lib/MiniTemplator.class.php";
$tpl = new MiniTemplator;
$tpl->readTemplateFromFile("templates/resetpass_template.txt");
$tpl->setVariable('LOGIN', $login);
$tpl->setVariable('NEWPASS', $tmp_user_pwd);
$tpl->addBlock('message');
$message = "";
$tpl->generateOutputToString($message);
$mail = new PHPMailer();
$mail->PluginDir = "lib/phpmailer/";
$mail->SetLanguage("en", "lib/phpmailer/language/");
$mail->CharSet = "UTF-8";
$mail->From = SMTP_FROM_ADDRESS;
$mail->FromName = SMTP_FROM_NAME;
$mail->AddAddress($email, $login);
if (SMTP_HOST) {
$mail->Host = SMTP_HOST;
$mail->Mailer = "smtp";
$mail->SMTPAuth = SMTP_LOGIN != '';
$mail->Username = SMTP_LOGIN;
$mail->Password = SMTP_PASSWORD;
}
$mail->IsHTML(false);
$mail->Subject = __("[tt-rss] Password change notification");
$mail->Body = $message;
$rc = $mail->Send();
if (!$rc) print_error($mail->ErrorInfo);
}
print "</div>";
}
function index() {
global $access_level_names;
print "<div id=\"pref-user-wrap\" dojoType=\"dijit.layout.BorderContainer\" gutters=\"false\">";
print "<div id=\"pref-user-header\" dojoType=\"dijit.layout.ContentPane\" region=\"top\">";
print "<div id=\"pref-user-toolbar\" dojoType=\"dijit.Toolbar\">";
$user_search = db_escape_string($_REQUEST["search"]);
if (array_key_exists("search", $_REQUEST)) {
$_SESSION["prefs_user_search"] = $user_search;
} else {
$user_search = $_SESSION["prefs_user_search"];
}
print "<div style='float : right; padding-right : 4px;'>
<input dojoType=\"dijit.form.TextBox\" id=\"user_search\" size=\"20\" type=\"search\"
value=\"$user_search\">
<button dojoType=\"dijit.form.Button\" onclick=\"javascript:updateUsersList()\">".
__('Search')."</button>
</div>";
$sort = db_escape_string($_REQUEST["sort"]);
if (!$sort || $sort == "undefined") {
$sort = "login";
}
print "<div dojoType=\"dijit.form.DropDownButton\">".
"<span>" . __('Select')."</span>";
print "<div dojoType=\"dijit.Menu\" style=\"display: none;\">";
print "<div onclick=\"selectTableRows('prefUserList', 'all')\"
dojoType=\"dijit.MenuItem\">".__('All')."</div>";
print "<div onclick=\"selectTableRows('prefUserList', 'none')\"
dojoType=\"dijit.MenuItem\">".__('None')."</div>";
print "</div></div>";
print "<button dojoType=\"dijit.form.Button\" onclick=\"javascript:addUser()\">".__('Create user')."</button>";
print "
<button dojoType=\"dijit.form.Button\" onclick=\"javascript:selectedUserDetails()\">".
__('Details')."</button dojoType=\"dijit.form.Button\">
<button dojoType=\"dijit.form.Button\" onclick=\"javascript:editSelectedUser()\">".
__('Edit')."</button dojoType=\"dijit.form.Button\">
<button dojoType=\"dijit.form.Button\" onclick=\"javascript:removeSelectedUsers()\">".
__('Remove')."</button dojoType=\"dijit.form.Button\">
<button dojoType=\"dijit.form.Button\" onclick=\"javascript:resetSelectedUserPass()\">".
__('Reset password')."</button dojoType=\"dijit.form.Button\">";
print "</div>"; #toolbar
print "</div>"; #pane
print "<div id=\"pref-user-content\" dojoType=\"dijit.layout.ContentPane\" region=\"center\">";
print "<div id=\"sticky-status-msg\"></div>";
if ($user_search) {
$user_search = split(" ", $user_search);
$tokens = array();
foreach ($user_search as $token) {
$token = trim($token);
array_push($tokens, "(UPPER(login) LIKE UPPER('%$token%'))");
}
$user_search_query = "(" . join($tokens, " AND ") . ") AND ";
} else {
$user_search_query = "";
}
$result = db_query($this->link, "SELECT
id,login,access_level,email,
".SUBSTRING_FOR_DATE."(last_login,1,16) as last_login,
".SUBSTRING_FOR_DATE."(created,1,16) as created
FROM
ttrss_users
WHERE
$user_search_query
id > 0
ORDER BY $sort");
if (db_num_rows($result) > 0) {
print "<p><table width=\"100%\" cellspacing=\"0\"
class=\"prefUserList\" id=\"prefUserList\">";
print "<tr class=\"title\">
<td align='center' width=\"5%\">&nbsp;</td>
<td width=''><a href=\"#\" onclick=\"updateUsersList('login')\">".__('Login')."</a></td>
<td width='20%'><a href=\"#\" onclick=\"updateUsersList('access_level')\">".__('Access Level')."</a></td>
<td width='20%'><a href=\"#\" onclick=\"updateUsersList('created')\">".__('Registered')."</a></td>
<td width='20%'><a href=\"#\" onclick=\"updateUsersList('last_login')\">".__('Last login')."</a></td></tr>";
$lnum = 0;
while ($line = db_fetch_assoc($result)) {
$class = ($lnum % 2) ? "even" : "odd";
$uid = $line["id"];
print "<tr class=\"$class\" id=\"UMRR-$uid\">";
$line["login"] = htmlspecialchars($line["login"]);
$line["created"] = make_local_datetime($this->link, $line["created"], false);
$line["last_login"] = make_local_datetime($this->link, $line["last_login"], false);
print "<td align='center'><input onclick='toggleSelectRow(this);'
type=\"checkbox\" id=\"UMCHK-$uid\"></td>";
$onclick = "onclick='editUser($uid, event)' title='".__('Click to edit')."'";
print "<td $onclick>" . $line["login"] . "</td>";
if (!$line["email"]) $line["email"] = "&nbsp;";
print "<td $onclick>" . $access_level_names[$line["access_level"]] . "</td>";
print "<td $onclick>" . $line["created"] . "</td>";
print "<td $onclick>" . $line["last_login"] . "</td>";
print "</tr>";
++$lnum;
}
print "</table>";
} else {
print "<p>";
if (!$user_search) {
print_warning(__('No users defined.'));
} else {
print_warning(__('No matching users found.'));
}
print "</p>";
}
print "</div>"; #pane
print "</div>"; #container
}
}
?>