addtag,removetag in meshctrl.js #7723

Signed-off-by: si458 <simonsmith5521@gmail.com>

si458 committed Apr 4, 2026 at 20:48 UTC 6c376c30c948b985ea198a351fcf2860e13bfce9
2 files changed +69 -14
meshctrl.js
+63 -14
@@ -865,6 +865,8 @@ if (args['_'].length == 0) {
865 case 'editdevice': {
866 console.log("Change information about a device, Example usages:\r\n");
867 console.log(winRemoveSingleQuotes(" MeshCtrl EditDevice --id 'deviceid' --name 'device1'"));
868 + console.log(winRemoveSingleQuotes(" MeshCtrl EditDevice --id 'deviceid' --addtag 'newtag'"));
869 + console.log(winRemoveSingleQuotes(" MeshCtrl EditDevice --id 'deviceid' --removetag 'oldtag'"));
870 console.log("\r\nRequired arguments:\r\n");
871 if (process.platform == 'win32') {
872 console.log(" --id [deviceid] - The device identifier.");
@@ -873,13 +875,17 @@ if (args['_'].length == 0) {
875 }
876 console.log("\r\nOptional arguments:\r\n");
877 if (process.platform == 'win32') {
876 - console.log(" --name [name] - Change device name.");
877 - console.log(" --desc [description] - Change device description.");
878 - console.log(" --tags [tag1,tags2] - Change device tags.");
878 + console.log(" --name [name] - Change device name.");
879 + console.log(" --desc [description] - Change device description.");
880 + console.log(" --tags [tag1,tag2] - Set device tags (replaces all existing tags).");
881 + console.log(" --addtag [tag1,tag2] - Add tags to existing tags.");
882 + console.log(" --removetag [tag1,tag2] - Remove tags from existing tags.");
883 } else {
880 - console.log(" --name '[name]' - Change device name.");
881 - console.log(" --desc '[description]' - Change device description.");
882 - console.log(" --tags '[tag1,tags2]' - Change device tags.");
884 + console.log(" --name '[name]' - Change device name.");
885 + console.log(" --desc '[description]' - Change device description.");
886 + console.log(" --tags '[tag1,tag2]' - Set device tags (replaces all existing tags).");
887 + console.log(" --addtag '[tag1,tag2]' - Add tags to existing tags.");
888 + console.log(" --removetag '[tag1,tag2]' - Remove tags from existing tags.");
889 }
890 console.log(" --icon [number] - Change the device icon (1 to 8).");
891 console.log(" --consent [flags] - Sum of the following numbers:");
@@ -1728,14 +1734,20 @@ function serverConnect() {
1734 break;
1735 }
1736 case 'editdevice': {
1731 - var op = { action: 'changedevice', nodeid: args.id, responseid: 'meshctrl' };
1732 - if (typeof args.name == 'string') { op.name = args.name; }
1733 - if (typeof args.name == 'number') { op.name = '' + args.name; }
1734 - if (args.desc) { if (args.desc === true) { op.desc = ''; } else if (typeof args.desc == 'string') { op.desc = args.desc; } else if (typeof args.desc == 'number') { op.desc = '' + args.desc; } }
1735 - if (args.tags) { if (args.tags === true) { op.tags = ''; } else if (typeof args.tags == 'string') { op.tags = args.tags.split(','); } else if (typeof args.tags == 'number') { op.tags = '' + args.tags; } }
1736 - if (args.icon) { op.icon = parseInt(args.icon); if ((typeof op.icon != 'number') || isNaN(op.icon) || (op.icon < 1) || (op.icon > 8)) { console.log("Icon must be between 1 and 8."); process.exit(1); return; } }
1737 - if (args.consent) { op.consent = parseInt(args.consent); if ((typeof op.consent != 'number') || isNaN(op.consent) || (op.consent < 1)) { console.log("Invalid consent flags."); process.exit(1); return; } }
1738 - ws.send(JSON.stringify(op));
1737 + if (args.addtag || args.removetag) {
1738 + // we need to fetch the node data first to then modify the tags
1739 + var nodeid = args.id;
1740 + ws.send(JSON.stringify({ action: 'nodes', id: args.id, responseid: 'meshctrl' }));
1741 + } else {
1742 + var op = { action: 'changedevice', nodeid: args.id, responseid: 'meshctrl' };
1743 + if (typeof args.name == 'string') { op.name = args.name; }
1744 + if (typeof args.name == 'number') { op.name = '' + args.name; }
1745 + if (args.desc) { if (args.desc === true) { op.desc = ''; } else if (typeof args.desc == 'string') { op.desc = args.desc; } else if (typeof args.desc == 'number') { op.desc = '' + args.desc; } }
1746 + if (args.tags) { if (args.tags === true) { op.tags = ''; } else if (typeof args.tags == 'string') { op.tags = args.tags.split(','); } else if (typeof args.tags == 'number') { op.tags = '' + args.tags; } }
1747 + if (args.icon) { op.icon = parseInt(args.icon); if ((typeof op.icon != 'number') || isNaN(op.icon) || (op.icon < 1) || (op.icon > 8)) { console.log("Icon must be between 1 and 8."); process.exit(1); return; } }
1748 + if (args.consent) { op.consent = parseInt(args.consent); if ((typeof op.consent != 'number') || isNaN(op.consent) || (op.consent < 1)) { console.log("Invalid consent flags."); process.exit(1); return; } }
1749 + ws.send(JSON.stringify(op));
1750 + }
1751 break;
1752 }
1753 case 'runcommand': {
@@ -2473,6 +2485,43 @@ function serverConnect() {
2485 }
2486 }
2487 }
2488 + if ((settings.cmd == 'editdevice') && (data.responseid == 'meshctrl')) {
2489 + // Find the node to get its current tags
2490 + var targetNode = null;
2491 + for (var i in data.nodes) {
2492 + for (var j in data.nodes[i]) {
2493 + if (data.nodes[i][j]._id == args.id) { targetNode = data.nodes[i][j]; break; }
2494 + }
2495 + if (targetNode != null) { break; }
2496 + }
2497 + if (targetNode == null) {
2498 + console.log('Node not found.');
2499 + process.exit();
2500 + return;
2501 + }
2502 + // Start with current tags or empty array
2503 + var tags = (Array.isArray(targetNode.tags)) ? targetNode.tags.slice() : [];
2504 + // Add tags: --addtag tag1,tag2
2505 + if (args.addtag) {
2506 + var addtags = (typeof args.addtag == 'string') ? args.addtag.split(',') : ['' + args.addtag];
2507 + for (var i in addtags) { var t = addtags[i].trim(); if (t && (tags.indexOf(t) < 0)) { tags.push(t); } }
2508 + }
2509 + // Remove tags: --removetag tag1,tag2
2510 + if (args.removetag) {
2511 + var removetags = (typeof args.removetag == 'string') ? args.removetag.split(',') : ['' + args.removetag];
2512 + var removetrimmed = removetags.map(function(r) { return r.trim(); });
2513 + tags = tags.filter(function(t) { return removetrimmed.indexOf(t) < 0; });
2514 + }
2515 + // Build and send the changedevice op
2516 + var op = { action: 'changedevice', nodeid: args.id, responseid: 'meshctrl' };
2517 + if (typeof args.name == 'string') { op.name = args.name; }
2518 + if (typeof args.name == 'number') { op.name = '' + args.name; }
2519 + if (args.desc) { if (args.desc === true) { op.desc = ''; } else if (typeof args.desc == 'string') { op.desc = args.desc; } else if (typeof args.desc == 'number') { op.desc = '' + args.desc; } }
2520 + if (args.icon) { op.icon = parseInt(args.icon); if ((typeof op.icon != 'number') || isNaN(op.icon) || (op.icon < 1) || (op.icon > 8)) { console.log("Icon must be between 1 and 8."); process.exit(1); return; } }
2521 + if (args.consent) { op.consent = parseInt(args.consent); if ((typeof op.consent != 'number') || isNaN(op.consent) || (op.consent < 1)) { console.log("Invalid consent flags."); process.exit(1); return; } }
2522 + op.tags = tags;
2523 + ws.send(JSON.stringify(op));
2524 + }
2525 break;
2526 }
2527 case 'meshes': { // LISTDEVICEGROUPS
meshuser.js
+6
@@ -729,6 +729,12 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
729 if (command.meshid == null) { err = 'Invalid group id'; }
730 }
731
732 + // Check if command.id is set with a domain id, if not, add the domain id to it.
733 + if (typeof command.id == 'string' && command.id !== '') {
734 + if (common.validateString(command.id, 1, 1024) == false) { err = 'Invalid device identifier'; }
735 + else if (command.id.indexOf('/') == -1) { command.id = 'node/' + domain.id + '/' + command.id; }
736 + }
737 +
738 if (err == null) {
739 try {
740 if (command.meshid == null) {