Added user bandwidth report.
Ylian Saint-Hilaire committed
Sep 12, 2021 at 19:21 UTC
508f29485808d7084660770853d2c2759ffd3a93
2 files changed
+68
-12
meshuser.js
+55
-5
@@ -5449,7 +5449,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
5449
}
5450
case 'report': {
5451
// Report request. Validate the input
5452
- if (common.validateInt(command.type, 1, 1) == false) break; // Validate type
5452
+ if (common.validateInt(command.type, 1, 2) == false) break; // Validate type
5453
if (common.validateInt(command.groupBy, 1, 3) == false) break; // Validate groupBy: 1 = User, 2 = Device, 3 = Day
5454
if ((typeof command.start != 'number') || (typeof command.end != 'number') || (command.start >= command.end)) break; // Validate start and end time
5455
const manageAllDeviceGroups = ((user.siteadmin == 0xFFFFFFFF) && (parent.parent.config.settings.managealldevicegroups.indexOf(user._id) >= 0));
@@ -5471,6 +5471,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
5471
db.GetEventsTimeRange(ids, domain.id, [5, 10, 11, 12, 122, 123, 124, 125, 126], new Date(command.start * 1000), new Date(command.end * 1000), function (err, docs) {
5472
if (err != null) return;
5473
var data = { groups: {} };
5474
+ var guestNamePresent = false;
5475
5476
// Columns
5477
if (command.groupBy == 1) {
@@ -5489,9 +5490,6 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
5490
data.columns.push({ id: 'bytesout', title: "bytesout", format: 'bytes', align: 'center', sumBy: 'protocol' });
5491
}
5492
5492
- // Remote guest column is not needed
5493
- if (!command.showGuestName) { data.columns.splice(2, 1); }
5494
-
5493
// Rows
5494
for (var i in docs) {
5495
// If MySQL or MariaDB query, we can't filter on MsgID, so we have to do it here.
@@ -5509,7 +5507,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
5507
if (command.showTraffic) { entry.bytesin = docs[i].bytesin; entry.bytesout = docs[i].bytesout; }
5508
5509
// Add guest name if present
5512
- if (docs[i].guestname != null) { entry.guestname = docs[i].guestname; }
5510
+ if (docs[i].guestname != null) { entry.guestname = docs[i].guestname; guestNamePresent = true; }
5511
5512
// Session length
5513
if (((docs[i].msgid >= 10) && (docs[i].msgid <= 12)) && (docs[i].msgArgs != null) && (typeof docs[i].msgArgs == 'object') && (typeof docs[i].msgArgs[3] == 'number')) { entry.length = docs[i].msgArgs[3]; }
@@ -5533,9 +5531,61 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
5531
}
5532
5533
}
5534
+
5535
+ // Remove guest column if not needed
5536
+ if (guestNamePresent == false) { data.columns.splice(2, 1); }
5537
+
5538
try { ws.send(JSON.stringify({ action: 'report', data: data })); } catch (ex) { }
5539
});
5540
}
5541
+
5542
+ if (command.type == 2) { // This is the user bandwidth usage report.
5543
+ // If we are not user administrator on this site, only search for events with our own user id.
5544
+ var ids = [user._id];
5545
+ if ((user.siteadmin & SITERIGHT_MANAGEUSERS) != 0) {
5546
+ if (command.devGroup != null) {
5547
+ ids = [user._id, command.devGroup];
5548
+ } else {
5549
+ if (manageAllDeviceGroups) { ids = ['*']; } else if (user.links) { for (var i in user.links) { ids.push(i); } }
5550
+ }
5551
+ }
5552
+
5553
+ // Get the events in the time range
5554
+ // MySQL or MariaDB query will ignore the MsgID filter.
5555
+ db.GetEventsTimeRange(ids, domain.id, [5, 10, 11, 12, 122, 123, 124, 125, 126], new Date(command.start * 1000), new Date(command.end * 1000), function (err, docs) {
5556
+ if (err != null) return;
5557
+ var data = { groups: { 0: { entries: [] } } };
5558
+ data.columns = [{ id: 'userid', title: "user", format: 'user' }, { id: 'length', title: "length", format: 'seconds', align: 'center', sumBy: true }, { id: 'bytesin', title: "bytesin", format: 'bytes', align: 'center', sumBy: true }, { id: 'bytesout', title: "bytesout", format: 'bytes', align: 'center', sumBy: true }];
5559
+ var userEntries = {};
5560
+
5561
+ // Sum all entry logs for each user
5562
+ for (var i in docs) {
5563
+ // If MySQL or MariaDB query, we can't filter on MsgID, so we have to do it here.
5564
+ if ((docs[i].msgid != 5) && (docs[i].msgid != 10) && (docs[i].msgid != 11) && (docs[i].msgid != 12) && ((docs[i].msgid < 122) && (docs[i].msgid > 126))) continue;
5565
+ if ((command.devGroup != null) && (docs[i].ids != null) && (docs[i].ids.indexOf(command.devGroup) == -1)) continue;
5566
+
5567
+ // Fetch or create the user entry
5568
+ var userEntry = userEntries[docs[i].userid];
5569
+ if (userEntry == null) { userEntry = { userid: docs[i].userid, length: 0, bytesin: 0, bytesout: 0}; }
5570
+ if (docs[i].bytesin) { userEntry.bytesin += docs[i].bytesin; }
5571
+ if (docs[i].bytesout) { userEntry.bytesout += docs[i].bytesout; }
5572
+
5573
+ // Session length
5574
+ if (((docs[i].msgid >= 10) && (docs[i].msgid <= 12)) && (docs[i].msgArgs != null) && (typeof docs[i].msgArgs == 'object') && (typeof docs[i].msgArgs[3] == 'number')) { userEntry.length += docs[i].msgArgs[3]; }
5575
+ else if ((docs[i].msgid >= 122) && (docs[i].msgid <= 126) && (docs[i].msgArgs != null) && (typeof docs[i].msgArgs == 'object') && (typeof docs[i].msgArgs[0] == 'number')) { userEntry.length += docs[i].msgArgs[0]; }
5576
+
5577
+ // Set the user entry
5578
+ userEntries[docs[i].userid] = userEntry;
5579
+ }
5580
+
5581
+ var userEntries2 = [];
5582
+ for (var i in userEntries) { userEntries2.push(userEntries[i]); }
5583
+ data.groups[0].entries = userEntries2;
5584
+
5585
+ try { ws.send(JSON.stringify({ action: 'report', data: data })); } catch (ex) { }
5586
+ });
5587
+ }
5588
+
5589
break;
5590
}
5591
default: {
views/default.handlebars
+13
-7
@@ -14925,19 +14925,23 @@
14925
if (xxdialogMode) return;
14926
var y = '', x = '', settings = JSON.parse(getstore('_ReportSettings', '{}'));
14927
14928
- var options = { 1 : "Remote Sessions" }
14928
+ var options = { 1 : "Remote Sessions", 2 : "User Bandwidth Usage" }
14929
for (var i in options) { y += '<option value=' + i + ((settings.type == i)?' selected':'') + '>' + options[i] + '</option>'; }
14930
x += addHtmlValue("Type", '<select id=d2reportType style=float:right;width:250px onchange=generateReportDialogValidate()>' + y + '</select>');
14931
14932
+ x += '<div id=d2GroupByDiv style=display:none>';
14933
y = '';
14934
var options = { 1 : "User", 2: "Device", 3: "Day" }
14935
for (var i in options) { y += '<option value=' + i + ((settings.groupBy == i)?' selected':'') + '>' + options[i] + '</option>'; }
14936
x += addHtmlValue("Group by", '<select id=d2groupBy style=float:right;width:250px onchange=generateReportDialogValidate()>' + y + '</select>');
14937
+ x += '</div>';
14938
14939
+ x += '<div id=d2DeviceGroupDiv style=display:none>';
14940
y = '<option value=0' + ((settings.devGroup == 0)?' selected':'') + '>' + "All" + '</option>';
14941
var omeshs = getOrderedList(meshes, 'name');
14942
for (var i in omeshs) { y += '<option value=' + encodeURIComponentEx(omeshs[i]._id) + ((settings.devGroup == omeshs[i]._id)?' selected':'') + '>' + EscapeHtml(omeshs[i].name) + '</option>'; }
14943
x += addHtmlValue("Device Group", '<select onchange=generateReportDialogValidate() id=d2groupId style=float:right;width:250px>' + y + '</select>');
14944
+ x += '</div>';
14945
14946
y = '';
14947
if (settings.timeRange == null) { settings.timeRange = 1; }
@@ -14951,7 +14955,6 @@
14955
14956
x += '<div id=d2showTrafficDiv style=display:none>';
14957
x += addHtmlValue("", '<div style=width:250px><label><input type=checkbox id=d2showTraffic ' + ((settings.showTraffic) ? 'checked' : '') + '>' + "Show Traffic" + '</label><div>');
14954
- x += addHtmlValue("", '<div style=width:250px><label><input type=checkbox id=d2showGuestName ' + ((settings.showGuestName) ? 'checked' : '') + '>' + "Show Guest Name" + '</label><div>');
14958
x += '</div>';
14959
14960
setDialogMode(2, "Generate Report", 3, generateReportDialogEx, x);
@@ -14965,6 +14968,8 @@
14968
14969
function generateReportDialogValidate() {
14970
QV('d2timeRangeDiv', Q('d2timeRange').value == 0);
14971
+ QV('d2GroupByDiv', Q('d2reportType').value == 1);
14972
+ QV('d2DeviceGroupDiv', Q('d2reportType').value == 1);
14973
QV('d2showTrafficDiv', Q('d2reportType').value == 1);
14974
}
14975
@@ -14982,8 +14987,8 @@
14987
try { tz = Intl.DateTimeFormat().resolvedOptions().timeZone; } catch (ex) {}
14988
var devGroup = decodeURIComponent(Q('d2groupId').value);
14989
if (devGroup == 0) { devGroup = null; }
14985
- putstore('_ReportSettings', JSON.stringify({ type: parseInt(Q('d2reportType').value), groupBy: parseInt(Q('d2groupBy').value), timeRange: parseInt(Q('d2timeRange').value), devGroup: devGroup, showTraffic: Q('d2showTraffic').checked, showGuestName: Q('d2showGuestName').checked }));
14986
- meshserver.send({ action: 'report', type: parseInt(Q('d2reportType').value), groupBy: parseInt(Q('d2groupBy').value), start: start, end: end, tz: tz, tf: new Date().getTimezoneOffset(), l: getLang(), devGroup: devGroup, showTraffic: Q('d2showTraffic').checked, showGuestName: Q('d2showGuestName').checked });
14990
+ putstore('_ReportSettings', JSON.stringify({ type: parseInt(Q('d2reportType').value), groupBy: parseInt(Q('d2groupBy').value), timeRange: parseInt(Q('d2timeRange').value), devGroup: devGroup, showTraffic: Q('d2showTraffic').checked }));
14991
+ meshserver.send({ action: 'report', type: parseInt(Q('d2reportType').value), groupBy: parseInt(Q('d2groupBy').value), start: start, end: end, tz: tz, tf: new Date().getTimezoneOffset(), l: getLang(), devGroup: devGroup, showTraffic: Q('d2showTraffic').checked });
14992
}
14993
14994
function renderReport(r) {
@@ -15014,12 +15019,12 @@
15019
for (var i in r.groups) {
15020
x += '<tr style=height:8px></tr>'
15021
x += '<tr><td colspan=' + r.columns.length + ' style="border-bottom:1pt solid black"><b>'
15017
- x += renderReportFormat(i, r.groupFormat);
15022
+ if (i != 0) { x += renderReportFormat(i, r.groupFormat); }
15023
x += '</b></td></tr>'
15024
for (var j in r.groups[i].entries) {
15025
var e = r.groups[i].entries[j];
15026
x += '<tr>'
15022
- reportCSV += '"' + csvClean(renderReportFormatCSV(i, r.groupFormat)) + '"';
15027
+ if (i != 0) { reportCSV += '"' + csvClean(renderReportFormatCSV(i, r.groupFormat)) + '"'; } else { reportCSV += '""'; }
15028
for (var k in r.columns) {
15029
var style = '';
15030
if (r.columns[k].align) { style = 'text-align:' + EscapeHtml(r.columns[k].align); }
@@ -15032,6 +15037,7 @@
15037
}
15038
if (r.columns[k].sumBy != null) {
15039
var v1 = e[r.columns[k].sumBy];
15040
+ if (r.columns[k].sumBy === true) { v1 = true; }
15041
var v2 = e[r.columns[k].id];
15042
sumByCol = r.columns[k].sumBy;
15043
if (v2 != null) {
@@ -15050,7 +15056,7 @@
15056
// Display totals
15057
if (sumByCol != null) {
15058
var sumByColNum = -1;
15053
- for (var i in r.columns) { if (r.columns[i].id == sumByCol) { sumByColNum = i; } }
15059
+ if (sumByCol === true) { sumByColNum = 99999; } else { for (var i in r.columns) { if (r.columns[i].id == sumByCol) { sumByColNum = i; } } }
15060
if (sumByColNum >= 0) {
15061
sumByValues.sort();
15062
var firstRow = true;