Plugin admin partial

Ryan Blenis committed Nov 2, 2019 at 06:27 UTC bbb402b533594354cc1478aabfe5dcd917b87171
5 files changed +126 -13
meshuser.js
+1
@@ -3147,6 +3147,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
3147 parent.parent.pluginHandler.disablePlugin(command.id, function(){
3148 parent.db.getPlugins(function(err, docs) {
3149 try { ws.send(JSON.stringify({ action: 'updatePluginList', list: docs, result: err })); } catch (ex) { }
3150 + // @TODO delete plugin object from handler
3151 });
3152 });
3153 break;
pluginHandler.js
+25 -10
@@ -54,21 +54,15 @@ module.exports.pluginHandler = function (parent) {
54 });
55 }
56
57 - obj.prepExportsForPlugin = function(plugin) {
58 - var str = '';
59 - str += ' obj.' + plugin + ' = {};\r\n';
60 - for (const l of Object.values(obj.exports[plugin])) {
61 - str += ' obj.' + plugin + '.' + l + ' = ' + obj.plugins[plugin][l].toString() + '\r\n';
62 - }
63 - return str;
64 - };
65 -
57 obj.prepExports = function () {
58 var str = 'function() {\r\n';
59 str += ' var obj = {};\r\n';
60
61 for (const p of Object.keys(obj.plugins)) {
71 - str += obj.prepExportsForPlugin(p);
62 + str += ' obj.' + p + ' = {};\r\n';
63 + for (const l of Object.values(obj.exports[p])) {
64 + str += ' obj.' + p + '.' + l + ' = ' + obj.plugins[p][l].toString() + '\r\n';
65 + }
66 }
67
68 str += `obj.onDeviceRefeshEnd = function(nodeid, panel, refresh, event) {
@@ -371,5 +365,26 @@ module.exports.pluginHandler = function (parent) {
365 });
366 };
367
368 + obj.handleAdminReq = function (req, res, serv) {
369 + var path = obj.path.join(obj.pluginPath, req.query.pin, 'views');
370 + serv.app.set('views', path);
371 + if (obj.plugins[req.query.pin] != null && typeof obj.plugins[req.query.pin].handleAdminReq == 'function') {
372 + obj.plugins[req.query.pin].handleAdminReq(req, res);
373 + }
374 + else {
375 + res.sendStatus(401);
376 + }
377 + }
378 +
379 + obj.handleAdminPostReq = function(req, res, serv) {
380 + var path = obj.path.join(obj.pluginPath, req.query.pin, 'views');
381 + serv.app.set('views', path);
382 + if (obj.plugins[req.query.pin] != null && typeof obj.plugins[req.query.pin].handleAdminPostReq == 'function') {
383 + obj.plugins[req.query.pin].handleAdminPostReq(req, res);
384 + }
385 + else {
386 + res.sendStatus(401);
387 + }
388 + }
389 return obj;
390 };
\ No newline at end of file
public/styles/style.css
+41
@@ -2627,4 +2627,45 @@ a {
2627 text-align: center;
2628 padding: 14px;
2629 margin: 50px auto;
2630 +}
2631 +
2632 +.pluginOverlayBg {
2633 + width: 95%; /* Full width (cover the whole page) */
2634 + height: 95%; /* Full height (cover the whole page) */
2635 + margin: 10px;
2636 + background-color: rgba(0,0,0,0.8); /* Black background with opacity */
2637 + z-index: 2; /* Specify a stack order in case you're using a different order for other elements */
2638 + position: absolute;
2639 + cursor: pointer; /* Add a pointer on hover */
2640 + filter:blur(4px);
2641 + -o-filter:blur(4px);
2642 + -ms-filter:blur(4px);
2643 + -moz-filter:blur(4px);
2644 + -webkit-filter:blur(4px);
2645 +}
2646 +
2647 +.pluginOverlay {
2648 + width: 95%; /* Full width (cover the whole page) */
2649 + height: 95%; /* Full height (cover the whole page) */
2650 + margin: 10px;
2651 + background-color: #FFFFFF; /* Black background with opacity */
2652 + z-index: 2; /* Specify a stack order in case you're using a different order for other elements */
2653 + position: absolute;
2654 + cursor: pointer; /* Add a pointer on hover */
2655 +}
2656 +
2657 +.pluginTitleBar {
2658 + padding: 4px;
2659 + height: 25px;
2660 + border-bottom: double;
2661 + font-size: 20px;
2662 +}
2663 +
2664 +.pluginCloseBtn {
2665 + border: none;
2666 + outline: none;
2667 + cursor: pointer;
2668 + float: right;
2669 + position: relative;
2670 + padding: 0;
2671 }
\ No newline at end of file
views/default.handlebars
+35 -3
@@ -9408,7 +9408,7 @@
9408 // Fetch the server timeline stats if needed
9409 if ((x == 40) && (serverTimelineStats == null)) { refreshServerTimelineStats(); }
9410
9411 - if (x == 7) refreshPluginLatest();
9411 + if (x == 7) refreshPluginLatest(); else noGoPlugin();
9412
9413 // Update the web page title
9414 if ((currentNode) && (x >= 10) && (x < 20)) {
@@ -9456,7 +9456,7 @@
9456 installedPluginList.forEach(function(p){
9457 var cant_action = [];
9458 if (p.hasAdminPanel == true) {
9459 - p.name = `<a onclick="return goPlugin('${p._id}');">${p.name}</a>`;
9459 + p.nameHtml = `<a onclick="return goPlugin('${p.shortName}', '${p.name}');">${p.name}</a>`;
9460 }
9461 p.statusText = statusMap[p.status].text;
9462 p.statusColor = statusMap[p.status].color;
@@ -9490,7 +9490,7 @@
9490 }
9491 p.actions += '</select>';
9492
9493 - 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 class="pluginUpgradeAvailable">${p.upgradeAvail}</td><td style="color: #${p.statusColor}">${p.statusText}</td><td class="pluginAction">${p.actions}</td>`;
9493 + let tpl = `<td>${p.nameHtml}</td><td>${p.description}</td><td><a href="${p.homepage}" target="_blank">Homepage</a></td><td>${p.version}</td><td class="pluginUpgradeAvailable">${p.upgradeAvail}</td><td style="color: #${p.statusColor}">${p.statusText}</td><td class="pluginAction">${p.actions}</td>`;
9494 let tr = tbl.insertRow(-1);
9495 tr.innerHTML = tpl;
9496 tr.classList.add('p7tblRow');
@@ -9532,6 +9532,38 @@
9532 elem.value = '';
9533 }
9534
9535 + function goPlugin(pname, title) {
9536 + let xwin = `<div class="pluginTitleBar"><span>${title}</span><span class="pluginCloseBtn"><button onclick="return noGoPlugin(this);">X</button></span></div>`
9537 + let dif = document.createElement('div');
9538 + dif.classList.add('pluginOverlay');
9539 + dif.innerHTML = xwin;
9540 + let pif = document.createElement('iframe');
9541 + pif.src = '/pluginadmin.ashx?pin='+pname;
9542 + pif.setAttribute('frameBorder', '0');
9543 + pif.style.width = '100%';
9544 + pif.style.height = '100%';
9545 + pif.setAttribute('frameBorder', '0');
9546 +
9547 + dif.append(pif);
9548 + let x = Q('p7');
9549 + x.parentNode.insertBefore(dif, x.nextSibling);
9550 + Q('p7').classList.add('pluginOverlayBg');
9551 + }
9552 +
9553 + function noGoPlugin(el) {
9554 + if (el == null) {
9555 + var boxes = document.querySelectorAll('.pluginOverlay');
9556 + for (const b in Object.values(boxes)) {
9557 + boxes[b].parentNode.removeChild(boxes[b]);
9558 + }
9559 + Q('p7').classList.remove('pluginOverlayBg');
9560 + return;
9561 + }
9562 + var box = document.querySelector('.pluginOverlay').closest(".pluginOverlay");
9563 + box.parentNode.removeChild(box);
9564 + Q('p7').classList.remove('pluginOverlayBg');
9565 + }
9566 +
9567 // Generic methods
9568 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('/'); }
9569 function putstore(name, val) {
webserver.js
+24
@@ -3188,6 +3188,26 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
3188 }
3189 });
3190 }
3191 +
3192 + obj.handlePluginAdminReq = function(req, res) {
3193 + const domain = checkUserIpAddress(req, res);
3194 + if (domain == null) { res.sendStatus(404); return; }
3195 + if ((!req.session) || (req.session == null) || (!req.session.userid)) { res.sendStatus(401); return; }
3196 + var user = obj.users[req.session.userid];
3197 + if ((user == null) || ((user.siteadmin & 0xFFFFFFFF) == 0)) { res.sendStatus(401); return; }
3198 +
3199 + parent.pluginHandler.handleAdminReq(req, res, obj);
3200 + }
3201 +
3202 + obj.handlePluginAdminPostReq = function(req, res) {
3203 + const domain = checkUserIpAddress(req, res);
3204 + if (domain == null) { res.sendStatus(404); return; }
3205 + if ((!req.session) || (req.session == null) || (!req.session.userid)) { res.sendStatus(401); return; }
3206 + var user = obj.users[req.session.userid];
3207 + if ((user == null) || ((user.siteadmin & 0xFFFFFFFF) == 0)) { res.sendStatus(401); return; }
3208 +
3209 + parent.pluginHandler.handleAdminPostReq(req, res, obj);
3210 + }
3211
3212 // Starts the HTTPS server, this should be called after the user/mesh tables are loaded
3213 function serverStart() {
@@ -3311,6 +3331,10 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
3331 obj.app.get(url + 'logo.png', handleLogoRequest);
3332 obj.app.get(url + 'welcome.jpg', handleWelcomeImageRequest);
3333 obj.app.ws(url + 'amtactivate', handleAmtActivateWebSocket);
3334 + if (parent.pluginHandler != null) {
3335 + obj.app.get(url + 'pluginadmin.ashx', obj.handlePluginAdminReq);
3336 + obj.app.post(url + 'pluginadmin.ashx', obj.handlePluginAdminPostReq);
3337 + }
3338
3339 // Server redirects
3340 if (parent.config.domains[i].redirects) { for (var j in parent.config.domains[i].redirects) { if (j[0] != '_') { obj.app.get(url + j, obj.handleDomainRedirect); } } }