mirror of
https://github.com/Ylianst/MeshCentral.git
synced 2024-11-22 12:52:50 +03:00
gui plugin updates partial
This commit is contained in:
parent
a98340cdc7
commit
f1ea4ae1b8
23
db.js
23
db.js
@ -442,6 +442,9 @@ module.exports.CreateDB = function (parent, func) {
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Setup plugin info collection
|
||||
obj.pluginsfile = db.collection('plugins');
|
||||
|
||||
setupFunctions(func); // Completed setup of MongoDB
|
||||
});
|
||||
@ -543,6 +546,9 @@ module.exports.CreateDB = function (parent, func) {
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Setup plugin info collection
|
||||
obj.pluginsfile = db.collection('plugins');
|
||||
|
||||
setupFunctions(func); // Completed setup of MongoJS
|
||||
} else {
|
||||
@ -604,6 +610,10 @@ module.exports.CreateDB = function (parent, func) {
|
||||
obj.serverstatsfile.ensureIndex({ fieldName: 'time', expireAfterSeconds: 60 * 60 * 24 * 30 }); // Limit the server stats log to 30 days (Seconds * Minutes * Hours * Days)
|
||||
obj.serverstatsfile.ensureIndex({ fieldName: 'expire', expireAfterSeconds: 0 }); // Auto-expire events
|
||||
|
||||
// Setup plugin info collection
|
||||
obj.pluginsfile = new Datastore({ filename: parent.getConfigFilePath('meshcentral-plugins.db'), autoload: true });
|
||||
obj.pluginsfile.persistence.setAutocompactionInterval(36000);
|
||||
|
||||
setupFunctions(func); // Completed setup of NeDB
|
||||
}
|
||||
|
||||
@ -741,6 +751,19 @@ module.exports.CreateDB = function (parent, func) {
|
||||
func(r);
|
||||
});
|
||||
}
|
||||
|
||||
// Add a plugin
|
||||
obj.addPlugin = function (plugin) { obj.pluginsfile.insertOne(plugin); };
|
||||
|
||||
// Get all plugins
|
||||
obj.getPlugins = function (func) { obj.pluginsfile.find().sort({ name: 1 }).toArray(func); };
|
||||
|
||||
// Get plugin
|
||||
obj.getPlugin = function (id, func) { obj.pluginsfile.find({ _id: id }).sort({ name: 1 }).toArray(func); };
|
||||
|
||||
// Delete plugin
|
||||
obj.deletePlugin = function (id) { obj.pluginsfile.deleteOne({ _id: id }); };
|
||||
|
||||
} else {
|
||||
// Database actions on the main collection (NeDB and MongoJS)
|
||||
obj.Set = function (data, func) {
|
||||
|
19
meshuser.js
19
meshuser.js
@ -3102,6 +3102,25 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'plugins': {
|
||||
if ((user.siteadmin & 0xFFFFFFFF) == 0 || parent.parent.pluginHandler == null) break; // must be full admin, plugins enabled
|
||||
parent.db.getPlugins(function(err, docs) {
|
||||
try { ws.send(JSON.stringify({ action: 'updatePluginList', list: docs, result: err })); } catch (ex) { }
|
||||
});
|
||||
break;
|
||||
}
|
||||
case 'addplugin': {
|
||||
// @Ylianst - Do we need a new permission here?
|
||||
if ((user.siteadmin & 0xFFFFFFFF) == 0 || parent.parent.pluginHandler == null) break; // must be full admin, plugins enabled
|
||||
parent.parent.pluginHandler.addPlugin(command.url);
|
||||
break;
|
||||
}
|
||||
case 'removeplugin': {
|
||||
// @Ylianst - Do we need a new permission here?
|
||||
if ((user.siteadmin & 0xFFFFFFFF) == 0 || parent.parent.pluginHandler == null) break; // must be full admin, plugins enabled
|
||||
parent.parent.pluginHandler.removePlugin(command.id);
|
||||
break;
|
||||
}
|
||||
case 'plugin': {
|
||||
if (parent.parent.pluginHandler == null) break; // If the plugin's are not supported, reject this command.
|
||||
command.userid = user._id;
|
||||
|
@ -71,6 +71,13 @@ module.exports.pluginHandler = function (parent) {
|
||||
for (const i of pages) { i.style.display = 'none'; }
|
||||
QV(id, true);
|
||||
};
|
||||
obj.addPluginEx = function() {
|
||||
meshserver.send({ action: 'addplugin', url: Q('pluginurlinput').value});
|
||||
};
|
||||
obj.addPluginDlg = function() {
|
||||
setDialogMode(2, "Plugin URL", 3, obj.addPluginEx, '<input type=text id=pluginurlinput style=width:100% />');
|
||||
focusTextBox('pluginurlinput');
|
||||
};
|
||||
return obj; };`;
|
||||
return str;
|
||||
}
|
||||
@ -152,7 +159,88 @@ module.exports.pluginHandler = function (parent) {
|
||||
}
|
||||
}
|
||||
return panel;
|
||||
}
|
||||
};
|
||||
|
||||
obj.isValidConfig = function(conf, url) { // check for the required attributes
|
||||
var isValid = true;
|
||||
if (!(
|
||||
typeof conf.name == 'string'
|
||||
&& typeof conf.version == 'string'
|
||||
&& typeof conf.author == 'string'
|
||||
&& typeof conf.description == 'string'
|
||||
&& typeof conf.hasAdminPanel == 'boolean'
|
||||
&& typeof conf.homepage == 'string'
|
||||
&& typeof conf.changelogUrl == 'string'
|
||||
&& typeof conf.configUrl == 'string'
|
||||
&& typeof conf.repository == 'object'
|
||||
&& typeof conf.repository.type == 'string'
|
||||
&& typeof conf.repository.url == 'string'
|
||||
&& typeof conf.meshCentralCompat == 'string'
|
||||
// && conf.configUrl == url // make sure we're loading a plugin from its desired config
|
||||
)) isValid = false;
|
||||
// more checks here?
|
||||
return isValid;
|
||||
};
|
||||
|
||||
obj.addPlugin = function(url) {
|
||||
var https = require('https');
|
||||
//var pit = obj.path.join(obj.pluginPath, )
|
||||
|
||||
https.get(url, function(res) {
|
||||
var configStr = '';
|
||||
res.on('data', function(chunk){
|
||||
configStr += chunk;
|
||||
});
|
||||
res.on('end', function(){
|
||||
if (configStr[0] == '{') {
|
||||
try {
|
||||
var pluginConfig = JSON.parse(configStr);
|
||||
if (obj.isValidConfig(pluginConfig, url)) {
|
||||
// add to database
|
||||
// we met the requirements of a valid config, but in case there's extra, let's rebuild for what we need
|
||||
parent.db.addPlugin({
|
||||
"name": pluginConfig.name,
|
||||
"version": pluginConfig.version,
|
||||
"description": pluginConfig.description,
|
||||
"hasAdminPanel": pluginConfig.hasAdminPanel,
|
||||
"homepage": pluginConfig.homepage,
|
||||
"changelogUrl": pluginConfig.changelogUrl,
|
||||
"configUrl": pluginConfig.configUrl,
|
||||
"repository": {
|
||||
"type": pluginConfig.repository.type,
|
||||
"url": pluginConfig.repository.url
|
||||
},
|
||||
"meshCentralCompat": pluginConfig.meshCentralCompat,
|
||||
"status": 0 // 0: disabled, 1: enabled
|
||||
});
|
||||
parent.db.getPlugins(function(err, docs){
|
||||
var targets = ['*', 'server-users'];
|
||||
parent.DispatchEvent(targets, obj, { action: 'updatePluginList', list: docs });
|
||||
|
||||
})
|
||||
} else {
|
||||
// @TODO return error to user
|
||||
}
|
||||
|
||||
} catch (e) { console.log('Error processing addPlugin request. Check that you have valid JSON.'); }
|
||||
}
|
||||
});
|
||||
|
||||
}).on('error', function(e) {
|
||||
console.log("Got error: " + e.message);
|
||||
});
|
||||
/* const file = fs.createWriteStream("file.jpg");
|
||||
const request = http.get("http://i3.ytimg.com/vi/J---aiyznGQ/mqdefault.jpg", function(response) {
|
||||
response.pipe(file);
|
||||
}); */
|
||||
};
|
||||
|
||||
obj.getPlugins = function() {
|
||||
var p = parent.db.getPlugins();
|
||||
if (typeof p == 'undefined' || p.length == 0) {
|
||||
return null;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
return obj;
|
||||
};
|
BIN
public/images/plus32.png
Normal file
BIN
public/images/plus32.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 656 B |
@ -2563,4 +2563,51 @@ a {
|
||||
padding: 3px;
|
||||
border-radius: 3px;
|
||||
background-color: #DDD;
|
||||
}
|
||||
|
||||
#p7tbl {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
#p7tbl th, #p7tbl td {
|
||||
text-align: left;
|
||||
padding: 12px;
|
||||
}
|
||||
|
||||
#p7tbl tr:nth-child(n+2):nth-child(odd) {
|
||||
background-color: #cfeeff;
|
||||
}
|
||||
|
||||
#p7tbl .chName {
|
||||
width: 20%;
|
||||
}
|
||||
|
||||
#p7tbl .chDescription {
|
||||
width: 40%;
|
||||
}
|
||||
|
||||
#p7tbl .chSite {
|
||||
width: 10%;
|
||||
}
|
||||
|
||||
#p7tbl .chVersion {
|
||||
width: 10%;
|
||||
}
|
||||
|
||||
#p7tbl .chStatus {
|
||||
width: 10%;
|
||||
}
|
||||
|
||||
#p7tbl .chAction {
|
||||
width: 10%;
|
||||
}
|
||||
|
||||
#addPlugin {
|
||||
background-image: url(../images/plus32.png);
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
float: right;
|
||||
cursor: pointer;
|
||||
margin-right: 12px;
|
||||
}
|
@ -88,6 +88,9 @@
|
||||
<div id=LeftMenuMyServer tabindex=0 class="lbbutton" style="display:none" title="My Server" onclick=go(6,event) onkeypress="if (event.key=='Enter') { go(6); }">
|
||||
<div class="lb6"></div>
|
||||
</div>
|
||||
<div id=LeftMenuMyPlugins tabindex=0 class="lbbutton" style="display:none" title="My Plugins" onclick=go(7,event) onkeypress="if (event.key=='Enter') { go(7); }">
|
||||
<div class="lb7"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div id=topbar class=noselect>
|
||||
<div>
|
||||
@ -109,6 +112,7 @@
|
||||
<td tabindex=0 id=MainMenuMyFiles class="topbar_td style3x" onclick=go(5,event) onkeypress="if (event.key == 'Enter') go(5)">My Files</td>
|
||||
<td tabindex=0 id=MainMenuMyUsers class="topbar_td style3x" onclick=go(4,event) onkeypress="if (event.key == 'Enter') go(4)">My Users</td>
|
||||
<td tabindex=0 id=MainMenuMyServer class="topbar_td style3x" onclick=go(6,event) onkeypress="if (event.key == 'Enter') go(6)">My Server</td>
|
||||
<td tabindex=0 id=MainMenuMyPlugins class="topbar_td style3x" onclick=go(7,event) onkeypress="if (event.key == 'Enter') go(7)">My Plugins</td>
|
||||
<td class="topbar_td_end style3"> </td>
|
||||
</tr>
|
||||
</table>
|
||||
@ -405,6 +409,13 @@
|
||||
<div id="serverStatsTable"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div id=p7 style="display:none">
|
||||
<h1>My Plugins</h1>
|
||||
<div id="addPlugin" onclick="return pluginHandler.addPluginDlg();"></div>
|
||||
<table id="p7tbl">
|
||||
<tr><th class="chName">Name</th><th class="chDescription">Description</th><th class="chSite">Link</th><th class="chVersion">Version</th><th class="chStatus">Status</th><th class="chAction">Action</th></tr>
|
||||
</table>
|
||||
</div>
|
||||
<div id=p10 style="display:none">
|
||||
<table style="width:100%" cellpadding="0" cellspacing="0">
|
||||
<tr>
|
||||
@ -1042,6 +1053,7 @@
|
||||
var pluginHandlerBuilder = {{{pluginHandler}}};
|
||||
var pluginHandler = null;
|
||||
if (pluginHandlerBuilder != null) { pluginHandler = new pluginHandlerBuilder(); }
|
||||
var installedPluginList = null;
|
||||
|
||||
// Console Message Display Timers
|
||||
var p11DeskConsoleMsgTimer = null;
|
||||
@ -1295,6 +1307,7 @@
|
||||
// Fetch list of meshes, nodes, files
|
||||
meshserver.send({ action: 'meshes' });
|
||||
meshserver.send({ action: 'nodes', id: '{{currentNode}}' });
|
||||
meshserver.send({ action: 'plugins' });
|
||||
if ('{{currentNode}}' == '') { meshserver.send({ action: 'files' }); }
|
||||
if ('{{viewmode}}' == '') { go(1); }
|
||||
authCookieRenewTimer = setInterval(function () { meshserver.send({ action: 'authcookie' }); }, 1800000); // Request a cookie refresh every 30 minutes.
|
||||
@ -1337,6 +1350,7 @@
|
||||
QV('p2ServerActionsVersion', siteRights & 16);
|
||||
QV('MainMenuMyFiles', siteRights & 8);
|
||||
QV('LeftMenuMyFiles', siteRights & 8);
|
||||
QV('MainMenuMyPlugins', (pluginHandler != null));
|
||||
if (((siteRights & 8) == 0) && (xxcurrentView == 5)) { setDialogMode(0); go(1); }
|
||||
if (currentNode != null) { gotoDevice(currentNode._id, xxcurrentView, true); }
|
||||
|
||||
@ -2284,6 +2298,12 @@
|
||||
//console.log(message.msg);
|
||||
break;
|
||||
}
|
||||
case 'updatePluginList': {
|
||||
// @Ylianst - Do we need a rights check here?
|
||||
installedPluginList = message.event.list;
|
||||
updatePluginList();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
//console.log('Unknown message.event.action', message.event.action);
|
||||
break;
|
||||
@ -2337,6 +2357,11 @@
|
||||
QH('p0span', message.msg);
|
||||
break;
|
||||
}
|
||||
case 'updatePluginList': {
|
||||
installedPluginList = message.list;
|
||||
updatePluginList();
|
||||
break;
|
||||
}
|
||||
case 'plugin': {
|
||||
if ((pluginHandler == null) || (typeof message.plugin != 'string')) break;
|
||||
try { pluginHandler[message.plugin][message.method](server, message); } catch (e) { console.log('Error loading plugin handler ('+ e + ')'); }
|
||||
@ -9250,6 +9275,9 @@
|
||||
|
||||
// Remove top bar selection
|
||||
var mainBarItems = ['MainMenuMyDevices', 'MainMenuMyAccount', 'MainMenuMyEvents', 'MainMenuMyFiles', 'MainMenuMyUsers', 'MainMenuMyServer'];
|
||||
if (pluginHandler != null) {
|
||||
mainBarItems.push('MainMenuMyPlugins');
|
||||
}
|
||||
for (var i in mainBarItems) {
|
||||
QC(mainBarItems[i]).remove('fullselect');
|
||||
QC(mainBarItems[i]).remove('semiselect');
|
||||
@ -9257,6 +9285,9 @@
|
||||
|
||||
// Remove left bar selection
|
||||
var leftBarItems = ['LeftMenuMyDevices', 'LeftMenuMyAccount', 'LeftMenuMyEvents', 'LeftMenuMyFiles', 'LeftMenuMyUsers', 'LeftMenuMyServer'];
|
||||
if (pluginHandler != null) {
|
||||
leftBarItems.push('LeftMenuMyPlugins');
|
||||
}
|
||||
for (var i in leftBarItems) {
|
||||
QC(leftBarItems[i]).remove('lbbuttonsel');
|
||||
QC(leftBarItems[i]).remove('lbbuttonsel2');
|
||||
@ -9289,7 +9320,11 @@
|
||||
// My Server
|
||||
if ((x == 6) || (x == 115)) QC('MainMenuMyServer').add(mainMenuActiveClass);
|
||||
if ((x == 6) || (x == 115) || (x == 40)) QC('LeftMenuMyServer').add(leftMenuActiveClass);
|
||||
|
||||
|
||||
// My Plugins
|
||||
if (x == 7) QC('MainMenuMyPlugins').add(mainMenuActiveClass);
|
||||
if (x == 7) QC('LeftMenuMyPlugins').add(leftMenuActiveClass);
|
||||
|
||||
// column_l max-height
|
||||
if (webPageStackMenu && (x >= 10)) { QC('column_l').add('room4submenu'); } else { QC('column_l').remove('room4submenu'); }
|
||||
|
||||
@ -9333,7 +9368,34 @@
|
||||
document.title = decodeURIComponent('{{{extitle}}}');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function updatePluginList() {
|
||||
if (installedPluginList.length) {
|
||||
var tr = Q('p7tbl').querySelectorAll(".p7tblRow");
|
||||
if (tr.length) {
|
||||
for (const i in Object.values(tr)) {
|
||||
tr[i].parentNode.removeChild(tr[i]);
|
||||
}
|
||||
}
|
||||
var statusMap = {
|
||||
0: 'Disabled',
|
||||
1: 'Installed'
|
||||
}
|
||||
var tbl = Q('p7tbl');
|
||||
installedPluginList.forEach(function(p){
|
||||
if (p.hasAdminPanel == true) {
|
||||
p.name = `<a onclick="return goPlugin('${p._id}');">${p.name}</a>`;
|
||||
}
|
||||
p.status = statusMap[p.status];
|
||||
p.actions = 'TODO'; // Install / Upgrade / Disable / Delete
|
||||
let tpl = `<td>${p.name}</td><td>${p.description}</td><td><a href="${p.homepage}" target="_blank">Homepage</a></td><td>${p.version}</td><td>${p.status}</td><td>${p.actions}</td>`;
|
||||
let tr = tbl.insertRow(-1);
|
||||
tr.innerHTML = tpl;
|
||||
tr.classList.add('p7tblRow');
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
// Generic methods
|
||||
function joinPaths() { var x = []; for (var i in arguments) { var w = arguments[i]; if ((w != null) && (w != '')) { while (w.endsWith('/') || w.endsWith('\\')) { w = w.substring(0, w.length - 1); } while (w.startsWith('/') || w.startsWith('\\')) { w = w.substring(1); } x.push(w); } } return x.join('/'); }
|
||||
function putstore(name, val) {
|
||||
|
Loading…
Reference in New Issue
Block a user