diff --git a/meshuser.js b/meshuser.js index 2d655efa..30d50cf8 100644 --- a/meshuser.js +++ b/meshuser.js @@ -657,17 +657,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use links = parent.GetAllMeshIdWithRights(user); // Add any nodes with direct rights or any nodes with user group direct rights - if (obj.user.links != null) { - for (var i in obj.user.links) { - if (i.startsWith('node/')) { if (extraids == null) { extraids = []; } extraids.push(i); } - else if (i.startsWith('ugrp/')) { - const g = parent.userGroups[i]; - if ((g != null) && (g.links != null)) { - for (var j in g.links) { if (j.startsWith('node/')) { if (extraids == null) { extraids = []; } extraids.push(j); } } - } - } - } - } + extraids = getUserExtraIds(); } else { // Request list of all nodes for one specific meshid meshid = command.meshid; @@ -5414,6 +5404,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use 'getnetworkinfo': serverCommandGetNetworkInfo, 'getsysinfo': serverCommandGetSysInfo, 'lastconnect': serverCommandLastConnect, + 'lastseen': serverCommandLastSeen, 'meshes': serverCommandMeshes, 'serverconsole': serverCommandServerConsole, 'servererrors': serverCommandServerErrors, @@ -5547,6 +5538,31 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use }); } + function serverCommandLastSeen(command) { + var links = parent.GetAllMeshIdWithRights(user); + var extraids = getUserExtraIds(); + db.GetAllTypeNoTypeFieldMeshFiltered(links, extraids, domain.id, 'node', null, (err, docs) => { + if (docs == null) { docs = []; } + + // use associative array to join lastconnects on to users's nodes (left join) + var LCs = {} + for (var i in docs) { + LCs[docs[i]._id] = ''; + } + + db.GetAllType('lastconnect', (err, docs) => { + for (var j in docs) { + var nodeid = docs[j]._id.substring(2); + if (LCs[nodeid] != null) { + LCs[nodeid] = docs[j].time; + } + } + + try { ws.send(JSON.stringify({ action: 'lastseen', lastconnects: LCs })); } catch (ex) { } + }); + }); + } + function serverCommandMeshes(command) { // Request a list of all meshes this user as rights to try { ws.send(JSON.stringify({ action: 'meshes', meshes: parent.GetAllMeshWithRights(user).map(parent.CloneSafeMesh), tag: command.tag })); } catch (ex) { } @@ -6181,6 +6197,22 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use return true; } + function getUserExtraIds() { + var extraids = null; + if (obj.user.links != null) { + for (var i in obj.user.links) { + if (i.startsWith('node/')) { if (extraids == null) { extraids = []; } extraids.push(i); } + else if (i.startsWith('ugrp/')) { + const g = parent.userGroups[i]; + if ((g != null) && (g.links != null)) { + for (var j in g.links) { if (j.startsWith('node/')) { if (extraids == null) { extraids = []; } extraids.push(j); } } + } + } + } + } + return extraids; + } + function csvClean(s) { return '\"' + s.split('\"').join('').split(',').join('').split('\r').join('').split('\n').join('') + '\"'; } // Return detailed information about an array of nodeid's @@ -6229,18 +6261,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use var links = parent.GetAllMeshIdWithRights(user); // Add any nodes with direct rights or any nodes with user group direct rights - var extraids = null; - if (obj.user.links != null) { - for (var i in obj.user.links) { - if (i.startsWith('node/')) { if (extraids == null) { extraids = []; } extraids.push(i); } - else if (i.startsWith('ugrp/')) { - const g = parent.userGroups[i]; - if ((g != null) && (g.links != null)) { - for (var j in g.links) { if (j.startsWith('node/')) { if (extraids == null) { extraids = []; } extraids.push(j); } } - } - } - } - } + var extraids = getUserExtraIds(); // Request a list of all nodes db.GetAllTypeNoTypeFieldMeshFiltered(links, extraids, domain.id, 'node', null, function (err, docs) { diff --git a/views/default.handlebars b/views/default.handlebars index 8ba5b988..962eb380 100644 --- a/views/default.handlebars +++ b/views/default.handlebars @@ -1929,6 +1929,7 @@ meshserver.send({ action: 'usergroups' }); meshserver.send({ action: 'meshes' }); meshserver.send({ action: 'nodes', id: '{{currentNode}}' }); + meshserver.send({ action: 'lastseen' }); meshserver.send({ action: 'loginTokens' }); if (pluginHandler != null) { meshserver.send({ action: 'plugins' }); } if ('{{currentNode}}'.toLowerCase() == '') { meshserver.send({ action: 'files' }); } @@ -2291,6 +2292,14 @@ } break; } + case 'lastseen': { + var lcnodes = Object.keys(message.lastconnects); + for (var i in lcnodes) { + var lcnodeid = lcnodes[i]; + var node = getNodeFromId(lcnodeid); + if (node != null) { node.lastconnect = message.lastconnects[lcnodeid] } + } + } case 'msg': { // Check if this is a message from a node if (message.nodeid != null) { @@ -3547,6 +3556,7 @@ x += '
'; x += '
'; x += '
'; + x += '
'; setDialogMode(2, "Device View Columns", 3, onDeviceViewSettingsEx, x); } @@ -3558,6 +3568,7 @@ if (Q('d2c4').checked) { cols.push('conn'); } if (Q('d2c5').checked) { cols.push('os'); } if (Q('d2c6').checked) { cols.push('desc'); } + if (Q('d2c7').checked) { cols.push('lastseen'); } deviceViewSettings.devsCols = cols; putstore('_deviceViewSettings', JSON.stringify(deviceViewSettings)); mainUpdate(4); @@ -3973,6 +3984,7 @@ if (deviceViewSettings.devsCols.indexOf('user') >= 0) { colums += '' + "User"; } if (deviceViewSettings.devsCols.indexOf('ip') >= 0) { colums += '' + "Address"; } if (deviceViewSettings.devsCols.indexOf('conn') >= 0) { colums += '' + "Connectivity"; } + if (deviceViewSettings.devsCols.indexOf('lastseen') >= 0) { colums += '' + "Last Seen"; } // This height of 1 div at the end to fix a problem in Linux firefox browsers r = '
' + colums + r + '
'; @@ -4232,6 +4244,7 @@ if (deviceViewSettings.devsCols.indexOf('user') >= 0) { r += '' + getUserShortStr(node); } // User if (deviceViewSettings.devsCols.indexOf('ip') >= 0) { r += '' + (node.ip != null ? node.ip : ''); } // IP address if (deviceViewSettings.devsCols.indexOf('conn') >= 0) { r += '' + states.join(' + '); } // Connectivity + if (deviceViewSettings.devsCols.indexOf('lastseen') >= 0) { r += '' + ((node.conn & 23 > 0 || node.lastconnect == null) ? '' : printDateTime(new Date(node.lastconnect))); } div.innerHTML = r; } else if ((view == 3) || (view == 5)) {