From 418d5441feda828c8fcf52c3c3a1fa14f31f662e Mon Sep 17 00:00:00 2001 From: Dominic Bosch Date: Fri, 4 Apr 2014 19:53:42 +0200 Subject: [PATCH] User-parameter support implemented, system seems to run smoothly --- coffee/components-manager.coffee | 69 ++++++--- coffee/dynamic-modules.coffee | 75 ++++++--- coffee/engine.coffee | 122 ++++++++++----- coffee/persistence.coffee | 49 ++++-- js-coffee/components-manager.js | 83 +++++++--- js-coffee/dynamic-modules.js | 73 ++++++--- js-coffee/engine.js | 146 +++++++++++------- js-coffee/persistence.js | 63 +++++++- testing/files/testObjects.json | 68 ++++---- testing/test_dynamic-modules.coffee | 97 ++++++++++-- testing/test_engine.coffee | 40 +++-- webpages/handlers/coffee/admin.coffee | 28 ++-- webpages/handlers/coffee/edit_rules.coffee | 63 ++++++++ .../coffee/forge_action_invoker.coffee | 22 +-- webpages/handlers/coffee/forge_event.coffee | 15 +- .../handlers/coffee/forge_event_poller.coffee | 22 +-- webpages/handlers/coffee/forge_rule.coffee | 102 ++++++------ webpages/handlers/js/admin.js | 20 ++- webpages/handlers/js/edit_rules.js | 86 +++++++++++ webpages/handlers/js/forge_action_invoker.js | 32 ++-- webpages/handlers/js/forge_event.js | 20 ++- webpages/handlers/js/forge_event_poller.js | 32 ++-- webpages/handlers/js/forge_rule.js | 141 ++++++++++------- webpages/handlers/templates/edit_rules.html | 12 ++ .../templates/forge_action_invoker.html | 8 +- webpages/handlers/templates/menubar.html | 9 +- webpages/public/cross.jpg | Bin 496 -> 0 bytes webpages/public/logicon.png | Bin 0 -> 443 bytes webpages/public/style.css | 8 + 29 files changed, 1053 insertions(+), 452 deletions(-) create mode 100644 webpages/handlers/coffee/edit_rules.coffee create mode 100644 webpages/handlers/js/edit_rules.js create mode 100644 webpages/handlers/templates/edit_rules.html delete mode 100644 webpages/public/cross.jpg create mode 100644 webpages/public/logicon.png diff --git a/coffee/components-manager.coffee b/coffee/components-manager.coffee index 31640f8..5129aa5 100644 --- a/coffee/components-manager.coffee +++ b/coffee/components-manager.coffee @@ -144,22 +144,23 @@ forgeModule = ( user, oPayload, dbMod, callback ) => dbMod.getModule oPayload.id, ( err, mod ) => if mod answ.code = 409 - answ.message = 'Event Poller module name already existing: ' + oPayload.id + answ.message = 'Module name already existing: ' + oPayload.id + callback answ else src = oPayload.data - cm = dynmod.compileString src, user.username, oPayload.id, {}, oPayload.lang - answ = cm.answ - if answ.code is 200 - funcs = [] - funcs.push name for name, id of cm.module - @log.info "CM | Storing new module with functions #{ funcs.join() }" - answ.message = - "Event Poller module successfully stored! Found following function(s): #{ funcs }" - oPayload.functions = JSON.stringify funcs - dbMod.storeModule user.username, oPayload - if oPayload.public is 'true' - dbMod.publish oPayload.id - callback answ + dynmod.compileString src, user.username, 'dummyRule', oPayload.id, oPayload.lang, null, ( cm ) => + answ = cm.answ + if answ.code is 200 + funcs = [] + funcs.push name for name, id of cm.module + @log.info "CM | Storing new module with functions #{ funcs.join() }" + answ.message = + "Event Poller module successfully stored! Found following function(s): #{ funcs }" + oPayload.functions = JSON.stringify funcs + dbMod.storeModule user.username, oPayload + if oPayload.public is 'true' + dbMod.publish oPayload.id + callback answ commandFunctions = get_public_key: ( user, oPayload, callback ) -> @@ -174,19 +175,47 @@ commandFunctions = getModules user, oPayload, db.actionInvokers, callback get_event_poller_params: ( user, oPayload, callback ) -> - getModuleParams user, oPayload, db.eventPollers, callback + getModuleParams user, oPayload, db.eventPollers, callback get_action_invoker_params: ( user, oPayload, callback ) -> - getModuleParams user, oPayload, db.actionInvokers, callback + getModuleParams user, oPayload, db.actionInvokers, callback forge_event_poller: ( user, oPayload, callback ) -> - forgeModule user, oPayload, db.eventPollers, callback + forgeModule user, oPayload, db.eventPollers, callback forge_action_invoker: ( user, oPayload, callback ) -> - forgeModule user, oPayload, db.actionInvokers, callback + forgeModule user, oPayload, db.actionInvokers, callback get_rules: ( user, oPayload, callback ) -> - console.log 'CM | Implement get_rules' + db.getUserLinkedRules user.username, ( err, obj ) -> + callback + code: 200 + message: obj + + get_rule_log: ( user, oPayload, callback ) -> + answ = hasRequiredParams [ 'id' ], oPayload + if answ.code isnt 200 + callback answ + else + db.getLog user.username, oPayload.id, ( err, obj ) -> + callback + code: 200 + message: obj + + delete_rule: ( user, oPayload, callback ) -> + answ = hasRequiredParams [ 'id' ], oPayload + if answ.code isnt 200 + callback answ + else + db.deleteRule oPayload.id + eventEmitter.emit 'rule', + event: 'del' + user: user.username + rule: null + ruleId: oPayload.id + callback + code: 200 + message: 'OK!' # A rule needs to be in following format: # - id @@ -224,5 +253,5 @@ commandFunctions = rule: rule answ = code: 200 - message: 'Rule stored and activated!' + message: "Rule '#{ rule.id }' stored and activated!" callback answ \ No newline at end of file diff --git a/coffee/dynamic-modules.coffee b/coffee/dynamic-modules.coffee index 3ab7530..100b6f1 100644 --- a/coffee/dynamic-modules.coffee +++ b/coffee/dynamic-modules.coffee @@ -8,6 +8,8 @@ Dynamic Modules # **Loads Modules:** +db = require './persistence' + # - Node.js Modules: [vm](http://nodejs.org/api/vm.html) and # [events](http://nodejs.org/api/events.html) vm = require 'vm' @@ -31,11 +33,12 @@ exports = module.exports = ( args ) => @log = args.logger # FIXME this can't come through the arguments if not @strPublicKey and args[ 'keygen' ] + db args passPhrase = args[ 'keygen' ] numBits = 1024 @oPrivateRSAkey = cryptico.generateRSAKey passPhrase, numBits @strPublicKey = cryptico.publicKeyString @oPrivateRSAkey - @log.info "Public Key generated: #{ @strPublicKey }" + @log.info "DM | Public Key generated: #{ @strPublicKey }" # plainText = "Matt, I need you to help me with my Starcraft strategy." # oEncrypted = cryptico.encrypt plainText, strPublicKey @@ -61,7 +64,7 @@ compile it first into JS. @param {Object} params @param {String} lang ### -exports.compileString = ( src, userId, modId, params, lang ) => +exports.compileString = ( src, userId, ruleId, modId, lang, dbMod, cb ) => answ = code: 200 message: 'Successfully compiled' @@ -73,26 +76,48 @@ exports.compileString = ( src, userId, modId, params, lang ) => answ.code = 400 answ.message = 'Compilation of CoffeeScript failed at line ' + err.location.first_line - #FIXME not log but debug module is required to provide information to the user - sandbox = - id: userId + '.' + modId + '.vm' - params: params - needle: needle - log: console.log - # console: console #TODO remove! - exports: {} - #TODO child_process to run module! - #Define max runtime per loop as 10 seconds, after that the child will be killed - #it can still be active after that if there was a timing function or a callback used... - #kill the child each time? how to determine whether there's still a token in the module? - try - vm.runInNewContext src, sandbox, sandbox.id - # TODO We should investigate memory usage and garbage collection (global.gc())? - # Start Node with the flags —nouse_idle_notification and —expose_gc, and then when you want to run the GC, just call global.gc(). - catch err - answ.code = 400 - answ.message = 'Loading Module failed: ' + err.message - ret = - answ: answ - module: sandbox.exports - ret \ No newline at end of file + + logFunction = ( uId, rId, mId ) -> + ( msg ) -> + db.appendLog uId, rId, mId, msg + db.resetLog userId, ruleId + + fTryToLoad = ( params ) => + if params + try + oDecrypted = cryptico.decrypt params, @oPrivateRSAkey + params = JSON.parse oDecrypted.plaintext + catch err + @log.warn "DM | Error during parsing of user defined params for #{ userId }, #{ ruleId }, #{ modId }" + params = {} + else + params = {} + sandbox = + id: userId + '.' + modId + '.vm' + params: params + needle: needle + log: logFunction userId, ruleId, modId + # debug: console.log + exports: {} + + #TODO child_process to run module! + #Define max runtime per loop as 10 seconds, after that the child will be killed + #it can still be active after that if there was a timing function or a callback used... + #kill the child each time? how to determine whether there's still a token in the module? + try + vm.runInNewContext src, sandbox, sandbox.id + # TODO We should investigate memory usage and garbage collection (global.gc())? + # Start Node with the flags —nouse_idle_notification and —expose_gc, and then when you want to run the GC, just call global.gc(). + catch err + console.log err + answ.code = 400 + answ.message = 'Loading Module failed: ' + err.message + cb + answ: answ + module: sandbox.exports + + if dbMod + dbMod.getUserParams modId, userId, ( err, obj ) -> + fTryToLoad obj + else + fTryToLoad() diff --git a/coffee/engine.coffee b/coffee/engine.coffee index 1177cb2..2009ea0 100644 --- a/coffee/engine.coffee +++ b/coffee/engine.coffee @@ -19,6 +19,25 @@ dynmod = require './dynamic-modules' # [js-select](https://www.npmjs.org/package/js-select) jsonQuery = require 'js-select' +### +This is ging to have a structure like: +An object of users with their active rules and the required action modules +"user-1": + "rule-1": + "rule": oRule-1 + "actions": + "action-1": oAction-1 + "action-2": oAction-2 + "rule-2": + "rule": oRule-2 + "actions": + "action-1": oAction-1 +"user-2": + "rule-3": + "rule": oRule-3 + "actions": + "action-3": oAction-3 +### listUserRules = {} isRunning = false @@ -35,7 +54,7 @@ exports = module.exports = ( args ) => @log = args.logger db args dynmod args - pollQueue() + setTimeout pollQueue, 10 # Very important, this forks a token for the poll task module.exports @@ -59,50 +78,48 @@ are basically CRUD on rules. ### exports.internalEvent = ( evt ) => if not listUserRules[evt.user] and evt.event isnt 'del' - listUserRules[evt.user] = - rules: {} - actions: {} + listUserRules[evt.user] = {} oUser = listUserRules[evt.user] oRule = evt.rule - if evt.event is 'new' or ( evt.event is 'init' and not oUser.rules[oRule.id] ) - oUser.rules[oRule.id] = oRule - updateActionModules oRule, false + if evt.event is 'new' or ( evt.event is 'init' and not oUser[oRule.id] ) + oUser[oRule.id] = + rule: oRule + actions: {} + updateActionModules oRule.id if evt.event is 'del' and oUser - delete oUser.rules[oRule.id] - updateActionModules oRule, true + delete oUser[evt.ruleId] + + # If a user is empty after all the updates above, we remove her from the list + if JSON.stringify( oUser ) is "{}" + delete listUserRules[evt.user] + ### As soon as changes were made to the rule set we need to ensure that the aprropriate action invoker modules are loaded, updated or deleted. -@private updateActionModules ( *oNewRule* ) -@param {Object} oNewRule +@private updateActionModules ( *updatedRuleId* ) +@param {Object} updatedRuleId ### -updateActionModules = ( oNewRule, isDeleteOp ) -> +updateActionModules = ( updatedRuleId ) -> # Remove all action invoker modules that are not required anymore fRemoveNotRequired = ( oUser ) -> - # Check whether the action is still existing in a rule + # Check whether the action is still existing in the rule fRequired = ( actionName ) -> - # return true for nmRl, oRl of oUser.rules when actionName in oRl.actions - for nmRl, oRl of oUser.rules - for action in oRl.actions - mod = (action.split ' -> ')[0] - if mod is actionName - return true + for action in oUser[updatedRuleId].rule.actions + # Since the event is in the format 'module -> function' we need to split the string + if (action.split ' -> ')[0] is actionName + return true false - - # Go thorugh all actions and check whether the action is still required - for action of oUser.actions - req = fRequired action - if not req - delete oUser.actions[action] - # delete oUser.actions[action] for action of oUser.actions when not fRequired action + # Go thorugh all loaded action modules and check whether the action is still required + for action of oUser[updatedRuleId].rule.actions + delete oUser[updatedRuleId].actions[action] if not fRequired action fRemoveNotRequired oUser for name, oUser of listUserRules @@ -110,26 +127,35 @@ updateActionModules = ( oNewRule, isDeleteOp ) -> fAddRequired = ( userName, oUser ) -> # Check whether the action is existing in a rule and load if not - fCheckRules = ( oRule ) -> + fCheckRules = ( oMyRule ) -> # Load the action invoker module if it was part of the updated rule or if it's new fAddIfNewOrNotExisting = ( actionName ) -> moduleName = (actionName.split ' -> ')[0] - if not isDeleteOp and ( not oUser.actions[moduleName] or oRule.id is oNewRule.id ) + if not oMyRule.actions[moduleName] or oMyRule.rule.id is updatedRuleId db.actionInvokers.getModule moduleName, ( err, obj ) -> - params = {} - res = dynmod.compileString obj.data, userName, moduleName, params, obj.lang - oUser.actions[moduleName] = res.module + # we compile the module and pass: + dynmod.compileString obj.data, # code + userName, # userId + oMyRule.rule.id, # ruleId + moduleName, # moduleId + obj.lang, # script language + db.actionInvokers, # the DB interface + ( result ) -> + if not result.answ is 200 + @log.error "EN | Compilation of code failed! #{ userName }, + #{ oMyRule.rule.id }, #{ moduleName }" + oMyRule.actions[moduleName] = result.module - fAddIfNewOrNotExisting action for action in oRule.actions + fAddIfNewOrNotExisting action for action in oMyRule.rule.actions - # Go thorugh all actions and check whether the action is still required - fCheckRules oRl for nmRl, oRl of oUser.rules - if JSON.stringify( oUser.rules ) is "{}" # TODO check whether this is really doing what it is supposed to do - delete listUserRules[userName] + # Go thorugh all rules and check whether the action is still required + fCheckRules oRl for nmRl, oRl of oUser + # load all required modules for all users fAddRequired userName, oUser for userName, oUser of listUserRules + pollQueue = () -> if isRunning db.popEvent ( err, obj ) -> @@ -145,6 +171,8 @@ Checks whether all conditions of the rule are met by the event. @param {Object} rule ### validConditions = ( evt, rule ) -> + if rule.conditions.length is 0 + return true for prop in rule.conditions return false if jsonQuery( evt, prop ).nodes().length is 0 return true @@ -156,15 +184,27 @@ Handles retrieved events. @param {Object} evt ### processEvent = ( evt ) => + + fSearchAndInvokeAction = ( node, arrPath, evt, depth ) -> + if not node + @log.error "EN | Didn't find property in user rule list: " + arrPath.join ', ' + " at depth " + depth + return + if depth is arrPath.length + try + node evt.payload + catch err + @log.info "EN | ERROR IN ACTION INVOKER: " + err.message + else + fSearchAndInvokeAction node[arrPath[depth]], arrPath, evt, depth + 1 + @log.info 'EN | processing event: ' + evt.event + '(' + evt.eventid + ')' for userName, oUser of listUserRules - for ruleName, oRule of oUser.rules - if evt.event is oRule.event and validConditions evt, oRule + for ruleName, oMyRule of oUser + if evt.event is oMyRule.rule.event and validConditions evt, oMyRule.rule @log.info 'EN | EVENT FIRED: ' + evt.event + '(' + evt.eventid + ') for rule ' + ruleName - # fStoreAction userName, action for action in oRule.actions - for action in oRule.actions + for action in oMyRule.rule.actions arr = action.split ' -> ' - listUserRules[userName]['actions'][arr[0]][arr[1]] evt + fSearchAndInvokeAction listUserRules, [ userName, ruleName, 'actions', arr[0], arr[1]], evt, 0 exports.shutDown = () -> isRunning = false \ No newline at end of file diff --git a/coffee/persistence.coffee b/coffee/persistence.coffee index 8ca80ae..44abdf0 100644 --- a/coffee/persistence.coffee +++ b/coffee/persistence.coffee @@ -202,7 +202,6 @@ class IndexedModules setDB: ( @db ) -> @log.info "DB | (IdxedMods) Registered new DB connection for '#{ @setname }'" - ### Stores a module and links it to the user. @@ -252,7 +251,7 @@ class IndexedModules #TODO add testing getModuleParams: ( mId, cb ) => - @log.info "DB | (IdxedMods) #{ @setname }.getModule( #{ mId } )" + @log.info "DB | (IdxedMods) #{ @setname }.getModuleParams( #{ mId } )" @db.hget "#{ @setname }:#{ mId }", "params", cb #TODO add testing @@ -277,13 +276,7 @@ class IndexedModules @unpublish mId @db.smembers "#{ @setname }:#{ mId }:users", ( err, obj ) => @unlinkModule mId, userId for userId in obj - # TODO remove from public modules - # TODO remove parameters - # @log.info "DB | linkModule(#{ @setname }): #{ mId } to #{ userId }" - # @db.sadd "#{ @setname }:#{ mId }:users", userId, - # replyHandler "Linking '#{ @setname }:#{ mId }:users' #{ userId }" - # @db.sadd "user:#{ userId }:#{ @setname }s", mId, - # replyHandler "Linking 'user:#{ userId }:#{ @setname }s' #{ mId }" + @deleteUserParams mId, userId for userId in obj ### Stores user params for a module. They are expected to be RSA encrypted with helps of @@ -303,8 +296,7 @@ class IndexedModules getUserParams: ( mId, userId, cb ) => @log.info "DB | (IdxedMods) #{ @setname }.getUserParams( #{ mId }, #{ userId } )" - @db.get "#{ @setname }-params:#{ mId }:#{ userId }", ( err, data ) -> - cb err, data + @db.get "#{ @setname }-params:#{ mId }:#{ userId }", cb getUserParamsIds: ( cb ) => @log.info "DB | (IdxedMods) #{ @setname }.getUserParamsIds()" @@ -322,6 +314,41 @@ class IndexedModules ## Rules ### + +### +Appends a log entry. + +@public log( *userId, ruleId, message* ) +@param {String} userId +@param {String} ruleId +@param {String} message +### +exports.appendLog = ( userId, ruleId, moduleId, message ) => + @db.append "#{ userId }:#{ ruleId }", + "[#{ ( new Date ).toISOString() }] {#{ moduleId }} #{ message }\n" + +### +Retrieves a log entry. + +@public getLog( *userId, ruleId* ) +@param {String} userId +@param {String} ruleId +@param {function} cb +### +exports.getLog = ( userId, ruleId, cb ) => + @db.get "#{ userId }:#{ ruleId }", cb + +### +Resets a log entry. + +@public resetLog( *userId, ruleId* ) +@param {String} userId +@param {String} ruleId +### +exports.resetLog = ( userId, ruleId ) => + @db.del "#{ userId }:#{ ruleId }", + replyHandler "RESET LOG '#{ userId }:#{ ruleId }'" + ### Query the DB for a rule and pass it to cb(err, obj). diff --git a/js-coffee/components-manager.js b/js-coffee/components-manager.js index f1b93bf..c6e5322 100644 --- a/js-coffee/components-manager.js +++ b/js-coffee/components-manager.js @@ -199,31 +199,34 @@ Components Manager return callback(answ); } else { return dbMod.getModule(oPayload.id, function(err, mod) { - var cm, funcs, id, name, src, _ref; + var src; if (mod) { answ.code = 409; - answ.message = 'Event Poller module name already existing: ' + oPayload.id; + answ.message = 'Module name already existing: ' + oPayload.id; + return callback(answ); } else { src = oPayload.data; - cm = dynmod.compileString(src, user.username, oPayload.id, {}, oPayload.lang); - answ = cm.answ; - if (answ.code === 200) { - funcs = []; - _ref = cm.module; - for (name in _ref) { - id = _ref[name]; - funcs.push(name); + return dynmod.compileString(src, user.username, 'dummyRule', oPayload.id, oPayload.lang, null, function(cm) { + var funcs, id, name, _ref; + answ = cm.answ; + if (answ.code === 200) { + funcs = []; + _ref = cm.module; + for (name in _ref) { + id = _ref[name]; + funcs.push(name); + } + _this.log.info("CM | Storing new module with functions " + (funcs.join())); + answ.message = "Event Poller module successfully stored! Found following function(s): " + funcs; + oPayload.functions = JSON.stringify(funcs); + dbMod.storeModule(user.username, oPayload); + if (oPayload["public"] === 'true') { + dbMod.publish(oPayload.id); + } } - _this.log.info("CM | Storing new module with functions " + (funcs.join())); - answ.message = "Event Poller module successfully stored! Found following function(s): " + funcs; - oPayload.functions = JSON.stringify(funcs); - dbMod.storeModule(user.username, oPayload); - if (oPayload["public"] === 'true') { - dbMod.publish(oPayload.id); - } - } + return callback(answ); + }); } - return callback(answ); }); } }; @@ -255,7 +258,45 @@ Components Manager return forgeModule(user, oPayload, db.actionInvokers, callback); }, get_rules: function(user, oPayload, callback) { - return console.log('CM | Implement get_rules'); + return db.getUserLinkedRules(user.username, function(err, obj) { + return callback({ + code: 200, + message: obj + }); + }); + }, + get_rule_log: function(user, oPayload, callback) { + var answ; + answ = hasRequiredParams(['id'], oPayload); + if (answ.code !== 200) { + return callback(answ); + } else { + return db.getLog(user.username, oPayload.id, function(err, obj) { + return callback({ + code: 200, + message: obj + }); + }); + } + }, + delete_rule: function(user, oPayload, callback) { + var answ; + answ = hasRequiredParams(['id'], oPayload); + if (answ.code !== 200) { + return callback(answ); + } else { + db.deleteRule(oPayload.id); + eventEmitter.emit('rule', { + event: 'del', + user: user.username, + rule: null, + ruleId: oPayload.id + }); + return callback({ + code: 200, + message: 'OK!' + }); + } }, forge_rule: function(user, oPayload, callback) { var answ; @@ -297,7 +338,7 @@ Components Manager }); answ = { code: 200, - message: 'Rule stored and activated!' + message: "Rule '" + rule.id + "' stored and activated!" }; } return callback(answ); diff --git a/js-coffee/dynamic-modules.js b/js-coffee/dynamic-modules.js index a6942da..19ae4a0 100644 --- a/js-coffee/dynamic-modules.js +++ b/js-coffee/dynamic-modules.js @@ -9,7 +9,9 @@ Dynamic Modules */ (function() { - var cryptico, cs, exports, needle, vm; + var cryptico, cs, db, exports, needle, vm; + + db = require('./persistence'); vm = require('vm'); @@ -33,11 +35,12 @@ Dynamic Modules var numBits, passPhrase; _this.log = args.logger; if (!_this.strPublicKey && args['keygen']) { + db(args); passPhrase = args['keygen']; numBits = 1024; _this.oPrivateRSAkey = cryptico.generateRSAKey(passPhrase, numBits); _this.strPublicKey = cryptico.publicKeyString(_this.oPrivateRSAkey); - _this.log.info("Public Key generated: " + _this.strPublicKey); + _this.log.info("DM | Public Key generated: " + _this.strPublicKey); } return module.exports; }; @@ -63,8 +66,8 @@ Dynamic Modules */ exports.compileString = (function(_this) { - return function(src, userId, modId, params, lang) { - var answ, err, ret, sandbox; + return function(src, userId, ruleId, modId, lang, dbMod, cb) { + var answ, err, fTryToLoad, logFunction; answ = { code: 200, message: 'Successfully compiled' @@ -78,25 +81,53 @@ Dynamic Modules answ.message = 'Compilation of CoffeeScript failed at line ' + err.location.first_line; } } - sandbox = { - id: userId + '.' + modId + '.vm', - params: params, - needle: needle, - log: console.log, - exports: {} + logFunction = function(uId, rId, mId) { + return function(msg) { + return db.appendLog(uId, rId, mId, msg); + }; }; - try { - vm.runInNewContext(src, sandbox, sandbox.id); - } catch (_error) { - err = _error; - answ.code = 400; - answ.message = 'Loading Module failed: ' + err.message; + db.resetLog(userId, ruleId); + fTryToLoad = function(params) { + var oDecrypted, sandbox; + if (params) { + try { + oDecrypted = cryptico.decrypt(params, _this.oPrivateRSAkey); + params = JSON.parse(oDecrypted.plaintext); + } catch (_error) { + err = _error; + _this.log.warn("DM | Error during parsing of user defined params for " + userId + ", " + ruleId + ", " + modId); + params = {}; + } + } else { + params = {}; + } + sandbox = { + id: userId + '.' + modId + '.vm', + params: params, + needle: needle, + log: logFunction(userId, ruleId, modId), + exports: {} + }; + try { + vm.runInNewContext(src, sandbox, sandbox.id); + } catch (_error) { + err = _error; + console.log(err); + answ.code = 400; + answ.message = 'Loading Module failed: ' + err.message; + } + return cb({ + answ: answ, + module: sandbox.exports + }); + }; + if (dbMod) { + return dbMod.getUserParams(modId, userId, function(err, obj) { + return fTryToLoad(obj); + }); + } else { + return fTryToLoad(); } - ret = { - answ: answ, - module: sandbox.exports - }; - return ret; }; })(this); diff --git a/js-coffee/engine.js b/js-coffee/engine.js index ce344b1..9b29b5e 100644 --- a/js-coffee/engine.js +++ b/js-coffee/engine.js @@ -18,6 +18,27 @@ Engine jsonQuery = require('js-select'); + + /* + This is ging to have a structure like: + An object of users with their active rules and the required action modules + "user-1": + "rule-1": + "rule": oRule-1 + "actions": + "action-1": oAction-1 + "action-2": oAction-2 + "rule-2": + "rule": oRule-2 + "actions": + "action-1": oAction-1 + "user-2": + "rule-3": + "rule": oRule-3 + "actions": + "action-3": oAction-3 + */ + listUserRules = {}; isRunning = false; @@ -38,7 +59,7 @@ Engine _this.log = args.logger; db(args); dynmod(args); - pollQueue(); + setTimeout(pollQueue, 10); return module.exports; } }; @@ -70,20 +91,22 @@ Engine return function(evt) { var oRule, oUser; if (!listUserRules[evt.user] && evt.event !== 'del') { - listUserRules[evt.user] = { - rules: {}, - actions: {} - }; + listUserRules[evt.user] = {}; } oUser = listUserRules[evt.user]; oRule = evt.rule; - if (evt.event === 'new' || (evt.event === 'init' && !oUser.rules[oRule.id])) { - oUser.rules[oRule.id] = oRule; - updateActionModules(oRule, false); + if (evt.event === 'new' || (evt.event === 'init' && !oUser[oRule.id])) { + oUser[oRule.id] = { + rule: oRule, + actions: {} + }; + updateActionModules(oRule.id); } if (evt.event === 'del' && oUser) { - delete oUser.rules[oRule.id]; - return updateActionModules(oRule, true); + delete oUser[evt.ruleId]; + } + if (JSON.stringify(oUser) === "{}") { + return delete listUserRules[evt.user]; } }; })(this); @@ -93,35 +116,29 @@ Engine As soon as changes were made to the rule set we need to ensure that the aprropriate action invoker modules are loaded, updated or deleted. - @private updateActionModules ( *oNewRule* ) - @param {Object} oNewRule + @private updateActionModules ( *updatedRuleId* ) + @param {Object} updatedRuleId */ - updateActionModules = function(oNewRule, isDeleteOp) { + updateActionModules = function(updatedRuleId) { var fAddRequired, fRemoveNotRequired, name, oUser, userName, _results; fRemoveNotRequired = function(oUser) { - var action, fRequired, req, _results; + var action, fRequired, _results; fRequired = function(actionName) { - var action, mod, nmRl, oRl, _i, _len, _ref, _ref1; - _ref = oUser.rules; - for (nmRl in _ref) { - oRl = _ref[nmRl]; - _ref1 = oRl.actions; - for (_i = 0, _len = _ref1.length; _i < _len; _i++) { - action = _ref1[_i]; - mod = (action.split(' -> '))[0]; - if (mod === actionName) { - return true; - } + var action, _i, _len, _ref; + _ref = oUser[updatedRuleId].rule.actions; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + action = _ref[_i]; + if ((action.split(' -> '))[0] === actionName) { + return true; } } return false; }; _results = []; - for (action in oUser.actions) { - req = fRequired(action); - if (!req) { - _results.push(delete oUser.actions[action]); + for (action in oUser[updatedRuleId].rule.actions) { + if (!fRequired(action)) { + _results.push(delete oUser[updatedRuleId].actions[action]); } else { _results.push(void 0); } @@ -133,22 +150,24 @@ Engine fRemoveNotRequired(oUser); } fAddRequired = function(userName, oUser) { - var fCheckRules, nmRl, oRl, _ref; - fCheckRules = function(oRule) { + var fCheckRules, nmRl, oRl, _results; + fCheckRules = function(oMyRule) { var action, fAddIfNewOrNotExisting, _i, _len, _ref, _results; fAddIfNewOrNotExisting = function(actionName) { var moduleName; moduleName = (actionName.split(' -> '))[0]; - if (!isDeleteOp && (!oUser.actions[moduleName] || oRule.id === oNewRule.id)) { + if (!oMyRule.actions[moduleName] || oMyRule.rule.id === updatedRuleId) { return db.actionInvokers.getModule(moduleName, function(err, obj) { - var params, res; - params = {}; - res = dynmod.compileString(obj.data, userName, moduleName, params, obj.lang); - return oUser.actions[moduleName] = res.module; + return dynmod.compileString(obj.data, userName, oMyRule.rule.id, moduleName, obj.lang, db.actionInvokers, function(result) { + if (!result.answ === 200) { + this.log.error("EN | Compilation of code failed! " + userName + ", " + oMyRule.rule.id + ", " + moduleName); + } + return oMyRule.actions[moduleName] = result.module; + }); }); } }; - _ref = oRule.actions; + _ref = oMyRule.rule.actions; _results = []; for (_i = 0, _len = _ref.length; _i < _len; _i++) { action = _ref[_i]; @@ -156,14 +175,12 @@ Engine } return _results; }; - _ref = oUser.rules; - for (nmRl in _ref) { - oRl = _ref[nmRl]; - fCheckRules(oRl); - } - if (JSON.stringify(oUser.rules) === "{}") { - return delete listUserRules[userName]; + _results = []; + for (nmRl in oUser) { + oRl = oUser[nmRl]; + _results.push(fCheckRules(oRl)); } + return _results; }; _results = []; for (userName in listUserRules) { @@ -195,6 +212,9 @@ Engine validConditions = function(evt, rule) { var prop, _i, _len, _ref; + if (rule.conditions.length === 0) { + return true; + } _ref = rule.conditions; for (_i = 0, _len = _ref.length; _i < _len; _i++) { prop = _ref[_i]; @@ -215,27 +235,43 @@ Engine processEvent = (function(_this) { return function(evt) { - var action, arr, oRule, oUser, ruleName, userName, _results; + var action, arr, fSearchAndInvokeAction, oMyRule, oUser, ruleName, userName, _results; + fSearchAndInvokeAction = function(node, arrPath, evt, depth) { + var err; + if (!node) { + this.log.error("EN | Didn't find property in user rule list: " + arrPath.join(', ' + " at depth " + depth)); + return; + } + if (depth === arrPath.length) { + try { + return node(evt.payload); + } catch (_error) { + err = _error; + return this.log.info("EN | ERROR IN ACTION INVOKER: " + err.message); + } + } else { + return fSearchAndInvokeAction(node[arrPath[depth]], arrPath, evt, depth + 1); + } + }; _this.log.info('EN | processing event: ' + evt.event + '(' + evt.eventid + ')'); _results = []; for (userName in listUserRules) { oUser = listUserRules[userName]; _results.push((function() { - var _ref, _results1; - _ref = oUser.rules; + var _results1; _results1 = []; - for (ruleName in _ref) { - oRule = _ref[ruleName]; - if (evt.event === oRule.event && validConditions(evt, oRule)) { + for (ruleName in oUser) { + oMyRule = oUser[ruleName]; + if (evt.event === oMyRule.rule.event && validConditions(evt, oMyRule.rule)) { this.log.info('EN | EVENT FIRED: ' + evt.event + '(' + evt.eventid + ') for rule ' + ruleName); _results1.push((function() { - var _i, _len, _ref1, _results2; - _ref1 = oRule.actions; + var _i, _len, _ref, _results2; + _ref = oMyRule.rule.actions; _results2 = []; - for (_i = 0, _len = _ref1.length; _i < _len; _i++) { - action = _ref1[_i]; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + action = _ref[_i]; arr = action.split(' -> '); - _results2.push(listUserRules[userName]['actions'][arr[0]][arr[1]](evt)); + _results2.push(fSearchAndInvokeAction(listUserRules, [userName, ruleName, 'actions', arr[0], arr[1]], evt, 0)); } return _results2; })()); diff --git a/js-coffee/persistence.js b/js-coffee/persistence.js index 6ed7f23..d60fd30 100644 --- a/js-coffee/persistence.js +++ b/js-coffee/persistence.js @@ -314,7 +314,7 @@ Persistence }; IndexedModules.prototype.getModuleParams = function(mId, cb) { - this.log.info("DB | (IdxedMods) " + this.setname + ".getModule( " + mId + " )"); + this.log.info("DB | (IdxedMods) " + this.setname + ".getModuleParams( " + mId + " )"); return this.db.hget("" + this.setname + ":" + mId, "params", cb); }; @@ -340,11 +340,15 @@ Persistence this.unpublish(mId); return this.db.smembers("" + this.setname + ":" + mId + ":users", (function(_this) { return function(err, obj) { - var userId, _i, _len, _results; - _results = []; + var userId, _i, _j, _len, _len1, _results; for (_i = 0, _len = obj.length; _i < _len; _i++) { userId = obj[_i]; - _results.push(_this.unlinkModule(mId, userId)); + _this.unlinkModule(mId, userId); + } + _results = []; + for (_j = 0, _len1 = obj.length; _j < _len1; _j++) { + userId = obj[_j]; + _results.push(_this.deleteUserParams(mId, userId)); } return _results; }; @@ -370,9 +374,7 @@ Persistence IndexedModules.prototype.getUserParams = function(mId, userId, cb) { this.log.info("DB | (IdxedMods) " + this.setname + ".getUserParams( " + mId + ", " + userId + " )"); - return this.db.get("" + this.setname + "-params:" + mId + ":" + userId, function(err, data) { - return cb(err, data); - }); + return this.db.get("" + this.setname + "-params:" + mId + ":" + userId, cb); }; IndexedModules.prototype.getUserParamsIds = function(cb) { @@ -396,6 +398,53 @@ Persistence */ + /* + Appends a log entry. + + @public log( *userId, ruleId, message* ) + @param {String} userId + @param {String} ruleId + @param {String} message + */ + + exports.appendLog = (function(_this) { + return function(userId, ruleId, moduleId, message) { + return _this.db.append("" + userId + ":" + ruleId, "[" + ((new Date).toISOString()) + "] {" + moduleId + "} " + message + "\n"); + }; + })(this); + + + /* + Retrieves a log entry. + + @public getLog( *userId, ruleId* ) + @param {String} userId + @param {String} ruleId + @param {function} cb + */ + + exports.getLog = (function(_this) { + return function(userId, ruleId, cb) { + return _this.db.get("" + userId + ":" + ruleId, cb); + }; + })(this); + + + /* + Resets a log entry. + + @public resetLog( *userId, ruleId* ) + @param {String} userId + @param {String} ruleId + */ + + exports.resetLog = (function(_this) { + return function(userId, ruleId) { + return _this.db.del("" + userId + ":" + ruleId, replyHandler("RESET LOG '" + userId + ":" + ruleId + "'")); + }; + })(this); + + /* Query the DB for a rule and pass it to cb(err, obj). diff --git a/testing/files/testObjects.json b/testing/files/testObjects.json index fae6abe..48a0939 100644 --- a/testing/files/testObjects.json +++ b/testing/files/testObjects.json @@ -1,27 +1,4 @@ { - "events": { - "eventOne":{ - "event": "test_1", - "payload": { - "property": "test_1", - "nestedProperty": { - "more": "really nested" - } - } - }, - "eventTwo":{ - "event": "test_2" - }, - "eventReal":{ - "event": "epOne -> newMail", - "payload": { - "property": "test_1", - "nestedProperty": { - "more": "really nested" - } - } - } - }, "eps": { "epOne": { "id":"epOne", @@ -44,18 +21,26 @@ "aiOne": { "id":"aiOne", "lang":"CoffeeScript", - "data":"# Send a mail through emailyak\nexports.sendMail = ( args ) ->\n\turl = 'https://api.emailyak.com/v1/' + params.apikey + '/json/send/email/'\n\tpayload =\n\t FromAddress : \"testsender@mscliveweb.simpleyak.com\",\n\t ToAddress: \"dominic.bosch@gmail.com\",\n\t Subject: \"TestMAIL\",\n\t TextBody: \"Hello\"\n\t\n\tneedle.post url, payload, ( err, resp, body ) ->\n\t\tif err\n\t\t\tlog err\n\t\tif resp.statusCode isnt 200\n\t\t\tlog 'Request not successful:'\n\t\t\tlog body\n", + "data":"exports.printToLog = ( evt ) ->\n\tlog evt.property", "public":"false", "params":"[\"apikey\"]", - "functions":"[\"sendMail\"]" + "functions":"[\"printToLog\"]" }, "aiTwo": { "id":"aiTwo", "lang":"CoffeeScript", - "data":"# Send a mail through emailyak\nexports.otherEvent = ( args ) ->\n\turl = 'https://api.emailyak.com/v1/' + params.apikey + '/json/send/email/'\n\tpayload =\n\t FromAddress : \"testsender@mscliveweb.simpleyak.com\",\n\t ToAddress: \"dominic.bosch@gmail.com\",\n\t Subject: \"TestMAIL\",\n\t TextBody: \"Hello\"\n\t\n\tneedle.post url, payload, ( err, resp, body ) ->\n\t\tif err\n\t\t\tlog err\n\t\tif resp.statusCode isnt 200\n\t\t\tlog 'Request not successful:'\n\t\t\tlog body\n", + "data":"# Send a mail through emailyak\nexports.otherEvent = ( evt ) ->\n\turl = 'https://api.emailyak.com/v1/' + params.apikey + '/json/send/email/'\n\tpayload =\n\t FromAddress : \"testsender@mscliveweb.simpleyak.com\",\n\t ToAddress: \"dominic.bosch@gmail.com\",\n\t Subject: \"TestMAIL\",\n\t TextBody: \"Hello\"\n\t\n\tneedle.post url, payload, ( err, resp, body ) ->\n\t\tif err\n\t\t\tlog err\n\t\tif resp.statusCode isnt 200\n\t\t\tlog 'Request not successful:'\n\t\t\tlog body\n", "public":"false", "params":"[\"apikey\",\"andmore\"]", "functions":"[\"otherEvent\"]" + }, + "aiThree": { + "id":"aiThree", + "lang":"CoffeeScript", + "data":"exports.printUserParamToLog = ( evt ) ->\n\tlog params.password", + "public":"false", + "params":"[\"password\"]", + "functions":"[\"printUserParamToLog\"]" } }, "userparams": { @@ -63,6 +48,29 @@ "apikey": "testkey" } }, + "events": { + "eventOne":{ + "event": "test_1", + "payload": { + "property": "test_1", + "nestedProperty": { + "more": "really nested" + } + } + }, + "eventTwo":{ + "event": "test_2" + }, + "eventReal":{ + "event": "epOne -> newMail", + "payload": { + "property": "test_1", + "nestedProperty": { + "more": "really nested" + } + } + } + }, "rules": { "ruleOne": { "id": "ruleOne_id", @@ -86,13 +94,19 @@ "id": "ruleReal", "event": "epOne -> newMail", "conditions": [".more:val(\"really nested\")"], - "actions": ["aiOne -> sendMail"] + "actions": ["aiOne -> printToLog"] }, "ruleRealTwo": { "id": "ruleRealTwo", "event": "epOne -> newMail", "conditions": [], "actions": ["aiTwo -> otherEvent"] + }, + "ruleRealThree": { + "id": "ruleRealThree", + "event": "epOne -> newMail", + "conditions": [], + "actions": ["aiThree -> printUserParamToLog"] } }, "users": { diff --git a/testing/test_dynamic-modules.coffee b/testing/test_dynamic-modules.coffee index dd935e8..c2c7c20 100644 --- a/testing/test_dynamic-modules.coffee +++ b/testing/test_dynamic-modules.coffee @@ -1,5 +1,11 @@ fs = require 'fs' path = require 'path' +cryptico = require 'my-cryptico' + +passPhrase = 'UNIT TESTING PASSWORD' +numBits = 1024 +oPrivateRSAkey = cryptico.generateRSAKey passPhrase, numBits +strPublicKey = cryptico.publicKeyString oPrivateRSAkey try data = fs.readFileSync path.resolve( 'testing', 'files', 'testObjects.json' ), 'utf8' @@ -15,27 +21,88 @@ log = logger.getLogger nolog: true opts = logger: log + keygen: passPhrase + +db = require path.join '..', 'js-coffee', 'persistence' +db opts + +engine = require path.join '..', 'js-coffee', 'engine' +engine opts dm = require path.join '..', 'js-coffee', 'dynamic-modules' dm opts +oUser = objects.users.userOne +oRuleReal = objects.rules.ruleRealThree +oAi = objects.ais.aiThree + +exports.tearDown = ( cb ) -> + db.storeUser oUser + db.deleteRule oRuleReal.id + db.actionInvokers.deleteModule oAi.id + setTimeout cb, 200 + exports.testCompile = ( test ) -> test.expect 5 - paramsOne = - testParam: 'First Test' - paramsTwo = - testParam: 'Second Test' + paramOne = 'First Test' + code = "exports.testFunc = () ->\n\t'#{ paramOne }'" + dm.compileString code, 'userOne', 'ruleOne', 'moduleOne', 'CoffeeScript', null, ( result ) -> + test.strictEqual 200, result.answ.code + moduleOne = result.module + test.strictEqual paramOne, moduleOne.testFunc(), "Other result expected" - code = "exports.testFunc = () ->\n\tparams.testParam" - result = dm.compileString code, 'userOne', 'moduleOne', paramsOne, 'CoffeeScript' - test.strictEqual 200, result.answ.code - moduleOne = result.module - test.strictEqual paramsOne.testParam, moduleOne.testFunc(), "Other result expected" + paramTwo = 'Second Test' + code = "exports.testFunc = () ->\n\t'#{ paramTwo }'" + dm.compileString code, 'userOne', 'ruleOne', 'moduleOne', 'CoffeeScript', null, ( result ) -> + test.strictEqual 200, result.answ.code + moduleTwo = result.module + test.strictEqual paramTwo, moduleTwo.testFunc(), "Other result expected" + test.notStrictEqual paramOne, moduleTwo.testFunc(), "Other result expected" + setTimeout test.done, 200 + + +exports.testCorrectUserParams = ( test ) -> + test.expect 1 + + db.storeUser oUser + db.storeRule oRuleReal.id, JSON.stringify oRuleReal + db.linkRule oRuleReal.id, oUser.username + db.activateRule oRuleReal.id, oUser.username + db.actionInvokers.storeModule oUser.username, oAi + + pw = 'This password should come out cleartext' + userparams = JSON.stringify password: pw + oEncrypted = cryptico.encrypt userparams, strPublicKey + + db.actionInvokers.storeUserParams oAi.id, oUser.username, oEncrypted.cipher + + engine.internalEvent + event: 'new' + user: oUser.username + rule: oRuleReal + + fWaitForPersistence = () -> + evt = objects.events.eventReal + evt.eventid = 'event_testid' + db.pushEvent evt + + fWaitAgain = () -> + db.getLog oUser.username, oRuleReal.id, ( err, data ) -> + try + logged = data.split( '] ' )[1] + test.strictEqual logged, "{#{ oAi.id }} " + pw + "\n", 'Did not log the right thing' + catch e + test.ok false, 'Parsing log failed' + + engine.internalEvent + event: 'del' + user: oUser.username + rule: null + ruleId: oRuleReal.id + setTimeout test.done, 200 + + setTimeout fWaitAgain, 200 + + setTimeout fWaitForPersistence, 200 - result = dm.compileString code, 'userOne', 'moduleOne', paramsTwo, 'CoffeeScript' - test.strictEqual 200, result.answ.code - moduleTwo = result.module - test.strictEqual paramsTwo.testParam, moduleTwo.testFunc(), "Other result expected" - test.notStrictEqual paramsOne.testParam, moduleTwo.testFunc(), "Other result expected" - test.done() \ No newline at end of file diff --git a/testing/test_engine.coffee b/testing/test_engine.coffee index a43a74b..f240a33 100644 --- a/testing/test_engine.coffee +++ b/testing/test_engine.coffee @@ -11,8 +11,8 @@ catch err console.log 'Error fetching standard objects file: ' + err.message logger = require path.join '..', 'js-coffee', 'logging' -log = logger.getLogger() - # nolog: true +log = logger.getLogger + nolog: true opts = logger: log @@ -61,7 +61,7 @@ exports.ruleEvents = db.actionInvokers.storeModule oUser.username, oAiTwo test.strictEqual listRules[oUser.username], undefined, 'Initial user object exists!?' - + engine.internalEvent event: 'new' user: oUser.username @@ -71,7 +71,8 @@ exports.ruleEvents = for act in oRuleReal.actions mod = ( act.split ' -> ' )[0] - test.ok listRules[oUser.username].actions[mod], 'Missing action!' + test.ok listRules[oUser.username][oRuleReal.id].actions[mod], 'Missing action!' + engine.internalEvent event: 'new' @@ -82,21 +83,23 @@ exports.ruleEvents = for act in oRuleRealTwo.actions mod = ( act.split ' -> ' )[0] - test.ok listRules[oUser.username].actions[mod], 'Missing action!' - + test.ok listRules[oUser.username][oRuleRealTwo.id].actions[mod], 'Missing action!' + engine.internalEvent event: 'del' user: oUser.username - rule: oRuleRealTwo + rule: null + ruleId: oRuleRealTwo.id for act in oRuleReal.actions mod = ( act.split ' -> ' )[0] - test.ok listRules[oUser.username].actions[mod], 'Missing action!' - + test.ok listRules[oUser.username][oRuleReal.id].actions[mod], 'Missing action!' + engine.internalEvent event: 'del' user: oUser.username - rule: oRuleReal + rule: null + ruleId: oRuleReal.id test.strictEqual listRules[oUser.username], undefined, 'Final user object exists!?' test.done() @@ -135,7 +138,8 @@ exports.ruleEvents = # setTimeout fCheckRules, 500 exports.engine = - matchingEvent: ( test ) -> + testMatchingEvent: ( test ) -> + test.expect 1 db.storeUser oUser db.storeRule oRuleReal.id, JSON.stringify oRuleReal @@ -152,6 +156,16 @@ exports.engine = evt = objects.events.eventReal evt.eventid = 'event_testid' db.pushEvent evt - setTimeout fWaitForPersistence, 200 - setTimeout test.done, 500 + fWaitAgain = () -> + db.getLog oUser.username, oRuleReal.id, ( err, data ) -> + try + logged = data.split( '] ' )[1] + test.strictEqual logged, "{#{ oAiOne.id }} " + evt.payload.property + "\n", 'Did not log the right thing' + catch e + test.ok false, 'Parsing log failed' + test.done() + + setTimeout fWaitAgain, 200 + + setTimeout fWaitForPersistence, 200 diff --git a/webpages/handlers/coffee/admin.coffee b/webpages/handlers/coffee/admin.coffee index d034aca..b2d33c4 100644 --- a/webpages/handlers/coffee/admin.coffee +++ b/webpages/handlers/coffee/admin.coffee @@ -3,18 +3,20 @@ fOnLoad = () -> document.title = 'Administrate' $( '#pagetitle' ).text 'Hi {{{user.username}}}, issue your commands please:' $( '#but_submit' ).click () -> - data = - command: $( '#inp_command' ).val() - $.post( 'admincommand', data ) - .done ( data ) -> - $( '#info' ).text data.message - $( '#info' ).attr 'class', 'success' - .fail ( err ) -> - if err.responseText is '' - err.responseText = 'No Response from Server!' - $( '#info' ).text 'Error: ' + err.responseText - $( '#info' ).attr 'class', 'error' - if err.status is 401 - window.location.href = 'admin' + data = + command: $( '#inp_command' ).val() + $.post( 'admincommand', data ) + .done ( data ) -> + $( '#info' ).text data.message + $( '#info' ).attr 'class', 'success' + .fail ( err ) -> + fDelayed = () -> + if err.responseText is '' + err.responseText = 'No Response from Server!' + $( '#info' ).text 'Error: ' + err.responseText + $( '#info' ).attr 'class', 'error' + if err.status is 401 + window.location.href = 'admin' + setTimeout fDelayed, 500 window.addEventListener 'load', fOnLoad, true diff --git a/webpages/handlers/coffee/edit_rules.coffee b/webpages/handlers/coffee/edit_rules.coffee new file mode 100644 index 0000000..29fd81b --- /dev/null +++ b/webpages/handlers/coffee/edit_rules.coffee @@ -0,0 +1,63 @@ + +fOnLoad = () -> + document.title = 'Edit Rules' + $( '#pagetitle' ).text "{{{user.username}}}, edit your Rules!" + + fErrHandler = ( errMsg ) -> + ( err ) -> + fDelayed = () -> + if err.responseText is '' + msg = 'No Response from Server!' + else + try + oErr = JSON.parse err.responseText + msg = oErr.message + $( '#info' ).text errMsg + msg + $( '#info' ).attr 'class', 'error' + setTimeout fDelayed, 500 + + fFetchRules = () -> + $.post( '/usercommand', command: 'get_rules' ) + .done fUpdateRuleList + .fail fErrHandler 'Did not retrieve rules! ' + + fUpdateRuleList = ( data ) -> + $( '#tableRules tr' ).remove() + for ruleName in data.message + tr = $ '' + img = $( '' ).attr( 'class', 'del' ).attr 'src', 'red_cross_small.png' + imgTwo = $( '' ).attr( 'class', 'log' ).attr 'src', 'logicon.png' + inp = $( '
' ).text ruleName + tr.append( $( '' ).append img ) + tr.append( $( '' ).append imgTwo ) + tr.append( $( '' ).append inp ) + $( '#tableRules' ).append tr + + fFetchRules() + + $( '#tableRules' ).on 'click', 'img.del', () -> + ruleName = $( 'div', $( this ).closest( 'tr' )).text() + if confirm "Do you really want to delete the rule '#{ ruleName }'?" + data = + command: 'delete_rule' + payload: + id: ruleName + data.payload = JSON.stringify data.payload + $.post( '/usercommand', data ) + .done fFetchRules + .fail fErrHandler 'Could not delete rule! ' + + $( '#tableRules' ).on 'click', 'img.log', () -> + ruleName = $( 'div', $( this ).closest( 'tr' )).text() + data = + command: 'get_rule_log' + payload: + id: ruleName + data.payload = JSON.stringify data.payload + $.post( '/usercommand', data ) + .done ( data ) -> + log = data.message.replace new RegExp("\n", 'g'), "
" + $( '#log_col' ).html "

