diff --git a/README/README.md b/README/README.md index d2b5257..95518f7 100644 --- a/README/README.md +++ b/README/README.md @@ -3,49 +3,50 @@ Crontab UI Editing the plain text crontab is error prone for managing jobs, e.g., adding jobs, deleting jobs, or pausing jobs. A small mistake can easily bring down all the jobs and might cost you a lot of time. With Crontab UI, it is very easy to manage crontab. Here are the key features of Crontab UI. -![flow](http://alseambusher.github.io/files/flow.gif) +![flow](https://github.com/alseambusher/crontab-ui/raw/gh-pages/screenshots/flow.gif) -1. Easy setup +1. Easy setup. You can even import from existing crontab. 2. Safe adding, deleting or pausing jobs. Easy to maintain hundreds of jobs. 3. Backup your crontabs. 4. Export crontab and deploy on other machines without much hassle. -5. Error log support (NEW) +5. Error log support. Read [this](http://lifepluslinux.blogspot.in/2015/06/crontab-ui-easy-and-safe-way-to-manage.html) to see more details. ##Setup - npm install crontab-ui + npm install -g crontab-ui crontab-ui ###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. -![basic](http://2.bp.blogspot.com/-kU8K-suZYMY/VX1Ml5b_JOI/AAAAAAAABEo/MAfgg7hWEz8/s1600/1.png) +![basic](https://github.com/alseambusher/crontab-ui/raw/gh-pages/screenshots/main.png) + +###Import from existing crontab + +Import from existing crontab file automatically. +![import](https://github.com/alseambusher/crontab-ui/raw/gh-pages/screenshots/import.gif) ###Backup and restore crontab Keep backups of your crontab in case you mess up. -![backup](http://3.bp.blogspot.com/-qHxCbtNny9I/VX1M7k5UE3I/AAAAAAAABEw/cpiPgS9-gXo/s1600/2.png) +![backup](https://github.com/alseambusher/crontab-ui/raw/gh-pages/screenshots/backup.png) ###Export and import crontab on multiple instances of Crontab UI. If you want to run the same jobs on multiple machines simply export from one instance and import the same on the other. No SSH, No copy paste! -![export](http://2.bp.blogspot.com/-trpHt_etz5I/VX1NyElIicI/AAAAAAAABE4/GTZFBCfybLk/s1600/3.png) +![export](https://github.com/alseambusher/crontab-ui/raw/gh-pages/screenshots/import_db.png) But make sure to take a backup before importing. -###See when the job is going to run next. -![future](http://4.bp.blogspot.com/-gN-wLmhd5Os/VX6fQ5wM2LI/AAAAAAAABcA/_Ej0PqrByBU/s1600/next.gif) - ###Separate error log support for every job -![logs](http://alseambusher.github.io/files/crontab_ui_log_feature.gif) +![logs](https://github.com/alseambusher/crontab-ui/raw/gh-pages/screenshots/log.gif) ###Contribute Fork Crontab UI and contribute to it. Pull requests are encouraged. ###License [MIT](LICENSE.md) - diff --git a/app.js b/app.js index 90d9119..f8ea462 100755 --- a/app.js +++ b/app.js @@ -16,12 +16,12 @@ var routes = require("./routes").routes; // set the view engine to ejs app.set('view engine', 'ejs'); -var bodyParser = require('body-parser') +var bodyParser = require('body-parser'); app.use( bodyParser.json() ); // to support JSON-encoded bodies app.use(bodyParser.urlencoded({ // to support URL-encoded bodies extended: true })); -app.use(busboy()) // to support file uploads +app.use(busboy()); // to support file uploads // include all folders app.use(express.static(__dirname + '/public')); @@ -44,7 +44,7 @@ app.get(routes.root, function(req, res) { moment: moment }); }); -}) +}); app.post(routes.save, function(req, res) { // new job @@ -56,31 +56,31 @@ app.post(routes.save, function(req, res) { crontab.update(req.body); } res.end(); -}) +}); app.post(routes.stop, function(req, res) { crontab.status(req.body._id, true); res.end(); -}) +}); app.post(routes.start, function(req, res) { crontab.status(req.body._id, false); res.end(); -}) +}); 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.backup, function(req, res) { crontab.backup(); res.end(); -}) +}); app.get(routes.restore, function(req, res) { // get all the crontabs @@ -92,17 +92,17 @@ app.get(routes.restore, function(req, res) { db: req.query.db }); }); -}) +}); app.get(routes.delete_backup, function(req, res) { restore.delete(req.query.db); res.end(); -}) +}); app.get(routes.restore_backup, function(req, res) { crontab.restore(req.query.db); res.end(); -}) +}); app.get(routes.export, function(req, res) { var file = __dirname + '/crontabs/crontab.db'; @@ -115,7 +115,7 @@ app.get(routes.export, function(req, res) { var filestream = fs.createReadStream(file); filestream.pipe(res); -}) +}); app.post(routes.import, function(req, res) { @@ -129,12 +129,12 @@ app.post(routes.import, function(req, res) { res.redirect(routes.root); }); }); -}) +}); app.get(routes.import_crontab, function(req, res) { - crontab.import_crontab() + crontab.import_crontab(); res.end(); -}) +}); app.get(routes.logger, function(req, res) { var fs = require("fs"); @@ -143,8 +143,8 @@ app.get(routes.logger, function(req, res) { res.sendFile(_file); else res.end("No errors logged yet"); -}) +}); app.listen(app.get('port'), function() { - console.log("Crontab UI is running at localhost:" + app.get('port')) -}) + console.log("Crontab UI is running at localhost:" + app.get('port')); +}); diff --git a/crontab.js b/crontab.js index 92e9784..cbc636d 100644 --- a/crontab.js +++ b/crontab.js @@ -5,8 +5,8 @@ db.loadDatabase(function (err) { }); var exec = require('child_process').exec; var fs = require('fs'); -var cron_parser = require("cron-parser") -var os = require("os") +var cron_parser = require("cron-parser"); +var os = require("os"); exports.log_folder = __dirname + '/crontabs/logs'; exports.env_file = __dirname + '/crontabs/env.db'; @@ -22,36 +22,36 @@ crontab = function(name, command, schedule, stopped, logging){ data.timestamp = (new Date()).toString(); data.logging = logging; return data; -} +}; exports.create_new = function(name, command, schedule, logging){ var tab = crontab(name, command, schedule, false, logging); 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)); -} +}; exports.status = function(_id, stopped){ db.update({_id: _id},{$set: {stopped: stopped}}); -} +}; exports.remove = function(_id){ db.remove({_id: _id}, {}); -} +}; exports.crontabs = function(callback){ db.find({}).sort({ created: -1 }).exec(function(err, docs){ for(var i=0; i/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"; } @@ -79,10 +79,10 @@ exports.set_crontab = function(env_vars){ }); }); -} +}; exports.get_backup_names = function(){ - var backups = [] + var backups = []; fs.readdirSync(__dirname + '/crontabs').forEach(function(file){ // file name begins with backup if(file.indexOf("backup") == 0){ @@ -92,10 +92,10 @@ exports.get_backup_names = function(){ // Sort by date. Newest on top for(var i=0; i Tj){ var temp = backups[i]; @@ -106,50 +106,48 @@ exports.get_backup_names = function(){ } return backups; -} +}; exports.backup = function(){ //TODO check if it failed fs.createReadStream( __dirname + '/crontabs/crontab.db').pipe(fs.createWriteStream( __dirname + '/crontabs/backup ' + (new Date()).toString().replace("+", " ") + '.db')); -} +}; exports.restore = function(db_name){ fs.createReadStream( __dirname + '/crontabs/' + db_name).pipe(fs.createWriteStream( __dirname + '/crontabs/crontab.db')); db.loadDatabase(); // reload the database -} +}; exports.reload_db= function(){ db.loadDatabase(); -} +}; exports.get_env = function(){ if (fs.existsSync(exports.env_file)) { return fs.readFileSync(exports.env_file , 'utf8').replace("\n", "\n"); } - return "" -} + return ""; +}; -// TODO exports.import_crontab = function(){ exec("crontab -l", function(error, stdout, stderr){ var lines = stdout.split("\n"); - var namePrefix = new Date().getTime(); lines.forEach(function(line, index){ var regex = /^((\@[a-zA-Z]+\s)|(([^\s]+)\s([^\s]+)\s([^\s]+)\s([^\s]+)\s([^\s]+)\s))/; var command = line.replace(regex, '').trim(); var schedule = line.replace(command, '').trim(); - + if(command && schedule){ var name = namePrefix + '_' + index; - db.crontabs.findOne({ command: command, schedule: schedule }, function(err, doc) { + db.findOne({ command: command, schedule: schedule }, function(err, doc) { if(err) { throw err; } if(!doc){ - exports.create_new(name, command, null, null, schedule, null); + exports.create_new(name, command, schedule, null); } else{ doc.command = command; @@ -157,11 +155,7 @@ exports.import_crontab = function(){ exports.update(doc); } }); - - } - - }) - //console.log(stdout); + }); }); -} +}; diff --git a/package.json b/package.json index bcc8b7b..8548dba 100755 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "crontab-ui", - "version": "0.1.7", + "version": "0.1.8", "description": "Easy and safe way to manage your crontab file", "main": "index.js", "scripts": { diff --git a/views/index.ejs b/views/index.ejs index 60b0da2..553949a 100644 --- a/views/index.ejs +++ b/views/index.ejs @@ -35,7 +35,7 @@ Import Export - Get from crontab + Get from crontab Save to crontab