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 += '
' + colums + r + ' |
---|