summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/ep.json4
-rw-r--r--src/node/hooks/express/adminplugins.js34
-rw-r--r--src/static/js/pluginfw/installer.js45
-rw-r--r--src/templates/admin/plugins.html86
4 files changed, 167 insertions, 2 deletions
diff --git a/src/ep.json b/src/ep.json
index 59cbf3aa..a4242890 100644
--- a/src/ep.json
+++ b/src/ep.json
@@ -8,7 +8,7 @@
{ "name": "apicalls", "hooks": { "expressCreateServer": "ep_etherpad-lite/node/hooks/express/apicalls:expressCreateServer" } },
{ "name": "importexport", "hooks": { "expressCreateServer": "ep_etherpad-lite/node/hooks/express/importexport:expressCreateServer" } },
{ "name": "errorhandling", "hooks": { "expressCreateServer": "ep_etherpad-lite/node/hooks/express/errorhandling:expressCreateServer" } },
- { "name": "socketio", "hooks": { "expressCreateServer": "ep_etherpad-lite/node/hooks/express/socketio:expressCreateServer" } }
-
+ { "name": "socketio", "hooks": { "expressCreateServer": "ep_etherpad-lite/node/hooks/express/socketio:expressCreateServer" } },
+ { "name": "adminplugins", "hooks": { "expressCreateServer": "ep_etherpad-lite/node/hooks/express/adminplugins:expressCreateServer" } }
]
}
diff --git a/src/node/hooks/express/adminplugins.js b/src/node/hooks/express/adminplugins.js
new file mode 100644
index 00000000..a3fbc2af
--- /dev/null
+++ b/src/node/hooks/express/adminplugins.js
@@ -0,0 +1,34 @@
+var path = require('path');
+var eejs = require('ep_etherpad-lite/node/eejs');
+var installer = require('ep_etherpad-lite/static/js/pluginfw/installer');
+
+exports.expressCreateServer = function (hook_name, args, cb) {
+ args.app.get('/admin/plugins', function(req, res) {
+ var plugins = require("ep_etherpad-lite/static/js/pluginfw/plugins");
+ var render_args = {
+ plugins: plugins.plugins,
+ query: req.query,
+ search_results: {},
+ errors: [],
+ };
+
+ var render = function () {
+ res.send(eejs.require(
+ "ep_etherpad-lite/templates/admin/plugins.html",
+ render_args), {});
+ };
+
+ if (req.query.search && req.query.search != "") {
+ installer.search(req.query.search, function (er, data) {
+ if (er) {
+ render_args.errors.push(er);
+ return render();
+ }
+ render_args.search_results = data;
+ render();
+ });
+ } else {
+ render();
+ }
+ });
+} \ No newline at end of file
diff --git a/src/static/js/pluginfw/installer.js b/src/static/js/pluginfw/installer.js
new file mode 100644
index 00000000..3ba7f458
--- /dev/null
+++ b/src/static/js/pluginfw/installer.js
@@ -0,0 +1,45 @@
+var plugins = require("ep_etherpad-lite/static/js/pluginfw/plugins");
+var hooks = require("ep_etherpad-lite/static/js/pluginfw/hooks");
+var npm = require("npm");
+var registry = require("npm/lib/utils/npm-registry-client/index.js");
+
+exports.uninstall = function(plugin_name, cb) {
+ npm.load({}, function (er) {
+ if (er) return cb(er)
+ npm.commands.uninstall([plugin_name], function (er) {
+ if (er) return cb(er);
+ hooks.aCallAll("pluginUninstall", {plugin_name: plugin_name}, function (er) {
+ cb(er);
+ });
+ })
+ })
+}
+
+exports.install = function(plugin_name, cb) {
+ npm.load({}, function (er) {
+ if (er) return cb(er)
+ npm.commands.install([plugin_name], function (er) {
+ if (er) return cb(er);
+ hooks.aCallAll("pluginInstall", {plugin_name: plugin_name}, function (er) {
+ cb(er);
+ });
+ });
+ })
+}
+
+exports.search = function(pattern, cb) {
+ npm.load({}, function (er) {
+ registry.get(
+ "/-/all", null, 600, false, true,
+ function (er, data) {
+ if (er) return cb(er);
+ var res = {};
+ for (key in data) {
+ if (/*key.indexOf(plugins.prefix) == 0 &&*/ key.indexOf(pattern) != -1)
+ res[key] = data[key];
+ }
+ cb(null, res);
+ }
+ );
+ });
+}
diff --git a/src/templates/admin/plugins.html b/src/templates/admin/plugins.html
new file mode 100644
index 00000000..2b40d33c
--- /dev/null
+++ b/src/templates/admin/plugins.html
@@ -0,0 +1,86 @@
+<html>
+ <head>
+ <title>Plugin manager</title>
+ <style>
+ table {
+ border-collapse: collapse;
+ }
+ td, th {
+ border: 1px solid black;
+ padding-left: 10px;
+ padding-right: 10px;
+ padding-top: 2px;
+ padding-bottom: 2px;
+ }
+ </style>
+ </head>
+ <body>
+ <% if (errors.length) { %>
+ <div class="errors">
+ <% errors.forEach(function (item) { %>
+ <div class="error"><%= item.toString() %></div>
+ <% }) %>
+ </div>
+ <% } %>
+
+
+ <h1>Installed plugins</h1>
+ <table>
+ <thead>
+ <tr>
+ <th>Name</th>
+ <th>Description</th>
+ <td></td>
+ </tr>
+ </thead>
+ <tbody>
+ <% for (var plugin_name in plugins) { %>
+ <% var plugin = plugins[plugin_name]; %>
+ <tr>
+ <td><%= plugin.package.name %></td>
+ <td><%= plugin.package.description %></td>
+ <td>
+ <form method="post">
+ <input type="hidden" name="uninstall_plugin" value="<%= plugin.package.name %>">
+ <input type="submit" value="U">
+ </form>
+ </td>
+ </tr>
+ <% } %>
+ </tbody>
+ </table>
+
+
+
+ <h1>Search for plugins to install</h1>
+ <form>
+ <input type="text" name="search" value="<%= query.search %>"><input type="submit">
+ </form>
+ <table>
+ <thead>
+ <tr>
+ <th>Name</th>
+ <th>Description</th>
+ <td></td>
+ </tr>
+ </thead>
+ <tbody>
+ <% for (var plugin_name in search_results) { %>
+ <% var plugin = search_results[plugin_name]; %>
+ <tr>
+ <td><%= plugin.name %></td>
+ <td><%= plugin.description %></td>
+ <td>
+ <form method="post">
+ <input type="hidden" name="install_plugin" value="<%= plugin.name %>">
+ <input type="submit" value="I">
+ </form>
+ </td>
+ </tr>
+ <% } %>
+ </tbody>
+ </table>
+
+
+ </body>
+</html>