From 12a06b91024ebe1dc8039d8116a54084795aa9f2 Mon Sep 17 00:00:00 2001 From: Suresh Alse Date: Wed, 28 Sep 2016 09:52:50 -0700 Subject: [PATCH 1/8] Update issues.md --- README/issues.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README/issues.md b/README/issues.md index 60b4573..9ac439c 100644 --- a/README/issues.md +++ b/README/issues.md @@ -8,3 +8,7 @@ __crontab-ui is running but is not accessible on browser__ - This is usually because the place where your crontab-ui is installed does not give access to others. It can be resolved by either giving permission to the user (Recommended) or running crontab-ui as root. Refer [this](https://github.com/alseambusher/crontab-ui/issues/8) __Hosting crontab-ui : it works on localhost but not outside the server__ - You have to host it using nginx, apache2, etc. Refer [this](nginx.md). + +__crontab-ui stopped working__ - It can happen that your crontab-ui can stop working for some reason like adding incorrect jobs or timings. In order to fix it, you can just go ahead a remove the job from `crontab.db` or `env.db` in "crontabs" folder and restart crontab-ui. + +__Where is my root node_modules folder__ - You can find it by `npm root -g` From 40c7008d1aea56cdf80b5ec3e21b50d72d679851 Mon Sep 17 00:00:00 2001 From: Joerg Henning Date: Thu, 29 Sep 2016 10:48:57 +0530 Subject: [PATCH 2/8] Proper, node-js style error handling for set_crontab It's a start... --- app.js | 32 ++++++++++++++++++++++++++------ crontab.js | 29 ++++++++++++++++++++--------- public/js/script.js | 11 +++++++++++ 3 files changed, 57 insertions(+), 15 deletions(-) diff --git a/app.js b/app.js index 113fbf8..3087b38 100755 --- a/app.js +++ b/app.js @@ -72,9 +72,11 @@ app.post(routes.remove, function(req, res) { crontab.remove(req.body._id); res.end(); }); -app.get(routes.crontab, function(req, res) { - crontab.set_crontab(req.query.env_vars); - res.end(); +app.get(routes.crontab, function(req, res, next) { + crontab.set_crontab(req.query.env_vars, function(err) { + if (err) next(err); + else res.end(); + }); }); app.get(routes.backup, function(req, res) { @@ -127,8 +129,8 @@ app.post(routes.import, function(req, res) { fstream.on('close', function () { crontab.reload_db(); res.redirect(routes.root); - }); - }); + }); + }); }); app.get(routes.import_crontab, function(req, res) { @@ -145,6 +147,24 @@ app.get(routes.logger, function(req, res) { res.end("No errors logged yet"); }); +// error handler +app.use(function(err, req, res, next) { + var data = {}; + var statusCode = err.statusCode || 500; + + data.message = err.message || 'Internal Server Error'; + + if (process.env.NODE_ENV === 'development' && err.stack) { + data.stack = err.stack + } + + if (parseInt(data.statusCode) >= 500) { + console.error(err); + } + + res.status(statusCode).json(data); +}); + app.listen(app.get('port'), function() { - console.log("Crontab UI is running at http://localhost:" + app.get('port')); + console.log("Crontab UI is running at http://localhost:" + app.get('port')); }); diff --git a/crontab.js b/crontab.js index 253c760..b6f743f 100644 --- a/crontab.js +++ b/crontab.js @@ -1,8 +1,11 @@ //load database var Datastore = require('nedb'); var db = new Datastore({ filename: __dirname + '/crontabs/crontab.db' }); + db.loadDatabase(function (err) { + if (err) throw err; // no hope, just terminate }); + var exec = require('child_process').exec; var fs = require('fs'); var cron_parser = require("cron-parser"); @@ -52,32 +55,40 @@ exports.crontabs = function(callback){ callback(docs); }); }; -exports.set_crontab = function(env_vars){ +exports.set_crontab = function(env_vars, callback){ exports.crontabs( function(tabs){ var crontab_string = ""; if (env_vars) { crontab_string = env_vars + "\n"; } tabs.forEach(function(tab){ - if(!tab.stopped){ - if (tab.logging && tab.logging == "true"){ + if(!tab.stopped) { + if (tab.logging && tab.logging == "true") { tmp_log = "/tmp/" + tab._id + ".log"; log_file = exports.log_folder + "/" + tab._id + ".log"; if(tab.command[tab.command.length-1] != ";") // add semicolon tab.command +=";"; //{ command; } 2>/tmp/.log|| {if test -f /tmp/; then date >> ; cat /tmp/.log >> ; rm /tmp.log } crontab_string += tab.schedule + " { " + tab.command + " } 2> " + tmp_log +"; if test -f " + tmp_log +"; then date >> " + log_file + "; cat " + tmp_log + " >> " + log_file + "; rm " + tmp_log + "; fi \n"; - } - else + } + else { crontab_string += tab.schedule + " " + tab.command + "\n"; + } } }); - fs.writeFile(exports.env_file, env_vars); - fs.writeFile("/tmp/crontab", crontab_string, function(err) { - exec("crontab /tmp/crontab"); - }); + fs.writeFile(exports.env_file, env_vars, function(err) { + if (err) callback(err); + fs.writeFile("/tmp/crontab", crontab_string, function(err) { + if (err) return callback(err); + + exec("crontab /tmp/crontab", function(err) { + if (err) return callback(err); + else callback(); + }); + }); + }); }); }; diff --git a/public/js/script.js b/public/js/script.js index c704a95..174b2d3 100644 --- a/public/js/script.js +++ b/public/js/script.js @@ -6,6 +6,15 @@ function infoMessageBox(message, title){ $("#info-title").html(title); $("#info-popup").modal('show'); } +// like info, but for errors. +function errorMessageBox(message) { + var msg = + "Operation failed: " + message + ". " + + "Please see error log for details."; + $("#info-body").html(msg); + $("#info-title").html("Error"); + $("#info-popup").modal('show'); +} // modal with full control function messageBox(body, title, ok_text, close_text, callback){ $("#modal-body").html(body); @@ -50,6 +59,8 @@ function setCrontab(){ $.get(routes.crontab, { "env_vars": $("#env_vars").val() }, function(){ // TODO show only if success infoMessageBox("Successfuly set crontab file!","Information"); + }).fail(function(response) { + errorMessageBox(response.statusText,"Error"); }); }); } From f2987e7ee412057ef99cea4eabe5341c688fe463 Mon Sep 17 00:00:00 2001 From: Suresh Alse Date: Wed, 28 Sep 2016 22:54:53 -0700 Subject: [PATCH 3/8] Update script.js --- public/js/script.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/public/js/script.js b/public/js/script.js index 174b2d3..95c69b1 100644 --- a/public/js/script.js +++ b/public/js/script.js @@ -11,9 +11,7 @@ function errorMessageBox(message) { var msg = "Operation failed: " + message + ". " + "Please see error log for details."; - $("#info-body").html(msg); - $("#info-title").html("Error"); - $("#info-popup").modal('show'); + infoMessageBox(msg, "Error"); } // modal with full control function messageBox(body, title, ok_text, close_text, callback){ From 8a347b5597b614e7ad7bb3ad6738c8fb47b02fbe Mon Sep 17 00:00:00 2001 From: Suresh Alse Date: Wed, 26 Oct 2016 09:56:08 -0700 Subject: [PATCH 4/8] Update README.md --- README/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README/README.md b/README/README.md index 1eb10a7..c3098fa 100644 --- a/README/README.md +++ b/README/README.md @@ -21,6 +21,8 @@ Read [this](http://lifepluslinux.blogspot.in/2015/06/crontab-ui-easy-and-safe-wa If you need to set/use an alternate port, you may do so by setting an environment variable before starting the process: PORT=9000 crontab-ui + +Also, you may have to **set permissions** for your `node_modules` folder. Refer [this](https://docs.npmjs.com/getting-started/fixing-npm-permissions). ###Adding, deleting, pausing and resuming jobs. From 65acd94271bd9683c95bdde260de434d3ef8b0a2 Mon Sep 17 00:00:00 2001 From: alseambusher Date: Sat, 3 Dec 2016 21:09:12 +0530 Subject: [PATCH 5/8] autosave mode --- README/README.md | 6 +++++- app.js | 42 +++++++++++++++++++++++++++++++++++------- crontab.js | 9 +++++++-- package.json | 2 +- 4 files changed, 48 insertions(+), 11 deletions(-) diff --git a/README/README.md b/README/README.md index 1eb10a7..21ba14f 100644 --- a/README/README.md +++ b/README/README.md @@ -17,11 +17,15 @@ Read [this](http://lifepluslinux.blogspot.in/2015/06/crontab-ui-easy-and-safe-wa npm install -g crontab-ui crontab-ui - + If you need to set/use an alternate port, you may do so by setting an environment variable before starting the process: PORT=9000 crontab-ui +If you need to autosave your changes to crontab directly: + + crontab-ui --autosave + ###Adding, deleting, pausing and resuming jobs. Once setup Crontab UI provides you with a web interface using which you can manage all the jobs without much hassle. diff --git a/app.js b/app.js index 3087b38..18d904a 100755 --- a/app.js +++ b/app.js @@ -1,3 +1,4 @@ +/*jshint esversion: 6*/ var express = require('express'); var app = express(); var crontab = require("./crontab"); @@ -9,7 +10,6 @@ var mime = require('mime'); var fs = require('fs'); var busboy = require('connect-busboy'); // for file upload - // include the routes var routes = require("./routes").routes; @@ -17,7 +17,7 @@ var routes = require("./routes").routes; app.set('view engine', 'ejs'); var bodyParser = require('body-parser'); -app.use( bodyParser.json() ); // to support JSON-encoded bodies +app.use(bodyParser.json()); // to support JSON-encoded bodies app.use(bodyParser.urlencoded({ // to support URL-encoded bodies extended: true })); @@ -29,12 +29,14 @@ app.use(express.static(__dirname + '/public/css')); app.use(express.static(__dirname + '/public/js')); app.set('views', __dirname + '/views'); -//set port +// set port to 8000 or the value set by environment var PORT app.set('port', (process.env.PORT || 8000)); +// root page handler app.get(routes.root, function(req, res) { - // get all the crontabs + // reload the database before rendering crontab.reload_db(); + // send all the required parameters crontab.crontabs( function(docs){ res.render('index', { routes : JSON.stringify(routes), @@ -46,6 +48,11 @@ app.get(routes.root, function(req, res) { }); }); +/* +Handle to save crontab to database +If it is a new job @param _id is set to -1 +@param name, command, schedule, logging has to be sent with _id (if exists) +*/ app.post(routes.save, function(req, res) { // new job if(req.body._id == -1){ @@ -58,20 +65,25 @@ app.post(routes.save, function(req, res) { res.end(); }); +// set stop to job app.post(routes.stop, function(req, res) { crontab.status(req.body._id, true); res.end(); }); +// set start to job app.post(routes.start, function(req, res) { crontab.status(req.body._id, false); res.end(); }); +// remove a job app.post(routes.remove, function(req, res) { crontab.remove(req.body._id); res.end(); }); + +// set crontab. Needs env_vars to be passed app.get(routes.crontab, function(req, res, next) { crontab.set_crontab(req.query.env_vars, function(err) { if (err) next(err); @@ -79,11 +91,13 @@ app.get(routes.crontab, function(req, res, next) { }); }); +// backup crontab db app.get(routes.backup, function(req, res) { crontab.backup(); res.end(); }); +// This renders the restore page similar to backup page app.get(routes.restore, function(req, res) { // get all the crontabs restore.crontabs(req.query.db, function(docs){ @@ -96,16 +110,19 @@ app.get(routes.restore, function(req, res) { }); }); +// delete backup db app.get(routes.delete_backup, function(req, res) { restore.delete(req.query.db); res.end(); }); +// restore from backup db app.get(routes.restore_backup, function(req, res) { crontab.restore(req.query.db); res.end(); }); +// export current crontab db so that user can download it app.get(routes.export, function(req, res) { var file = __dirname + '/crontabs/crontab.db'; @@ -119,7 +136,7 @@ app.get(routes.export, function(req, res) { filestream.pipe(res); }); - +// import from exported crontab db app.post(routes.import, function(req, res) { var fstream; req.pipe(req.busboy); @@ -133,13 +150,14 @@ app.post(routes.import, function(req, res) { }); }); +// import from current ACTUALL crontab app.get(routes.import_crontab, function(req, res) { crontab.import_crontab(); res.end(); }); +// get the log file a given job. id passed as query param app.get(routes.logger, function(req, res) { - var fs = require("fs"); _file = crontab.log_folder +"/"+req.query.id+".log"; if (fs.existsSync(_file)) res.sendFile(_file); @@ -155,7 +173,7 @@ app.use(function(err, req, res, next) { data.message = err.message || 'Internal Server Error'; if (process.env.NODE_ENV === 'development' && err.stack) { - data.stack = err.stack + data.stack = err.stack; } if (parseInt(data.statusCode) >= 500) { @@ -166,5 +184,15 @@ app.use(function(err, req, res, next) { }); app.listen(app.get('port'), function() { + // If --autosave is used then we will also save whatever is in the db automatically without having to mention it explictly + // we do this by watching log file and setting a on change hook to it + if (process.argv.includes("--autosave")){ + crontab.autosave_crontab(()=>{}); + fs.watchFile(__dirname + '/crontabs/crontab.db', () => { + crontab.autosave_crontab(()=>{ + console.log("Attempted to autosave crontab"); + }); + }); + } console.log("Crontab UI is running at http://localhost:" + app.get('port')); }); diff --git a/crontab.js b/crontab.js index b6f743f..3c41f89 100644 --- a/crontab.js +++ b/crontab.js @@ -1,3 +1,4 @@ +/*jshint esversion: 6*/ //load database var Datastore = require('nedb'); var db = new Datastore({ filename: __dirname + '/crontabs/crontab.db' }); @@ -68,7 +69,6 @@ exports.set_crontab = function(env_vars, callback){ log_file = exports.log_folder + "/" + tab._id + ".log"; if(tab.command[tab.command.length-1] != ";") // add semicolon tab.command +=";"; - //{ command; } 2>/tmp/.log|| {if test -f /tmp/; then date >> ; cat /tmp/.log >> ; rm /tmp.log } crontab_string += tab.schedule + " { " + tab.command + " } 2> " + tmp_log +"; if test -f " + tmp_log +"; then date >> " + log_file + "; cat " + tmp_log + " >> " + log_file + "; rm " + tmp_log + "; fi \n"; } else { @@ -129,7 +129,7 @@ exports.restore = function(db_name){ db.loadDatabase(); // reload the database }; -exports.reload_db= function(){ +exports.reload_db = function(){ db.loadDatabase(); }; @@ -170,3 +170,8 @@ exports.import_crontab = function(){ }); }); }; + +exports.autosave_crontab = function(callback) { + let env_vars = exports.get_env(); + exports.set_crontab(env_vars, callback); +}; diff --git a/package.json b/package.json index 3c0cc74..47a168c 100755 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "crontab-ui", - "version": "0.2.0", + "version": "0.2.1", "description": "Easy and safe way to manage your crontab file", "main": "index.js", "scripts": { From b207df5332b9c6a017d6d12a6ca5b405d128b2c0 Mon Sep 17 00:00:00 2001 From: alseambusher Date: Mon, 12 Dec 2016 17:04:04 +0530 Subject: [PATCH 6/8] adding a check to jobs before importing from file --- crontab.js | 19 ++++++++++++++----- package.json | 2 +- public/js/script.js | 13 ++++++++++--- views/popup.ejs | 3 ++- 4 files changed, 27 insertions(+), 10 deletions(-) diff --git a/crontab.js b/crontab.js index 3c41f89..1b39b94 100644 --- a/crontab.js +++ b/crontab.js @@ -65,11 +65,17 @@ exports.set_crontab = function(env_vars, callback){ tabs.forEach(function(tab){ if(!tab.stopped) { if (tab.logging && tab.logging == "true") { - tmp_log = "/tmp/" + tab._id + ".log"; - log_file = exports.log_folder + "/" + tab._id + ".log"; + let tmp_log = "/tmp/" + tab._id + ".log"; + let log_file = exports.log_folder + "/" + tab._id + ".log"; if(tab.command[tab.command.length-1] != ";") // add semicolon tab.command +=";"; - crontab_string += tab.schedule + " { " + tab.command + " } 2> " + tmp_log +"; if test -f " + tmp_log +"; then date >> " + log_file + "; cat " + tmp_log + " >> " + log_file + "; rm " + tmp_log + "; fi \n"; + // hook is in beta + if (tab.hook){ + let tmp_hook = "/tmp/" + tab._id + ".hook"; + crontab_string += tab.schedule + " ({ " + tab.command + " } | tee " + tmp_hook + ") 3>&1 1>&2 2>&3 | tee " + tmp_log +"; if test -f " + tmp_log +"; then date >> " + log_file + "; cat " + tmp_log + " >> " + log_file + "; rm " + tmp_log + "; fi; if test -f " + tmp_hook + "; then " + tab.hook + " < " + tmp_hook + "; rm " + tmp_hook + "; fi \n"; + } else { + crontab_string += tab.schedule + " { " + tab.command + " } 2> " + tmp_log +"; if test -f " + tmp_log +"; then date >> " + log_file + "; cat " + tmp_log + " >> " + log_file + "; rm " + tmp_log + "; fi \n"; + } } else { crontab_string += tab.schedule + " " + tab.command + "\n"; @@ -96,7 +102,7 @@ exports.get_backup_names = function(){ var backups = []; fs.readdirSync(__dirname + '/crontabs').forEach(function(file){ // file name begins with backup - if(file.indexOf("backup") == 0){ + if(file.indexOf("backup") === 0){ backups.push(file); } }); @@ -150,7 +156,10 @@ exports.import_crontab = function(){ var command = line.replace(regex, '').trim(); var schedule = line.replace(command, '').trim(); - if(command && schedule){ + var is_valid = false; + try { is_valid = cron_parser.parseString(line).expressions.length > 0; } catch (e){} + + if(command && schedule && is_valid){ var name = namePrefix + '_' + index; db.findOne({ command: command, schedule: schedule }, function(err, doc) { diff --git a/package.json b/package.json index 47a168c..ebaad85 100755 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "crontab-ui", - "version": "0.2.1", + "version": "0.2.2", "description": "Easy and safe way to manage your crontab file", "main": "index.js", "scripts": { diff --git a/public/js/script.js b/public/js/script.js index 95c69b1..66b1f7a 100644 --- a/public/js/script.js +++ b/public/js/script.js @@ -26,6 +26,9 @@ function messageBox(body, title, ok_text, close_text, callback){ /*********** crontab actions ****************/ +// TODO get rid of global variables +var schedule = ""; +var job_command = ""; function deleteJob(_id){ // TODO fix this. pass callback properly @@ -84,7 +87,7 @@ function editJob(_id){ $("#job-name").val(job.name); $("#job-command").val(job.command); // if macro not used - if(job.schedule.indexOf("@") != 0){ + if(job.schedule.indexOf("@") !== 0){ var components = job.schedule.split(" "); $("#job-minute").val(components[0]); $("#job-hour").val(components[1]); @@ -102,6 +105,9 @@ function editJob(_id){ $("#job-save").unbind("click"); // remove existing events attached to this $("#job-save").click(function(){ // TODO good old boring validations + if (!schedule) { + schedule = "* * * * *"; + } $.post(routes.save, {name: $("#job-name").val(), command: job_command , schedule: schedule, _id: _id, logging: $("#job-logging").prop("checked")}, function(){ location.reload(); }); @@ -124,6 +130,9 @@ function newJob(){ $("#job-save").unbind("click"); // remove existing events attached to this $("#job-save").click(function(){ // TODO good old boring validations + if (!schedule) { + schedule = "* * * * *"; + } $.post(routes.save, {name: $("#job-name").val(), command: job_command , schedule: schedule, _id: -1, logging: $("#job-logging").prop("checked")}, function(){ location.reload(); }); @@ -162,8 +171,6 @@ function import_db(){ // script corresponding to job popup management -var schedule = ""; -var job_command = ""; function job_string(){ $("#job-string").val(schedule + " " + job_command); return schedule + " " + job_command; diff --git a/views/popup.ejs b/views/popup.ejs index 931f979..f9bb15e 100644 --- a/views/popup.ejs +++ b/views/popup.ejs @@ -72,7 +72,8 @@

- +
+ + + + + From 3d56cb1db0a0e19aa7186f3628902d26635d0b0d Mon Sep 17 00:00:00 2001 From: alseambusher Date: Wed, 14 Dec 2016 09:48:15 +0530 Subject: [PATCH 8/8] store mail options in db --- README/mail.md | 2 ++ app.js | 2 +- crontab.js | 11 +++++++---- public/js/script.js | 16 +++++++++++++--- views/popup.ejs | 2 +- 5 files changed, 24 insertions(+), 9 deletions(-) create mode 100644 README/mail.md diff --git a/README/mail.md b/README/mail.md new file mode 100644 index 0000000..2e72454 --- /dev/null +++ b/README/mail.md @@ -0,0 +1,2 @@ +Mailing and Hooks +================= diff --git a/app.js b/app.js index 25cc60c..e95ee28 100755 --- a/app.js +++ b/app.js @@ -57,7 +57,7 @@ If it is a new job @param _id is set to -1 app.post(routes.save, function(req, res) { // new job if(req.body._id == -1){ - crontab.create_new(req.body.name, req.body.command, req.body.schedule, req.body.logging); + crontab.create_new(req.body.name, req.body.command, req.body.schedule, req.body.logging, req.body.mailing); } // edit job else{ diff --git a/crontab.js b/crontab.js index 84065e7..5707610 100644 --- a/crontab.js +++ b/crontab.js @@ -15,7 +15,7 @@ var os = require("os"); exports.log_folder = __dirname + '/crontabs/logs'; exports.env_file = __dirname + '/crontabs/env.db'; -crontab = function(name, command, schedule, stopped, logging){ +crontab = function(name, command, schedule, stopped, logging, mailing){ var data = {}; data.name = name; data.command = command; @@ -25,17 +25,20 @@ crontab = function(name, command, schedule, stopped, logging){ } data.timestamp = (new Date()).toString(); data.logging = logging; + if (!mailing) + mailing = {}; + data.mailing = mailing; return data; }; -exports.create_new = function(name, command, schedule, logging){ - var tab = crontab(name, command, schedule, false, logging); +exports.create_new = function(name, command, schedule, logging, mailing){ + var tab = crontab(name, command, schedule, false, logging, mailing); tab.created = new Date().valueOf(); db.insert(tab); }; exports.update = function(data){ - db.update({_id: data._id}, crontab(data.name, data.command, data.schedule, null, data.logging)); + db.update({_id: data._id}, crontab(data.name, data.command, data.schedule, null, data.logging, data.mailing)); }; exports.status = function(_id, stopped){ diff --git a/public/js/script.js b/public/js/script.js index f7ba184..9777b19 100644 --- a/public/js/script.js +++ b/public/js/script.js @@ -95,6 +95,9 @@ function editJob(_id){ $("#job-month").val(components[3]); $("#job-week").val(components[4]); } + if (job.mailing) { + $("#job-mailing").attr("data-json", JSON.stringify(job.mailing)); + } schedule = job.schedule; job_command = job.command; if (job.logging && job.logging != "false") @@ -108,7 +111,10 @@ function editJob(_id){ if (!schedule) { schedule = "* * * * *"; } - $.post(routes.save, {name: $("#job-name").val(), command: job_command , schedule: schedule, _id: _id, logging: $("#job-logging").prop("checked")}, function(){ + let name = $("#job-name").val(); + let mailing = JSON.parse($("#job-mailing").attr("data-json")); + let logging = $("#job-logging").prop("checked"); + $.post(routes.save, {name: name, command: job_command , schedule: schedule, _id: _id, logging: logging, mailing: mailing}, function(){ location.reload(); }); }); @@ -126,6 +132,7 @@ function newJob(){ $("#job").modal("show"); $("#job-name").val(""); $("#job-command").val(""); + $("#job-mailing").attr("data-json", "{}"); job_string(); $("#job-save").unbind("click"); // remove existing events attached to this $("#job-save").click(function(){ @@ -133,7 +140,10 @@ function newJob(){ if (!schedule) { schedule = "* * * * *"; } - $.post(routes.save, {name: $("#job-name").val(), command: job_command , schedule: schedule, _id: -1, logging: $("#job-logging").prop("checked")}, function(){ + let name = $("#job-name").val(); + let mailing = JSON.parse($("#job-mailing").attr("data-json")); + let logging = $("#job-logging").prop("checked"); + $.post(routes.save, {name: name, command: job_command , schedule: schedule, _id: -1, logging: logging, mailing: mailing}, function(){ location.reload(); }); }); @@ -173,7 +183,7 @@ function setMailConfig(a){ let data = JSON.parse(a.getAttribute("data-json")); let container = document.createElement("div"); - let message = "

This is based on nodemailer. Refer this for more details.

"; + let message = "

This is based on nodemailer. Refer this for more details.

"; container.innerHTML += message; let transporterLabel = document.createElement("label"); diff --git a/views/popup.ejs b/views/popup.ejs index ea64f10..06bc9d7 100644 --- a/views/popup.ejs +++ b/views/popup.ejs @@ -40,7 +40,7 @@

- Mailing + Mailing Hooks