#{ ruleName } Log:

#{ log }" + .fail fErrHandler 'Could not get rule log! ' + +window.addEventListener 'load', fOnLoad, true diff --git a/webpages/handlers/coffee/forge_action_invoker.coffee b/webpages/handlers/coffee/forge_action_invoker.coffee index 0380058..9e94f0f 100644 --- a/webpages/handlers/coffee/forge_action_invoker.coffee +++ b/webpages/handlers/coffee/forge_action_invoker.coffee @@ -68,15 +68,17 @@ fOnLoad = () -> $( '#info' ).text data.message $( '#info' ).attr 'class', 'success' .fail ( err ) -> - if err.responseText is '' - msg = 'No Response from Server!' - else - try - oErr = JSON.parse err.responseText - msg = oErr.message - $( '#info' ).text 'Action Invoker not stored! ' + msg - $( '#info' ).attr 'class', 'error' - if err.status is 401 - window.location.href = 'forge?page=forge_action_invoker' + fDelayed = () -> + if err.responseText is '' + msg = 'No Response from Server!' + else + try + oErr = JSON.parse err.responseText + msg = oErr.message + $( '#info' ).text 'Action Invoker not stored! ' + msg + $( '#info' ).attr 'class', 'error' + if err.status is 401 + window.location.href = 'forge?page=forge_action_invoker' + setTimeout fDelayed, 500 window.addEventListener 'load', fOnLoad, true diff --git a/webpages/handlers/coffee/forge_event.coffee b/webpages/handlers/coffee/forge_event.coffee index a627521..30535d2 100644 --- a/webpages/handlers/coffee/forge_event.coffee +++ b/webpages/handlers/coffee/forge_event.coffee @@ -20,12 +20,15 @@ fOnLoad = () -> $( '#info' ).text data.message $( '#info' ).attr 'class', 'success' .fail ( err ) -> - if err.responseText is '' - err.responseText = 'No Response from Server!' - $( '#info' ).text 'Error in upload: ' + err.responseText - $( '#info' ).attr 'class', 'error' - if err.status is 401 - window.location.href = 'forge?page=forge_event' + fDelayed = () -> + if err.responseText is '' + err.responseText = 'No Response from Server!' + $( '#info' ).text 'Error in upload: ' + err.responseText + $( '#info' ).attr 'class', 'error' + if err.status is 401 + window.location.href = 'forge?page=forge_event' + setTimeout fDelayed, 500 + catch err $( '#info' ).text 'You have errors in your JSON object! ' + err $( '#info' ).attr 'class', 'error' diff --git a/webpages/handlers/coffee/forge_event_poller.coffee b/webpages/handlers/coffee/forge_event_poller.coffee index 3b31051..2deb55e 100644 --- a/webpages/handlers/coffee/forge_event_poller.coffee +++ b/webpages/handlers/coffee/forge_event_poller.coffee @@ -68,15 +68,17 @@ fOnLoad = () -> $( '#info' ).text data.message $( '#info' ).attr 'class', 'success' .fail ( err ) -> - if err.responseText is '' - msg = 'No Response from Server!' - else - try - oErr = JSON.parse err.responseText - msg = oErr.message - $( '#info' ).text 'Event Poller not stored! ' + msg - $( '#info' ).attr 'class', 'error' - if err.status is 401 - window.location.href = 'forge?page=forge_event_poller' + fDelayed = () -> + if err.responseText is '' + msg = 'No Response from Server!' + else + try + oErr = JSON.parse err.responseText + msg = oErr.message + $( '#info' ).text 'Event Poller not stored! ' + msg + $( '#info' ).attr 'class', 'error' + if err.status is 401 + window.location.href = 'forge?page=forge_event_poller' + setTimeout fDelayed, 500 window.addEventListener 'load', fOnLoad, true diff --git a/webpages/handlers/coffee/forge_rule.coffee b/webpages/handlers/coffee/forge_rule.coffee index 80b3b2f..a61b6d1 100644 --- a/webpages/handlers/coffee/forge_rule.coffee +++ b/webpages/handlers/coffee/forge_rule.coffee @@ -14,32 +14,35 @@ fOnLoad = () -> # Fetch Event Poller user-specific parameters fFetchEventParams = ( name ) -> - arr = name.split ' -> ' - obj = - command: 'get_event_poller_params' - payload: - id: arr[0] - obj.payload = JSON.stringify( obj.payload ); - $.post( '/usercommand', obj ) - .done ( data ) -> - if data.message - arrParams = JSON.parse data.message - $( '#event_poller_params table' ).remove() - if arrParams.length > 0 - table = $ '' - $( '#event_poller_params' ).append table - fAppendParam = ( name ) -> - tr = $( '' ) - tr.append $( '
' ).css 'width', '20px' - tr.append $( '' ).attr( 'class', 'key' ).text name - inp = $( '' ).attr( 'type', 'password' ).attr 'id', "#{ name }" - tr.append $( '' ).text( ' :' ).append inp - table.append tr - fAppendParam name for name in arrParams - .fail ( err ) -> - console.log err - $( '#info' ).text 'Error fetching event poller params' - $( '#info' ).attr 'class', 'error' + if name + arr = name.split ' -> ' + obj = + command: 'get_event_poller_params' + payload: + id: arr[0] + obj.payload = JSON.stringify( obj.payload ); + $.post( '/usercommand', obj ) + .done ( data ) -> + if data.message + arrParams = JSON.parse data.message + $( '#event_poller_params table' ).remove() + if arrParams.length > 0 + table = $ '' + $( '#event_poller_params' ).append table + fAppendParam = ( name ) -> + tr = $( '' ) + tr.append $( ''); + img = $('').attr('class', 'del').attr('src', 'red_cross_small.png'); + imgTwo = $('').attr('class', 'log').attr('src', 'logicon.png'); + inp = $('
').text(ruleName); + tr.append($('
' ).css 'width', '20px' + tr.append $( '' ).attr( 'class', 'key' ).text name + inp = $( '' ).attr( 'type', 'password' ).attr 'id', "#{ name }" + tr.append $( '' ).text( ' :' ).append inp + table.append tr + fAppendParam name for name in arrParams + .fail ( err ) -> + fDelayed = () -> + console.log err + $( '#info' ).text 'Error fetching event poller params' + $( '#info' ).attr 'class', 'error' + setTimeout fDelayed, 500 #FIXME Add possibility for custom event via text input @@ -65,9 +68,11 @@ fOnLoad = () -> fAppendEvents id, events for id, events of oEps fFetchEventParams $( '#select_event option:selected' ).text() .fail ( err ) -> - console.log err - $( '#info' ).text 'Error fetching event poller' - $( '#info' ).attr 'class', 'error' + fDelayed = () -> + console.log err + $( '#info' ).text 'Error fetching event poller' + $( '#info' ).attr 'class', 'error' + setTimeout fDelayed, 500 $( '#select_event' ).change () -> fFetchEventParams $( this ).val() @@ -91,10 +96,12 @@ fOnLoad = () -> fAppendAction act for act in actions fAppendActions id, actions for id, actions of oAis - .fail ( err ) -> + .fail ( err ) -> console.log err - $( '#info' ).text 'Error fetching event poller' - $( '#info' ).attr 'class', 'error' + fDelayed = () -> + $( '#info' ).text 'Error fetching event poller' + $( '#info' ).attr 'class', 'error' + setTimeout fDelayed, 500 # Fetch Action Invoker user-specific parameters fFetchActionParams = ( div, name ) -> @@ -119,8 +126,10 @@ fOnLoad = () -> fAppendActionParam name for name in arrParams .fail ( err ) -> console.log err - $( '#info' ).text 'Error fetching action invoker params' - $( '#info' ).attr 'class', 'error' + fDelayed = () -> + $( '#info' ).text 'Error fetching action invoker params' + $( '#info' ).attr 'class', 'error' + setTimeout fDelayed, 500 $( '#select_actions' ).on 'change', () -> opt = $ 'option:selected', this @@ -201,26 +210,27 @@ fOnLoad = () -> id: $( '#input_id' ).val() event: $( '#select_event option:selected' ).val() event_params: encryptedParams.cipher - conditions: {} #TODO Add conditions! + conditions: [] #TODO Add conditions! actions: acts action_params: ap obj.payload = JSON.stringify obj.payload $.post( '/usercommand', obj ) .done ( data ) -> - console.log 'success' $( '#info' ).text data.message $( '#info' ).attr 'class', 'success' .fail ( err ) -> - if err.responseText is '' - msg = 'No Response from Server!' - else - try - oErr = JSON.parse err.responseText - msg = oErr.message - $( '#info' ).text 'Error in upload: ' + msg - $( '#info' ).attr 'class', 'error' - if err.status is 401 - window.location.href = 'forge?page=forge_rule' + fDelayed = () -> + if err.responseText is '' + msg = 'No Response from Server!' + else + try + oErr = JSON.parse err.responseText + msg = oErr.message + $( '#info' ).text 'Error in upload: ' + msg + $( '#info' ).attr 'class', 'error' + if err.status is 401 + window.location.href = 'forge?page=forge_rule' + setTimeout fDelayed, 500 catch err alert err.message diff --git a/webpages/handlers/js/admin.js b/webpages/handlers/js/admin.js index 8d7b0aa..bb5fcec 100644 --- a/webpages/handlers/js/admin.js +++ b/webpages/handlers/js/admin.js @@ -14,14 +14,18 @@ $('#info').text(data.message); return $('#info').attr('class', 'success'); }).fail(function(err) { - if (err.responseText === '') { - err.responseText = 'No Response from Server!'; - } - $('#info').text('Error: ' + err.responseText); - $('#info').attr('class', 'error'); - if (err.status === 401) { - return window.location.href = 'admin'; - } + var fDelayed; + fDelayed = function() { + if (err.responseText === '') { + err.responseText = 'No Response from Server!'; + } + $('#info').text('Error: ' + err.responseText); + $('#info').attr('class', 'error'); + if (err.status === 401) { + return window.location.href = 'admin'; + } + }; + return setTimeout(fDelayed, 500); }); }); }; diff --git a/webpages/handlers/js/edit_rules.js b/webpages/handlers/js/edit_rules.js new file mode 100644 index 0000000..b535ea4 --- /dev/null +++ b/webpages/handlers/js/edit_rules.js @@ -0,0 +1,86 @@ +// Generated by CoffeeScript 1.7.1 +(function() { + var fOnLoad; + + fOnLoad = function() { + var fErrHandler, fFetchRules, fUpdateRuleList; + document.title = 'Edit Rules'; + $('#pagetitle').text("{{{user.username}}}, edit your Rules!"); + fErrHandler = function(errMsg) { + return function(err) { + var fDelayed; + fDelayed = function() { + var msg, oErr; + if (err.responseText === '') { + msg = 'No Response from Server!'; + } else { + try { + oErr = JSON.parse(err.responseText); + msg = oErr.message; + } catch (_error) {} + } + $('#info').text(errMsg + msg); + return $('#info').attr('class', 'error'); + }; + return setTimeout(fDelayed, 500); + }; + }; + fFetchRules = function() { + return $.post('/usercommand', { + command: 'get_rules' + }).done(fUpdateRuleList).fail(fErrHandler('Did not retrieve rules! ')); + }; + fUpdateRuleList = function(data) { + var img, imgTwo, inp, ruleName, tr, _i, _len, _ref, _results; + $('#tableRules tr').remove(); + _ref = data.message; + _results = []; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + ruleName = _ref[_i]; + tr = $('
').append(img)); + tr.append($('').append(imgTwo)); + tr.append($('').append(inp)); + _results.push($('#tableRules').append(tr)); + } + return _results; + }; + fFetchRules(); + $('#tableRules').on('click', 'img.del', function() { + var data, ruleName; + ruleName = $('div', $(this).closest('tr')).text(); + if (confirm("Do you really want to delete the rule '" + ruleName + "'?")) { + data = { + command: 'delete_rule', + payload: { + id: ruleName + } + }; + data.payload = JSON.stringify(data.payload); + return $.post('/usercommand', data).done(fFetchRules).fail(fErrHandler('Could not delete rule! ')); + } + }); + return $('#tableRules').on('click', 'img.log', function() { + var data, ruleName; + ruleName = $('div', $(this).closest('tr')).text(); + data = { + command: 'get_rule_log', + payload: { + id: ruleName + } + }; + data.payload = JSON.stringify(data.payload); + return $.post('/usercommand', data).done(function(data) { + var log; + log = data.message.replace(new RegExp("\n", 'g'), "
"); + return $('#log_col').html("

