diff --git a/backend.php b/backend.php index 206d866b7..e310322f2 100644 --- a/backend.php +++ b/backend.php @@ -135,6 +135,9 @@ } else { if (method_exists($handler, "catchall")) { $handler->catchall($method); + } else { + header("Content-Type: text/json"); + print Errors::to_json(Errors::E_UNKNOWN_METHOD, ["info" => get_class($handler) . "->$method"]); } } $handler->after(); @@ -154,6 +157,6 @@ } header("Content-Type: text/json"); - print Errors::to_json(Errors::E_UNKNOWN_METHOD); + print Errors::to_json(Errors::E_UNKNOWN_METHOD, ["info" => get_class($handler) . "->$method"]); ?> diff --git a/classes/pref/prefs.php b/classes/pref/prefs.php index 14ca9b49c..7ab9966ba 100644 --- a/classes/pref/prefs.php +++ b/classes/pref/prefs.php @@ -842,6 +842,8 @@ class Pref_Prefs extends Handler_Protected { $is_checked = "checked='1'"; } + $can_update = is_dir(dirname(dirname(__DIR__)) . "/plugins.local/$name/.git"); + ?>
@@ -853,12 +855,19 @@ class Pref_Prefs extends Handler_Protected { + = 10 && $can_update) { ?> + + + get_all($plugin)) > 0) { if (in_array($name, $system_enabled) || in_array($name, $user_enabled)) { ?> - @@ -937,6 +946,12 @@ class Pref_Prefs extends Handler_Protected { + = 10) { ?> + + @@ -1073,6 +1088,59 @@ class Pref_Prefs extends Handler_Protected { set_pref(Prefs::_ENABLED_PLUGINS, $plugins); } + private function _update_plugin($root_dir, $plugin_name) { + $plugin_dir = "$root_dir/plugins.local/" . basename($plugin_name); + $rv = []; + + if (is_dir($plugin_dir) && is_dir("$plugin_dir/.git")) { + $pipes = []; + + $descriptorspec = [ + 0 => ["pipe", "r"], // STDIN + 1 => ["pipe", "w"], // STDOUT + 2 => ["pipe", "w"], // STDERR + ]; + + $proc = proc_open("git pull --ff-only -q origin master", $descriptorspec, $pipes, $plugin_dir); + + if (is_resource($proc)) { + $rv["o"] = stream_get_contents($pipes[1]); + $rv["e"] = stream_get_contents($pipes[2]); + $status = proc_close($proc); + $rv["s"] = $status; + } + } + + return $rv; + } + + function updateLocalPlugins() { + if ($_SESSION["access_level"] >= 10) { + $plugin_name = $_REQUEST["name"] ?? ""; + + # we're in classes/pref/ + $root_dir = dirname(dirname(__DIR__)); + + $rv = []; + + if (!empty($plugin_name)) { + array_push($rv, ["plugin" => $plugin_name, "rv" => $this->_update_plugin($root_dir, $plugin_name)]); + } else { + $plugin_dirs = array_filter(glob("$root_dir/plugins.local/*"), "is_dir"); + + foreach ($plugin_dirs as $dir) { + if (is_dir("$dir/.git")) { + $plugin_name = basename($dir); + + array_push($rv, ["plugin" => $plugin_name, "rv" => $this->_update_plugin($root_dir, $plugin_name)]); + } + } + } + + print json_encode($rv); + } + } + function clearplugindata() { $name = clean($_REQUEST["name"]); diff --git a/js/PrefHelpers.js b/js/PrefHelpers.js index 62f6d91b1..125cc20d0 100644 --- a/js/PrefHelpers.js +++ b/js/PrefHelpers.js @@ -278,15 +278,6 @@ const Helpers = { }); } }, - clearPluginData: function(name) { - if (confirm(__("Clear stored data for this plugin?"))) { - Notify.progress("Loading, please wait..."); - - xhr.post("backend.php", {op: "pref-prefs", method: "clearplugindata", name: name}, () => { - Helpers.Prefs.refresh(); - }); - } - }, refresh: function() { xhr.post("backend.php", { op: "pref-prefs" }, (reply) => { dijit.byId('prefsTab').attr('content', reply); @@ -294,6 +285,67 @@ const Helpers = { }); }, }, + Plugins: { + clearPluginData: function(name) { + if (confirm(__("Clear stored data for this plugin?"))) { + Notify.progress("Loading, please wait..."); + + xhr.post("backend.php", {op: "pref-prefs", method: "clearPluginData", name: name}, () => { + Helpers.Prefs.refresh(); + }); + } + }, + updateLocal: function(name = null) { + const msg = name ? __("Update %p using git?").replace("%p", name) : + __("Update all local plugins using git?"); + + if (confirm(msg)) { + + const dialog = new fox.SingleUseDialog({ + title: __("Plugin Updater"), + content: ` + + + + `, + }); + + const tmph = dojo.connect(dialog, 'onShow', function () { + dojo.disconnect(tmph); + + xhr.json("backend.php", {op: "pref-prefs", method: "updateLocalPlugins", name: name}, (reply) => { + const container = dialog.domNode.querySelector(".update-results"); + + if (!reply) { + container.innerHTML = __("Operation failed: check event log."); + } else { + container.innerHTML = ""; + + reply.forEach((p) => { + container.innerHTML += + ` +
  • ${p.plugin}

    + ${p.rv.e ? `
    ${p.rv.e}
    ` : ''} + ${p.rv.o ? `
    ${p.rv.o}
    ` : ''} +

    + ${p.rv.s ? __("Exited with RC: %d").replace("%d", p.rv.s) : __("OK")} +

    +
  • + ` + }); + } + }); + + }); + + dialog.show(); + } + }, + }, OPML: { import: function() { const opml_file = App.byId("opml_file");