Feeds: load quickaddfeed and search dialogs via XHR w/ CSRF protection

master
Andrew Dolgov 4 years ago
parent 8080c525fd
commit cbcb10a272

@ -8,7 +8,7 @@ class Feeds extends Handler_Protected {
private $params; private $params;
function csrf_ignore($method) { function csrf_ignore($method) {
$csrf_ignored = array("index", "quickaddfeed", "search"); $csrf_ignored = array("index");
return array_search($method, $csrf_ignored) !== false; return array_search($method, $csrf_ignored) !== false;
} }

@ -75,116 +75,120 @@ const CommonDialogs = {
return false; return false;
}, },
quickAddFeed: function() { quickAddFeed: function() {
const query = "backend.php?op=feeds&method=quickAddFeed";
// overlapping widgets // overlapping widgets
if (dijit.byId("batchSubDlg")) dijit.byId("batchSubDlg").destroyRecursive(); if (dijit.byId("batchSubDlg")) dijit.byId("batchSubDlg").destroyRecursive();
if (dijit.byId("feedAddDlg")) dijit.byId("feedAddDlg").destroyRecursive(); if (dijit.byId("feedAddDlg")) dijit.byId("feedAddDlg").destroyRecursive();
const dialog = new dijit.Dialog({ xhrPost("backend.php",
id: "feedAddDlg", {op: "feeds", method: "quickAddFeed"},
title: __("Subscribe to Feed"), (transport) => {
style: "width: 600px",
show_error: function (msg) {
const elem = $("fadd_error_message");
elem.innerHTML = msg;
if (!Element.visible(elem))
new Effect.Appear(elem);
},
execute: function () {
if (this.validate()) {
console.log(dojo.objectToQuery(this.attr('value')));
const feed_url = this.attr('value').feed;
Element.show("feed_add_spinner");
Element.hide("fadd_error_message");
xhrPost("backend.php", this.attr('value'), (transport) => {
try {
let reply;
try { const dialog = new dijit.Dialog({
reply = JSON.parse(transport.responseText); id: "feedAddDlg",
} catch (e) { title: __("Subscribe to Feed"),
Element.hide("feed_add_spinner"); style: "width: 600px",
alert(__("Failed to parse output. This can indicate server timeout and/or network issues. Backend output was logged to browser console.")); content: transport.responseText,
console.log('quickAddFeed, backend returned:' + transport.responseText); show_error: function (msg) {
return; const elem = $("fadd_error_message");
}
const rc = reply['result'];
Notify.close();
Element.hide("feed_add_spinner");
console.log(rc); elem.innerHTML = msg;
switch (parseInt(rc['code'])) { if (!Element.visible(elem))
case 1: new Effect.Appear(elem);
dialog.hide();
Notify.info(__("Subscribed to %s").replace("%s", feed_url));
if (App.isPrefs()) },
dijit.byId("feedTree").reload(); execute: function () {
else if (this.validate()) {
Feeds.reload(); console.log(dojo.objectToQuery(this.attr('value')));
break; const feed_url = this.attr('value').feed;
case 2:
dialog.show_error(__("Specified URL seems to be invalid."));
break;
case 3:
dialog.show_error(__("Specified URL doesn't seem to contain any feeds."));
break;
case 4:
{
const feeds = rc['feeds'];
Element.show("fadd_multiple_notify"); Element.show("feed_add_spinner");
Element.hide("fadd_error_message");
const select = dijit.byId("feedDlg_feedContainerSelect"); xhrPost("backend.php", this.attr('value'), (transport) => {
try {
while (select.getOptions().length > 0) let reply;
select.removeOption(0);
select.addOption({value: '', label: __("Expand to select feed")}); try {
reply = JSON.parse(transport.responseText);
} catch (e) {
Element.hide("feed_add_spinner");
alert(__("Failed to parse output. This can indicate server timeout and/or network issues. Backend output was logged to browser console."));
console.log('quickAddFeed, backend returned:' + transport.responseText);
return;
}
for (const feedUrl in feeds) { const rc = reply['result'];
if (feeds.hasOwnProperty(feedUrl)) {
select.addOption({value: feedUrl, label: feeds[feedUrl]}); Notify.close();
} Element.hide("feed_add_spinner");
console.log(rc);
switch (parseInt(rc['code'])) {
case 1:
dialog.hide();
Notify.info(__("Subscribed to %s").replace("%s", feed_url));
if (App.isPrefs())
dijit.byId("feedTree").reload();
else
Feeds.reload();
break;
case 2:
dialog.show_error(__("Specified URL seems to be invalid."));
break;
case 3:
dialog.show_error(__("Specified URL doesn't seem to contain any feeds."));
break;
case 4:
{
const feeds = rc['feeds'];
Element.show("fadd_multiple_notify");
const select = dijit.byId("feedDlg_feedContainerSelect");
while (select.getOptions().length > 0)
select.removeOption(0);
select.addOption({value: '', label: __("Expand to select feed")});
for (const feedUrl in feeds) {
if (feeds.hasOwnProperty(feedUrl)) {
select.addOption({value: feedUrl, label: feeds[feedUrl]});
}
}
Effect.Appear('feedDlg_feedsContainer', {duration: 0.5});
}
break;
case 5:
dialog.show_error(__("Couldn't download the specified URL: %s").replace("%s", rc['message']));
break;
case 6:
dialog.show_error(__("XML validation failed: %s").replace("%s", rc['message']));
break;
case 0:
dialog.show_error(__("You are already subscribed to this feed."));
break;
} }
Effect.Appear('feedDlg_feedsContainer', {duration: 0.5}); } catch (e) {
console.error(transport.responseText);
App.Error.report(e);
} }
break; });
case 5:
dialog.show_error(__("Couldn't download the specified URL: %s").replace("%s", rc['message']));
break;
case 6:
dialog.show_error(__("XML validation failed: %s").replace("%s", rc['message']));
break;
case 0:
dialog.show_error(__("You are already subscribed to this feed."));
break;
} }
},
} catch (e) {
console.error(transport.responseText);
App.Error.report(e);
}
}); });
}
},
href: query
});
dialog.show(); dialog.show();
});
}, },
showFeedsWithErrors: function() { showFeedsWithErrors: function() {
const query = {op: "pref-feeds", method: "feedsWithErrors"}; const query = {op: "pref-feeds", method: "feedsWithErrors"};

@ -552,47 +552,50 @@ const Feeds = {
return tree.model.store.getValue(nuf, 'bare_id'); return tree.model.store.getValue(nuf, 'bare_id');
}, },
search: function() { search: function() {
const query = "backend.php?op=feeds&method=search&param=" +
encodeURIComponent(Feeds.getActive() + ":" + Feeds.activeIsCat());
if (dijit.byId("searchDlg")) if (dijit.byId("searchDlg"))
dijit.byId("searchDlg").destroyRecursive(); dijit.byId("searchDlg").destroyRecursive();
const dialog = new dijit.Dialog({ xhrPost("backend.php",
id: "searchDlg", {op: "feeds", method: "search",
title: __("Search"), param: Feeds.getActive() + ":" + Feeds.activeIsCat()},
style: "width: 600px", (transport) => {
execute: function () { const dialog = new dijit.Dialog({
if (this.validate()) { id: "searchDlg",
Feeds._search_query = this.attr('value'); content: transport.responseText,
title: __("Search"),
// disallow empty queries style: "width: 600px",
if (!Feeds._search_query.query) execute: function () {
Feeds._search_query = false; if (this.validate()) {
Feeds._search_query = this.attr('value');
this.hide();
Feeds.reloadCurrent(); // disallow empty queries
} if (!Feeds._search_query.query)
}, Feeds._search_query = false;
href: query
}); this.hide();
Feeds.reloadCurrent();
const tmph = dojo.connect(dialog, 'onLoad', function () { }
dojo.disconnect(tmph); },
});
if (Feeds._search_query) {
if (Feeds._search_query.query) const tmph = dojo.connect(dialog, 'onLoad', function () {
dijit.byId('search_query') dojo.disconnect(tmph);
.attr('value', Feeds._search_query.query);
if (Feeds._search_query) {
if (Feeds._search_query.search_language) if (Feeds._search_query.query)
dijit.byId('search_language') dijit.byId('search_query')
.attr('value', Feeds._search_query.search_language); .attr('value', Feeds._search_query.query);
}
if (Feeds._search_query.search_language)
}); dijit.byId('search_language')
.attr('value', Feeds._search_query.search_language);
}
});
dialog.show();
});
dialog.show();
}, },
updateRandom: function() { updateRandom: function() {
console.log("in update_random_feed"); console.log("in update_random_feed");

Loading…
Cancel
Save