" + ruleName + " Log:

" + log); + }).fail(fErrHandler('Could not get rule log! ')); + }); + }; + + window.addEventListener('load', fOnLoad, true); + +}).call(this); diff --git a/webpages/handlers/js/forge_action_invoker.js b/webpages/handlers/js/forge_action_invoker.js index 0ff2b84..d691c54 100644 --- a/webpages/handlers/js/forge_action_invoker.js +++ b/webpages/handlers/js/forge_action_invoker.js @@ -80,20 +80,24 @@ $('#info').text(data.message); return $('#info').attr('class', 'success'); }).fail(function(err) { - var msg, oErr; - if (err.responseText === '') { - msg = 'No Response from Server!'; - } else { - try { - oErr = JSON.parse(err.responseText); - msg = oErr.message; - } catch (_error) {} - } - $('#info').text('Action Invoker not stored! ' + msg); - $('#info').attr('class', 'error'); - if (err.status === 401) { - return window.location.href = 'forge?page=forge_action_invoker'; - } + var fDelayed; + fDelayed = function() { + var msg, oErr; + if (err.responseText === '') { + msg = 'No Response from Server!'; + } else { + try { + oErr = JSON.parse(err.responseText); + msg = oErr.message; + } catch (_error) {} + } + $('#info').text('Action Invoker not stored! ' + msg); + $('#info').attr('class', 'error'); + if (err.status === 401) { + return window.location.href = 'forge?page=forge_action_invoker'; + } + }; + return setTimeout(fDelayed, 500); }); } }); diff --git a/webpages/handlers/js/forge_event.js b/webpages/handlers/js/forge_event.js index 4951d18..7f6670c 100644 --- a/webpages/handlers/js/forge_event.js +++ b/webpages/handlers/js/forge_event.js @@ -21,14 +21,18 @@ $('#info').text(data.message); return $('#info').attr('class', 'success'); }).fail(function(err) { - if (err.responseText === '') { - err.responseText = 'No Response from Server!'; - } - $('#info').text('Error in upload: ' + err.responseText); - $('#info').attr('class', 'error'); - if (err.status === 401) { - return window.location.href = 'forge?page=forge_event'; - } + var fDelayed; + fDelayed = function() { + if (err.responseText === '') { + err.responseText = 'No Response from Server!'; + } + $('#info').text('Error in upload: ' + err.responseText); + $('#info').attr('class', 'error'); + if (err.status === 401) { + return window.location.href = 'forge?page=forge_event'; + } + }; + return setTimeout(fDelayed, 500); }); } catch (_error) { err = _error; diff --git a/webpages/handlers/js/forge_event_poller.js b/webpages/handlers/js/forge_event_poller.js index 28e3262..fb8c640 100644 --- a/webpages/handlers/js/forge_event_poller.js +++ b/webpages/handlers/js/forge_event_poller.js @@ -80,20 +80,24 @@ $('#info').text(data.message); return $('#info').attr('class', 'success'); }).fail(function(err) { - var msg, oErr; - if (err.responseText === '') { - msg = 'No Response from Server!'; - } else { - try { - oErr = JSON.parse(err.responseText); - msg = oErr.message; - } catch (_error) {} - } - $('#info').text('Event Poller not stored! ' + msg); - $('#info').attr('class', 'error'); - if (err.status === 401) { - return window.location.href = 'forge?page=forge_event_poller'; - } + var fDelayed; + fDelayed = function() { + var msg, oErr; + if (err.responseText === '') { + msg = 'No Response from Server!'; + } else { + try { + oErr = JSON.parse(err.responseText); + msg = oErr.message; + } catch (_error) {} + } + $('#info').text('Event Poller not stored! ' + msg); + $('#info').attr('class', 'error'); + if (err.status === 401) { + return window.location.href = 'forge?page=forge_event_poller'; + } + }; + return setTimeout(fDelayed, 500); }); } }); diff --git a/webpages/handlers/js/forge_rule.js b/webpages/handlers/js/forge_rule.js index 3fed0f6..0658d62 100644 --- a/webpages/handlers/js/forge_rule.js +++ b/webpages/handlers/js/forge_rule.js @@ -20,44 +20,50 @@ $('#pagetitle').text('{{{user.username}}}, forge your rule!'); fFetchEventParams = function(name) { var arr, obj; - arr = name.split(' -> '); - obj = { - command: 'get_event_poller_params', - payload: { - id: arr[0] - } - }; - obj.payload = JSON.stringify(obj.payload); - return $.post('/usercommand', obj).done(function(data) { - var arrParams, fAppendParam, table, _i, _len, _results; - if (data.message) { - arrParams = JSON.parse(data.message); - $('#event_poller_params table').remove(); - if (arrParams.length > 0) { - table = $(''); - $('#event_poller_params').append(table); - fAppendParam = function(name) { - var inp, tr; - tr = $(''); - tr.append($('
').css('width', '20px')); - tr.append($('').attr('class', 'key').text(name)); - inp = $('').attr('type', 'password').attr('id', "" + name); - tr.append($('').text(' :').append(inp)); - return table.append(tr); - }; - _results = []; - for (_i = 0, _len = arrParams.length; _i < _len; _i++) { - name = arrParams[_i]; - _results.push(fAppendParam(name)); - } - return _results; + if (name) { + arr = name.split(' -> '); + obj = { + command: 'get_event_poller_params', + payload: { + id: arr[0] } - } - }).fail(function(err) { - console.log(err); - $('#info').text('Error fetching event poller params'); - return $('#info').attr('class', 'error'); - }); + }; + obj.payload = JSON.stringify(obj.payload); + return $.post('/usercommand', obj).done(function(data) { + var arrParams, fAppendParam, table, _i, _len, _results; + if (data.message) { + arrParams = JSON.parse(data.message); + $('#event_poller_params table').remove(); + if (arrParams.length > 0) { + table = $(''); + $('#event_poller_params').append(table); + fAppendParam = function(name) { + var inp, tr; + tr = $(''); + tr.append($('
').css('width', '20px')); + tr.append($('').attr('class', 'key').text(name)); + inp = $('').attr('type', 'password').attr('id', "" + name); + tr.append($('').text(' :').append(inp)); + return table.append(tr); + }; + _results = []; + for (_i = 0, _len = arrParams.length; _i < _len; _i++) { + name = arrParams[_i]; + _results.push(fAppendParam(name)); + } + return _results; + } + } + }).fail(function(err) { + var fDelayed; + fDelayed = function() { + console.log(err); + $('#info').text('Error fetching event poller params'); + return $('#info').attr('class', 'error'); + }; + return setTimeout(fDelayed, 500); + }); + } }; obj = { command: 'get_event_pollers' @@ -89,9 +95,13 @@ } return fFetchEventParams($('#select_event option:selected').text()); }).fail(function(err) { - console.log(err); - $('#info').text('Error fetching event poller'); - return $('#info').attr('class', 'error'); + var fDelayed; + fDelayed = function() { + console.log(err); + $('#info').text('Error fetching event poller'); + return $('#info').attr('class', 'error'); + }; + return setTimeout(fDelayed, 500); }); $('#select_event').change(function() { return fFetchEventParams($(this).val()); @@ -130,9 +140,13 @@ } return _results; }).fail(function(err) { + var fDelayed; console.log(err); - $('#info').text('Error fetching event poller'); - return $('#info').attr('class', 'error'); + fDelayed = function() { + $('#info').text('Error fetching event poller'); + return $('#info').attr('class', 'error'); + }; + return setTimeout(fDelayed, 500); }); fFetchActionParams = function(div, name) { obj = { @@ -166,9 +180,13 @@ } } }).fail(function(err) { + var fDelayed; console.log(err); - $('#info').text('Error fetching action invoker params'); - return $('#info').attr('class', 'error'); + fDelayed = function() { + $('#info').text('Error fetching action invoker params'); + return $('#info').attr('class', 'error'); + }; + return setTimeout(fDelayed, 500); }); }; $('#select_actions').on('change', function() { @@ -258,31 +276,34 @@ id: $('#input_id').val(), event: $('#select_event option:selected').val(), event_params: encryptedParams.cipher, - conditions: {}, + conditions: [], actions: acts, action_params: ap } }; obj.payload = JSON.stringify(obj.payload); return $.post('/usercommand', obj).done(function(data) { - console.log('success'); $('#info').text(data.message); return $('#info').attr('class', 'success'); }).fail(function(err) { - var msg, oErr; - if (err.responseText === '') { - msg = 'No Response from Server!'; - } else { - try { - oErr = JSON.parse(err.responseText); - msg = oErr.message; - } catch (_error) {} - } - $('#info').text('Error in upload: ' + msg); - $('#info').attr('class', 'error'); - if (err.status === 401) { - return window.location.href = 'forge?page=forge_rule'; - } + var fDelayed; + fDelayed = function() { + var msg, oErr; + if (err.responseText === '') { + msg = 'No Response from Server!'; + } else { + try { + oErr = JSON.parse(err.responseText); + msg = oErr.message; + } catch (_error) {} + } + $('#info').text('Error in upload: ' + msg); + $('#info').attr('class', 'error'); + if (err.status === 401) { + return window.location.href = 'forge?page=forge_rule'; + } + }; + return setTimeout(fDelayed, 500); }); } catch (_error) { err = _error; diff --git a/webpages/handlers/templates/edit_rules.html b/webpages/handlers/templates/edit_rules.html new file mode 100644 index 0000000..57b4f93 --- /dev/null +++ b/webpages/handlers/templates/edit_rules.html @@ -0,0 +1,12 @@ + + + + + + +
+

