From ca2f6e06ffc51adffa5175bfb65dc9e9d89fa47b Mon Sep 17 00:00:00 2001 From: Dominic Bosch Date: Sat, 26 Apr 2014 16:01:33 +0200 Subject: [PATCH] UI more user friendly, still needs completion --- coffee/components-manager.coffee | 8 +- coffee/engine.coffee | 13 +- coffee/persistence.coffee | 53 +- coffee/request-handler.coffee | 23 +- js/components-manager.js | 10 +- js/engine.js | 71 +- js/persistence.js | 52 +- js/request-handler.js | 32 +- webpages/handlers/coffee/forge_rule.coffee | 850 +++++++------ webpages/handlers/coffee/forge_webhook.coffee | 34 +- webpages/handlers/js/forge_rule.js | 1114 +++++++++-------- webpages/handlers/js/forge_webhook.js | 43 +- webpages/handlers/skeleton.html | 1 + .../handlers/templates/forge_webhook.html | 7 +- webpages/handlers/templates/menubar.html | 45 +- webpages/public/index.html | 45 +- webpages/public/js/menubar.js | 41 + webpages/public/style.css | 16 +- 18 files changed, 1311 insertions(+), 1147 deletions(-) create mode 100644 webpages/public/js/menubar.js diff --git a/coffee/components-manager.coffee b/coffee/components-manager.coffee index 456ac9c..7bc8076 100644 --- a/coffee/components-manager.coffee +++ b/coffee/components-manager.coffee @@ -470,12 +470,13 @@ commandFunctions = else hookid hookid = genHookID arrHooks - db.createWebhook user.username, oBody.hookname, hookid - rh.activateWebhook hookid, oBody.hookname + db.createWebhook user.username, hookid, oBody.hookname + rh.activateWebhook user.username, hookid, oBody.hookname callback code: 200 message: JSON.stringify hookid: hookid + hookname: oBody.hookname get_all_webhooks: ( user, oBody, callback ) -> db.getAllUserWebhooks user.username, ( err, data ) -> @@ -484,9 +485,10 @@ commandFunctions = code: 400 message: "We didn't like your request!" else + data = JSON.stringify data || '' callback code: 200 - message: JSON.stringify data + message: data delete_webhook: ( user, oBody, callback ) -> answ = hasRequiredParams [ 'hookid' ], oBody diff --git a/coffee/engine.coffee b/coffee/engine.coffee index 6bac51e..20b3698 100644 --- a/coffee/engine.coffee +++ b/coffee/engine.coffee @@ -272,9 +272,8 @@ processEvent = ( evt ) => else fSearchAndInvokeAction node[arrPath[depth]], arrPath, funcName, evt, depth + 1 - @log.info 'EN | processing event: ' + evt.eventname - for userName, oUser of listUserRules - + @log.info 'EN | Processing event: ' + evt.eventname + fCheckEventForUser = ( userName, oUser ) -> for ruleName, oMyRule of oUser ruleEvent = oMyRule.rule.eventname @@ -288,6 +287,14 @@ processEvent = ( evt ) => arr = action.split ' -> ' fSearchAndInvokeAction listUserRules, [ userName, ruleName, 'actions', arr[0]], arr[1], evt, 0 + # If the event is bound to a user, we only process it for him + if evt.username + fCheckEventForUser evt.username, listUserRules[ evt.username ] + + # Else we loop through all users + else + fCheckEventForUser userName, oUser for userName, oUser of listUserRules + exports.shutDown = () -> isRunning = false listUserRules = {} diff --git a/coffee/persistence.coffee b/coffee/persistence.coffee index 19422d2..71ef805 100644 --- a/coffee/persistence.coffee +++ b/coffee/persistence.coffee @@ -797,16 +797,16 @@ exports.removeUserRole = ( userId, role ) => ### Creates and stores a webhook. -@public createWebhook( *userId, hookname* ) -@param {String} userId +@public createWebhook( *username, hookname* ) +@param {String} username @param {String} hookname ### -exports.createWebhook = ( userId, hookname, hookid ) => +exports.createWebhook = ( username, hookid, hookname ) => @db.sadd "webhooks", hookid, replyHandler "sadd 'webhooks' -> '#{ hookid }'" - @db.sadd "user:#{ userId }:webhooks", hookid, - replyHandler "sadd 'user:#{ userId }:webhooks' -> '#{ hookid }'" - @db.set "webhook:#{ hookid }", hookname, - replyHandler "set webhook:#{ hookid } -> #{ hookname }" + @db.sadd "user:#{ username }:webhooks", hookid, + replyHandler "sadd 'user:#{ username }:webhooks' -> '#{ hookid }'" + @db.hmset "webhook:#{ hookid }", 'hookname', hookname, 'username', username, + replyHandler "set webhook:#{ hookid } -> [#{ hookname }, #{ username }]" ### Returns a webhook name. @@ -815,25 +815,34 @@ Returns a webhook name. @param {String} hookid ### exports.getWebhookName = ( hookid, cb ) => - @db.get "webhook:#{ hookid }", cb + @db.hget "webhook:#{ hookid }", "hookname", cb + +### +Returns all webhook properties. + +@public getFullWebhookName( *hookid* ) +@param {String} hookid +### +exports.getFullWebhook = ( hookid, cb ) => + @db.hgetall "webhook:#{ hookid }", cb ### Returns all the user's webhooks by ID. -@public getUserWebhookIDs( *userId* ) -@param {String} userId +@public getUserWebhookIDs( *username* ) +@param {String} username ### -exports.getUserWebhookIDs = ( userId, cb ) => - @db.smembers "user:#{ userId }:webhooks", cb +exports.getUserWebhookIDs = ( username, cb ) => + @db.smembers "user:#{ username }:webhooks", cb ### Gets all the user's webhooks with names. -@public getAllUserWebhooks( *userId* ) -@param {String} userId +@public getAllUserWebhooks( *username* ) +@param {String} username ### -exports.getAllUserWebhooks = ( userId, cb ) => - getSetRecords "user:#{ userId }:webhooks", exports.getWebhookName, cb +exports.getAllUserWebhooks = ( username, cb ) => + getSetRecords "user:#{ username }:webhooks", exports.getWebhookName, cb ### Returns all webhook IDs. @@ -849,19 +858,19 @@ Returns all webhooks with names. @public getAllWebhooks() ### exports.getAllWebhooks = ( cb ) => - getSetRecords "webhooks", exports.getWebhookName, cb + getSetRecords "webhooks", exports.getFullWebhook, cb ### Delete a webhook. -@public deleteWebhook( *userId, hookid* ) -@param {String} userId +@public deleteWebhook( *username, hookid* ) +@param {String} username @param {String} hookid ### -exports.deleteWebhook = ( userId, hookid ) => +exports.deleteWebhook = ( username, hookid ) => @db.srem "webhooks", hookid, replyHandler "srem 'webhooks' -> '#{ hookid }'" - @db.srem "user:#{ userId }:webhooks", hookid, - replyHandler "srem 'user:#{ userId }:webhooks' -> '#{ hookid }'" + @db.srem "user:#{ username }:webhooks", hookid, + replyHandler "srem 'user:#{ username }:webhooks' -> '#{ hookid }'" @db.del "webhook:#{ hookid }", replyHandler "del webhook:#{ hookid }" ### diff --git a/coffee/request-handler.coffee b/coffee/request-handler.coffee index 8d20d46..2941fb1 100644 --- a/coffee/request-handler.coffee +++ b/coffee/request-handler.coffee @@ -354,7 +354,8 @@ exports.handleAdminCommand = ( req, resp ) => resp.send 401, 'You need to be logged in as admin!' -indexEvent = ( eventname, body, resp ) -> +# Parse events and register to user if it's a user specific event +parsePushAndAnswerEvent = ( eventname, username, body, resp ) -> if typeof body is 'string' try body = JSON.parse body @@ -367,8 +368,12 @@ indexEvent = ( eventname, body, resp ) -> obj = eventname: eventname body: body + if username + obj.username = username db.pushEvent obj - msg = "Thank you for the event: '#{ eventname }'" + resp.send 200, JSON.stringify + message: "Thank you for the event: '#{ eventname }'" + evt: obj obj @@ -381,7 +386,7 @@ exports.handleMeasurements = ( req, resp ) => body += data req.on 'end', -> - obj = indexEvent name, body, resp + obj = parsePushAndAnswerEvent name, null, body, resp if obj.eventname is 'uptimestatistics' # This is a hack to quickly allow storing of public accessible data fPath = path.resolve __dirname, '..', 'webpages', 'public', 'data', 'histochart.json' @@ -392,22 +397,24 @@ Handles webhook posts ### exports.handleWebhooks = ( req, resp ) => hookid = req.url.substring( 10 ).split( '/' )[ 0 ] - hookname = @allowedHooks[ hookid ] - if hookname + oHook = @allowedHooks[ hookid ] + if oHook body = '' req.on 'data', ( data ) -> body += data req.on 'end', () -> - obj = indexEvent hookname, body, resp + parsePushAndAnswerEvent oHook.hookname, oHook.username, body, resp else resp.send 404, "Webhook not existing!" # Activate a webhook. the body will be JSON parsed, the name of the webhook will # be the event name given to the event object, a timestamp will be added -exports.activateWebhook = ( hookid, name ) => +exports.activateWebhook = ( user, hookid, name ) => @log.info "HL | Webhook '#{ hookid }' activated" - @allowedHooks[ hookid ] = name + @allowedHooks[ hookid ] = + hookname: name + username: user # Deactivate a webhook exports.deactivateWebhook = ( hookid ) => diff --git a/js/components-manager.js b/js/components-manager.js index f78983b..0cbb7c2 100644 --- a/js/components-manager.js +++ b/js/components-manager.js @@ -592,12 +592,13 @@ Components Manager } }; hookid = genHookID(arrHooks); - db.createWebhook(user.username, oBody.hookname, hookid); - rh.activateWebhook(hookid, oBody.hookname); + db.createWebhook(user.username, hookid, oBody.hookname); + rh.activateWebhook(user.username, hookid, oBody.hookname); return callback({ code: 200, message: JSON.stringify({ - hookid: hookid + hookid: hookid, + hookname: oBody.hookname }) }); }); @@ -614,9 +615,10 @@ Components Manager message: "We didn't like your request!" }); } else { + data = JSON.stringify(data || ''); return callback({ code: 200, - message: JSON.stringify(data) + message: data }); } }); diff --git a/js/engine.js b/js/engine.js index e842fa3..1b73ce2 100644 --- a/js/engine.js +++ b/js/engine.js @@ -298,7 +298,7 @@ Engine processEvent = (function(_this) { return function(evt) { - var action, arr, fSearchAndInvokeAction, oMyRule, oUser, ruleEvent, ruleName, userName, _results; + var fCheckEventForUser, fSearchAndInvokeAction, oUser, userName, _results; fSearchAndInvokeAction = function(node, arrPath, funcName, evt, depth) { var argument, arrArgs, arrSelectors, data, err, oArg, sel, selector, _i, _j, _len, _len1, _ref; if (!node) { @@ -346,40 +346,45 @@ Engine return fSearchAndInvokeAction(node[arrPath[depth]], arrPath, funcName, evt, depth + 1); } }; - _this.log.info('EN | processing event: ' + evt.eventname); - _results = []; - for (userName in listUserRules) { - oUser = listUserRules[userName]; - _results.push((function() { - var _results1; - _results1 = []; - for (ruleName in oUser) { - oMyRule = oUser[ruleName]; - ruleEvent = oMyRule.rule.eventname; - if (oMyRule.rule.timestamp) { - ruleEvent += '_created:' + oMyRule.rule.timestamp; - } - if (evt.eventname === ruleEvent && validConditions(evt, oMyRule.rule, userName, ruleName)) { - this.log.info('EN | EVENT FIRED: ' + evt.eventname + ' for rule ' + ruleName); - _results1.push((function() { - var _i, _len, _ref, _results2; - _ref = oMyRule.rule.actions; - _results2 = []; - for (_i = 0, _len = _ref.length; _i < _len; _i++) { - action = _ref[_i]; - arr = action.split(' -> '); - _results2.push(fSearchAndInvokeAction(listUserRules, [userName, ruleName, 'actions', arr[0]], arr[1], evt, 0)); - } - return _results2; - })()); - } else { - _results1.push(void 0); - } + _this.log.info('EN | Processing event: ' + evt.eventname); + fCheckEventForUser = function(userName, oUser) { + var action, arr, oMyRule, ruleEvent, ruleName, _results; + _results = []; + for (ruleName in oUser) { + oMyRule = oUser[ruleName]; + ruleEvent = oMyRule.rule.eventname; + if (oMyRule.rule.timestamp) { + ruleEvent += '_created:' + oMyRule.rule.timestamp; } - return _results1; - }).call(_this)); + if (evt.eventname === ruleEvent && validConditions(evt, oMyRule.rule, userName, ruleName)) { + this.log.info('EN | EVENT FIRED: ' + evt.eventname + ' for rule ' + ruleName); + _results.push((function() { + var _i, _len, _ref, _results1; + _ref = oMyRule.rule.actions; + _results1 = []; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + action = _ref[_i]; + arr = action.split(' -> '); + _results1.push(fSearchAndInvokeAction(listUserRules, [userName, ruleName, 'actions', arr[0]], arr[1], evt, 0)); + } + return _results1; + })()); + } else { + _results.push(void 0); + } + } + return _results; + }; + if (evt.username) { + return fCheckEventForUser(evt.username, listUserRules[evt.username]); + } else { + _results = []; + for (userName in listUserRules) { + oUser = listUserRules[userName]; + _results.push(fCheckEventForUser(userName, oUser)); + } + return _results; } - return _results; }; })(this); diff --git a/js/persistence.js b/js/persistence.js index f6c65bf..e836284 100644 --- a/js/persistence.js +++ b/js/persistence.js @@ -1038,16 +1038,16 @@ Persistence /* Creates and stores a webhook. - @public createWebhook( *userId, hookname* ) - @param {String} userId + @public createWebhook( *username, hookname* ) + @param {String} username @param {String} hookname */ exports.createWebhook = (function(_this) { - return function(userId, hookname, hookid) { + return function(username, hookid, hookname) { _this.db.sadd("webhooks", hookid, replyHandler("sadd 'webhooks' -> '" + hookid + "'")); - _this.db.sadd("user:" + userId + ":webhooks", hookid, replyHandler("sadd 'user:" + userId + ":webhooks' -> '" + hookid + "'")); - return _this.db.set("webhook:" + hookid, hookname, replyHandler("set webhook:" + hookid + " -> " + hookname)); + _this.db.sadd("user:" + username + ":webhooks", hookid, replyHandler("sadd 'user:" + username + ":webhooks' -> '" + hookid + "'")); + return _this.db.hmset("webhook:" + hookid, 'hookname', hookname, 'username', username, replyHandler("set webhook:" + hookid + " -> [" + hookname + ", " + username + "]")); }; })(this); @@ -1061,7 +1061,21 @@ Persistence exports.getWebhookName = (function(_this) { return function(hookid, cb) { - return _this.db.get("webhook:" + hookid, cb); + return _this.db.hget("webhook:" + hookid, "hookname", cb); + }; + })(this); + + + /* + Returns all webhook properties. + + @public getFullWebhookName( *hookid* ) + @param {String} hookid + */ + + exports.getFullWebhook = (function(_this) { + return function(hookid, cb) { + return _this.db.hgetall("webhook:" + hookid, cb); }; })(this); @@ -1069,13 +1083,13 @@ Persistence /* Returns all the user's webhooks by ID. - @public getUserWebhookIDs( *userId* ) - @param {String} userId + @public getUserWebhookIDs( *username* ) + @param {String} username */ exports.getUserWebhookIDs = (function(_this) { - return function(userId, cb) { - return _this.db.smembers("user:" + userId + ":webhooks", cb); + return function(username, cb) { + return _this.db.smembers("user:" + username + ":webhooks", cb); }; })(this); @@ -1083,13 +1097,13 @@ Persistence /* Gets all the user's webhooks with names. - @public getAllUserWebhooks( *userId* ) - @param {String} userId + @public getAllUserWebhooks( *username* ) + @param {String} username */ exports.getAllUserWebhooks = (function(_this) { - return function(userId, cb) { - return getSetRecords("user:" + userId + ":webhooks", exports.getWebhookName, cb); + return function(username, cb) { + return getSetRecords("user:" + username + ":webhooks", exports.getWebhookName, cb); }; })(this); @@ -1115,7 +1129,7 @@ Persistence exports.getAllWebhooks = (function(_this) { return function(cb) { - return getSetRecords("webhooks", exports.getWebhookName, cb); + return getSetRecords("webhooks", exports.getFullWebhook, cb); }; })(this); @@ -1123,15 +1137,15 @@ Persistence /* Delete a webhook. - @public deleteWebhook( *userId, hookid* ) - @param {String} userId + @public deleteWebhook( *username, hookid* ) + @param {String} username @param {String} hookid */ exports.deleteWebhook = (function(_this) { - return function(userId, hookid) { + return function(username, hookid) { _this.db.srem("webhooks", hookid, replyHandler("srem 'webhooks' -> '" + hookid + "'")); - _this.db.srem("user:" + userId + ":webhooks", hookid, replyHandler("srem 'user:" + userId + ":webhooks' -> '" + hookid + "'")); + _this.db.srem("user:" + username + ":webhooks", hookid, replyHandler("srem 'user:" + username + ":webhooks' -> '" + hookid + "'")); return _this.db.del("webhook:" + hookid, replyHandler("del webhook:" + hookid)); }; })(this); diff --git a/js/request-handler.js b/js/request-handler.js index b3252d7..013c3f4 100644 --- a/js/request-handler.js +++ b/js/request-handler.js @@ -11,7 +11,7 @@ Request Handler */ (function() { - var crypto, db, dirHandlers, exports, fs, getHandlerPath, getRemoteScripts, getScript, getTemplate, indexEvent, mustache, path, pathUsers, qs, renderPage; + var crypto, db, dirHandlers, exports, fs, getHandlerPath, getRemoteScripts, getScript, getTemplate, mustache, parsePushAndAnswerEvent, path, pathUsers, qs, renderPage; db = require('./persistence'); @@ -433,8 +433,8 @@ Request Handler }; })(this); - indexEvent = function(eventname, body, resp) { - var err, msg, obj; + parsePushAndAnswerEvent = function(eventname, username, body, resp) { + var err, obj; if (typeof body === 'string') { try { body = JSON.parse(body); @@ -453,8 +453,14 @@ Request Handler eventname: eventname, body: body }; + if (username) { + obj.username = username; + } db.pushEvent(obj); - msg = "Thank you for the event: '" + eventname + "'"; + resp.send(200, JSON.stringify({ + message: "Thank you for the event: '" + eventname + "'", + evt: obj + })); return obj; }; @@ -472,7 +478,7 @@ Request Handler }); return req.on('end', function() { var fPath, obj; - obj = indexEvent(name, body, resp); + obj = parsePushAndAnswerEvent(name, null, body, resp); if (obj.eventname === 'uptimestatistics') { fPath = path.resolve(__dirname, '..', 'webpages', 'public', 'data', 'histochart.json'); return fs.writeFile(fPath, JSON.stringify(JSON.parse(body), void 0, 2), 'utf8'); @@ -488,17 +494,16 @@ Request Handler exports.handleWebhooks = (function(_this) { return function(req, resp) { - var body, hookid, hookname; + var body, hookid, oHook; hookid = req.url.substring(10).split('/')[0]; - hookname = _this.allowedHooks[hookid]; - if (hookname) { + oHook = _this.allowedHooks[hookid]; + if (oHook) { body = ''; req.on('data', function(data) { return body += data; }); return req.on('end', function() { - var obj; - return obj = indexEvent(hookname, body, resp); + return parsePushAndAnswerEvent(oHook.hookname, oHook.username, body, resp); }); } else { return resp.send(404, "Webhook not existing!"); @@ -507,9 +512,12 @@ Request Handler })(this); exports.activateWebhook = (function(_this) { - return function(hookid, name) { + return function(user, hookid, name) { _this.log.info("HL | Webhook '" + hookid + "' activated"); - return _this.allowedHooks[hookid] = name; + return _this.allowedHooks[hookid] = { + hookname: name, + username: user + }; }; })(this); diff --git a/webpages/handlers/coffee/forge_rule.coffee b/webpages/handlers/coffee/forge_rule.coffee index 6a4cc81..571ac9f 100644 --- a/webpages/handlers/coffee/forge_rule.coffee +++ b/webpages/handlers/coffee/forge_rule.coffee @@ -1,3 +1,9 @@ +# +# General Helper Fucntions +# + +strPublicKey = '' + # Fetch the search string and transform it into an object for easy access arrParams = window.location.search.substring(1).split '&' oParams = {} @@ -8,15 +14,6 @@ for param in arrParams if oParams.id oParams.id = decodeURIComponent oParams.id -strPublicKey = '' -# fPlaceAndPaintInterval = () -> -# $( '#event_start' ).html 'Start Time: -# -# "hh:mm", default = 12:00' -# $( '#event_interval' ).html 'Interval: -# -# "days hours:minutes", default = 10 minutes' - fDisplayError = ( msg ) -> window.scrollTo 0, 0 $( '#info' ).text "Error: #{ msg }" @@ -34,7 +31,380 @@ fIssueRequest = ( args ) -> $.post( '/usercommand', args.body ) .done args.done .fail args.fail + +# Convert a time string ( d h:m ) to a date +fConvertTimeToDate = ( str ) -> + txtStart = $( '#input_start' ).val() + dateConv = new Date() + if not txtStart + dateConv.setHours 12 + dateConv.setMinutes 0 + else + arrInp = txtStart.split ':' + # There's only one string entered: hour + if arrInp.length is 1 + txtHr = txtStart + dateConv.setMinutes 0 + else + txtHr = arrInp[ 0 ] + intMin = parseInt( arrInp[ 1 ] ) || 0 + m = Math.max 0, Math.min intMin, 59 + dateConv.setMinutes m + intHour = parseInt( txtHr ) || 12 + h = Math.max 0, Math.min intHour, 24 + dateConv.setHours h + + dateConv.setSeconds 0 + dateConv.setMilliseconds 0 + if dateConv < new Date() + dateConv.setDate dateConv.getDate() + 17 + dateConv + +# Convert a day hour string ( h:m ) to minutes +fConvertDayHourToMinutes = ( strDayHour ) -> + # Parse a time string + fParseTime = ( str, hasDay ) -> + arrTime = str.split ':' + # If there's only one entry, this is the amount of minutes + if hasDay + def = 0 + else + def = 10 + if arrTime.length is 1 + time = parseInt( str ) || def + if hasDay + time * 60 + else + time + else + h = parseInt( arrTime[ 0 ] ) || 0 + if h > 0 + def = 0 + h * 60 + ( parseInt( arrTime[ 1 ] ) || def ) + + if not strDayHour + mins = 10 + else + arrInp = strDayHour.split ' ' + # There's only one string entered, either day or hour + if arrInp.length is 1 + mins = fParseTime strDayHour + else + d = parseInt( arrInp[ 0 ] ) || 0 + mins = d * 24 * 60 + fParseTime arrInp[ 1 ], true + + # We have to limit this to 24 days because setTimeout only takes integer values + # until we implement a scheduler that deals with larger intervals + mins = Math.min mins, 35700 + Math.max 1, mins + + +# +# EVENT Related Helper Functions +# + +# fPlaceAndPaintInterval = () -> +# $( '#event_start' ).html 'Start Time: +# +# "hh:mm", default = 12:00' +# $( '#event_interval' ).html 'Interval: +# +# "days hours:minutes", default = 10 minutes' + +# Prepare the event section when a different event type is selected +fPrepareEventType = ( eventtype ) -> + $( '#select_event_type' ).val eventtype + $( '#event_parameters *' ).remove() + switch eventtype + + # The user wants to react to custom event + when 'Custom Event' + inpEvt = $( '' ).attr( 'type', 'text' ) + .attr( 'style', 'font-size:1em' ).attr 'id', 'input_eventname' + $( '#event_parameters' ).append $( '

' ).text( 'Event Name : ' ).append inpEvt + + # The user wants a webhook as event producer + when 'Webhook' + fIssueRequest + body: command: 'get_all_webhooks' + done: ( data ) -> + try + oHooks = JSON.parse data.message + selHook = $( '' ).attr( 'type', 'text' ) + .attr( 'style', 'font-size:1em' ).attr 'id', 'select_eventpoller' + $( '#event_parameters' ).append $( '

' ).text( 'Event Poller Name : ' ).append selPoller + fIssueRequest + body: command: 'get_event_pollers' + done: ( data ) -> + try + + oEps = JSON.parse data.message + fAppendEvents = ( id, events ) -> + fAppendEvent = ( evt ) -> + $( '#select_eventpoller' ).append $( '