diff --git a/public/src/forum/admin/plugins.js b/public/src/forum/admin/plugins.js
index 01b4e4589f..68b03c4b50 100644
--- a/public/src/forum/admin/plugins.js
+++ b/public/src/forum/admin/plugins.js
@@ -6,30 +6,65 @@ define(function() {
init: function() {
var pluginsList = $('.plugins'),
numPlugins = pluginsList[0].querySelectorAll('li').length,
- pluginID, pluginTgl;
+ pluginID;
if (numPlugins > 0) {
+
pluginsList.on('click', 'button[data-action="toggleActive"]', function() {
pluginID = $(this).parents('li').attr('data-plugin-id');
- socket.emit('admin.plugins.toggle', pluginID);
+ var btn = $(this);
+ socket.emit('admin.plugins.toggleActive', pluginID, function(err, status) {
+
+ btn.html(' ' + (status.active ? 'Dea' : 'A') + 'ctivate');
+ btn.toggleClass('btn-warning', status.active).toggleClass('btn-success', !status.active);
+
+ app.alert({
+ alert_id: 'plugin_toggled',
+ title: 'Plugin ' + (status.active ? 'Enabled' : 'Disabled'),
+ message: 'Please restart your NodeBB to fully ' + (status.active ? 'activate' : 'deactivate') + ' this plugin',
+ type: 'info',
+ timeout: 5000,
+ clickfn: function() {
+ socket.emit('admin.restart');
+ }
+ });
+ });
});
- socket.on('admin.plugins.toggle', function(status) {
- pluginTgl = $('.plugins li[data-plugin-id="' + status.id + '"] button');
- pluginTgl.html(' ' + (status.active ? 'Dea' : 'A') + 'ctivate');
- pluginTgl.toggleClass('btn-warning', status.active).toggleClass('btn-success', !status.active);
-
- app.alert({
- alert_id: 'plugin_toggled',
- title: 'Plugin ' + (status.active ? 'Enabled' : 'Disabled'),
- message: 'Please restart your NodeBB to fully ' + (status.active ? 'activate' : 'deactivate') + ' this plugin',
- type: 'info',
- timeout: 5000,
- clickfn: function() {
- socket.emit('admin.restart');
+ pluginsList.on('click', 'button[data-action="toggleInstall"]', function() {
+ pluginID = $(this).parents('li').attr('data-plugin-id');
+
+ var btn = $(this);
+ btn.html(btn.html() + 'ing')
+ .attr('disabled', true)
+ .find('i').attr('class', 'fa fa-refresh fa-spin');
+
+ socket.emit('admin.plugins.toggleInstall', pluginID, function(err, status) {
+ var activateBtn = $('.plugins li[data-plugin-id="' + pluginID + '"] button[data-action="toggleActive"]');
+
+ if (status.installed) {
+ btn.html(' Uninstall');
+ } else {
+ btn.html(' Install');
}
+
+ btn.toggleClass('btn-warning', status.installed).toggleClass('btn-success', !status.installed)
+ .attr('disabled', false);
+
+ activateBtn.toggleClass('hide', !status.installed);
+ activateBtn.html(' Activate');
+ activateBtn.toggleClass('btn-success', true).toggleClass('btn-warning', false);
+
+ app.alert({
+ alert_id: 'plugin_toggled',
+ title: 'Plugin ' + (status.installed ? 'Installed' : 'Uninstalled'),
+ message: status.installed ? 'You still have to activate this plugin to use it!' : 'The plugin is also deactivated!',
+ type: 'info',
+ timeout: 5000
+ });
});
});
+
} else {
pluginsList.append('
No plugins found.
');
}
diff --git a/src/controllers/admin.js b/src/controllers/admin.js
index e978c85a78..92ac358c62 100644
--- a/src/controllers/admin.js
+++ b/src/controllers/admin.js
@@ -80,15 +80,15 @@ adminController.events.get = function(req, res, next) {
};
adminController.plugins.get = function(req, res, next) {
- plugins.showInstalled(function (err, plugins) {
+ plugins.getAll(function(err, plugins) {
if (err || !Array.isArray(plugins)) {
plugins = [];
}
- res.render('admin/plugins', {
+ res.render('admin/plugins' , {
plugins: plugins
});
- });
+ })
};
adminController.languages.get = function(req, res, next) {
diff --git a/src/plugins.js b/src/plugins.js
index 351629d85c..d660d90eae 100644
--- a/src/plugins.js
+++ b/src/plugins.js
@@ -373,20 +373,23 @@ var fs = require('fs'),
Plugins.toggleActive = function(id, callback) {
Plugins.isActive(id, function(err, active) {
if (err) {
- if (global.env === 'development') winston.info('[plugins] Could not toggle active state on plugin \'' + id + '\'');
- return;
+ if (global.env === 'development') {
+ winston.info('[plugins] Could not toggle active state on plugin \'' + id + '\'');
+ }
+ return callback(err);
}
db[(active ? 'setRemove' : 'setAdd')]('plugins:active', id, function(err, success) {
if (err) {
- if (global.env === 'development') winston.info('[plugins] Could not toggle active state on plugin \'' + id + '\'');
- return;
+ if (global.env === 'development') {
+ winston.info('[plugins] Could not toggle active state on plugin \'' + id + '\'');
+ }
+ return callback(err);
}
- // Restart Required flag
meta.restartRequired = true;
- if(active) {
+ if (active) {
Plugins.fireHook('action:plugin.deactivate', id);
}
@@ -397,8 +400,8 @@ var fs = require('fs'),
Plugins.fireHook('action:plugin.activate', id);
}
- if (callback) {
- callback({
+ if (typeof callback === 'function') {
+ callback(null, {
id: id,
active: !active
});
@@ -408,6 +411,42 @@ var fs = require('fs'),
});
};
+ Plugins.toggleInstall = function(id, callback) {
+ Plugins.isInstalled(id, function(err, installed) {
+ if (err) {
+ return callback(err);
+ }
+
+ var npm = require('npm');
+
+ async.waterfall([
+ function(next) {
+ Plugins.isActive(id, next);
+ },
+ function(active, next) {
+ if (active) {
+ Plugins.toggleActive(id, function(err, status) {
+ next(err);
+ });
+ return;
+ }
+ next();
+ },
+ function(next) {
+ npm.load({}, next);
+ },
+ function(res, next) {
+ npm.commands[installed ? 'uninstall' : 'install'](installed ? id : [id], next);
+ }
+ ], function(err) {
+ callback(err, {
+ id: id,
+ installed: !installed
+ });
+ });
+ });
+ };
+
Plugins.getTemplates = function(callback) {
var templates = {};
@@ -431,6 +470,52 @@ var fs = require('fs'),
});
};
+ Plugins.getAll = function(callback) {
+ var request = require('request');
+ request('http://npm.aws.af.cm/api/v1/plugins', function(err, res, body) {
+ if (err) {
+ return callback(err);
+ }
+ var plugins = [];
+ try {
+ plugins = JSON.parse(body);
+ } catch(err) {
+ winston.error('Error parsing plugins : ' + err.message);
+ return callback(null, []);
+ }
+
+ async.map(plugins, function(plugin, next) {
+
+ plugin.id = plugin.name;
+
+ async.parallel({
+ active: function(next) {
+ Plugins.isActive(plugin.id, next);
+ },
+ installed: function(next) {
+ Plugins.isInstalled(plugin.id, next);
+ }
+ }, function(err, results) {
+ if (err) {
+ return next(err);
+ }
+ plugin.active = results.active;
+ plugin.installed = results.installed;
+ next(null, plugin);
+ });
+
+ }, callback);
+ });
+ };
+
+ Plugins.isInstalled = function(id, callback) {
+ var pluginDir = path.join(__dirname, '../node_modules', id);
+
+ fs.stat(pluginDir, function(err, stats) {
+ callback(null, err ? false : stats.isDirectory());
+ });
+ };
+
Plugins.showInstalled = function(callback) {
var npmPluginPath = path.join(__dirname, '../node_modules');
@@ -483,7 +568,8 @@ var fs = require('fs'),
delete config.library;
delete config.hooks;
config.active = active;
- config.activeText = ' ' + (active ? 'Dea' : 'A') + 'ctivate';
+ config.installed = true;
+
next(null, config);
});
}
diff --git a/src/socket.io/admin.js b/src/socket.io/admin.js
index 05286f616b..94afaa2356 100644
--- a/src/socket.io/admin.js
+++ b/src/socket.io/admin.js
@@ -83,10 +83,12 @@ SocketAdmin.themes.set = function(socket, data, callback) {
});
};
-SocketAdmin.plugins.toggle = function(socket, plugin_id) {
- plugins.toggleActive(plugin_id, function(status) {
- socket.emit('admin.plugins.toggle', status);
- });
+SocketAdmin.plugins.toggleActive = function(socket, plugin_id, callback) {
+ plugins.toggleActive(plugin_id, callback);
+};
+
+SocketAdmin.plugins.toggleInstall = function(socket, plugin_id, callback) {
+ plugins.toggleInstall(plugin_id, callback);
};
SocketAdmin.widgets.set = function(socket, data, callback) {