User-parameter support implemented, system seems to run smoothly

This commit is contained in:
Dominic Bosch 2014-04-04 19:53:42 +02:00
parent c71bf520a4
commit 418d5441fe
29 changed files with 1053 additions and 452 deletions

View file

@ -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

View file

@ -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
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()

View file

@ -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

View file

@ -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).

View file

@ -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);

View file

@ -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);

View file

@ -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;
})());

View file

@ -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).

View file

@ -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": {

View file

@ -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()

View file

@ -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

View file

@ -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

View file

@ -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 = $ '<tr>'
img = $( '<img>' ).attr( 'class', 'del' ).attr 'src', 'red_cross_small.png'
imgTwo = $( '<img>' ).attr( 'class', 'log' ).attr 'src', 'logicon.png'
inp = $( '<div>' ).text ruleName
tr.append( $( '<td>' ).append img )
tr.append( $( '<td>' ).append imgTwo )
tr.append( $( '<td>' ).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'), "<br>"
$( '#log_col' ).html "<h3>#{ ruleName } Log:</h3>#{ log }"
.fail fErrHandler 'Could not get rule log! '
window.addEventListener 'load', fOnLoad, true

View file

@ -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

View file

@ -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'

View file

@ -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

View file

@ -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 = $ '<table>'
$( '#event_poller_params' ).append table
fAppendParam = ( name ) ->
tr = $( '<tr>' )
tr.append $( '<td>' ).css 'width', '20px'
tr.append $( '<td>' ).attr( 'class', 'key' ).text name
inp = $( '<input>' ).attr( 'type', 'password' ).attr 'id', "#{ name }"
tr.append $( '<td>' ).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 = $ '<table>'
$( '#event_poller_params' ).append table
fAppendParam = ( name ) ->
tr = $( '<tr>' )
tr.append $( '<td>' ).css 'width', '20px'
tr.append $( '<td>' ).attr( 'class', 'key' ).text name
inp = $( '<input>' ).attr( 'type', 'password' ).attr 'id', "#{ name }"
tr.append $( '<td>' ).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

View file

@ -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);
});
});
};

View file

@ -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 = $('<tr>');
img = $('<img>').attr('class', 'del').attr('src', 'red_cross_small.png');
imgTwo = $('<img>').attr('class', 'log').attr('src', 'logicon.png');
inp = $('<div>').text(ruleName);
tr.append($('<td>').append(img));
tr.append($('<td>').append(imgTwo));
tr.append($('<td>').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'), "<br>");
return $('#log_col').html("<h3>" + ruleName + " Log:</h3>" + log);
}).fail(fErrHandler('Could not get rule log! '));
});
};
window.addEventListener('load', fOnLoad, true);
}).call(this);

View file

@ -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);
});
}
});

View file

@ -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;

View file

@ -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);
});
}
});

View file

@ -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 = $('<table>');
$('#event_poller_params').append(table);
fAppendParam = function(name) {
var inp, tr;
tr = $('<tr>');
tr.append($('<td>').css('width', '20px'));
tr.append($('<td>').attr('class', 'key').text(name));
inp = $('<input>').attr('type', 'password').attr('id', "" + name);
tr.append($('<td>').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 = $('<table>');
$('#event_poller_params').append(table);
fAppendParam = function(name) {
var inp, tr;
tr = $('<tr>');
tr.append($('<td>').css('width', '20px'));
tr.append($('<td>').attr('class', 'key').text(name));
inp = $('<input>').attr('type', 'password').attr('id', "" + name);
tr.append($('<td>').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;

View file

@ -0,0 +1,12 @@
<table>
<tr>
<td valign="top">
<h3>Active Rules:</h3>
<table id="tableRules"></table>
</td>
<td width="50px"></td>
<td valign="top" id="log_col">
</td>
</tr>
</table>

View file

@ -21,7 +21,7 @@ Action Invoker Name: <input id="input_id" type="text" />
# - 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

View file

@ -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() {

Binary file not shown.

Before

Width:  |  Height:  |  Size: 496 B

BIN
webpages/public/logicon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 443 B

View file

@ -114,6 +114,14 @@ input[type=text]:focus {
margin-left: 10px;
}
#tableRules tr {
margin-bottom: 10px;
}
#log_col {
padding-left: 20px;
border-left: double #666;
}
.underlined {
padding-left: 10px;
font-style: italic;