diff --git a/README.md b/README.md index 562eaf1..a75e99a 100644 --- a/README.md +++ b/README.md @@ -17,10 +17,11 @@ Getting started **Prerequisites:** - node.js (find it [here](http://nodejs.org/)) + - *(optional) Pygments if you want to generate the doc: + `sudo apt-get install python-setuptools` and then + `sudo easy_install Pygments`* - *(optional) [CoffeeScript](http://coffeescript.org/), if you want to develop - and compile from coffee sources:* - - sudo npm -g install coffee-script + and compile from coffee sources: `sudo npm -g install coffee-script`* Clone project: diff --git a/coffee/db_interface.coffee b/coffee/db_interface.coffee index cab4a05..59caa69 100644 --- a/coffee/db_interface.coffee +++ b/coffee/db_interface.coffee @@ -300,16 +300,18 @@ exports.getEventModules = ( cb ) -> getSetRecords 'event-modules', exports.getEventModule, cb ### -Store a string representation of he authentication parameters for an event module. +Store a string representation of user-specific parameters for an event module. -@public storeEventAuth( *userId, moduleId, data* ) +@public storeEventParams( *userId, moduleId, data* ) @param {String} userId @param {String} moduleId @param {Object} data ### -exports.storeEventAuth = ( userId, moduleId, data ) => - log.print 'DB', 'storeEventAuth: ' + userId + ':' + moduleId - @db.set 'event-auth:' + userId + ':' + moduleId, hash(data), +# TODO is used, remove unused ones +exports.storeEventParams = ( userId, moduleId, data ) => + log.print 'DB', 'storeEventParams: ' + userId + ':' + moduleId + # TODO encryption based on user specific key? + @db.set 'event-params:' + moduleId + ':' + userId, encrypt(data), replyHandler 'storing event auth ' + userId + ':' + moduleId ### @@ -337,10 +339,12 @@ Store a string representation of a rule in the DB. @param {String} id @param {String} data ### -exports.storeRule = ( id, data ) => +exports.storeRule = ( id, user, data ) => log.print 'DB', 'storeRule: ' + id - @db.sadd 'rules', id, replyHandler 'storing rule key ' + id - @db.set 'rule:' + id, data, replyHandler 'storing rule ' + id + @db.sadd 'rules', id + ':' + user, replyHandler 'storing rule key "' + id + ':' + user + '"' + @db.sadd 'user:' + user + ':rules', id, replyHandler 'storing rule key to "user:' + user + ':rules"' + @db.sadd 'rule:' + id + ':users', user, replyHandler 'storing user key to "rule:' + id + ':users"' + @db.set 'rule:' + id + ':' + user, data, replyHandler 'storing rule "' + id + ':' + user + '"' ### Query the DB for a rule and pass it to the callback(err, obj) function. diff --git a/coffee/request_handler.coffee b/coffee/request_handler.coffee index 36955fe..1155b45 100644 --- a/coffee/request_handler.coffee +++ b/coffee/request_handler.coffee @@ -254,6 +254,7 @@ exports.handleUserCommand = ( req, resp ) -> body += data req.on 'end', -> obj = qs.parse body + console.log obj if typeof objUserCmds[obj.command] is 'function' objUserCmds[obj.command] req.session.user, obj, answerHandler req, resp else diff --git a/js-coffee/db_interface.js b/js-coffee/db_interface.js index 0aadeb8..d5230f8 100644 --- a/js-coffee/db_interface.js +++ b/js-coffee/db_interface.js @@ -387,18 +387,18 @@ DB Interface }; /* - Store a string representation of he authentication parameters for an event module. + Store a string representation of user-specific parameters for an event module. - @public storeEventAuth( *userId, moduleId, data* ) + @public storeEventParams( *userId, moduleId, data* ) @param {String} userId @param {String} moduleId @param {Object} data */ - exports.storeEventAuth = function(userId, moduleId, data) { - log.print('DB', 'storeEventAuth: ' + userId + ':' + moduleId); - return _this.db.set('event-auth:' + userId + ':' + moduleId, hash(data), replyHandler('storing event auth ' + userId + ':' + moduleId)); + exports.storeEventParams = function(userId, moduleId, data) { + log.print('DB', 'storeEventParams: ' + userId + ':' + moduleId); + return _this.db.set('event-params:' + moduleId + ':' + userId, encrypt(data), replyHandler('storing event auth ' + userId + ':' + moduleId)); }; /* @@ -432,10 +432,12 @@ DB Interface */ - exports.storeRule = function(id, data) { + exports.storeRule = function(id, user, data) { log.print('DB', 'storeRule: ' + id); - _this.db.sadd('rules', id, replyHandler('storing rule key ' + id)); - return _this.db.set('rule:' + id, data, replyHandler('storing rule ' + id)); + _this.db.sadd('rules', id + ':' + user, replyHandler('storing rule key "' + id + ':' + user + '"')); + _this.db.sadd('user:' + user + ':rules', id, replyHandler('storing rule key to "user:' + user + ':rules"')); + _this.db.sadd('rule:' + id + ':users', user, replyHandler('storing user key to "rule:' + id + ':users"')); + return _this.db.set('rule:' + id + ':' + user, data, replyHandler('storing rule "' + id + ':' + user + '"')); }; /* diff --git a/js-coffee/engine.js b/js-coffee/engine.js index 7e48da8..8f344af 100644 --- a/js-coffee/engine.js +++ b/js-coffee/engine.js @@ -75,10 +75,19 @@ function loadRulesFromDB() { * @param {Object} objModule the action module object */ exports.loadActionModule = function(name, objModule) { + + //TODO not used yet, load action modules from db for each rule per user + // TODO only load module once, load user specific parameters per user + // when rule is activated by user. invoked action then uses user specific + // parameters log.print('EN', 'Action module "' + name + '" loaded'); listActionModules[name] = objModule; }; +exports.getActionModule = function(name) { + return listActionModules[name]; +}; + /** * Add a rule into the working memory * @param {Object} objRule the rule object @@ -160,6 +169,8 @@ function validConditions(evt, rule) { function invokeAction(evt, action) { var actionargs = {}, arrModule = action.module.split('->'); + //TODO this requires change. the module property will be the identifier + // in the actions object (or shall we allow several times the same action?) if(arrModule.length < 2) { log.error('EN', 'Invalid rule detected!'); return; diff --git a/js-coffee/module_manager.js b/js-coffee/module_manager.js index 41f885c..bba1e6f 100644 --- a/js-coffee/module_manager.js +++ b/js-coffee/module_manager.js @@ -25,7 +25,7 @@ exports.addDBLink = function(db_link) { db = db_link; }; -exports.storeEventModule = function (user, obj, answHandler) { +exports.storeEventModule = function (objUser, obj, answHandler) { try { // TODO in the future we might want to link the modules close to the user // and allow for e.g. private modules @@ -40,33 +40,78 @@ exports.storeEventModule = function (user, obj, answHandler) { } }; -exports.getAllEventModules = function ( user, obj, answHandler ) { +exports.getAllEventModules = function ( objUser, obj, answHandler ) { db.getEventModules(function(err, obj) { if(err) answHandler.answerError('Failed fetching event modules: ' + err.message); else answHandler.answerSuccess(obj); }); }; -exports.storeActionModule = function (user, obj, answHandler) { +exports.storeActionModule = function (objUser, obj, answHandler) { var m = ml.requireFromString(obj.data, obj.id); obj.methods = Object.keys(m); answHandler.answerSuccess('Thank you for the action module!'); db.storeActionModule(obj.id, obj); }; -exports.getAllActionModules = function ( user, obj, answHandler ) { +exports.getAllActionModules = function ( objUser, obj, answHandler ) { db.getActionModules(function(err, obj) { if(err) answHandler.answerError('Failed fetching action modules: ' + err.message); else answHandler.answerSuccess(obj); }); }; -exports.storeRule = function (user, obj, answHandler) { - log.print('MM', 'implement storeRule'); - answHandler.answerSuccess('Thank you for the rule!'); +exports.storeRule = function (objUser, obj, answHandler) { + var cbEventModule = function (lst) { + return function(err, data) { + if(err) { + err.addInfo = 'fetching event module'; + log.error('MM', err); + } + if(!err && data) { + if(data.params) { + lst.eventmodule = data.params; + } + } + if(--semaphore === 0) answHandler.answerSuccess(lst); + }; + }; + var cbActionModule = function (lstParams) { + return function(err, data) { + if(err) { + err.addInfo = 'fetching action module'; + log.error('MM', err); + } + if(!err && data) { + if(data.params) { + lstParams.actionmodules[data.id] = data.params; + } + } + if(--semaphore === 0) answHandler.answerSuccess(lstParams); + }; + }; + + var semaphore = 1; + var lst = { + eventmodule: null, + actionmodules: {} + }; + try { + var objRule = JSON.parse(obj.data); + for(var i = 0; i < objRule.actions.length; i++) { + semaphore++; + db.getActionModule(objRule.actions[i].module.split('->')[0], cbActionModule(lst)); + } + db.getEventModule(objRule.event.split('->')[0], cbEventModule(lst)); + db.storeRule(objRule.id, objUser.username, obj.data); + } catch(err) { + answHandler.answerError(err.message); + log.error('MM', err); + } + }; - +// FIXME REMOVE /* * Legacy file system loaders */ @@ -91,7 +136,7 @@ exports.loadRulesFromFS = function(args, answHandler) { log.print('ML', 'Loading ' + arr.length + ' rules:'); for(var i = 0; i < arr.length; i++) { txt += arr[i].id + ', '; - db.storeRule(arr[i].id, JSON.stringify(arr[i])); + db.storeRule(arr[i].id, 'james-t', JSON.stringify(arr[i])); // funcLoadRule(arr[i]); } answHandler.answerSuccess('Yep, loaded rules: ' + txt); diff --git a/js-coffee/request_handler.js b/js-coffee/request_handler.js index 8d0fe2d..35d063d 100644 --- a/js-coffee/request_handler.js +++ b/js-coffee/request_handler.js @@ -101,10 +101,7 @@ Request Handler resp.send('Thank you for the event: ' + obj.event + ' (' + obj.eventid + ')!'); return db.pushEvent(obj); } else { - resp.writeHead(400, { - "Content-Type": "text/plain" - }); - return resp.send('Your event was missing important parameters!'); + return resp.send(400, 'Your event was missing important parameters!'); } }); }; @@ -308,6 +305,7 @@ Request Handler return req.on('end', function() { var obj; obj = qs.parse(body); + console.log(obj); if (typeof objUserCmds[obj.command] === 'function') { return objUserCmds[obj.command](req.session.user, obj, answerHandler(req, resp)); } else { diff --git a/js-coffee/server.js b/js-coffee/server.js index 4d98d07..79435a9 100644 --- a/js-coffee/server.js +++ b/js-coffee/server.js @@ -1,7 +1,7 @@ // Generated by CoffeeScript 1.6.3 /* -Rules Server +Server ============ >This is the main module that is used to run the whole server: diff --git a/js/engine.js b/js/engine.js index be48c0c..8b2f2b4 100644 --- a/js/engine.js +++ b/js/engine.js @@ -163,6 +163,8 @@ function validConditions(evt, rule) { function invokeAction(evt, action) { var actionargs = {}, arrModule = action.module.split('->'); + //TODO this requires change. the module property will be the identifier + // in the actions object (or shall we allow several times the same action?) if(arrModule.length < 2) { log.error('EN', 'Invalid rule detected!'); return; @@ -170,6 +172,7 @@ function invokeAction(evt, action) { var srvc = listActionModules[arrModule[0]]; if(srvc && srvc[arrModule[1]]) { //FIXME preprocessing not only on data + //FIXME no preprocessing at all, why don't we just pass the whole event to the action?' preprocessActionArguments(evt.payload, action.arguments, actionargs); try { if(srvc[arrModule[1]]) srvc[arrModule[1]](actionargs); diff --git a/webpages/handlers/forge_modules.html b/webpages/handlers/forge_modules.html index 6c89e9c..a32fc37 100644 --- a/webpages/handlers/forge_modules.html +++ b/webpages/handlers/forge_modules.html @@ -31,11 +31,11 @@ exports.myOwnEventFunction = function( callback ) { @@ -57,10 +57,10 @@ exports.myOwnEventFunction = function( callback ) {

-

+

Module requires user-specific parameters @@ -87,23 +87,29 @@ exports.myOwnEventFunction = function( callback ) { else { var obj = { id: $('#input_id').val(), - data: $('#textarea_module').val(), - description: $('#textarea_description').val(), + data: $('#textarea_module').val() + // description: $('#textarea_description').val(), // ispublic: $('#checkbox_public').is(':checked') }; - if($('#checkbox_params').is(':checked')) { - obj.params = $('#textarea_params').val(); + try { + if($('#checkbox_params').is(':checked')) { + //TODO if syntax error we should make better info's + JSON.parse($('#textarea_params').val()); + obj.params = $('#textarea_params').val(); + } + if($('#select_type').val() === '0') obj.command = 'store_action'; + else obj.command = 'store_event'; + $.post('/usercommand', obj) + .done(function(data) { + alert(data); + }) + .fail(function(err) { + console.error(err); + alert('Posting of module failed: ' + err.responseText); + }); + } catch(err) { + alert(err); } - if($('#select_type').val() === '0') obj.command = 'store_action'; - else obj.command = 'store_event'; - $.post('/usercommand', obj) - .done(function(data) { - alert(data); - }) - .fail(function(err) { - console.error(err); - alert('Posting of module failed: ' + err.responseText); - }); } }); $('#checkbox_params').click(function() { diff --git a/webpages/handlers/forge_rules.html b/webpages/handlers/forge_rules.html index 15e5bc3..452d873 100644 --- a/webpages/handlers/forge_rules.html +++ b/webpages/handlers/forge_rules.html @@ -3,6 +3,22 @@ Forge A Rule {{{head_requires}}} + + {{{div_menubar}}} @@ -10,40 +26,76 @@

Hi {{user.username}}, forge your own rules!

- + + +

+ +

-
+

Available Event Modules:

+
+
+

Available Action Modules:

+

\ No newline at end of file diff --git a/webpages/public/style.css b/webpages/public/style.css index 781cf5c..723c7a2 100644 --- a/webpages/public/style.css +++ b/webpages/public/style.css @@ -49,9 +49,14 @@ textarea { #div_left { float: left; - padding-right: 10px; +} + +#div_middle li { + font-size: 78%; + list-style-type: none; } #div_right li { + font-size: 78%; list-style-type: none; }