From 1b67b8436954f00abee27e802dd2dc87050f1780 Mon Sep 17 00:00:00 2001 From: Ylian Saint-Hilaire Date: Thu, 18 Aug 2022 18:03:03 -0700 Subject: [PATCH] More work on integrating the script-task. --- MeshCentralServer.njsproj | 1 + meshagent.js | 15 +- meshcentral.js | 6 + .../tail.datetime-default-blue.min.css | 3 + .../tail.datetime-default-blue.min.map | 1 + public/tail.datetime/tail.datetime.min.js | 2 + taskmanager.js | 714 +++++++++++ views/task-schedule.handlebars | 249 ++++ views/task-scriptedit.handlebars | 73 ++ views/task-user.handlebars | 1070 +++++++++++++++++ 10 files changed, 2120 insertions(+), 14 deletions(-) create mode 100644 public/tail.datetime/tail.datetime-default-blue.min.css create mode 100644 public/tail.datetime/tail.datetime-default-blue.min.map create mode 100644 public/tail.datetime/tail.datetime.min.js create mode 100644 taskmanager.js create mode 100644 views/task-schedule.handlebars create mode 100644 views/task-scriptedit.handlebars create mode 100644 views/task-user.handlebars diff --git a/MeshCentralServer.njsproj b/MeshCentralServer.njsproj index 8873df56..532cf25c 100644 --- a/MeshCentralServer.njsproj +++ b/MeshCentralServer.njsproj @@ -238,6 +238,7 @@ + diff --git a/meshagent.js b/meshagent.js index 500b7713..038c74d4 100644 --- a/meshagent.js +++ b/meshagent.js @@ -1740,20 +1740,7 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) { } case 'script-task': { // These command are for running regular batch jobs on the remote device - switch (command.subaction) { - case 'getScript': { - console.log('getScript'); - break; - } - case 'clearAllPendingTasks': { - console.log('clearAllPendingTasks'); - break; - } - case 'taskComplete': { - console.log('taskComplete'); - break; - } - } + if (parent.parent.taskManager != null) { parent.parent.taskManager.agentAction(command, obj); } break; } default: { diff --git a/meshcentral.js b/meshcentral.js index b90d2b2e..0dd31e92 100644 --- a/meshcentral.js +++ b/meshcentral.js @@ -33,6 +33,7 @@ function CreateMeshCentralServer(config, args) { obj.amtScanner = null; obj.amtManager = null; obj.meshScanner = null; + obj.taskManager = null; obj.letsencrypt = null; obj.eventsDispatch = {}; obj.fs = require('fs'); @@ -1497,6 +1498,11 @@ function CreateMeshCentralServer(config, args) { return; } + // Setup the task manager + if ((obj.config) && (obj.config.settings) && (obj.config.settings.taskmanager == true)) { + obj.taskManager = require('./taskmanager').createTaskManager(obj); + } + // Start plugin manager if configuration allows this. if ((obj.config) && (obj.config.settings) && (obj.config.settings.plugins != null) && (obj.config.settings.plugins != false) && ((typeof obj.config.settings.plugins != 'object') || (obj.config.settings.plugins.enabled != false))) { obj.pluginHandler = require('./pluginHandler.js').pluginHandler(obj); diff --git a/public/tail.datetime/tail.datetime-default-blue.min.css b/public/tail.datetime/tail.datetime-default-blue.min.css new file mode 100644 index 00000000..941a5aea --- /dev/null +++ b/public/tail.datetime/tail.datetime-default-blue.min.css @@ -0,0 +1,3 @@ +@charset "UTF-8"; /* pytesNET/tail.DateTime v.0.4.14 */ +/* @author SamBrishes, pytesNET | @license MIT */ +.tail-datetime-calendar,.tail-datetime-calendar *,.tail-datetime-calendar :after,.tail-datetime-calendar :before{box-sizing:border-box;-webkit-box-sizing:border-box}.tail-datetime-calendar{top:0;left:0;width:275px;height:auto;margin:15px;padding:0;z-index:3000;display:block;position:absolute;visibility:hidden;direction:ltr;border-collapse:separate;font-family:"Open Sans",Calibri,Arial,sans-serif;background-color:#fff;border-width:0;border-style:solid;border-color:transparent;border-radius:3px;box-shadow:0 1px 3px rgba(0,0,0,.3125);-webkit-box-shadow:0 1px 3px rgba(0,0,0,.3125)}.tail-datetime-calendar:after{clear:both;content:"";display:block;font-size:0;visibility:hidden}.tail-datetime-calendar.calendar-static{top:auto;left:auto;margin-left:auto;margin-right:auto;position:static;visibility:visible}.tail-datetime-calendar button.calendar-close{top:100%;right:15px;color:#303438;width:35px;height:25px;margin:1px 0 0 0;padding:5px 10px;opacity:.5;outline:0;display:inline-block;position:absolute;font-size:14px;line-height:1.125em;text-shadow:none;background-color:#fff;background-image:url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMiIgaGVpZ2h0PSIxNiIgdmlld0JveD0iMCAwIDEyIDE2Ij48cGF0aCBmaWxsPSIjMzAzNDM4IiBkPSJNNy40OCA4bDMuNzUgMy43NS0xLjQ4IDEuNDhMNiA5LjQ4bC0zLjc1IDMuNzUtMS40OC0xLjQ4TDQuNTIgOCAuNzcgNC4yNWwxLjQ4LTEuNDhMNiA2LjUybDMuNzUtMy43NSAxLjQ4IDEuNDhMNy40OCA4eiIvPjwvc3ZnPg==");background-repeat:no-repeat;background-position:center center;border-width:0;border-style:solid;border-color:transparent;border-radius:0 0 3px 3px;box-shadow:0 1px 3px rgba(0,0,0,.3125);-webkit-box-shadow:0 1px 3px rgba(0,0,0,.3125);transition:opacity 142ms linear;-webkit-transition:opacity 142ms linear}.tail-datetime-calendar button.calendar-close:hover{opacity:1}.tail-datetime-calendar .calendar-tooltip{color:#fff;width:auto;margin:0;padding:0;display:block;position:absolute;background-color:#202428;border-radius:3px}.tail-datetime-calendar .calendar-tooltip:before{top:-7px;left:50%;width:0;height:0;margin:0 0 0 -6px;content:"";display:block;position:absolute;border-width:0 7px 7px 7px;border-style:solid;border-color:transparent transparent #202428 transparent}.tail-datetime-calendar .calendar-tooltip .tooltip-inner{width:auto;margin:0;padding:4px 7px;display:block;font-size:12px;line-height:14px}.tail-datetime-calendar .calendar-actions{color:#fff;width:100%;height:36px;margin:0;padding:0;display:table;overflow:hidden;border-spacing:0;border-collapse:separate;background-color:#149be6;border-width:0;border-style:solid;border-color:transparent;border-radius:3px 3px 0 0}.tail-datetime-calendar .calendar-actions span{margin:0;padding:0;display:table-cell;position:relative;text-align:center;line-height:36px;text-shadow:-1px -1px 0 #0e6ca0;background-repeat:no-repeat;background-position:center center}.tail-datetime-calendar .calendar-actions span[data-action]{cursor:pointer}.tail-datetime-calendar .calendar-actions span.action{width:36px;font-size:22px}.tail-datetime-calendar .calendar-actions span.label{width:auto}.tail-datetime-calendar .calendar-actions span:first-child:before,.tail-datetime-calendar .calendar-actions span:last-child:before{top:5px;bottom:5px;width:1px;height:auto;margin:0;padding:0;content:"";display:inline-block;position:absolute;background-color:#107bb7}.tail-datetime-calendar .calendar-actions span:first-child:before{right:-1px}.tail-datetime-calendar .calendar-actions span:last-child:before{left:-1px}.tail-datetime-calendar .calendar-actions span:first-child:hover:before,.tail-datetime-calendar .calendar-actions span:last-child:hover:before{display:none}.tail-datetime-calendar .calendar-actions span[data-action]:hover{background-color:#107bb7}.tail-datetime-calendar .calendar-actions span.action-prev{background-image:url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI2IiBoZWlnaHQ9IjE2IiB2aWV3Qm94PSIwIDAgNiAxNiI+PHBhdGggZmlsbD0iI2ZmZmZmZiIgZD0iTTYgMkwwIDhsNiA2VjJ6Ii8+PC9zdmc+")}.tail-datetime-calendar .calendar-actions span.action-next{background-image:url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI2IiBoZWlnaHQ9IjE2IiB2aWV3Qm94PSIwIDAgNiAxNiI+PHBhdGggZmlsbD0iI2ZmZmZmZiIgZD0iTTAgMTRsNi02LTYtNnYxMnoiLz48L3N2Zz4=")}.tail-datetime-calendar .calendar-actions span.action-submit{background-image:url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMiIgaGVpZ2h0PSIxNiIgdmlld0JveD0iMCAwIDEyIDE2Ij48cGF0aCBmaWxsPSIjZmZmZmZmIiBkPSJNMTIgNWwtOCA4LTQtNCAxLjUtMS41TDQgMTBsNi41LTYuNUwxMiA1eiIvPjwvc3ZnPg==")}.tail-datetime-calendar .calendar-actions span.action-cancel{background-image:url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMiIgaGVpZ2h0PSIxNiIgdmlld0JveD0iMCAwIDEyIDE2Ij48cGF0aCBmaWxsPSIjZmZmZmZmIiBkPSJNNy40OCA4bDMuNzUgMy43NS0xLjQ4IDEuNDhMNiA5LjQ4bC0zLjc1IDMuNzUtMS40OC0xLjQ4TDQuNTIgOCAuNzcgNC4yNWwxLjQ4LTEuNDhMNiA2LjUybDMuNzUtMy43NSAxLjQ4IDEuNDhMNy40OCA4eiIvPjwvc3ZnPg==")}.tail-datetime-calendar .calendar-datepicker{width:100%;margin:0;padding:0;display:block;position:relative}.tail-datetime-calendar .calendar-datepicker table{width:100%;margin:0;padding:0;border-spacing:0;border-collapse:separate}.tail-datetime-calendar .calendar-datepicker table tr td,.tail-datetime-calendar .calendar-datepicker table tr th{color:#303438;height:30px;padding:0;position:relative;font-size:13px;text-align:center;font-weight:400;text-shadow:none;line-height:30px;background-color:transparent;border-width:0;border-style:solid;border-color:transparent;border-radius:0}.tail-datetime-calendar .calendar-datepicker table tr th{color:#fff;background-color:#303438}.tail-datetime-calendar .calendar-datepicker table tr td{cursor:pointer}.tail-datetime-calendar .calendar-datepicker table tr td span.inner{margin:0;padding:0;display:inline-block}.tail-datetime-calendar .calendar-datepicker table tr td.date-disabled{cursor:not-allowed;color:#909498;background-color:#f0f0f0}.tail-datetime-calendar .calendar-datepicker table tr td.date-disabled:after{left:3px;bottom:3px;width:35px;height:1px;margin:0;padding:0;content:"";display:inline-block;position:absolute;background-color:#bfbfbf;transform-origin:2px -5px;transform:rotate(-45deg);-moz-transform:rotate(-45deg);-webkit-transform:rotate(-45deg)}.tail-datetime-calendar .calendar-datepicker table tr td.date-next,.tail-datetime-calendar .calendar-datepicker table tr td.date-previous{color:#909498;background-color:#f0f0f0}.tail-datetime-calendar .calendar-datepicker table tr td .tooltip-tick,.tail-datetime-calendar .calendar-datepicker table tr td.date-today:before{top:5px;width:5px;height:5px;margin:0;padding:0;z-index:20;content:"";display:inline-block;position:absolute;border-width:0;border-style:solid;border-color:transparent;border-radius:50%}.tail-datetime-calendar .calendar-datepicker table tr td.date-today:before{left:5px;background-color:#32b93c}.tail-datetime-calendar .calendar-datepicker table tr td .tooltip-tick{right:5px;background-color:#202428}.tail-datetime-calendar .calendar-datepicker table tr td .tooltip-tick:after,.tail-datetime-calendar .calendar-datepicker table tr td .tooltip-tick:before{display:none}.tail-datetime-calendar .calendar-datepicker table tr td.calendar-day,.tail-datetime-calendar .calendar-datepicker table tr th.calendar-week{width:14.28571429%;height:35px}.tail-datetime-calendar .calendar-datepicker table tr td.calendar-day span.inner,.tail-datetime-calendar .calendar-datepicker table tr th.calendar-week span.inner{width:31px;height:31px;line-height:29px;border-width:1px;border-style:solid;border-color:transparent;border-radius:50%}.tail-datetime-calendar .calendar-datepicker table tr td.calendar-day:hover span.inner,.tail-datetime-calendar .calendar-datepicker table tr th.calendar-week:hover span.inner{border-color:#ccc}.tail-datetime-calendar .calendar-datepicker table tr td.calendar-day.date-disabled span.inner,.tail-datetime-calendar .calendar-datepicker table tr td.calendar-day.date-disabled:hover span.inner,.tail-datetime-calendar .calendar-datepicker table tr th.calendar-week.date-disabled span.inner,.tail-datetime-calendar .calendar-datepicker table tr th.calendar-week.date-disabled:hover span.inner{border-color:transparent}.tail-datetime-calendar .calendar-datepicker table tr td.calendar-day.date-select span.inner,.tail-datetime-calendar .calendar-datepicker table tr td.calendar-day.date-select:hover span.inner,.tail-datetime-calendar .calendar-datepicker table tr th.calendar-week.date-select span.inner,.tail-datetime-calendar .calendar-datepicker table tr th.calendar-week.date-select:hover span.inner{color:#32b93c;border-color:#32b93c}.tail-datetime-calendar .calendar-datepicker table tr td.calendar-decade,.tail-datetime-calendar .calendar-datepicker table tr td.calendar-month,.tail-datetime-calendar .calendar-datepicker table tr td.calendar-year{width:33.33333333%;height:40px;transition:color 142ms linear;-webkit-transition:color 142ms linear}.tail-datetime-calendar .calendar-datepicker table tr td.calendar-decade.date-today:before,.tail-datetime-calendar .calendar-datepicker table tr td.calendar-month.date-today:before,.tail-datetime-calendar .calendar-datepicker table tr td.calendar-year.date-today:before{left:50%;margin-left:-2.5px}.tail-datetime-calendar .calendar-datepicker table tr td.calendar-decade span.inner,.tail-datetime-calendar .calendar-datepicker table tr td.calendar-month span.inner,.tail-datetime-calendar .calendar-datepicker table tr td.calendar-year span.inner{width:auto;height:31px;line-height:29px}.tail-datetime-calendar .calendar-datepicker table tr td.calendar-decade span.inner:after,.tail-datetime-calendar .calendar-datepicker table tr td.calendar-decade span.inner:before,.tail-datetime-calendar .calendar-datepicker table tr td.calendar-month span.inner:after,.tail-datetime-calendar .calendar-datepicker table tr td.calendar-month span.inner:before,.tail-datetime-calendar .calendar-datepicker table tr td.calendar-year span.inner:after,.tail-datetime-calendar .calendar-datepicker table tr td.calendar-year span.inner:before{width:20px;height:20px;content:"";z-index:15;display:inline-block;position:absolute;border-width:1px;border-style:solid;border-color:transparent;transition:all 142ms linear;-webkit-transition:all 142ms linear}.tail-datetime-calendar .calendar-datepicker table tr td.calendar-decade span.inner:before,.tail-datetime-calendar .calendar-datepicker table tr td.calendar-month span.inner:before,.tail-datetime-calendar .calendar-datepicker table tr td.calendar-year span.inner:before{top:0;left:0}.tail-datetime-calendar .calendar-datepicker table tr td.calendar-decade:hover span.inner:before,.tail-datetime-calendar .calendar-datepicker table tr td.calendar-month:hover span.inner:before,.tail-datetime-calendar .calendar-datepicker table tr td.calendar-year:hover span.inner:before{top:6px;left:6px;border-top-color:#ccc;border-left-color:#ccc}.tail-datetime-calendar .calendar-datepicker table tr td.calendar-decade span.inner:after,.tail-datetime-calendar .calendar-datepicker table tr td.calendar-month span.inner:after,.tail-datetime-calendar .calendar-datepicker table tr td.calendar-year span.inner:after{right:0;bottom:0}.tail-datetime-calendar .calendar-datepicker table tr td.calendar-decade:hover span.inner:after,.tail-datetime-calendar .calendar-datepicker table tr td.calendar-month:hover span.inner:after,.tail-datetime-calendar .calendar-datepicker table tr td.calendar-year:hover span.inner:after{right:6px;bottom:6px;border-right-color:#ccc;border-bottom-color:#ccc}.tail-datetime-calendar .calendar-datepicker table tr td.calendar-decade,.tail-datetime-calendar .calendar-datepicker table tr td.calendar-year{width:25%}.tail-datetime-calendar .calendar-datepicker table tr td.calendar-decade span.inner{height:54px;padding:7px 15px;text-align:left;line-height:20px}.tail-datetime-calendar .calendar-timepicker{width:100%;margin:0;padding:0;display:block;text-align:center;border-width:1px 0 0 0;border-style:solid;border-color:#d9d9d9}.tail-datetime-calendar .calendar-timepicker .timepicker-field{width:28%;margin:0;padding:15px 0 7px 0;display:inline-block;position:relative;text-align:center}.tail-datetime-calendar .calendar-timepicker .timepicker-field:first-of-type{text-align:right}.tail-datetime-calendar .calendar-timepicker .timepicker-field:last-of-type{text-align:left}.tail-datetime-calendar .calendar-timepicker .timepicker-field input[type=text]{color:#303438;width:100%;height:29px;margin:0;z-index:4;padding:3px 20px 3px 5px;outline:0;display:inline-block;position:relative;font-size:12px;text-align:center;line-height:23px;appearance:textfield;-moz-appearance:textfield;-webkit-appearance:textfield;background-color:#f0f0f0;border-width:0;border-style:solid;border-color:transparent;border-radius:3px;box-shadow:none;-webkit-box-shadow:none;transition:color 142ms linear,border 142ms linear,background 142ms linear;-webkit-transition:color 142ms linear,border 142ms linear,background 142ms linear}.tail-datetime-calendar .calendar-timepicker .timepicker-field input[type=text]:hover{color:#303438;background-color:#e0e0e0}.tail-datetime-calendar .calendar-timepicker .timepicker-field input[type=text]:focus{color:#fff;background-color:#32b93c}.tail-datetime-calendar .calendar-timepicker .timepicker-field input[type=text]:disabled{cursor:not-allowed;color:#a0a4a8;background-color:#f6f6f6}.tail-datetime-calendar .calendar-timepicker .timepicker-field button.picker-step{width:20px;height:15px;right:0;margin:0;padding:0;z-index:15;display:inline-block;position:absolute;background-color:#f0f0f0;box-shadow:none;-webkit-box-shadow:none;transition:border 142ms linear,background 142ms linear;-webkit-transition:border 142ms linear,background 142ms linear}.tail-datetime-calendar .calendar-timepicker .timepicker-field button.picker-step:before{top:4px;left:50%;width:0;height:0;margin:0 0 0 -4px;padding:0;content:"";display:inline-block;position:absolute;transition:border 142ms linear;-webkit-transition:border 142ms linear}.tail-datetime-calendar .calendar-timepicker .timepicker-field button.picker-step.step-up{top:15px;border-width:0 0 1px 1px;border-style:solid;border-color:#fff;border-radius:0 2px 0 0}.tail-datetime-calendar .calendar-timepicker .timepicker-field button.picker-step.step-up:hover{background-color:#e0e0e0}.tail-datetime-calendar .calendar-timepicker .timepicker-field button.picker-step.step-up:before{border-width:0 4px 5px 4px;border-style:solid;border-color:transparent transparent #303438 transparent}.tail-datetime-calendar .calendar-timepicker .timepicker-field button.picker-step.step-down{top:29px;border-width:1px 0 0 1px;border-style:solid;border-color:#fff;border-radius:0 0 2px 0}.tail-datetime-calendar .calendar-timepicker .timepicker-field button.picker-step.step-down:hover{background-color:#e0e0e0}.tail-datetime-calendar .calendar-timepicker .timepicker-field button.picker-step.step-down:before{border-width:5px 4px 0 4px;border-style:solid;border-color:#303438 transparent transparent transparent}.tail-datetime-calendar .calendar-timepicker .timepicker-field input:focus+button.step-up{border-color:rgba(255,255,255,.8);background-color:#32b93c}.tail-datetime-calendar .calendar-timepicker .timepicker-field input:focus+button.step-up:hover{background-color:#27912f}.tail-datetime-calendar .calendar-timepicker .timepicker-field input:focus+button.step-up:before{border-bottom-color:#fff}.tail-datetime-calendar .calendar-timepicker .timepicker-field input:focus+button+button.step-down{border-color:rgba(255,255,255,.8);background-color:#32b93c}.tail-datetime-calendar .calendar-timepicker .timepicker-field input:focus+button+button.step-down:hover{background-color:#27912f}.tail-datetime-calendar .calendar-timepicker .timepicker-field input:focus+button+button.step-down:before{border-top-color:#fff}.tail-datetime-calendar .calendar-timepicker .timepicker-field input:disabled+button.step-up{cursor:not-allowed;border-color:rgba(255,255,255,.8);background-color:#f6f6f6}.tail-datetime-calendar .calendar-timepicker .timepicker-field input:disabled+button.step-up:hover{background-color:#f6f6f6}.tail-datetime-calendar .calendar-timepicker .timepicker-field input:disabled+button.step-up:before{border-bottom-color:#a0a4a8}.tail-datetime-calendar .calendar-timepicker .timepicker-field input:disabled+button+button.step-down{cursor:not-allowed;border-color:rgba(255,255,255,.8);background-color:#f6f6f6}.tail-datetime-calendar .calendar-timepicker .timepicker-field input:disabled+button+button.step-down:hover{background-color:#f6f6f6}.tail-datetime-calendar .calendar-timepicker .timepicker-field input:disabled+button+button.step-down:before{border-top-color:#a0a4a8}.tail-datetime-calendar .calendar-timepicker .timepicker-field label{color:#303438;margin:0;padding:0;display:block;font-size:12px;text-align:center}.tail-datetime-calendar .calendar-timepicker label.timepicker-switch{cursor:pointer;margin:15px 0 -5px 0;display:block;text-align:center;vertical-align:top}.tail-datetime-calendar .calendar-timepicker label.timepicker-switch:after,.tail-datetime-calendar .calendar-timepicker label.timepicker-switch:before{width:auto;margin:0;padding:0 5px;font-size:12px;line-height:16px;vertical-align:top}.tail-datetime-calendar .calendar-timepicker label.timepicker-switch:before{content:attr(data-am)}.tail-datetime-calendar .calendar-timepicker label.timepicker-switch:after{content:attr(data-pm)}.tail-datetime-calendar .calendar-timepicker label.timepicker-switch input[type=checkbox]{display:none}.tail-datetime-calendar .calendar-timepicker label.timepicker-switch input[type=checkbox]+span{display:inline-block;position:relative;vertical-align:top}.tail-datetime-calendar .calendar-timepicker label.timepicker-switch input[type=checkbox]+span:before{width:50px;height:16px;content:"";display:inline-block;vertical-align:top;border-width:1px;border-style:solid;border-color:#149be6;border-radius:14px;transition:border 284ms linear;-webkit-transition:border 284ms linear}.tail-datetime-calendar .calendar-timepicker label.timepicker-switch input[type=checkbox]+span:after{top:3px;left:4px;right:30px;width:auto;height:10px;margin:0;padding:0;content:"";display:inline-block;position:absolute;background-color:#149be6;border-radius:15px;vertical-align:top;transition:left 284ms linear,right 284ms linear 284ms,background 284ms linear;-webkit-transition:left 284ms linear,right 284ms linear 284ms,background 284ms linear}.tail-datetime-calendar .calendar-timepicker label.timepicker-switch input[type=checkbox]:checked+span:before{border-color:#32b93c}.tail-datetime-calendar .calendar-timepicker label.timepicker-switch input[type=checkbox]:checked+span:after{left:30px;right:4px;background-color:#32b93c;transition:right 284ms linear,left 284ms linear 284ms,background 284ms linear;-webkit-transition:right 284ms linear,left 284ms linear 284ms,background 284ms linear}.tail-datetime-calendar .calendar-actions+.calendar-timepicker{border-width:0}.tail-datetime-calendar.rtl{direction:rtl}.tail-datetime-calendar.rtl .calendar-actions span.action-next,.tail-datetime-calendar.rtl .calendar-actions span.action-prev{transform:rotate(180deg);-moz-transform:rotate(180deg);-webkit-transform:rotate(180deg)}.tail-datetime-calendar.rtl .calendar-datepicker table tr td.date-disabled:after{right:3px;transform:rotate(45deg);-moz-transform:rotate(45deg);-webkit-transform:rotate(45deg)}.tail-datetime-calendar.rtl .calendar-datepicker table tr td.date-today:before{right:5px}.tail-datetime-calendar.rtl .calendar-datepicker table tr td .tooltip-tick{left:5px}.tail-datetime-calendar.rtl .calendar-datepicker table tr td.calendar-decade.date-today:before,.tail-datetime-calendar.rtl .calendar-datepicker table tr td.calendar-month.date-today:before,.tail-datetime-calendar.rtl .calendar-datepicker table tr td.calendar-year.date-today:before{right:50%;margin-right:-2.5px}.tail-datetime-calendar.rtl .calendar-datepicker table tr td.calendar-decade:hover span.inner:before,.tail-datetime-calendar.rtl .calendar-datepicker table tr td.calendar-month:hover span.inner:before,.tail-datetime-calendar.rtl .calendar-datepicker table tr td.calendar-year:hover span.inner:before{right:6px;border-right-color:#ccc}.tail-datetime-calendar.rtl .calendar-datepicker table tr td.calendar-decade span.inner:after,.tail-datetime-calendar.rtl .calendar-datepicker table tr td.calendar-month span.inner:after,.tail-datetime-calendar.rtl .calendar-datepicker table tr td.calendar-year span.inner:after{left:0}.tail-datetime-calendar.rtl .calendar-datepicker table tr td.calendar-decade:hover span.inner:after,.tail-datetime-calendar.rtl .calendar-datepicker table tr td.calendar-month:hover span.inner:after,.tail-datetime-calendar.rtl .calendar-datepicker table tr td.calendar-year:hover span.inner:after{left:6px;border-left-color:#ccc}.tail-datetime-calendar.rtl .calendar-datepicker table tr td.calendar-decade span.inner{text-align:right}.tail-datetime-calendar.rtl .calendar-timepicker .timepicker-field:first-child{text-align:left;padding-left:0;padding-right:25px}.tail-datetime-calendar.rtl .calendar-timepicker .timepicker-field:last-child{text-align:right;padding-left:25px;padding-right:0}.tail-datetime-calendar.rtl .calendar-timepicker .timepicker-field:first-child input[type=text]{margin-left:-1px;margin-right:0;border-radius:0 3px 3px 0}.tail-datetime-calendar.rtl .calendar-timepicker .timepicker-field:last-child input[type=text]{margin-left:0;margin-right:-1px;border-radius:3px 0 0 3px} \ No newline at end of file diff --git a/public/tail.datetime/tail.datetime-default-blue.min.map b/public/tail.datetime/tail.datetime-default-blue.min.map new file mode 100644 index 00000000..aa615d22 --- /dev/null +++ b/public/tail.datetime/tail.datetime-default-blue.min.map @@ -0,0 +1 @@ +{"version":3,"sources":["$stdin"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/public/tail.datetime/tail.datetime.min.js b/public/tail.datetime/tail.datetime.min.js new file mode 100644 index 00000000..5225baa5 --- /dev/null +++ b/public/tail.datetime/tail.datetime.min.js @@ -0,0 +1,2 @@ +/* pytesNET/tail.DateTime v.0.4.14 | Basic Version | @author SamBrishes, pytesNET | @license MIT */ +!function(t,e){"function"==typeof define&&define.amd?define(function(){return e(t,t.document)}):"object"==typeof module&&module.exports?module.exports=e(t,t.document):(void 0===t.tail&&(t.tail={}),t.tail.DateTime=t.tail.datetime=e(t,t.document),"undefined"!=typeof jQuery&&(jQuery.fn.DateTime=jQuery.fn.datetime=function(t){var e,i=[];return this.each(function(){!1!==(e=tail.DateTime(this,t))&&i.push(e)}),1===i.length?i[0]:0!==i.length&&i}),"undefined"!=typeof MooTools&&(Element.implement({DateTime:function(t){return new tail.DateTime(this,t)}}),Element.implement({datetime:function(t){return new tail.DateTime(this,t)}})))}(window,function(h,d){"use strict";function u(t,e){return!!(t&&"classList"in t)&&t.classList.contains(e)}function a(t,e){return t&&"classList"in t?t.classList.add(e):void 0}function n(t,e){return t&&"classList"in t?t.classList.remove(e):void 0}function s(t,e,i){if(CustomEvent&&CustomEvent.name)var a=new CustomEvent(e,i);else(a=d.createEvent("CustomEvent")).initCustomEvent(e,!!i.bubbles,!!i.cancelable,i.detail);return t.dispatchEvent(a)}function o(t,e){if("function"==typeof Object.assign)return Object.assign({},t,e||{});var i=Object.constructor();for(var a in t)i[a]=a in e?e[a]:t[a];return i}function p(t,e){var i=d.createElement(t);return i.className=e&&e.join?e.join(" "):e||"",i}function r(t){return t.charAt(0).toUpperCase()+t.slice(1)}function c(t,e,i){var a=t instanceof Date?t:!!t&&new Date(t);return a instanceof Date&&!isNaN(a.getDate())&&(i&&a.setHours(0,0,0,0),!0===e?a.getTime():a)}d.forms.inputmode=!0;var l=function(t,e){if((t="string"==typeof t?d.querySelectorAll(t):t)instanceof NodeList||t instanceof HTMLCollection||t instanceof Array){for(var i=[],a=t.length,n=0;n\n\n";for(var e=0;e<7;e++)this.weekdays+=''+t[e]+"";this.weekdays+="\n\n",this.select=c(this.e.getAttribute("data-value")||this.e.value),(!this.select||this.selectthis.con.dateEnd)&&(this.select=null),null==this.view&&(this.view={type:this.con.viewDefault,date:this.select||new Date});var i=["Hours","Minutes","Seconds"];for(e=0;e<3;e++)if("number"==typeof this.con["time"+i[e]])this.view.date["set"+i[e]](this.con["time"+i[e]]);else for(;this.view.date["get"+i[e]]()%this.con["timeStep"+i[e]]!=0;)this.view.date["set"+i[e]](this.view.date["get"+i[e]]()+1);return this.ampm=!!this.con.time12h&&12n[i].end?[n[i].end,n[i].end=n[i].start][0]:n[i].start),n[i].days=!("days"in n[i])||n[i].days,n[i].days="boolean"!=typeof n[i].days?function(t){for(var e=[],i=t.length,a=0;a'+s[i].text||"Tooltip",r)}));this.con.tooltips=t}var r;return this},bind:function(){var e=this;return void 0===this._bind&&(this.e.addEventListener("focusin",function(t){e.open.call(e)}),this.e.addEventListener("keyup",function(t){e.callback.call(e,t)}),d.addEventListener("keyup",function(t){e.dt.contains(t.target)&&e.callback.call(e,t)}),d.addEventListener("click",function(t){e.dt.contains(t.target)?e.callback.call(e,t):!e.e.contains(t.target)&&u(e.dt,"calendar-open")&&(t.target==e.dt||t.target==e.e||e.con.stayOpen||e.close.call(e))}),d.addEventListener("mouseover",function(t){e.dt.contains(t.target)&&e.callback.call(e,t)}),this._bind=!0),this},callback:function(t){var e,i=t.target,a="getAttribute",n="data-action",s=i[a](n)?i:i.parentElement[a](n)?i.parentElement:i,r="data-tooltip";if("mouseover"==t.type&&(!1!==(e=i[a](r)?i:!!s[a](r)&&s)?this.dt.querySelector("#tooltip-"+e[a](r)+"-"+e[a](r+"-time"))||this.showTooltip(e[a](r),e,e[a](r+"-time")):this.dt.querySelector(".calendar-tooltip:not(.remove)")&&this.hideTooltip(this.dt.querySelector(".calendar-tooltip").id.slice(8))),"click"==t.type){if(!s||1!=t.buttons&&1!=(t.which||t.button))return;if(s.hasAttribute("data-disabled"))return;switch(s[a](n)){case"prev":case"next":return this.browseView(s[a](n));case"cancel":this.con.stayOpen||this.close();break;case"submit":return this.con.stayOpen||this.close(),this.selectDate(this.fetchDate(parseInt(s[a]("data-date"))));case"view":return this.switchDate(s[a]("data-year")||null,s[a]("data-month")||null,s[a]("data-day")||null),this.switchView(s[a]("data-view"))}}if("keyup"==t.type){if("INPUT"!=t.target.tagName&&t.target!==this.e&&/calendar-(static|close)/i.test(this.dt.className))return!1;13==(t.keyCode||t.which)&&(this.selectDate(this.fetchDate(this.select)),t.stopPropagation(),this.con.stayOpen||this.close()),27==(t.keyCode||t.which)&&(this.con.stayOpen||this.close())}},trigger:function(t){var e={bubbles:!1,cancelable:!0,detail:{args:arguments,self:this}};"change"==t&&(s(this.e,"input",e),s(this.e,"change",e)),s(this.dt,"tail::"+t,e);for(var i=(this.events[t]||[]).length,a=0;a':this.con.timeFormat&&(n=''),a.innerHTML=n?'
'+n+"
":"",this.con.dateFormat&&this.renderDatePicker(a,this.con.viewDefault),this.con.timeFormat&&this.renderTimePicker(a),this.con.closeButton&&!i){var s=p("BUTTON","calendar-close"),r=this;s.addEventListener("click",function(t){t.preventDefault(),r.close()}),a.appendChild(s)}return(i||d.body).appendChild(a),a},renderDatePicker:function(t,e){if((!e||["decades","years","months","days"].indexOf(e)<0)&&(e=this.con.viewDays?"days":this.con.viewMonths?"months":this.con.viewYears?"years":!!this.con.viewDecades&&"decades"),!e||!this.con["view"+r(e)]||!this.con.dateFormat)return!1;var i=d.createElement("DIV");return i.className="calendar-datepicker calendar-view-"+e,i.innerHTML=this["view"+r(e)](),t.querySelector(".calendar-datepicker")?t.replaceChild(i,t.querySelector(".calendar-datepicker")):t.appendChild(i),this.view.type=e,this.handleLabel(t)},renderTimePicker:function(t){if(!this.con.timeFormat)return!1;var e,i,a=[],n=0;if(this.con.time12h){var s=12")}for(var r in{Hours:0,Minutes:0,Seconds:0})!1!==this.con["time"+r]?((e=d.createElement("INPUT")).type="text",e.disabled=null===this.con["time"+r],e.setAttribute("min","Hours"===r&&this.con.time12h?"01":"00"),e.setAttribute("max","Hours"!==r?"60":this.con.time12h?"13":"24"),e.setAttribute("step",this.con["timeStep"+r]),e.setAttribute("value",(i=this.view.date["get"+r]())<10?"0"+i:i),e.setAttribute("pattern","d*"),e.setAttribute("inputmode","numeric"),e.setAttribute("data-input",r.toLowerCase()),a.push('
'+e.outerHTML+'
")):a.push((n++,null));var o=p("DIV","calendar-timepicker"),c=this;o.innerHTML=a.join("\n");var l=o.querySelectorAll("input");for(n=0;n=e.getYear()&&i<=e.getYear()+10?" date-today":""),n='data-action="view" data-view="down" data-year="'+e.getFullYear()+'"',s.push(''+e.getFullYear()+" - "+(e.getFullYear()+10)+""),4<=o&&o%4==0&&(r.push("\n"+s.join("\n")+"\n"),s=[]),e.setFullYear(e.getFullYear()+10);return'"+r.join("\n")+"
'+this.__.header[2]+"
"},viewYears:function(){var t=this.view.date.getFullYear(),e=new Date(this.view.date.getTime()),i=this.con.today?(new Date).getYear():0;e.setFullYear(t-parseInt(t.toString()[3])-2);for(var a,n,s=[],r=[],o=1;o<=16;o++)a="calendar-year"+(e.getYear()==i?" date-today":""),n='data-action="view" data-view="down" data-year="'+e.getFullYear()+'"',s.push(''+e.getFullYear()+""),4<=o&&o%4==0&&(r.push("\n"+s.join("\n")+"\n"),s=[]),e.setFullYear(e.getFullYear()+1);return'"+r.join("\n")+"
'+this.__.header[1]+"
"},viewMonths:function(){var t=this.__.months,e=this.con.today?(new Date).getMonth():-1;e=this.view.date.getYear()==(new Date).getYear()?e:-1;for(var i,a,n=[],s=[],r=0;r<12;r++)i="calendar-month"+(e==r?" date-today":""),a='data-action="view" data-view="down" data-month="'+r+'"',n.push(''+t[r]+""),3==n.length&&(s.push("\n"+n.join("\n")+"\n"),n=[]);return'"+s.join("\n")+"
'+this.__.header[0]+"
"},viewDays:function(){var i,t,e,a,n,s,r=new Date(this.view.date.getTime()),o=(new Date).toDateString(),c=r.getMonth(),l=[],h=[],d=[0,[]],u=([].concat(this.con.tooltips),[0,0]);for(r.setHours(0,0,0,0),r.setDate(1),r.setDate(1-(r.getDay()-this.con.weekStart));h.length<6;)i=r.getTime(),s=[].concat(this.con.dateRanges),e='data-action="submit" data-date="'+r.getTime()+'"',t="calendar-day date-"+(r.getMonth()>c?"next":r.getMonth()this.con.dateEnd)?d=[i=t.start&&i<=t.end?!(d=[t.end,t.days]):t.start>i},this):3==d.length&&(d=[0,[0,1,2,3,4,5,6]]),0=i&&(u=[t.date[1],e,t.color]):t.date==i&&(u=[t.date,e,t.color])},this),u[0]=i&&0<=d[1].indexOf(r.getDay()))&&this.con.dateBlacklist||!n&&!this.con.dateBlacklist?(t+=" date-disabled",e+=' data-disabled="true"'):0!==d[0]&&d[0]<=i&&(d=[0,[]]),this.select&&this.select.toDateString()==r.toDateString()&&(t+=" date-select"),a=''+r.getDate()+"",0':a+=''),l.push('"+a+""),7==l.length&&(h.push("\n"+l.join("\n")+"\n"),l=[]),r.setDate(r.getDate()+1);return h=""+h.join("\n")+"",''+this.weekdays+h+"
"},showTooltip:function(t,e,i){var a,n=this.con.tooltips[t].element,s=n.style,r=this.dt.querySelector(".calendar-datepicker");s.cssText="opacity:0;visibility:hidden;",n.id="tooltip-"+t+"-"+i,r.appendChild(n),a=n.offsetWidth,n.offsetHeight,s.top=e.offsetTop+e.offsetHeight+"px",s.left=e.offsetLeft+e.offsetWidth/2-a/2+"px",s.visibility="visible",this.con.animate?(n.setAttribute("data-top",parseInt(s.top)),s.top=parseInt(s.top)+5+"px",function t(){parseFloat(s.top)>n.getAttribute("data-top")&&(s.top=parseFloat(s.top)-.5+"px"),(s.opacity=parseFloat(s.opacity)+.125)<1&&setTimeout(t,20)}()):s.opacity=1},hideTooltip:function(t){var e=this.dt.querySelector("#tooltip-"+t),i=e.style;this.con.animate?(e.className+=" remove",function t(){if(parseFloat(i.top)'); + }; + + /* + // may not be needed, saving for later. Can be called to resize iFrame + obj.resizeContent = function() { + var iFrame = document.getElementById('pluginIframeScriptTask'); + var newHeight = 800; + var sHeight = iFrame.contentWindow.document.body.scrollHeight; + if (sHeight > newHeight) newHeight = sHeight; + if (newHeight > 1600) newHeight = 1600; + iFrame.style.height = newHeight + 'px'; + }; + */ + + obj.queueRun = async function() { + var onlineAgents = Object.keys(obj.meshServer.webserver.wsagents); + //obj.debug('ScriptTask', 'Queue Running', Date().toLocaleString(), 'Online agents: ', onlineAgents); + + obj.db.getPendingJobs(onlineAgents) + .then(function(jobs) { + if (jobs.length == 0) return; + //@TODO check for a large number and use taskLimiter to queue the jobs + jobs.forEach(function(job) { + obj.db.get(job.scriptId) + .then(async function(script) { + script = script[0]; + var foundVars = script.content.match(/#(.*?)#/g); + var replaceVars = {}; + if (foundVars != null && foundVars.length > 0) { + var foundVarNames = []; + foundVars.forEach(function(fv) { foundVarNames.push(fv.replace(/^#+|#+$/g, '')); }); + + var limiters = { + scriptId: job.scriptId, + nodeId: job.node, + meshId: obj.meshServer.webserver.wsagents[job.node]['dbMeshKey'], + names: foundVarNames + }; + var finvals = await obj.db.getVariables(limiters); + var ordering = { 'global': 0, 'script': 1, 'mesh': 2, 'node': 3 } + finvals.sort(function(a, b) { return (ordering[a.scope] - ordering[b.scope]) || a.name.localeCompare(b.name); }); + finvals.forEach(function(fv) { replaceVars[fv.name] = fv.value; }); + replaceVars['GBL:meshId'] = obj.meshServer.webserver.wsagents[job.node]['dbMeshKey']; + replaceVars['GBL:nodeId'] = job.node; + //console.log('FV IS', finvals); + //console.log('RV IS', replaceVars); + } + var dispatchTime = Math.floor(new Date() / 1000); + var jObj = { + action: 'task', + subaction: 'triggerJob', + jobId: job._id, + scriptId: job.scriptId, + replaceVars: replaceVars, + scriptHash: script.contentHash, + dispatchTime: dispatchTime + }; + //obj.debug('ScriptTask', 'Sending job to agent'); + try { + obj.meshServer.webserver.wsagents[job.node].send(JSON.stringify(jObj)); + obj.db.update(job._id, { dispatchTime: dispatchTime }); + } catch (ex) { } + }) + .catch(function (ex) { console.log('task: Could not dispatch job.', ex) }); + }); + }) + .then(function() { + obj.makeJobsFromSchedules(); + obj.cleanHistory(); + }) + .catch(function(ex) { console.log('task: Queue Run Error: ', ex); }); + }; + + obj.cleanHistory = function() { + if (Math.round(Math.random() * 100) == 99) { + //obj.debug('Task', 'Running history cleanup'); + obj.db.deleteOldHistory(); + } + }; + + obj.downloadFile = function(req, res, user) { + var id = req.query.dl; + obj.db.get(id) + .then(function(found) { + if (found.length != 1) { res.sendStatus(401); return; } + var file = found[0]; + res.setHeader('Content-disposition', 'attachment; filename=' + file.name); + res.setHeader('Content-type', 'text/plain'); + //var fs = require('fs'); + res.send(file.content); + }); + }; + + obj.updateFrontEnd = async function(ids){ + if (ids.scriptId != null) { + var scriptHistory = null; + obj.db.getJobScriptHistory(ids.scriptId) + .then(function(sh) { + scriptHistory = sh; + return obj.db.getJobSchedulesForScript(ids.scriptId); + }) + .then(function(scriptSchedule) { + var targets = ['*', 'server-users']; + obj.meshServer.DispatchEvent(targets, obj, { nolog: true, action: 'task', subaction: 'historyData', scriptId: ids.scriptId, nodeId: null, scriptHistory: scriptHistory, nodeHistory: null, scriptSchedule: scriptSchedule }); + }); + } + if (ids.nodeId != null) { + var nodeHistory = null; + obj.db.getJobNodeHistory(ids.nodeId) + .then(function(nh) { + nodeHistory = nh; + return obj.db.getJobSchedulesForNode(ids.nodeId); + }) + .then(function(nodeSchedule) { + var targets = ['*', 'server-users']; + obj.meshServer.DispatchEvent(targets, obj, { nolog: true, action: 'task', subaction: 'historyData', scriptId: null, nodeId: ids.nodeId, scriptHistory: null, nodeHistory: nodeHistory, nodeSchedule: nodeSchedule }); + }); + } + if (ids.tree === true) { + obj.db.getScriptTree() + .then(function(tree) { + var targets = ['*', 'server-users']; + obj.meshServer.DispatchEvent(targets, obj, { nolog: true, action: 'task', subaction: 'newScriptTree', tree: tree }); + }); + } + if (ids.variables === true) { + obj.db.getVariables() + .then(function(vars) { + var targets = ['*', 'server-users']; + obj.meshServer.DispatchEvent(targets, obj, { nolog: true, action: 'task', subaction: 'variableData', vars: vars }); + }); + } + }; + + obj.handleAdminReq = function(req, res, user) { + if ((user.siteadmin & 0xFFFFFFFF) == 1 && req.query.admin == 1) + { + // admin wants admin, grant + var vars = {}; + res.render(obj.VIEWS + 'admin', vars); + return; + } else if (req.query.admin == 1 && (user.siteadmin & 0xFFFFFFFF) == 0) { + // regular user wants admin + res.sendStatus(401); + return; + } else if (req.query.user == 1) { + // regular user wants regular access, grant + if (req.query.dl != null) return obj.downloadFile(req, res, user); + var vars = {}; + + if (req.query.edit == 1) { // edit script + if (req.query.id == null) return res.sendStatus(401); + obj.db.get(req.query.id) + .then(function(scripts) { + if (scripts[0].filetype == 'proc') { + vars.procData = JSON.stringify(scripts[0]); + res.render(obj.VIEWS + 'procedit', vars); + } else { + vars.scriptData = JSON.stringify(scripts[0]); + res.render(obj.VIEWS + 'scriptedit', vars); + } + }); + return; + } else if (req.query.schedule == 1) { + var vars = {}; + res.render(obj.VIEWS + 'schedule', vars); + return; + } + // default user view (tree) + vars.scriptTree = 'null'; + obj.db.getScriptTree() + .then(function(tree) { + vars.scriptTree = JSON.stringify(tree); + res.render(obj.VIEWS + 'user', vars); + }); + return; + } else if (req.query.include == 1) { + switch (req.query.path.split('/').pop().split('.').pop()) { + case 'css': res.contentType('text/css'); break; + case 'js': res.contentType('text/javascript'); break; + } + res.sendFile(__dirname + '/includes/' + req.query.path); // don't freak out. Express covers any path issues. + return; + } + res.sendStatus(401); + return; + }; + + obj.historyData = function (message) { + if (typeof pluginHandler.scripttask.loadHistory == 'function') pluginHandler.scripttask.loadHistory(message); + if (typeof pluginHandler.scripttask.loadSchedule == 'function') pluginHandler.scripttask.loadSchedule(message); + }; + + obj.variableData = function (message) { + if (typeof pluginHandler.scripttask.loadVariables == 'function') pluginHandler.scripttask.loadVariables(message); + }; + + obj.determineNextJobTime = function(s) { + var nextTime = null; + var nowTime = Math.floor(new Date() / 1000); + + // special case: we've reached the end of our run + if (s.endAt !== null && s.endAt <= nowTime) { + return nextTime; + } + + switch (s.recur) { + case 'once': + if (s.nextRun == null) nextTime = s.startAt; + else nextTime = null; + break; + case 'minutes': + /*var lRun = s.nextRun || nowTime; + if (lRun == null) lRun = nowTime; + nextTime = lRun + (s.interval * 60); + if (s.startAt > nextTime) nextTime = s.startAt;*/ + if (s.nextRun == null) { // hasn't run yet, set to start time + nextTime = s.startAt; + break; + } + nextTime = s.nextRun + (s.interval * 60); + // this prevents "catch-up" tasks being scheduled if an endpoint is offline for a long period of time + // e.g. always make sure the next scheduled time is relevant to the scheduled interval, but in the future + if (nextTime < nowTime) { + // initially I was worried about this causing event loop lockups + // if there was a long enough time gap. Testing over 50 years of backlog for a 3 min interval + // still ran under a fraction of a second. Safe to say this approach is safe! (~8.5 million times) + while (nextTime < nowTime) { + nextTime = nextTime + (s.interval * 60); + } + } + if (s.startAt > nextTime) nextTime = s.startAt; + break; + case 'hourly': + if (s.nextRun == null) { // hasn't run yet, set to start time + nextTime = s.startAt; + break; + } + nextTime = s.nextRun + (s.interval * 60 * 60); + if (nextTime < nowTime) { + while (nextTime < nowTime) { + nextTime = nextTime + (s.interval * 60 * 60); + } + } + if (s.startAt > nextTime) nextTime = s.startAt; + break; + case 'daily': + if (s.nextRun == null) { // hasn't run yet, set to start time + nextTime = s.startAt; + break; + } + nextTime = s.nextRun + (s.interval * 60 * 60 * 24); + if (nextTime < nowTime) { + while (nextTime < nowTime) { + nextTime = nextTime + (s.interval * 60 * 60 * 24); + } + } + if (s.startAt > nextTime) nextTime = s.startAt; + break; + case 'weekly': + var tempDate = new Date(); + var nowDate = new Date(tempDate.getFullYear(), tempDate.getMonth(), tempDate.getDate()); + + if (s.daysOfWeek.length == 0) { + nextTime = null; + break; + } + s.daysOfWeek = s.daysOfWeek.map(function (el) { Number(el) }); + var baseTime = s.startAt; + //console.log('dow is ', s.daysOfWeek); + var lastDayOfWeek = Math.max(...s.daysOfWeek); + var startX = 0; + //console.log('ldow is ', lastDayOfWeek); + if (s.nextRun != null) { + baseTime = s.nextRun; + //console.log('basetime 2: ', baseTime); + if (nowDate.getDay() == lastDayOfWeek) { + baseTime = baseTime + ( s.interval * 604800 ) - (lastDayOfWeek * 86400); + //console.log('basetime 3: ', baseTime); + } + startX = 0; + } else if (s.startAt < nowTime) { + baseTime = Math.floor(nowDate.getTime() / 1000); + //console.log('basetime 4: ', baseTime); + } + //console.log('startX is: ', startX); + //var secondsFromMidnight = nowTimeDate.getSeconds() + (nowTimeDate.getMinutes() * 60) + (nowTimeDate.getHours() * 60 * 60); + //console.log('seconds from midnight: ', secondsFromMidnight); + //var dBaseTime = new Date(0); dBaseTime.setUTCSeconds(baseTime); + //var dMidnight = new Date(dBaseTime.getFullYear(), dBaseTime.getMonth(), dBaseTime.getDate()); + //baseTime = Math.floor(dMidnight.getTime() / 1000); + for (var x = startX; x <= 7; x++){ + var checkDate = baseTime + (86400 * x); + var d = new Date(0); d.setUTCSeconds(checkDate); + var dm = new Date(d.getFullYear(), d.getMonth(), d.getDate()); + + console.log('testing date: ', dm.toLocaleString()); // dMidnight.toLocaleString()); + //console.log('if break check :', (s.daysOfWeek.indexOf(d.getDay()) !== -1 && checkDate >= nowTime)); + //console.log('checkDate vs nowTime: ', (checkDate - nowTime), ' if positive, nowTime is less than checkDate'); + if (s.nextRun == null && s.daysOfWeek.indexOf(dm.getDay()) !== -1 && dm.getTime() >= nowDate.getTime()) break; + if (s.daysOfWeek.indexOf(dm.getDay()) !== -1 && dm.getTime() > nowDate.getTime()) break; + //if (s.daysOfWeek.indexOf(d.getDay()) !== -1 && Math.floor(d.getTime() / 1000) >= nowTime) break; + } + var sa = new Date(0); sa.setUTCSeconds(s.startAt); + var sad = new Date(sa.getFullYear(), sa.getMonth(), sa.getDate()); + var diff = (sa.getTime() - sad.getTime()) / 1000; + nextTime = Math.floor(dm.getTime() / 1000) + diff; + //console.log('next schedule is ' + d.toLocaleString()); + break; + default: + nextTime = null; + break; + } + + if (s.endAt != null && nextTime > s.endAt) nextTime = null; // if the next time reaches the bound of the endAt time, nullify + + return nextTime; + }; + + obj.makeJobsFromSchedules = function(scheduleId) { + //obj.debug('ScriptTask', 'makeJobsFromSchedules starting'); + return obj.db.getSchedulesDueForJob(scheduleId) + .then(function(schedules) { + //obj.debug('ScriptTask', 'Found ' + schedules.length + ' schedules to process. Current time is: ' + Math.floor(new Date() / 1000)); + if (schedules.length) { + schedules.forEach(function(s) { + var nextJobTime = obj.determineNextJobTime(s); + var nextJobScheduled = false; + if (nextJobTime === null) { + //obj.debug('ScriptTask', 'Removing Job Schedule for', JSON.stringify(s)); + obj.db.removeJobSchedule(s._id); + } else { + //obj.debug('ScriptTask', 'Scheduling Job for', JSON.stringify(s)); + obj.db.get(s.scriptId) + .then(function(scripts) { + // if a script is scheduled to run, but a previous run hasn't completed, + // don't schedule another job for the same (device probably offline). + // results in the minimum jobs running once an agent comes back online. + return obj.db.getIncompleteJobsForSchedule(s._id) + .then(function(jobs) { + if (jobs.length > 0) { /* obj.debug('Task', 'Skipping job creation'); */ return Promise.resolve(); } + else { /* obj.debug('Task', 'Creating new job'); */ nextJobScheduled = true; return obj.db.addJob( { scriptId: s.scriptId, scriptName: scripts[0].name, node: s.node, runBy: s.scheduledBy, dontQueueUntil: nextJobTime, jobSchedule: s._id } ); } + }); + }) + .then(function() { + if (nextJobScheduled) { /* obj.debug('Plugin', 'ScriptTask', 'Updating nextRun time'); */ return obj.db.update(s._id, { nextRun: nextJobTime }); } + else { /* obj.debug('Plugin', 'ScriptTask', 'NOT updating nextRun time'); */ return Promise.resolve(); } + }) + .then(function() { + obj.updateFrontEnd( { scriptId: s.scriptId, nodeId: s.node } ); + }) + .catch(function(ex) { console.log('Task: Error managing job schedules: ', ex); }); + } + }); + } + }); + }; + + obj.deleteElement = function (command) { + var delObj = null; + obj.db.get(command.id) + .then(function(found) { + var file = found[0]; + delObj = {...{}, ...found[0]}; + return file; + }) + .then(function(file) { + if (file.type == 'folder') return obj.db.deleteByPath(file.path); //@TODO delete schedules for scripts within folders + if (file.type == 'script') return obj.db.deleteSchedulesForScript(file._id); + if (file.type == 'jobSchedule') return obj.db.deletePendingJobsForSchedule(file._id); + }) + .then(function() { + return obj.db.delete(command.id) + }) + .then(function() { + var updateObj = { tree: true }; + if (delObj.type == 'jobSchedule') { + updateObj.scriptId = delObj.scriptId; + updateObj.nodeId = delObj.node; + } + return obj.updateFrontEnd( updateObj ); + }) + .catch(function(ex) { console.log('Task: Error deleting ', ex.stack); }); + }; + + // Process 'task' commands received by an agent + obj.agentAction = function (command, agent) { + console.log('task-agentAction', command); + switch (command.subaction) { + case 'getScript': + // TODO + break; + case 'clearAllPendingTasks': + // TODO + break; + case 'taskComplete': + // TODO + break; + } + } + + obj.serveraction = function(command, myparent, grandparent) { + switch (command.subaction) { + case 'addScript': + obj.db.addScript(command.name, command.content, command.path, command.filetype) + .then(function() { obj.updateFrontEnd( { tree: true } ); }); + break; + case 'new': + var parent_path = '', new_path = ''; + obj.db.get(command.parent_id) + .then(function(found) { if (found.length > 0) { var file = found[0]; parent_path = file.path; } else { parent_path = 'Shared'; } }) + .then(function () { obj.db.addScript(command.name, '', parent_path, command.filetype); }) + .then(function() { obj.updateFrontEnd( { tree: true } ); }); + break; + case 'rename': + obj.db.get(command.id) + .then(function(docs) { + var doc = docs[0]; + if (doc.type == 'folder') { + console.log('old', doc.path, 'new', doc.path.replace(doc.path, command.name)); + return obj.db.update(command.id, { path: doc.path.replace(doc.name, command.name) }) + .then(function() { // update sub-items + return obj.db.getByPath(doc.path) + }) + .then(function(found) { + if (found.length > 0) { + var proms = []; + found.forEach(function(f) { proms.push(obj.db.update(f._id, { path: doc.path.replace(doc.name, command.name) } )); }) + return Promise.all(proms); + } + }) + } else { + return Promise.resolve(); + } + }) + .then(function() { + obj.db.update(command.id, { name: command.name }) + }) + .then(function() { + return obj.db.updateScriptJobName(command.id, command.name); + }) + .then(function() { + obj.updateFrontEnd( { scriptId: command.id, nodeId: command.currentNodeId, tree: true } ); + }); + break; + case 'move': + var toPath = null, fromPath = null, parentType = null; + obj.db.get(command.to) + .then(function(found) { // get target data + if (found.length > 0) { + var file = found[0]; + toPath = file.path; + } else throw Error('Target destination not found'); + }) + .then(function() { // get item to be moved + return obj.db.get(command.id); + }) + .then(function(found) { // set item to new location + var file = found[0]; + if (file.type == 'folder') { + fromPath = file.path; + toPath += '/' + file.name; + parentType = 'folder'; + if (file.name == 'Shared' && file.path == 'Shared') throw Error('Cannot move top level directory: Shared'); + } + return obj.db.update(command.id, { path: toPath } ); + }) + .then(function() { // update sub-items + return obj.db.getByPath(fromPath) + }) + .then(function(found) { + if (found.length > 0) { + var proms = []; + found.forEach(function(f) { + proms.push(obj.db.update(f._id, { path: toPath } )); + }) + return Promise.all(proms); + } + }) + .then(function() { + return obj.updateFrontEnd( { tree: true } ); + }) + .catch(function(ex) { console.log('Task: Error moving ', ex.stack); }); + break; + case 'newFolder': + var parent_path = ''; + var new_path = ''; + + obj.db.get(command.parent_id) + .then(function(found) { + if (found.length > 0) { + var file = found[0]; + parent_path = file.path; + } else { + parent_path = 'Shared'; + } + }) + .then(function() { + new_path = parent_path + '/' + command.name; + }) + .then(function() { + return obj.db.addFolder(command.name, new_path); + }) + .then(function () { + return obj.updateFrontEnd( { tree: true } ); + }) + .catch(function(ex) { console.log('Task: Error creating new folder ', ex.stack); }); + break; + case 'delete': + obj.deleteElement(command); + break; + case 'addScheduledJob': + /* { + scriptId: scriptId, + node: s, + scheduledBy: myparent.user.name, + recur: command.recur, // [once, minutes, hourly, daily, weekly, monthly] + interval: x, + daysOfWeek: x, // only used for weekly recur val + // onTheXDay: x, // only used for monthly + startAt: x, + endAt: x, + runCountLimit: x, + lastRun: x, + nextRun: x, + type: "scheduledJob" + } */ + var sj = command.schedule; + + var sched = { + scriptId: command.scriptId, + node: null, + scheduledBy: myparent.user.name, + recur: sj.recur, + interval: sj.interval, + daysOfWeek: sj.dayVals, + startAt: sj.startAt, + endAt: sj.endAt, + lastRun: null, + nextRun: null, + type: "jobSchedule" + }; + var sel = command.nodes; + var proms = []; + if (Array.isArray(sel)) { + sel.forEach(function(s) { + var sObj = {...sched, ...{ node: s }}; + proms.push(obj.db.addJobSchedule( sObj )); + }); + } else { test.push(sObj); + proms.push(obj.db.addJobSchedule( sObj )); + } + Promise.all(proms) + .then(function() { + obj.makeJobsFromSchedules(); + return Promise.resolve(); + }) + .catch(function(ex) { console.log('Task: Error adding schedules. The error was: ', ex); }); + break; + case 'runScript': + var scriptId = command.scriptId; + var sel = command.nodes; + var proms = []; + if (Array.isArray(sel)) { + sel.forEach(function(s) { + proms.push(obj.db.addJob( { scriptId: scriptId, node: s, runBy: myparent.user.name } )); + }); + } else { + proms.push(obj.db.addJob( { scriptId: scriptId, node: sel, runBy: myparent.user.name } )); + } + Promise.all(proms) + .then(function() { + return obj.db.get(scriptId); + }) + .then(function(scripts) { + return obj.db.updateScriptJobName(scriptId, scripts[0].name); + }) + .then(function() { + obj.resetQueueTimer(); + obj.queueRun(); + obj.updateFrontEnd( { scriptId: scriptId, nodeId: command.currentNodeId } ); + }); + break; + case 'getScript': + //obj.debug('ScriptTask', 'getScript Triggered', JSON.stringify(command)); + obj.db.get(command.scriptId) + .then(function(script) { + myparent.send(JSON.stringify({ + action: 'task', + subaction: 'cacheScript', + nodeid: myparent.dbNodeKey, + rights: true, + sessionid: true, + script: script[0] + })); + }); + break; + case 'jobComplete': + //obj.debug('ScriptTask', 'jobComplete Triggered', JSON.stringify(command)); + var jobNodeHistory = null, scriptHistory = null; + var jobId = command.jobId, retVal = command.retVal, errVal = command.errVal, dispatchTime = command.dispatchTime; + var completeTime = Math.floor(new Date() / 1000); + obj.db.update(jobId, { + completeTime: completeTime, + returnVal: retVal, + errorVal: errVal, + dispatchTime: dispatchTime + }) + .then(function() { + return obj.db.get(jobId) + .then(function(jobs) { + return Promise.resolve(jobs[0].jobSchedule); + }) + .then(function(sId) { + if (sId == null) return Promise.resolve(); + return obj.db.update(sId, { lastRun: completeTime } ) + .then(function() { + obj.makeJobsFromSchedules(sId); + }); + }); + }) + .then(function() { + obj.updateFrontEnd( { scriptId: command.scriptId, nodeId: myparent.dbNodeKey } ); + }) + .catch(function(ex) { console.log('Task: Failed to complete job. ', ex); }); + // update front end by eventing + break; + case 'loadNodeHistory': + obj.updateFrontEnd( { nodeId: command.nodeId } ); + break; + case 'loadScriptHistory': + obj.updateFrontEnd( { scriptId: command.scriptId } ); + break; + case 'editScript': + obj.db.update(command.scriptId, { type: command.scriptType, name: command.scriptName, content: command.scriptContent }) + .then(function() { obj.updateFrontEnd( { scriptId: command.scriptId, tree: true } ); }); + break; + case 'clearAllPendingJobs': + obj.db.deletePendingJobsForNode(myparent.dbNodeKey); + break; + case 'loadVariables': + obj.updateFrontEnd( { variables: true } ); + break; + case 'newVar': + obj.db.addVariable(command.name, command.scope, command.scopeTarget, command.value) + .then(function() { obj.updateFrontEnd( { variables: true } ); }) + break; + case 'editVar': + obj.db.update(command.id, { + name: command.name, + scope: command.scope, + scopeTarget: command.scopeTarget, + value: command.value + }) + .then(function() { obj.updateFrontEnd( { variables: true } ); }) + break; + case 'deleteVar': + obj.db.delete(command.id) + .then(function() { obj.updateFrontEnd( { variables: true } ); }) + break; + default: + console.log('Task: unknown action'); + break; + } + }; + + return obj; +} \ No newline at end of file diff --git a/views/task-schedule.handlebars b/views/task-schedule.handlebars new file mode 100644 index 00000000..228d8a96 --- /dev/null +++ b/views/task-schedule.handlebars @@ -0,0 +1,249 @@ + + + + + + + + +
+
+ + +
+
+
+ Recurrence +
    +
  • +
  • +
  • +
  • +
  • + +
+
+ +
+
+ + + \ No newline at end of file diff --git a/views/task-scriptedit.handlebars b/views/task-scriptedit.handlebars new file mode 100644 index 00000000..0e79eaaf --- /dev/null +++ b/views/task-scriptedit.handlebars @@ -0,0 +1,73 @@ + + + + + + +
+
Script Name:
+
+ + +
+
+ +
+
+ + + \ No newline at end of file diff --git a/views/task-user.handlebars b/views/task-user.handlebars new file mode 100644 index 00000000..b1c70b30 --- /dev/null +++ b/views/task-user.handlebars @@ -0,0 +1,1070 @@ + + + + + + +
+ + Upload: +
+
+ New + Rename + Edit + Delete + New Folder + Download + Run +
+
+
+
+
+
+
Advanced Run
+
+
+
+ + +
+
+
+ + +
Meshes
+
+
+ + +
Tags
+
+
+
Node Schedules
+
+ + + + + + + + + +
ScriptAuthorEveryStartingEndingLast RunNext RunAction
+
+
Script Schedules
+
+ + + + + + + + + +
NodeAuthorEveryStartingEndingLast RunNext RunAction
+
+
Node History
+
+ + + + + + +
TimeRun ByScriptStatusReturn Value
+
+
Script History
+
+ + + + + + +
TimeRun ByNodeStatusReturn Value
+
+
Variables
+
+ + + + + + +
Variable NameValueScopeScope TargetAction
+
+ [+] +
+
+ +
+
+
+ + + \ No newline at end of file