diff --git a/meshagent.js b/meshagent.js index 1f178464..686f9005 100644 --- a/meshagent.js +++ b/meshagent.js @@ -413,7 +413,7 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) { if (device.agent.ver != obj.agentInfo.agentVersion) { device.agent.ver = obj.agentInfo.agentVersion; change = 1; changes.push('agent version'); } if (device.agent.id != obj.agentInfo.agentId) { device.agent.id = obj.agentInfo.agentId; change = 1; changes.push('agent type'); } if ((device.agent.caps & 24) != (obj.agentInfo.capabilities & 24)) { device.agent.caps = obj.agentInfo.capabilities; change = 1; changes.push('agent capabilities'); } // If agent console or javascript support changes, update capabilities - if (device.meshid != obj.dbMeshKey) { device.meshid = obj.dbMeshKey; change = 1; log = 1; changes.push('agent meshid'); } // TODO: If the meshid changes, we need to event a device add/remove on both meshes + if (device.meshid != obj.dbMeshKey) { obj.dbMeshKey = device.meshid; obj.meshid = device.meshid.split('/')[2]; } // If the mesh does not match, the server mesh is the correct one. This is because we allow the server to change the mesh of a device server-side. if (change == 1) { obj.db.Set(device); diff --git a/meshuser.js b/meshuser.js index bb9121fd..839c1f32 100644 --- a/meshuser.js +++ b/meshuser.js @@ -1068,6 +1068,47 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use } break; } + case 'changeDeviceMesh': + { + if (obj.common.validateString(command.nodeid, 1, 256) == false) break; // Check nodeid string + if (obj.common.validateString(command.meshid, 1, 256) == false) break; // Check meshid string + + obj.db.Get(command.nodeid, function (err, nodes) { + if (nodes.length != 1) return; + var node = nodes[0]; + + // Check if already in the right mesh + if (node.meshid == command.meshid) return; + + // Make sure that we have rights on both source and destination mesh + var sourceMeshRights = user.links[node.meshid].rights; + var targetMeshRights = user.links[command.meshid].rights; + if (((sourceMeshRights & 4) == 0) || ((targetMeshRights & 4) == 0)) return; + + // Perform the switch, start by saving the node with the new meshid. + var oldMeshId = node.meshid; + node.meshid = command.meshid; + obj.db.Set(node); + + // If the device is connected on this server, switch it now. + var agentSession = obj.parent.wsagents[command.nodeid]; + if (agentSession != null) { agentSession.dbMeshKey = command.meshid; agentSession.meshid = command.meshid.split('/')[2]; } + + // Add the connection state + var state = obj.parent.parent.GetConnectivityState(node._id); + if (state) { + node.conn = state.connectivity; + node.pwr = state.powerState; + if ((state.connectivity & 1) != 0) { var agent = obj.parent.wsagents[node._id]; if (agent != null) { node.agct = agent.connectTime; } } + if ((state.connectivity & 2) != 0) { var cira = obj.parent.parent.mpsserver.ciraConnections[node._id]; if (cira != null) { node.cict = cira.tag.connectTime; } } + } + + // Event the node change + var newMesh = obj.parent.meshes[command.meshid]; + obj.parent.parent.DispatchEvent(['*', oldMeshId, command.meshid], obj, { etype: 'node', username: user.name, action: 'nodemeshchange', nodeid: node._id, node: node, oldMeshId: oldMeshId, newMeshId: command.meshid, msg: 'Moved device ' + node.name + ' to group ' + newMesh.name, domain: domain.id }); + }); + break; + } case 'removedevices': { if (obj.common.validateArray(command.nodeids, 1) == false) break; // Check nodeid's diff --git a/views/default-min.handlebars b/views/default-min.handlebars index e61f2c99..041ab905 100644 --- a/views/default-min.handlebars +++ b/views/default-min.handlebars @@ -1 +1 @@ - MeshCentral
{{{title}}}
{{{title2}}}

{{{logoutControl}}}

 

\ No newline at end of file + MeshCentral
{{{title}}}
{{{title2}}}

{{{logoutControl}}}

 

\ No newline at end of file diff --git a/views/default-mobile-min.handlebars b/views/default-mobile-min.handlebars index aaeccb37..b5e22b68 100644 --- a/views/default-mobile-min.handlebars +++ b/views/default-mobile-min.handlebars @@ -1 +1 @@ - MeshCentral
{{{title}}}
{{{title2}}}
\ No newline at end of file + MeshCentral
{{{title}}}
{{{title2}}}
\ No newline at end of file diff --git a/views/default-mobile.handlebars b/views/default-mobile.handlebars index b5cef093..159e4394 100644 --- a/views/default-mobile.handlebars +++ b/views/default-mobile.handlebars @@ -715,7 +715,7 @@ //onSearchInputChanged(); updateDevices(); //refreshMap(false, true); - if (xxcurrentView == 0) { if ('{{viewmode}}' != '') { go(parseInt('{{viewmode}}')); } else { setDialogMode(0); go(1); } } + if (xxcurrentView == 0) { if ('{{viewmode}}' != '') { go(parseInt('{{viewmode}}')); } else { setDialogMode(0); go(2); } } if ('{{currentNode}}' != '') { gotoDevice('{{currentNode}}', parseInt('{{viewmode}}')); } break; } @@ -827,7 +827,7 @@ nodes = newnodes; // If we are looking at a node in the deleted mesh, move back to "My Devices" - if (xxcurrentView >= 10 && xxcurrentView < 20 && currentNode && currentNode.meshid == message.event.meshid) { setDialogMode(0); go(1); } + if (xxcurrentView >= 10 && xxcurrentView < 20 && currentNode && currentNode.meshid == message.event.meshid) { setDialogMode(0); go(2); } } } updateMeshes(); @@ -855,7 +855,7 @@ // If we are looking at a mesh that is now deleted, move back to "My Account" if (xxcurrentView >= 20 && xxcurrentView < 30 && currentMesh._id == message.event.meshid) { setDialogMode(0); go(2); } // If we are looking at a node in the deleted mesh, move back to "My Devices" - if (xxcurrentView >= 10 && xxcurrentView < 20 && currentNode && currentNode.meshid == message.event.meshid) { setDialogMode(0); go(1); } + if (xxcurrentView >= 10 && xxcurrentView < 20 && currentNode && currentNode.meshid == message.event.meshid) { setDialogMode(0); go(2); } break; } @@ -881,7 +881,7 @@ if (index != -1) { var node = nodes[index]; if (currentNode == node) { - if (xxcurrentView >= 10 && xxcurrentView < 20) { setDialogMode(0); go(1); } + if (xxcurrentView >= 10 && xxcurrentView < 20) { setDialogMode(0); go(2); } currentNode = null; // TODO: Correctly disconnect from this node (Desktop/Terminal/Files...) } @@ -938,6 +938,43 @@ } break; } + case 'nodemeshchange': { + var index = -1; + for (var i in nodes) { if (nodes[i]._id == message.event.nodeid) { index = i; break; } } + if (index != -1) { + var node = nodes[index]; + if (meshes[message.event.newMeshId] == null) { + // We don't see the new mesh, remove this device + + // TODO: Correctly disconnect from this node (Desktop/Terminal/Files...) + if (currentNode == node) { if (xxcurrentView >= 10 && xxcurrentView < 20) { setDialogMode(0); go(2); } currentNode = null; } + nodes.splice(index, 1); + } else { + // We see the new mesh, move this device + node.meshid = message.event.newMeshId; + node.meshnamel = meshes[message.event.newMeshId].name.toLowerCase(); + } + updateDevices(); + refreshDevice(message.event.nodeid); + } else { + // This is a new device, add it. + var node = message.event.node; + if (!meshes[node.meshid]) break; // This is a node for a mesh we don't know. Happens when we are site administrator, we get all messages. + node.namel = node.name.toLowerCase(); + if (node.rname) { node.rnamel = node.rname.toLowerCase(); } else { node.rnamel = node.namel; } + node.meshnamel = meshes[node.meshid].name.toLowerCase(); + node.state = 0; + if (!node.icon) node.icon = 1; + node.ident = ++nodeShortIdent; + if (nodes == null) { } + nodes.push(node); + + // Web page update + //masterUpdate(1 | 2 | 4 | 16); + updateDevices(); + } + break; + } case 'nodeconnect': { // Indicated a node has changed connectivity state var index = -1; @@ -1652,9 +1689,9 @@ function getCurrentNode() { return currentNode; }; function gotoDevice(nodeid, panel, refresh) { var node = getNodeFromId(nodeid); - if (node == null) { goBack(); } + if (node == null) { goBack(); return; } var mesh = meshes[node.meshid]; - if (mesh == null) { goBack(); } + if (mesh == null) { goBack(); return; } var meshrights = mesh.links['user/' + domain + '/' + userinfo.name.toLowerCase()].rights; if (!currentNode || currentNode._id != node._id || refresh == true) { currentNode = node; diff --git a/views/default.handlebars b/views/default.handlebars index 760db9b2..cb284857 100644 --- a/views/default.handlebars +++ b/views/default.handlebars @@ -1680,6 +1680,43 @@ } break; } + case 'nodemeshchange': { + var index = -1; + for (var i in nodes) { if (nodes[i]._id == message.event.nodeid) { index = i; break; } } + if (index != -1) { + var node = nodes[index]; + if (meshes[message.event.newMeshId] == null) { + // We don't see the new mesh, remove this device + + // TODO: Correctly disconnect from this node (Desktop/Terminal/Files...) + if (currentNode == node) { if (xxcurrentView >= 10 && xxcurrentView < 20) { setDialogMode(0); go(1); } currentNode = null; } + nodes.splice(index, 1); + masterUpdate(4 | 16); + } else { + // We see the new mesh, move this device + node.meshid = message.event.newMeshId; + node.meshnamel = meshes[message.event.newMeshId].name.toLowerCase(); + masterUpdate(1 | 2 | 4); + } + refreshDevice(message.event.nodeid); + } else { + // This is a new device, add it. + var node = message.event.node; + if (!meshes[node.meshid]) break; // This is a node for a mesh we don't know. Happens when we are site administrator, we get all messages. + node.namel = node.name.toLowerCase(); + if (node.rname) { node.rnamel = node.rname.toLowerCase(); } else { node.rnamel = node.namel; } + node.meshnamel = meshes[node.meshid].name.toLowerCase(); + node.state = 0; + if (!node.icon) node.icon = 1; + node.ident = ++nodeShortIdent; + if (nodes == null) { } + nodes.push(node); + + // Web page update + masterUpdate(1 | 2 | 4 | 16); + } + break; + } case 'nodeconnect': { // Indicated a node has changed connectivity state var index = -1; @@ -3447,7 +3484,11 @@ // Show bottom buttons x = '
'; - if ((meshrights & 4) != 0) x += 'Delete Device'; + if ((meshrights & 4) != 0) { + // TODO: Show change group only if there is another mesh of the same type. + x += ' Change Group'; + x += ' Delete Device'; + } x += '
'; if (mesh.mtype == 2) x += 'Interfaces '; if (xxmap != null) x += 'Location '; @@ -3711,6 +3752,32 @@ } } + function p10showChangeGroupDialog(nodeid) { + var node = getNodeFromId(nodeid); + if (xxdialogMode || (node == null)) return; + var mesh1 = meshes[node.meshid]; + + // List all available alternative groups + var y = ""; + + if (count > 0) { + var x = "Select a new group for this device

"; + x += addHtmlValue('New Device Group', y); + setDialogMode(2, "Change Group", 3, p10showChangeGroupDialogEx, x, nodeid); + } else { + setDialogMode(2, "Change Group", 1, null, "No other device group of same type exists."); + } + } + + function p10showChangeGroupDialogEx(b, nodeid) { + meshserver.send({ action: 'changeDeviceMesh', nodeid: nodeid, meshid: Q('p10newGroup').value }); + } + function p10showDeleteNodeDialog(nodeid) { if (xxdialogMode) return; var x = "Are you sure you want to delete node \"" + EscapeHtml(currentNode.name) + "\"?

"; @@ -5657,7 +5724,7 @@ x += ''; // If we are full administrator on this mesh, allow deletion of the mesh - if (meshrights == 0xFFFFFFFF) { x += '
Delete Mesh
'; } + if (meshrights == 0xFFFFFFFF) { x += '
Delete Group
'; } QH('p20info', x); } @@ -5708,9 +5775,9 @@ function p20showDeleteMeshDialog() { if (xxdialogMode) return; - var x = "Are you sure you want to delete mesh \"" + EscapeHtml(currentMesh.name) + "\"? Deleting the mesh will also delete all information about computers within this mesh.

"; + var x = "Are you sure you want to delete group \"" + EscapeHtml(currentMesh.name) + "\"? Deleting the device group will also delete all information about devices within this group.

"; x += "Confirm"; - setDialogMode(2, "Delete Mesh", 3, p20showDeleteMeshDialogEx, x); + setDialogMode(2, "Delete Group", 3, p20showDeleteMeshDialogEx, x); p20validateDeleteMeshDialog(); }