Active Rules:

+
+
+ +
\ No newline at end of file diff --git a/webpages/handlers/templates/forge_action_invoker.html b/webpages/handlers/templates/forge_action_invoker.html index e59caba..a7ab17f 100644 --- a/webpages/handlers/templates/forge_action_invoker.html +++ b/webpages/handlers/templates/forge_action_invoker.html @@ -21,7 +21,7 @@ Action Invoker Name: # - company: The ProBidner company of the binder # - context: The ProBinder context (the binder ID) # -exports.createBinderEntry = ( args ) -> +exports.createBinderEntry = ( evt ) -> url = 'https://probinder.com/service/27/save' credentials = @@ -29,9 +29,9 @@ exports.createBinderEntry = ( args ) -> password: params.password data = - companyId: args.company - context: args.context - text: args.content + companyId: evt.company + context: evt.context + text: evt.content needle.post url, data, credentials, ( err, resp, body ) -> if err diff --git a/webpages/handlers/templates/menubar.html b/webpages/handlers/templates/menubar.html index e4eedd7..303d8dd 100644 --- a/webpages/handlers/templates/menubar.html +++ b/webpages/handlers/templates/menubar.html @@ -14,9 +14,6 @@ menubar.append(link); }; - fCreateLink( 'invoke event', - fRedirect( 'forge?page=forge_event' ) - ); fCreateLink( 'forge event poller', fRedirect( 'forge?page=forge_event_poller' ) ); @@ -26,6 +23,12 @@ fCreateLink( 'forge rule', fRedirect( 'forge?page=forge_rule' ) ); + fCreateLink( 'invoke event', + fRedirect( 'forge?page=forge_event' ) + ); + fCreateLink( 'edit rules', + fRedirect( 'forge?page=edit_rules' ) + ); fCreateLink( 'admin', fRedirect( 'admin' ) ); fCreateLink( 'logout', function() { diff --git a/webpages/public/cross.jpg b/webpages/public/cross.jpg deleted file mode 100644 index 71b77c2be5e16fcef8a9f02815b17587c15f77b9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 496 zcmex=PRz*i4VI@PO!p8r%7X)CxoVdaz6%ql&Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01JNr01JNsw&Zt`00007bV*G`2i^n( z2P!XL_W_&$00BEmL_t(2&vlJ0ivm#?M$f%7MV%{tU|S3ef?%@Eb|);{wmC9&8P zOq&IR#SJ1NnskGR+fh*e($z)hAqlfGD zO0(I-7{h2ZLTfFv+3edD5lW>Jg+k$8!We@whEAsgpc08h))f&v&%<$?$88vfgkcCk zGMU6$i>tL}KA*E#EQrJReUwtT)>?ufAP54UF&GS@;&eJ?y