From 8fbe21094b5317026224d9822dbb95ec29bc6cc6 Mon Sep 17 00:00:00 2001 From: Dominic Bosch Date: Mon, 10 Feb 2014 22:28:10 +0100 Subject: [PATCH] Updated tests in DB interface --- coffee/db_interface.coffee | 599 +++++++++++---- coffee/request_handler.coffee | 26 +- js-coffee/db_interface.js | 690 ++++++++++++++---- js-coffee/engine.js | 56 +- js-coffee/request_handler.js | 30 +- testing/{ => files}/jsonWrongConfig.json | 0 testing/js/test_config.js | 2 +- testing/js/test_db_interface.js | 480 ++++++++++-- testing/test_config.coffee | 2 +- testing/test_db_interface.coffee | 634 +++++++++++++--- webpages/handlers/command_answer.html | 1 + webpages/handlers/error.html | 1 + webpages/handlers/forge_modules.html | 1 + webpages/handlers/forge_rules.html | 1 + .../menubar.html} | 10 +- webpages/handlers/includes/requires.html | 11 + webpages/handlers/login.html | 7 +- webpages/handlers/part_requires.html | 3 - webpages/handlers/push_event.html | 1 + webpages/handlers/unauthorized.html | 1 + webpages/handlers/welcome.html | 1 + webpages/public/style.css | 8 + 22 files changed, 2083 insertions(+), 482 deletions(-) rename testing/{ => files}/jsonWrongConfig.json (100%) rename webpages/handlers/{part_menubar.html => includes/menubar.html} (65%) create mode 100644 webpages/handlers/includes/requires.html delete mode 100644 webpages/handlers/part_requires.html diff --git a/coffee/db_interface.coffee b/coffee/db_interface.coffee index 6d58040..ca72ecf 100644 --- a/coffee/db_interface.coffee +++ b/coffee/db_interface.coffee @@ -3,18 +3,18 @@ DB Interface ============ > Handles the connection to the database and provides functionalities for -> event/action modules, rules and the encrypted storing of authentication tokens. +> event pollers, action invokers, rules and the encrypted storing of authentication tokens. > General functionality as a wrapper for the module holds initialization, > encryption/decryption, the retrieval of modules and shut down. > > The general structure for linked data is that the key is stored in a set. > By fetching all set entries we can then fetch all elements, which is > automated in this function. -> For example modules of the same group, e.g. action modules are registered in an +> For example, modules of the same group, e.g. action invokers are registered in an > unordered set in the database, from where they can be retrieved again. For example -> a new action module has its ID (e.g 'probinder') first registered in the set -> 'action_modules' and then stored in the db with the key 'action\_module\_' + ID -> (e.g. action\_module\_probinder). +> a new action invoker has its ID (e.g 'probinder') first registered in the set +> 'action-invokers' and then stored in the db with the key 'action-invoker:' + ID +> (e.g. action-invoker:probinder). > ### @@ -50,6 +50,8 @@ exports = module.exports = ( args ) => @db.on 'error', ( err ) -> err.addInfo = 'message from DB' log.error 'DB', err + @ep = new IndexedModules( 'event-poller', @db ) + @ai = new IndexedModules( 'action-invoker', @db ) else log.error 'DB', 'Initialization failed because of missing config file!' @@ -83,7 +85,7 @@ Abstracts logging for simple action replies from the DB. replyHandler = ( action ) -> ( err, reply ) -> if err - err.addInfo = "during \"#{ action }\"" + err.addInfo = "during '#{ action }'" log.error 'DB', err else log.print 'DB', "#{ action }: #{ reply }" @@ -96,14 +98,14 @@ Push an event into the event queue. ### exports.pushEvent = ( oEvent ) => if oEvent - log.print 'DB', "Event pushed into the queue: #{ oEvent.eventid }" + log.print 'DB', "Event pushed into the queue: '#{ oEvent.eventid }'" @db.rpush 'event_queue', JSON.stringify( oEvent ) else log.error 'DB', 'Why would you give me an empty event...' ### -Pop an event from the event queue and pass it to the callback(err, obj) function. +Pop an event from the event queue and pass it to cb(err, obj). @public popEvent( *cb* ) @param {function} cb @@ -146,10 +148,8 @@ Encrypts a string using the crypto key from the config file, based on aes-256-cb ### encrypt = ( plainText ) => if !plainText? then return null - try - enciph = crypto.createCipher 'aes-256-cbc', @crypto_key - et = enciph.update plainText, 'utf8', 'base64' - et + enciph.final 'base64' + try + crypto.AES.encrypt plainText, @crypto_key catch err err.addInfo = 'during encryption' log.error 'DB', err @@ -164,203 +164,309 @@ Decrypts an encrypted string and hands it back on success or null. decrypt = ( crypticText ) => if !crypticText? then return null; try - deciph = crypto.createDecipher 'aes-256-cbc', @crypto_key - dt = deciph.update crypticText, 'base64', 'utf8' - dt + deciph.final 'utf8' + dec = crypto.AES.decrypt crypticText, @crypto_key + dec.toString(crypto.enc.Utf8) catch err err.addInfo = 'during decryption' log.error 'DB', err null ### -Fetches all linked data set keys from a linking set, fetches the single data objects -via the provided function and returns the results to the callback(err, obj) function. +Fetches all linked data set keys from a linking set, fetches the single +data objects via the provided function and returns the results to cb(err, obj). @private getSetRecords( *set, fSingle, cb* ) @param {String} set the set name how it is stored in the DB -@param {function} fSingle a function to retrieve a single data element per set entry -@param {function} cb the callback(err, obj) function that receives all the retrieved data or an error +@param {function} fSingle a function to retrieve a single data element + per set entry +@param {function} cb the callback(err, obj) function that receives all + the retrieved data or an error ### getSetRecords = ( set, fSingle, cb ) => - log.print 'DB', "Fetching set records: #{ set }" + log.print 'DB', "Fetching set records: '#{ set }'" + # Fetch all members of the set @db.smembers set, ( err, arrReply ) -> if err - err.addInfo = "fetching #{ set }" + # If an error happens we return it to the callback function + err.addInfo = "fetching '#{ set }'" log.error 'DB', err + cb err else if arrReply.length == 0 + # If the set was empty we return null to the callback cb() else + # We need to fetch all the entries from the set and use a semaphore + # since the fetching from the DB will happen asynchronously semaphore = arrReply.length objReplies = {} setTimeout -> + # We use a timeout function to cancel the operation + # in case the DB does not respond if semaphore > 0 - cb new Error "Timeout fetching #{ set }" + cb new Error "Timeout fetching '#{ set }'" , 2000 fCallback = ( prop ) -> + # The callback function is required to preprocess the result before + # handing it to the callback. This especially includes decrementing + # the semaphore ( err, data ) -> --semaphore if err - err.addInfo = "fetching single element: #{ prop }" + err.addInfo = "fetching single element: '#{ prop }'" log.error 'DB', err else if not data - log.error 'DB', new Error "Empty key in DB: #{ prop }" + # There was no data behind the key + log.error 'DB', new Error "Empty key in DB: '#{ prop }'" else + # We found a valid record and add it to the reply object objReplies[ prop ] = data if semaphore == 0 + # If all fetch calls returned we finally pass the result + # to the callback cb null, objReplies + # Since we retrieved an array of keys, we now execute the fSingle function + # on each of them, to retrieve the ata behind the key. Our fCallback function + # is used to preprocess the answer to determine correct execution fSingle reply, fCallback( reply ) for reply in arrReply +class IndexedModules + constructor: ( @setname, @db ) -> + log.print 'DB', "Instantiated indexed modules for '#{ @setname }'" + + storeModule: ( mId, data ) => + log.print 'DB', "storeModule(#{ @setname }): #{ mId }" + @db.sadd "#{ @setname }s", mId, + replyHandler "Storing '#{ @setname }' key '#{ mId }'" + @db.set "#{ @setname }:#{ mId }", data, + replyHandler "Storing '#{ @setname }:#{ mId }'" + + getModule: ( mId, cb ) => + log.print 'DB', "getModule('#{ @setname }): #{ mId }'" + @db.get "#{ @setname }:#{ mId }", cb + + getModuleIds: ( cb ) => + log.print 'DB', "getModuleIds(#{ @setname })" + @db.smembers "#{ @setname }s", cb + + getModules: ( cb ) => + log.print 'DB', "getModules(#{ @setname })" + getSetRecords "#{ @setname }s", @getModule, cb + + deleteModule: ( mId ) => + log.print 'DB', "deleteModule(#{ @setname }): #{ mId }" + @db.srem "#{ @setname }s", mId, + replyHandler "Deleting '#{ @setname }' key '#{ mId }'" + @db.del "#{ @setname }:#{ mId }", + replyHandler "Deleting '#{ @setname }:#{ mId }'" + + storeParameters: ( mId, userId, data ) => + log.print 'DB', "storeParameters(#{ @setname }): '#{ mId }:#{ userId }'" + @db.sadd "#{ @setname }-params", "#{ mId }:#{ userId }", + replyHandler "Storing '#{ @setname }' module parameters key '#{ mId }'" + @db.set "#{ @setname }-params:#{ mId }:#{ userId }", encrypt(data), + replyHandler "Storing '#{ @setname }' module parameters '#{ mId }:#{ userId }'" + + getParameters: ( mId, userId, cb ) => + log.print 'DB', "getParameters(#{ @setname }): '#{ mId }:#{ userId }'" + @db.get "#{ @setname }-params:#{ mId }:#{ userId }", ( err, data ) -> + cb err, decrypt data + + getParametersIds: ( cb ) => + log.print 'DB', "getParametersIds(#{ @setname })" + @db.smembers "#{ @setname }-params", cb + + deleteParameters: ( mId, userId ) => + log.print 'DB', "deleteParameters(#{ @setname }): '#{ mId }:#{ userId }'" + @db.srem "#{ @setname }-params", "#{ mId }:#{ userId }", + replyHandler "Deleting '#{ @setname }-params' key '#{ mId }:#{ userId }'" + @db.del "#{ @setname }-params:#{ mId }:#{ userId }", + replyHandler "Deleting '#{ @setname }-params:#{ mId }:#{ userId }'" + + ### -## Action Modules -#TODO Rename Action Modules into something like Action Caller +## Action Invokers ### ### -Store a string representation of an action module in the DB. +Store a string representation of an action invoker in the DB. -@public storeActionModule ( *amId, data* ) -@param {String} amId +@public storeActionInvoker ( *aiId, data* ) +@param {String} aiId @param {String} data ### -exports.storeActionModule = ( amId, data ) => - log.print 'DB', "storeActionModule: #{ amId }" - @db.sadd 'action-modules', amId, replyHandler "storing action module key #{ amId }" - @db.set "action-module:#{ amId }", data, replyHandler "storing action module #{ amId }" +exports.storeActionInvoker = ( aiId, data ) => + @ai.storeModule( aiId, data ) ### -Query the DB for an action module and pass it to the callback(err, obj) function. +Query the DB for an action invoker and pass it to cb(err, obj). -@public getActionModule( *amId, cb* ) -@param {String} amId +@public getActionInvoker( *aiId, cb* ) +@param {String} aiId @param {function} cb ### -exports.getActionModule = ( amId, cb ) => - log.print 'DB', "getActionModule: #{ amId }" - @db.get "action-module:#{ amId }", cb - -exports.getSetMembers = ( setId, cb ) => - @db.smembers setId, cb +exports.getActionInvoker = ( aiId, cb ) => + @ai.getModule aiId, cb ### -Fetch all action module IDs and hand them to the callback(err, obj) function. +Fetch all action invoker IDs and hand them to cb(err, obj). -@public getActionModuleIds( *cb* ) +@public getActionInvokerIds( *cb* ) @param {function} cb ### -exports.getActionModuleIds = ( cb ) => - @db.smembers 'action-modules', cb +exports.getActionInvokerIds = ( cb ) => + @ai.getModuleIds cb ### -Fetch all action modules and hand them to the callback(err, obj) function. +Fetch all action invokers and hand them to cb(err, obj). -@public getActionModules( *cb* ) +@public getActionInvokers( *cb* ) @param {function} cb ### -exports.getActionModules = ( cb ) -> - getSetRecords 'action-modules', exports.getActionModule, cb +exports.getActionInvokers = ( cb ) => + @ai.getModules cb ### -Fetch all action modules and hand them to the callback(err, obj) function. +Fetch all action invokers and hand them to cb(err, obj). -@public getActionModules( *cb* ) +@public getActionInvokers( *cb* ) @param {function} cb ### -exports.deleteActionModule = ( amId ) => - @db.srem 'action-modules', amId, replyHandler "deleting action module key #{ amId }" - @db.del "action-module:#{ amId }", replyHandler "deleting action module #{ amId }" +exports.deleteActionInvoker = ( aiId ) => + @ai.deleteModule aiId ### -Store user-specific action module parameters . +Store user-specific action invoker parameters . -@public storeActionParams( *userId, amId, data* ) +@public storeActionParams( *userId, aiId, data* ) @param {String} userId -@param {String} amId +@param {String} aiId @param {String} data ### -exports.storeActionParams = ( userId, amId, data ) => - log.print 'DB', "storeActionParams: #{ amId }:#{ userId }" - @db.set "action-params:#{ amId }:#{ userId }", hash(data), - replyHandler "storing action params #{ amId }:#{ userId }" +exports.storeActionParams = ( aiId, userId, data ) => + @ai.storeParameters aiId, userId, data ### Query the DB for user-specific action module parameters, -and pass it to the callback(err, obj) function. +and pass it to cb(err, obj). -@public getActionParams( *userId, amId, cb* ) +@public getActionParams( *userId, aiId, cb* ) @param {String} userId -@param {String} amId +@param {String} aiId @param {function} cb ### -exports.getActionParams = ( userId, amId, cb ) => - log.print 'DB', "getActionParams: #{ amId }:#{ userId }" - @db.get "action-params:#{ amId }:#{ userId }", ( err, data ) -> - cb err, decrypt data +exports.getActionParams = ( aiId, userId, cb ) => + @ai.getParameters aiId, userId, cb + +### +Fetch all action params IDs and hand them to cb(err, obj). + +@public getActionParamsIds( *cb* ) +@param {function} cb +### +exports.getActionParamsIds = ( cb ) => + @ai.getParametersIds cb + +### +Fetch all action modules and hand them to cb(err, obj). + +@public deleteActionParams( *cb* ) +@param {function} cb +### +exports.deleteActionParams = ( aiId, userId ) => + @ai.deleteParameters aiId, userId ### -## Event Modules -#TODO rename event modules to event puller or something like that +## Event Pollers ### ### -Store a string representation of an event module in the DB. +Store a string representation of an event poller in the DB. -@public storeEventModule( *emId, data* ) -@param {String} emId +@public storeEventPoller ( *epId, data* ) +@param {String} epId @param {String} data ### -exports.storeEventModule = ( emId, data ) => - log.print 'DB', "storeEventModule: #{ emId }" - @db.sadd 'event-modules', emId, replyHandler "storing event module key #{ emId }" - @db.set 'event-module:#{ emId }', data, replyHandler "storing event module #{ emId }" +exports.storeEventPoller = ( epId, data ) => + @ep.storeModule( epId, data ) ### -Query the DB for an event module and pass it to the callback(err, obj) function. +Query the DB for an event poller and pass it to cb(err, obj). -@public getEventModule( *emId, cb* ) -@param {String} emId +@public getEventPoller( *epId, cb* ) +@param {String} epId @param {function} cb ### -exports.getEventModule = ( emId, cb ) => - log.print 'DB', "getEventModule: #{ emId }" - @db.get "event-module:#{ emId }", cb +exports.getEventPoller = ( epId, cb ) => + @ep.getModule epId, cb ### -Fetch all event modules and pass them to the callback(err, obj) function. +Fetch all event poller IDs and hand them to cb(err, obj). -@public getEventModules( *cb* ) +@public getEventPollerIds( *cb* ) @param {function} cb ### -exports.getEventModules = ( cb ) -> - getSetRecords 'event-modules', exports.getEventModule, cb +exports.getEventPollerIds = ( cb ) => + @ep.getModuleIds cb ### -Store a string representation of user-specific parameters for an event module. +Fetch all event pollers and hand them to cb(err, obj). -@public storeEventParams( *userId, emId, data* ) +@public getEventPollers( *cb* ) +@param {function} cb +### +exports.getEventPollers = ( cb ) => + @ep.getModules cb + +### +Fetch all event pollers and hand them to cb(err, obj). + +@public getEventPollers( *cb* ) +@param {function} cb +### +exports.deleteEventPoller = ( epId ) => + @ep.deleteModule epId + +### +Store user-specific event poller parameters . + +@public storeEventParams( *userId, epId, data* ) @param {String} userId -@param {String} emId -@param {Object} data +@param {String} epId +@param {String} data ### -# TODO is used, remove unused ones -exports.storeEventParams = ( userId, emId, data ) => - log.print 'DB', "storeEventParams: #{ emId }:#{ userId }" - # TODO encryption based on user specific key? - @db.set "event-params:#{ emId }:#{ userId }", encrypt(data), - replyHandler "storing event auth #{ emId }:#{ userId }" - -### -Query the DB for an action module authentication token, associated with a user. +exports.storeEventParams = ( epId, userId, data ) => + @ep.storeParameters epId, userId, data -@public getEventAuth( *userId, emId, data* ) +### +Query the DB for user-specific event module parameters, +and pass it to cb(err, obj). + +@public getEventParams( *userId, epId, cb* ) @param {String} userId -@param {String} emId +@param {String} epId @param {function} cb ### -exports.getEventAuth = ( userId, emId, cb ) => - log.print 'DB', "getEventAuth: #{ emId }:#{ userId }" - @db.get "event-auth:#{ emId }:#{ userId }", ( err, data ) -> - cb err, decrypt data +exports.getEventParams = ( epId, userId, cb ) => + @ep.getParameters epId, userId, cb + +### +Fetch all event params IDs and hand them to cb(err, obj). + +@public getEventParamsIds( *cb* ) +@param {function} cb +### +exports.getEventParamsIds = ( cb ) => + @ep.getParametersIds cb + +### +Fetch all event modules and hand them to cb(err, obj). + +@public deleteEventParams( *cb* ) +@param {function} cb +### +exports.deleteEventParams = ( epId, userId ) => + @ep.deleteParameters epId, userId ### @@ -368,33 +474,18 @@ exports.getEventAuth = ( userId, emId, cb ) => ### ### -Store a string representation of a rule in the DB. - -@public storeRule( *ruleId, userId, data* ) -@param {String} ruleId -@param {String} userId -@param {String} data -### -exports.storeRule = ( ruleId, userId, data ) => - log.print 'DB', "storeRule: #{ ruleId }" - @db.sadd 'rules', "#{ ruleId }:#{ userId }", replyHandler "storing rule key \"#{ ruleId }:#{ userId }\"" - @db.sadd "user-set:#{ userId }:rules", ruleId, replyHandler "storing rule key to \"user:#{ userId }:rules\"" - @db.sadd "rule-set:#{ ruleId }:users", user, replyHandler "storing user key to \"rule:#{ ruleId }:users\"" - @db.set "rule:#{ ruleId }:#{ userId }", data, replyHandler "storing rule \"#{ ruleId }:#{ userId }\"" - -### -Query the DB for a rule and pass it to the callback(err, obj) function. +Query the DB for a rule and pass it to cb(err, obj). @public getRule( *ruleId, cb* ) @param {String} ruleId @param {function} cb ### exports.getRule = ( ruleId, cb ) => - log.print 'DB', "getRule: #{ ruleId }" + log.print 'DB', "getRule: '#{ ruleId }'" @db.get "rule:#{ ruleId }", cb ### -Fetch all rules from the database and pass them to the callback function. +Fetch all rules and pass them to cb(err, obj). @public getRules( *cb* ) @param {function} cb @@ -403,6 +494,203 @@ exports.getRules = ( cb ) -> log.print 'DB', 'Fetching all Rules' getSetRecords 'rules', exports.getRule, cb +### +Fetch all rule IDs and hand it to cb(err, obj). + +@public getRuleIds( *cb* ) +@param {function} cb +### +exports.getRuleIds = ( cb ) => + log.print 'DB', 'Fetching all Rule IDs' + @db.smembers 'rules', cb + +### +Store a string representation of a rule in the DB. + +@public storeRule( *ruleId, data* ) +@param {String} ruleId +@param {String} data +### +exports.storeRule = ( ruleId, data ) => + log.print 'DB', "storeRule: '#{ ruleId }'" + @db.sadd 'rules', "#{ ruleId }", + replyHandler "storing rule key '#{ ruleId }'" + @db.set "rule:#{ ruleId }", data, + replyHandler "storing rule '#{ ruleId }'" + +### +Delete a string representation of a rule. + +@public deleteRule( *ruleId, userId* ) +@param {String} ruleId +@param {String} userId +### +exports.deleteRule = ( ruleId ) => + log.print 'DB', "deleteRule: '#{ ruleId }'" + @db.srem "rules", ruleId, replyHandler "Deleting rule key '#{ ruleId }'" + @db.del "rule:#{ ruleId }", replyHandler "Deleting rule '#{ ruleId }'" + + # We also need to delete all references in linked and active users + @db.smembers "rule:#{ ruleId }:users", ( err, obj ) => + delLinkedUserRule = ( userId ) => + @db.srem "user:#{ userId }:rules", ruleId, + replyHandler "Deleting rule key '#{ ruleId }'' in linked user '#{ userId }'" + delLinkedUserRule( id ) for id in obj + @db.del "rule:#{ ruleId }:users", replyHandler "Deleting rule '#{ ruleId }' users" + + @db.smembers "rule:#{ ruleId }:active-users", ( err, obj ) => + delActiveUserRule = ( userId ) => + @db.srem "user:#{ userId }:active-rules", ruleId, + replyHandler "Deleting rule key '#{ ruleId }' in active user '#{ userId }'" + delActiveUserRule( id ) for id in obj + @db.del "rule:#{ ruleId }:active-users", + replyHandler "Deleting rule '#{ ruleId }' active users" + +### +Associate a rule to a user. + +@public linkRule( *ruleId, userId* ) +@param {String} ruleId +@param {String} userId +### +exports.linkRule = ( ruleId, userId ) => + log.print 'DB', "linkRule: '#{ ruleId }' for user '#{ userId }'" + @db.sadd "rule:#{ ruleId }:users", userId, + replyHandler "storing user '#{ userId }' for rule key '#{ ruleId }'" + @db.sadd "user:#{ userId }:rules", ruleId, + replyHandler "storing rule key '#{ ruleId }' for user '#{ userId }'" + +### +Get rules linked to a user and hand it to cb(err, obj). + +@public getUserLinkRule( *userId, cb* ) +@param {String} userId +@param {function} cb +### +exports.getUserLinkedRules = ( userId, cb ) => + log.print 'DB', "getUserLinkedRules: for user '#{ userId }'" + @db.smembers "user:#{ userId }:rules", cb + +### +Get users linked to a rule and hand it to cb(err, obj). + +@public getRuleLinkedUsers( *ruleId, cb* ) +@param {String} ruleId +@param {function} cb +### +exports.getRuleLinkedUsers = ( ruleId, cb ) => + log.print 'DB', "getRuleLinkedUsers: for rule '#{ ruleId }'" + @db.smembers "rule:#{ ruleId }:users", cb + +### +Delete an association of a rule to a user. + +@public unlinkRule( *ruleId, userId* ) +@param {String} ruleId +@param {String} userId +### +exports.unlinkRule = ( ruleId, userId ) => + log.print 'DB', "unlinkRule: '#{ ruleId }:#{ userId }'" + @db.srem "rule:#{ ruleId }:users", userId, + replyHandler "removing user '#{ userId }' for rule key '#{ ruleId }'" + @db.srem "user:#{ userId }:rules", ruleId, + replyHandler "removing rule key '#{ ruleId }' for user '#{ userId }'" + +### +Activate a rule. + +@public activateRule( *ruleId, userId* ) +@param {String} ruleId +@param {String} userId +### +exports.activateRule = ( ruleId, userId ) => + log.print 'DB', "activateRule: '#{ ruleId }' for '#{ userId }'" + @db.sadd "rule:#{ ruleId }:active-users", userId, + replyHandler "storing activated user '#{ userId }' in rule '#{ ruleId }'" + @db.sadd "user:#{ userId }:active-rules", ruleId, + replyHandler "storing activated rule '#{ ruleId }' in user '#{ userId }'" + +### +Get rules activated for a user and hand it to cb(err, obj). + +@public getUserLinkRule( *userId, cb* ) +@param {String} userId +@param {function} cb +### +exports.getUserActivatedRules = ( userId, cb ) => + log.print 'DB', "getUserActivatedRules: for user '#{ userId }'" + @db.smembers "user:#{ userId }:active-rules", cb + +### +Get users activated for a rule and hand it to cb(err, obj). + +@public getRuleActivatedUsers ( *ruleId, cb* ) +@param {String} ruleId +@param {function} cb +### +exports.getRuleActivatedUsers = ( ruleId, cb ) => + log.print 'DB', "getRuleLinkedUsers: for rule '#{ ruleId }'" + @db.smembers "rule:#{ ruleId }:active-users", cb + +### +Deactivate a rule. + +@public deactivateRule( *ruleId, userId* ) +@param {String} ruleId +@param {String} userId +### +exports.deactivateRule = ( ruleId, userId ) => + log.print 'DB', "deactivateRule: '#{ ruleId }' for '#{ userId }'" + @db.srem "rule:#{ ruleId }:active-users", userId, + replyHandler "removing activated user '#{ userId }' in rule '#{ ruleId }'" + @db.srem "user:#{ userId }:active-rules", ruleId, + replyHandler "removing activated rule '#{ ruleId }' in user '#{ userId }'" + +### +Fetch all active ruleIds and pass them to cb(err, obj). + +@public getAllActivatedRuleIds( *cb* ) +@param {function} cb +### +exports.getAllActivatedRuleIdsPerUser = ( cb ) => + log.print 'DB', "Fetching all active rules" + @db.smembers 'users', ( err, obj ) => + result = {} + console.log 'checking length' + if obj.length is 0 + console.log 'length cehcked is 0' + cb null, result + else + console.log 'length cehcked' + semaphore = obj.length + fFetchActiveUserRules = ( userId ) => + @db.smembers "user:#{ user }:active-rules", ( err, obj ) => + console.log obj + console.log obj.length + if obj.length is 0 + console.log 'is 0' + else + result[userId] = obj + if --semaphore is 0 + cb null, result + fFetchActiveUserRules(user) for user in obj + + +### +Fetch all active rules and pass them to cb(err, obj). + +@public getAllActivatedRules( *cb* ) +@param {function} cb +### +exports.getAllActivatedRules = ( cb ) => + log.print 'DB', "Fetching all active rules" + fCb = ( err, obj ) -> + console.log 'fetched something' + console.log err + console.log obj + @db.smembers 'users', ( err, obj ) => + getSetRecords "user:#{ user }:active-rules", exports.getRule, fCb for user in obj + ### Store a user object (needs to be a flat structure). @@ -412,11 +700,13 @@ Store a user object (needs to be a flat structure). exports.storeUser = ( objUser ) => #TODO Only store user if not already existing, or at least only then add a private key #for his encryption. we would want to have one private key per user, right? - log.print 'DB', "storeUser: #{ objUser.username }" + log.print 'DB', "storeUser: '#{ objUser.username }'" if objUser and objUser.username and objUser.password - @db.sadd 'users', objUser.username, replyHandler "storing user key #{ objUser.username }" + @db.sadd 'users', objUser.username, + replyHandler "storing user key '#{ objUser.username }'" objUser.password = hash objUser.password - @db.hmset "user:#{ objUser.username }", objUser, replyHandler "storing user properties #{ objUser.username }" + @db.hmset "user:#{ objUser.username }", objUser, + replyHandler "storing user properties '#{ objUser.username }'" else log.error 'DB', new Error 'username or password was missing' @@ -428,29 +718,31 @@ Associate a role with a user. @param {String} role ### exports.storeUserRole = ( userId, role ) => - log.print 'DB', "storeUserRole: #{ userId }:#{ role }" - @db.sadd 'roles', role, replyHandler "adding role #{ role } to role index set" - @db.sadd "user:#{ userId }:roles", role, replyHandler "adding role #{ role } to user #{ userId }" - @db.sadd "role:#{ role }:users", userId, replyHandler "adding user #{ userId } to role #{ role }" + log.print 'DB', "storeUserRole: '#{ userId }:#{ role }'" + @db.sadd 'roles', role, replyHandler "adding role '#{ role }' to role index set" + @db.sadd "user:#{ userId }:roles", role, + replyHandler "adding role '#{ role }' to user '#{ userId }'" + @db.sadd "role:#{ role }:users", userId, + replyHandler "adding user '#{ userId }' to role '#{ role }'" ### -Fetch all roles of a user and pass them to the callback(err, obj) +Fetch all roles of a user and pass them to cb(err, obj). @public getUserRoles( *userId* ) @param {String} userId ### exports.getUserRoles = ( userId ) => - log.print 'DB', "getUserRole: #{ userId }" + log.print 'DB', "getUserRole: '#{ userId }'" @db.get "user-roles:#{ userId }", cb ### -Fetch all users of a role and pass them to the callback(err, obj) +Fetch all users of a role and pass them to cb(err, obj). @public getUserRoles( *role* ) @param {String} role ### exports.getRoleUsers = ( role ) => - log.print 'DB', "getRoleUsers: #{ role }" + log.print 'DB', "getRoleUsers: '#{ role }'" @db.get "role-users:#{ role }", cb ### @@ -466,14 +758,14 @@ because we only store hashes of passwords for safety reasons. ### #TODO verify and test whole function exports.loginUser = ( userId, password, cb ) => - log.print 'DB', "User \"#{ userId }\" tries to log in" + log.print 'DB', "User '#{ userId }' tries to log in" fCheck = ( pw ) -> ( err, obj ) -> if err cb err else if obj and obj.password if pw == obj.password - log.print 'DB', "User \"#{ obj.username }\" logged in!" + log.print 'DB', "User '#{ obj.username }' logged in!" cb null, obj else cb new Error 'Wrong credentials!' @@ -481,7 +773,36 @@ exports.loginUser = ( userId, password, cb ) => cb new Error 'User not found!' @db.hgetall "user:#{ userId }", fCheck password -#TODO implement functions required for user sessions and the rule activation +### +Deletes a user and all his associated linked and active rules. + +@public deleteUser( *userId* ) +@param {String} userId +### +exports.deleteUser = ( userId ) => + log.print 'DB', "deleteUser: '#{ userId }'" + @db.srem "users", userId, replyHandler "Deleting user key '#{ userId }'" + @db.del "user:#{ userId }", replyHandler "Deleting user '#{ userId }'" + + # We also need to delete all linked rules + @db.smembers "user:#{ userId }:rules", ( err, obj ) => + delLinkedRuleUser = ( ruleId ) => + @db.srem "rule:#{ ruleId }:users", userId, + replyHandler "Deleting user key '#{ userId }' in linked rule '#{ ruleId }'" + delLinkedRuleUser( id ) for id in obj + @db.del "user:#{ userId }:rules", + replyHandler "Deleting user '#{ userId }' rules" + + # We also need to delete all active rules + @db.smembers "user:#{ userId }:rules", ( err, obj ) => + delActivatedRuleUser = ( ruleId ) => + @db.srem "rule:#{ ruleId }:active-users", userId, + replyHandler "Deleting user key '#{ userId }' in active rule '#{ ruleId }'" + delActivatedRuleUser( id ) for id in obj + @db.del "user:#{ userId }:active-rules", replyHandler "Deleting user '#{ userId }' rules" + + +#TODO implement functions required for user sessions? ### Shuts down the db link. diff --git a/coffee/request_handler.coffee b/coffee/request_handler.coffee index 1155b45..59b5f03 100644 --- a/coffee/request_handler.coffee +++ b/coffee/request_handler.coffee @@ -160,6 +160,16 @@ Resolves the path to a handler webpage and returns it as a string. getHandlerFileAsString = ( name ) -> fs.readFileSync getHandlerPath( name ), 'utf8' +### +Fetches an include file. + +@private getIncludeFileAsString( *name* ) +@param {String} name +### +getIncludeFileAsString = ( name ) -> + pth = path.resolve __dirname, '..', 'webpages', 'handlers', 'includes', name + '.html' + fs.readFileSync pth, 'utf8' + ### Renders a page depending on the user session and returns it. @@ -169,8 +179,8 @@ Renders a page depending on the user session and returns it. ### renderPage = ( name, sess, msg ) -> template = getHandlerFileAsString name - menubar = getHandlerFileAsString 'part_menubar' - requires = getHandlerFileAsString 'part_requires' + menubar = getIncludeFileAsString 'menubar' + requires = getIncludeFileAsString 'requires' view = user: sess.user, head_requires: requires, @@ -190,10 +200,14 @@ objects.* @param {String} pagename ### sendLoginOrPage = ( pagename, req, resp ) -> - if req.session and req.session.user - resp.send renderPage pagename, req.session - else - resp.sendfile getHandlerPath 'login' + if !req.session + req.session = {} + if !req.session.user + pagename = 'login' + # resp.send renderPage pagename, req.session + # else + # resp.sendfile getHandlerPath 'login' + resp.send renderPage pagename, req.session ### Present the module forge to the user. diff --git a/js-coffee/db_interface.js b/js-coffee/db_interface.js index 442561e..4c43d13 100644 --- a/js-coffee/db_interface.js +++ b/js-coffee/db_interface.js @@ -4,25 +4,26 @@ DB Interface ============ > Handles the connection to the database and provides functionalities for -> event/action modules, rules and the encrypted storing of authentication tokens. +> event pollers, action invokers, rules and the encrypted storing of authentication tokens. > General functionality as a wrapper for the module holds initialization, > encryption/decryption, the retrieval of modules and shut down. > > The general structure for linked data is that the key is stored in a set. > By fetching all set entries we can then fetch all elements, which is > automated in this function. -> For example modules of the same group, e.g. action modules are registered in an +> For example, modules of the same group, e.g. action invokers are registered in an > unordered set in the database, from where they can be retrieved again. For example -> a new action module has its ID (e.g 'probinder') first registered in the set -> 'action_modules' and then stored in the db with the key 'action\_module\_' + ID -> (e.g. action\_module\_probinder). +> a new action invoker has its ID (e.g 'probinder') first registered in the set +> 'action-invokers' and then stored in the db with the key 'action-invoker:' + ID +> (e.g. action-invoker:probinder). > */ (function() { - var crypto, decrypt, encrypt, exports, getSetRecords, hash, log, redis, replyHandler, - _this = this; + var IndexedModules, crypto, decrypt, encrypt, exports, getSetRecords, hash, log, redis, replyHandler, + _this = this, + __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }; log = require('./logging'); @@ -54,10 +55,12 @@ DB Interface _this.db = redis.createClient(config.getDBPort(), 'localhost', { connect_timeout: 2000 }); - return _this.db.on('error', function(err) { + _this.db.on('error', function(err) { err.addInfo = 'message from DB'; return log.error('DB', err); }); + _this.ep = new IndexedModules('event-poller', _this.db); + return _this.ai = new IndexedModules('action-invoker', _this.db); } else { return log.error('DB', 'Initialization failed because of missing config file!'); } @@ -103,7 +106,7 @@ DB Interface replyHandler = function(action) { return function(err, reply) { if (err) { - err.addInfo = "during \"" + action + "\""; + err.addInfo = "during '" + action + "'"; return log.error('DB', err); } else { return log.print('DB', "" + action + ": " + reply); @@ -121,7 +124,7 @@ DB Interface exports.pushEvent = function(oEvent) { if (oEvent) { - log.print('DB', "Event pushed into the queue: " + oEvent.eventid); + log.print('DB', "Event pushed into the queue: '" + oEvent.eventid + "'"); return _this.db.rpush('event_queue', JSON.stringify(oEvent)); } else { return log.error('DB', 'Why would you give me an empty event...'); @@ -129,7 +132,7 @@ DB Interface }; /* - Pop an event from the event queue and pass it to the callback(err, obj) function. + Pop an event from the event queue and pass it to cb(err, obj). @public popEvent( *cb* ) @param {function} cb @@ -191,14 +194,12 @@ DB Interface encrypt = function(plainText) { - var enciph, err, et; + var err; if (plainText == null) { return null; } try { - enciph = crypto.createCipher('aes-256-cbc', _this.crypto_key); - et = enciph.update(plainText, 'utf8', 'base64'); - return et + enciph.final('base64'); + return crypto.AES.encrypt(plainText, _this.crypto_key); } catch (_error) { err = _error; err.addInfo = 'during encryption'; @@ -216,14 +217,13 @@ DB Interface decrypt = function(crypticText) { - var deciph, dt, err; + var dec, err; if (crypticText == null) { return null; } try { - deciph = crypto.createDecipher('aes-256-cbc', _this.crypto_key); - dt = deciph.update(crypticText, 'base64', 'utf8'); - return dt + deciph.final('utf8'); + dec = crypto.AES.decrypt(crypticText, _this.crypto_key); + return dec.toString(crypto.enc.Utf8); } catch (_error) { err = _error; err.addInfo = 'during decryption'; @@ -233,23 +233,26 @@ DB Interface }; /* - Fetches all linked data set keys from a linking set, fetches the single data objects - via the provided function and returns the results to the callback(err, obj) function. + Fetches all linked data set keys from a linking set, fetches the single + data objects via the provided function and returns the results to cb(err, obj). @private getSetRecords( *set, fSingle, cb* ) @param {String} set the set name how it is stored in the DB - @param {function} fSingle a function to retrieve a single data element per set entry - @param {function} cb the callback(err, obj) function that receives all the retrieved data or an error + @param {function} fSingle a function to retrieve a single data element + per set entry + @param {function} cb the callback(err, obj) function that receives all + the retrieved data or an error */ getSetRecords = function(set, fSingle, cb) { - log.print('DB', "Fetching set records: " + set); + log.print('DB', "Fetching set records: '" + set + "'"); return _this.db.smembers(set, function(err, arrReply) { var fCallback, objReplies, reply, semaphore, _i, _len, _results; if (err) { - err.addInfo = "fetching " + set; - return log.error('DB', err); + err.addInfo = "fetching '" + set + "'"; + log.error('DB', err); + return cb(err); } else if (arrReply.length === 0) { return cb(); } else { @@ -257,17 +260,17 @@ DB Interface objReplies = {}; setTimeout(function() { if (semaphore > 0) { - return cb(new Error("Timeout fetching " + set)); + return cb(new Error("Timeout fetching '" + set + "'")); } }, 2000); fCallback = function(prop) { return function(err, data) { --semaphore; if (err) { - err.addInfo = "fetching single element: " + prop; + err.addInfo = "fetching single element: '" + prop + "'"; log.error('DB', err); } else if (!data) { - log.error('DB', new Error("Empty key in DB: " + prop)); + log.error('DB', new Error("Empty key in DB: '" + prop + "'")); } else { objReplies[prop] = data; } @@ -286,192 +289,315 @@ DB Interface }); }; + IndexedModules = (function() { + function IndexedModules(setname, db) { + this.setname = setname; + this.db = db; + this.deleteParameters = __bind(this.deleteParameters, this); + this.getParametersIds = __bind(this.getParametersIds, this); + this.getParameters = __bind(this.getParameters, this); + this.storeParameters = __bind(this.storeParameters, this); + this.deleteModule = __bind(this.deleteModule, this); + this.getModules = __bind(this.getModules, this); + this.getModuleIds = __bind(this.getModuleIds, this); + this.getModule = __bind(this.getModule, this); + this.storeModule = __bind(this.storeModule, this); + log.print('DB', "Instantiated indexed modules for '" + this.setname + "'"); + } + + IndexedModules.prototype.storeModule = function(mId, data) { + log.print('DB', "storeModule(" + this.setname + "): " + mId); + this.db.sadd("" + this.setname + "s", mId, replyHandler("Storing '" + this.setname + "' key '" + mId + "'")); + return this.db.set("" + this.setname + ":" + mId, data, replyHandler("Storing '" + this.setname + ":" + mId + "'")); + }; + + IndexedModules.prototype.getModule = function(mId, cb) { + log.print('DB', "getModule('" + this.setname + "): " + mId + "'"); + return this.db.get("" + this.setname + ":" + mId, cb); + }; + + IndexedModules.prototype.getModuleIds = function(cb) { + log.print('DB', "getModuleIds(" + this.setname + ")"); + return this.db.smembers("" + this.setname + "s", cb); + }; + + IndexedModules.prototype.getModules = function(cb) { + log.print('DB', "getModules(" + this.setname + ")"); + return getSetRecords("" + this.setname + "s", this.getModule, cb); + }; + + IndexedModules.prototype.deleteModule = function(mId) { + log.print('DB', "deleteModule(" + this.setname + "): " + mId); + this.db.srem("" + this.setname + "s", mId, replyHandler("Deleting '" + this.setname + "' key '" + mId + "'")); + return this.db.del("" + this.setname + ":" + mId, replyHandler("Deleting '" + this.setname + ":" + mId + "'")); + }; + + IndexedModules.prototype.storeParameters = function(mId, userId, data) { + log.print('DB', "storeParameters(" + this.setname + "): '" + mId + ":" + userId + "'"); + this.db.sadd("" + this.setname + "-params", "" + mId + ":" + userId, replyHandler("Storing '" + this.setname + "' module parameters key '" + mId + "'")); + return this.db.set("" + this.setname + "-params:" + mId + ":" + userId, encrypt(data), replyHandler("Storing '" + this.setname + "' module parameters '" + mId + ":" + userId + "'")); + }; + + IndexedModules.prototype.getParameters = function(mId, userId, cb) { + log.print('DB', "getParameters(" + this.setname + "): '" + mId + ":" + userId + "'"); + return this.db.get("" + this.setname + "-params:" + mId + ":" + userId, function(err, data) { + return cb(err, decrypt(data)); + }); + }; + + IndexedModules.prototype.getParametersIds = function(cb) { + log.print('DB', "getParametersIds(" + this.setname + ")"); + return this.db.smembers("" + this.setname + "-params", cb); + }; + + IndexedModules.prototype.deleteParameters = function(mId, userId) { + log.print('DB', "deleteParameters(" + this.setname + "): '" + mId + ":" + userId + "'"); + this.db.srem("" + this.setname + "-params", "" + mId + ":" + userId, replyHandler("Deleting '" + this.setname + "-params' key '" + mId + ":" + userId + "'")); + return this.db.del("" + this.setname + "-params:" + mId + ":" + userId, replyHandler("Deleting '" + this.setname + "-params:" + mId + ":" + userId + "'")); + }; + + return IndexedModules; + + })(); + /* - ## Action Modules - #TODO Rename Action Modules into something like Action Caller + ## Action Invokers */ /* - Store a string representation of an action module in the DB. + Store a string representation of an action invoker in the DB. - @public storeActionModule ( *amId, data* ) - @param {String} amId + @public storeActionInvoker ( *aiId, data* ) + @param {String} aiId @param {String} data */ - exports.storeActionModule = function(amId, data) { - log.print('DB', "storeActionModule: " + amId); - _this.db.sadd('action-modules', amId, replyHandler("storing action module key " + amId)); - return _this.db.set("action-module:" + amId, data, replyHandler("storing action module " + amId)); + exports.storeActionInvoker = function(aiId, data) { + return _this.ai.storeModule(aiId, data); }; /* - Query the DB for an action module and pass it to the callback(err, obj) function. + Query the DB for an action invoker and pass it to cb(err, obj). - @public getActionModule( *amId, cb* ) - @param {String} amId + @public getActionInvoker( *aiId, cb* ) + @param {String} aiId @param {function} cb */ - exports.getActionModule = function(amId, cb) { - log.print('DB', "getActionModule: " + amId); - return _this.db.get("action-module:" + amId, cb); - }; - - exports.getSetMembers = function(setId, cb) { - return _this.db.smembers(setId, cb); + exports.getActionInvoker = function(aiId, cb) { + return _this.ai.getModule(aiId, cb); }; /* - Fetch all action module IDs and hand them to the callback(err, obj) function. + Fetch all action invoker IDs and hand them to cb(err, obj). - @public getActionModuleIds( *cb* ) + @public getActionInvokerIds( *cb* ) @param {function} cb */ - exports.getActionModuleIds = function(cb) { - return _this.db.smembers('action-modules', cb); + exports.getActionInvokerIds = function(cb) { + return _this.ai.getModuleIds(cb); }; /* - Fetch all action modules and hand them to the callback(err, obj) function. + Fetch all action invokers and hand them to cb(err, obj). - @public getActionModules( *cb* ) + @public getActionInvokers( *cb* ) @param {function} cb */ - exports.getActionModules = function(cb) { - return getSetRecords('action-modules', exports.getActionModule, cb); + exports.getActionInvokers = function(cb) { + return _this.ai.getModules(cb); }; /* - Fetch all action modules and hand them to the callback(err, obj) function. + Fetch all action invokers and hand them to cb(err, obj). - @public getActionModules( *cb* ) + @public getActionInvokers( *cb* ) @param {function} cb */ - exports.deleteActionModule = function(amId) { - _this.db.srem('action-modules', amId, replyHandler("deleting action module key " + amId)); - return _this.db.del("action-module:" + amId, replyHandler("deleting action module " + amId)); + exports.deleteActionInvoker = function(aiId) { + return _this.ai.deleteModule(aiId); }; /* - Store user-specific action module parameters . + Store user-specific action invoker parameters . - @public storeActionParams( *userId, amId, data* ) + @public storeActionParams( *userId, aiId, data* ) @param {String} userId - @param {String} amId + @param {String} aiId @param {String} data */ - exports.storeActionParams = function(userId, amId, data) { - log.print('DB', "storeActionParams: " + amId + ":" + userId); - return _this.db.set("action-params:" + amId + ":" + userId, hash(data), replyHandler("storing action params " + amId + ":" + userId)); + exports.storeActionParams = function(aiId, userId, data) { + return _this.ai.storeParameters(aiId, userId, data); }; /* Query the DB for user-specific action module parameters, - and pass it to the callback(err, obj) function. + and pass it to cb(err, obj). - @public getActionParams( *userId, amId, cb* ) + @public getActionParams( *userId, aiId, cb* ) @param {String} userId - @param {String} amId + @param {String} aiId @param {function} cb */ - exports.getActionParams = function(userId, amId, cb) { - log.print('DB', "getActionParams: " + amId + ":" + userId); - return _this.db.get("action-params:" + amId + ":" + userId, function(err, data) { - return cb(err, decrypt(data)); - }); + exports.getActionParams = function(aiId, userId, cb) { + return _this.ai.getParameters(aiId, userId, cb); }; /* - ## Event Modules - #TODO rename event modules to event puller or something like that + Fetch all action params IDs and hand them to cb(err, obj). + + @public getActionParamsIds( *cb* ) + @param {function} cb + */ + + + exports.getActionParamsIds = function(cb) { + return _this.ai.getParametersIds(cb); + }; + + /* + Fetch all action modules and hand them to cb(err, obj). + + @public deleteActionParams( *cb* ) + @param {function} cb + */ + + + exports.deleteActionParams = function(aiId, userId) { + return _this.ai.deleteParameters(aiId, userId); + }; + + /* + ## Event Pollers */ /* - Store a string representation of an event module in the DB. + Store a string representation of an event poller in the DB. - @public storeEventModule( *emId, data* ) - @param {String} emId + @public storeEventPoller ( *epId, data* ) + @param {String} epId @param {String} data */ - exports.storeEventModule = function(emId, data) { - log.print('DB', "storeEventModule: " + emId); - _this.db.sadd('event-modules', emId, replyHandler("storing event module key " + emId)); - return _this.db.set('event-module:#{ emId }', data, replyHandler("storing event module " + emId)); + exports.storeEventPoller = function(epId, data) { + return _this.ep.storeModule(epId, data); }; /* - Query the DB for an event module and pass it to the callback(err, obj) function. + Query the DB for an event poller and pass it to cb(err, obj). - @public getEventModule( *emId, cb* ) - @param {String} emId + @public getEventPoller( *epId, cb* ) + @param {String} epId @param {function} cb */ - exports.getEventModule = function(emId, cb) { - log.print('DB', "getEventModule: " + emId); - return _this.db.get("event-module:" + emId, cb); + exports.getEventPoller = function(epId, cb) { + return _this.ep.getModule(epId, cb); }; /* - Fetch all event modules and pass them to the callback(err, obj) function. + Fetch all event poller IDs and hand them to cb(err, obj). - @public getEventModules( *cb* ) + @public getEventPollerIds( *cb* ) @param {function} cb */ - exports.getEventModules = function(cb) { - return getSetRecords('event-modules', exports.getEventModule, cb); + exports.getEventPollerIds = function(cb) { + return _this.ep.getModuleIds(cb); }; /* - Store a string representation of user-specific parameters for an event module. + Fetch all event pollers and hand them to cb(err, obj). - @public storeEventParams( *userId, emId, data* ) + @public getEventPollers( *cb* ) + @param {function} cb + */ + + + exports.getEventPollers = function(cb) { + return _this.ep.getModules(cb); + }; + + /* + Fetch all event pollers and hand them to cb(err, obj). + + @public getEventPollers( *cb* ) + @param {function} cb + */ + + + exports.deleteEventPoller = function(epId) { + return _this.ep.deleteModule(epId); + }; + + /* + Store user-specific event poller parameters . + + @public storeEventParams( *userId, epId, data* ) @param {String} userId - @param {String} emId - @param {Object} data + @param {String} epId + @param {String} data */ - exports.storeEventParams = function(userId, emId, data) { - log.print('DB', "storeEventParams: " + emId + ":" + userId); - return _this.db.set("event-params:" + emId + ":" + userId, encrypt(data), replyHandler("storing event auth " + emId + ":" + userId)); + exports.storeEventParams = function(epId, userId, data) { + return _this.ep.storeParameters(epId, userId, data); }; /* - Query the DB for an action module authentication token, associated with a user. + Query the DB for user-specific event module parameters, + and pass it to cb(err, obj). - @public getEventAuth( *userId, emId, data* ) + @public getEventParams( *userId, epId, cb* ) @param {String} userId - @param {String} emId + @param {String} epId @param {function} cb */ - exports.getEventAuth = function(userId, emId, cb) { - log.print('DB', "getEventAuth: " + emId + ":" + userId); - return _this.db.get("event-auth:" + emId + ":" + userId, function(err, data) { - return cb(err, decrypt(data)); - }); + exports.getEventParams = function(epId, userId, cb) { + return _this.ep.getParameters(epId, userId, cb); + }; + + /* + Fetch all event params IDs and hand them to cb(err, obj). + + @public getEventParamsIds( *cb* ) + @param {function} cb + */ + + + exports.getEventParamsIds = function(cb) { + return _this.ep.getParametersIds(cb); + }; + + /* + Fetch all event modules and hand them to cb(err, obj). + + @public deleteEventParams( *cb* ) + @param {function} cb + */ + + + exports.deleteEventParams = function(epId, userId) { + return _this.ep.deleteParameters(epId, userId); }; /* @@ -480,25 +606,7 @@ DB Interface /* - Store a string representation of a rule in the DB. - - @public storeRule( *ruleId, userId, data* ) - @param {String} ruleId - @param {String} userId - @param {String} data - */ - - - exports.storeRule = function(ruleId, userId, data) { - log.print('DB', "storeRule: " + ruleId); - _this.db.sadd('rules', "" + ruleId + ":" + userId, replyHandler("storing rule key \"" + ruleId + ":" + userId + "\"")); - _this.db.sadd("user-set:" + userId + ":rules", ruleId, replyHandler("storing rule key to \"user:" + userId + ":rules\"")); - _this.db.sadd("rule-set:" + ruleId + ":users", user, replyHandler("storing user key to \"rule:" + ruleId + ":users\"")); - return _this.db.set("rule:" + ruleId + ":" + userId, data, replyHandler("storing rule \"" + ruleId + ":" + userId + "\"")); - }; - - /* - Query the DB for a rule and pass it to the callback(err, obj) function. + Query the DB for a rule and pass it to cb(err, obj). @public getRule( *ruleId, cb* ) @param {String} ruleId @@ -507,12 +615,12 @@ DB Interface exports.getRule = function(ruleId, cb) { - log.print('DB', "getRule: " + ruleId); + log.print('DB', "getRule: '" + ruleId + "'"); return _this.db.get("rule:" + ruleId, cb); }; /* - Fetch all rules from the database and pass them to the callback function. + Fetch all rules and pass them to cb(err, obj). @public getRules( *cb* ) @param {function} cb @@ -524,6 +632,262 @@ DB Interface return getSetRecords('rules', exports.getRule, cb); }; + /* + Fetch all rule IDs and hand it to cb(err, obj). + + @public getRuleIds( *cb* ) + @param {function} cb + */ + + + exports.getRuleIds = function(cb) { + log.print('DB', 'Fetching all Rule IDs'); + return _this.db.smembers('rules', cb); + }; + + /* + Store a string representation of a rule in the DB. + + @public storeRule( *ruleId, data* ) + @param {String} ruleId + @param {String} data + */ + + + exports.storeRule = function(ruleId, data) { + log.print('DB', "storeRule: '" + ruleId + "'"); + _this.db.sadd('rules', "" + ruleId, replyHandler("storing rule key '" + ruleId + "'")); + return _this.db.set("rule:" + ruleId, data, replyHandler("storing rule '" + ruleId + "'")); + }; + + /* + Delete a string representation of a rule. + + @public deleteRule( *ruleId, userId* ) + @param {String} ruleId + @param {String} userId + */ + + + exports.deleteRule = function(ruleId) { + log.print('DB', "deleteRule: '" + ruleId + "'"); + _this.db.srem("rules", ruleId, replyHandler("Deleting rule key '" + ruleId + "'")); + _this.db.del("rule:" + ruleId, replyHandler("Deleting rule '" + ruleId + "'")); + _this.db.smembers("rule:" + ruleId + ":users", function(err, obj) { + var delLinkedUserRule, id, _i, _len, _results; + delLinkedUserRule = function(userId) { + return _this.db.srem("user:" + userId + ":rules", ruleId, replyHandler("Deleting rule key '" + ruleId + "'' in linked user '" + userId + "'")); + }; + _results = []; + for (_i = 0, _len = obj.length; _i < _len; _i++) { + id = obj[_i]; + _results.push(delLinkedUserRule(id)); + } + return _results; + }); + _this.db.del("rule:" + ruleId + ":users", replyHandler("Deleting rule '" + ruleId + "' users")); + _this.db.smembers("rule:" + ruleId + ":active-users", function(err, obj) { + var delActiveUserRule, id, _i, _len, _results; + delActiveUserRule = function(userId) { + return _this.db.srem("user:" + userId + ":active-rules", ruleId, replyHandler("Deleting rule key '" + ruleId + "' in active user '" + userId + "'")); + }; + _results = []; + for (_i = 0, _len = obj.length; _i < _len; _i++) { + id = obj[_i]; + _results.push(delActiveUserRule(id)); + } + return _results; + }); + return _this.db.del("rule:" + ruleId + ":active-users", replyHandler("Deleting rule '" + ruleId + "' active users")); + }; + + /* + Associate a rule to a user. + + @public linkRule( *ruleId, userId* ) + @param {String} ruleId + @param {String} userId + */ + + + exports.linkRule = function(ruleId, userId) { + log.print('DB', "linkRule: '" + ruleId + "' for user '" + userId + "'"); + _this.db.sadd("rule:" + ruleId + ":users", userId, replyHandler("storing user '" + userId + "' for rule key '" + ruleId + "'")); + return _this.db.sadd("user:" + userId + ":rules", ruleId, replyHandler("storing rule key '" + ruleId + "' for user '" + userId + "'")); + }; + + /* + Get rules linked to a user and hand it to cb(err, obj). + + @public getUserLinkRule( *userId, cb* ) + @param {String} userId + @param {function} cb + */ + + + exports.getUserLinkedRules = function(userId, cb) { + log.print('DB', "getUserLinkedRules: for user '" + userId + "'"); + return _this.db.smembers("user:" + userId + ":rules", cb); + }; + + /* + Get users linked to a rule and hand it to cb(err, obj). + + @public getRuleLinkedUsers( *ruleId, cb* ) + @param {String} ruleId + @param {function} cb + */ + + + exports.getRuleLinkedUsers = function(ruleId, cb) { + log.print('DB', "getRuleLinkedUsers: for rule '" + ruleId + "'"); + return _this.db.smembers("rule:" + ruleId + ":users", cb); + }; + + /* + Delete an association of a rule to a user. + + @public unlinkRule( *ruleId, userId* ) + @param {String} ruleId + @param {String} userId + */ + + + exports.unlinkRule = function(ruleId, userId) { + log.print('DB', "unlinkRule: '" + ruleId + ":" + userId + "'"); + _this.db.srem("rule:" + ruleId + ":users", userId, replyHandler("removing user '" + userId + "' for rule key '" + ruleId + "'")); + return _this.db.srem("user:" + userId + ":rules", ruleId, replyHandler("removing rule key '" + ruleId + "' for user '" + userId + "'")); + }; + + /* + Activate a rule. + + @public activateRule( *ruleId, userId* ) + @param {String} ruleId + @param {String} userId + */ + + + exports.activateRule = function(ruleId, userId) { + log.print('DB', "activateRule: '" + ruleId + "' for '" + userId + "'"); + _this.db.sadd("rule:" + ruleId + ":active-users", userId, replyHandler("storing activated user '" + userId + "' in rule '" + ruleId + "'")); + return _this.db.sadd("user:" + userId + ":active-rules", ruleId, replyHandler("storing activated rule '" + ruleId + "' in user '" + userId + "'")); + }; + + /* + Get rules activated for a user and hand it to cb(err, obj). + + @public getUserLinkRule( *userId, cb* ) + @param {String} userId + @param {function} cb + */ + + + exports.getUserActivatedRules = function(userId, cb) { + log.print('DB', "getUserActivatedRules: for user '" + userId + "'"); + return _this.db.smembers("user:" + userId + ":active-rules", cb); + }; + + /* + Get users activated for a rule and hand it to cb(err, obj). + + @public getRuleActivatedUsers ( *ruleId, cb* ) + @param {String} ruleId + @param {function} cb + */ + + + exports.getRuleActivatedUsers = function(ruleId, cb) { + log.print('DB', "getRuleLinkedUsers: for rule '" + ruleId + "'"); + return _this.db.smembers("rule:" + ruleId + ":active-users", cb); + }; + + /* + Deactivate a rule. + + @public deactivateRule( *ruleId, userId* ) + @param {String} ruleId + @param {String} userId + */ + + + exports.deactivateRule = function(ruleId, userId) { + log.print('DB', "deactivateRule: '" + ruleId + "' for '" + userId + "'"); + _this.db.srem("rule:" + ruleId + ":active-users", userId, replyHandler("removing activated user '" + userId + "' in rule '" + ruleId + "'")); + return _this.db.srem("user:" + userId + ":active-rules", ruleId, replyHandler("removing activated rule '" + ruleId + "' in user '" + userId + "'")); + }; + + /* + Fetch all active ruleIds and pass them to cb(err, obj). + + @public getAllActivatedRuleIds( *cb* ) + @param {function} cb + */ + + + exports.getAllActivatedRuleIdsPerUser = function(cb) { + log.print('DB', "Fetching all active rules"); + return _this.db.smembers('users', function(err, obj) { + var fFetchActiveUserRules, result, semaphore, user, _i, _len, _results; + result = {}; + console.log('checking length'); + if (obj.length === 0) { + console.log('length cehcked is 0'); + return cb(null, result); + } else { + console.log('length cehcked'); + semaphore = obj.length; + fFetchActiveUserRules = function(userId) { + return _this.db.smembers("user:" + user + ":active-rules", function(err, obj) { + console.log(obj); + console.log(obj.length); + if (obj.length === 0) { + console.log('is 0'); + } else { + result[userId] = obj; + } + if (--semaphore === 0) { + return cb(null, result); + } + }); + }; + _results = []; + for (_i = 0, _len = obj.length; _i < _len; _i++) { + user = obj[_i]; + _results.push(fFetchActiveUserRules(user)); + } + return _results; + } + }); + }; + + /* + Fetch all active rules and pass them to cb(err, obj). + + @public getAllActivatedRules( *cb* ) + @param {function} cb + */ + + + exports.getAllActivatedRules = function(cb) { + var fCb; + log.print('DB', "Fetching all active rules"); + fCb = function(err, obj) { + console.log('fetched something'); + console.log(err); + return console.log(obj); + }; + return _this.db.smembers('users', function(err, obj) { + var user, _i, _len, _results; + _results = []; + for (_i = 0, _len = obj.length; _i < _len; _i++) { + user = obj[_i]; + _results.push(getSetRecords("user:" + user + ":active-rules", exports.getRule, fCb)); + } + return _results; + }); + }; + /* Store a user object (needs to be a flat structure). @@ -533,11 +897,11 @@ DB Interface exports.storeUser = function(objUser) { - log.print('DB', "storeUser: " + objUser.username); + log.print('DB', "storeUser: '" + objUser.username + "'"); if (objUser && objUser.username && objUser.password) { - _this.db.sadd('users', objUser.username, replyHandler("storing user key " + objUser.username)); + _this.db.sadd('users', objUser.username, replyHandler("storing user key '" + objUser.username + "'")); objUser.password = hash(objUser.password); - return _this.db.hmset("user:" + objUser.username, objUser, replyHandler("storing user properties " + objUser.username)); + return _this.db.hmset("user:" + objUser.username, objUser, replyHandler("storing user properties '" + objUser.username + "'")); } else { return log.error('DB', new Error('username or password was missing')); } @@ -553,14 +917,14 @@ DB Interface exports.storeUserRole = function(userId, role) { - log.print('DB', "storeUserRole: " + userId + ":" + role); - _this.db.sadd('roles', role, replyHandler("adding role " + role + " to role index set")); - _this.db.sadd("user:" + userId + ":roles", role, replyHandler("adding role " + role + " to user " + userId)); - return _this.db.sadd("role:" + role + ":users", userId, replyHandler("adding user " + userId + " to role " + role)); + log.print('DB', "storeUserRole: '" + userId + ":" + role + "'"); + _this.db.sadd('roles', role, replyHandler("adding role '" + role + "' to role index set")); + _this.db.sadd("user:" + userId + ":roles", role, replyHandler("adding role '" + role + "' to user '" + userId + "'")); + return _this.db.sadd("role:" + role + ":users", userId, replyHandler("adding user '" + userId + "' to role '" + role + "'")); }; /* - Fetch all roles of a user and pass them to the callback(err, obj) + Fetch all roles of a user and pass them to cb(err, obj). @public getUserRoles( *userId* ) @param {String} userId @@ -568,12 +932,12 @@ DB Interface exports.getUserRoles = function(userId) { - log.print('DB', "getUserRole: " + userId); + log.print('DB', "getUserRole: '" + userId + "'"); return _this.db.get("user-roles:" + userId, cb); }; /* - Fetch all users of a role and pass them to the callback(err, obj) + Fetch all users of a role and pass them to cb(err, obj). @public getUserRoles( *role* ) @param {String} role @@ -581,7 +945,7 @@ DB Interface exports.getRoleUsers = function(role) { - log.print('DB', "getRoleUsers: " + role); + log.print('DB', "getRoleUsers: '" + role + "'"); return _this.db.get("role-users:" + role, cb); }; @@ -600,14 +964,14 @@ DB Interface exports.loginUser = function(userId, password, cb) { var fCheck; - log.print('DB', "User \"" + userId + "\" tries to log in"); + log.print('DB', "User '" + userId + "' tries to log in"); fCheck = function(pw) { return function(err, obj) { if (err) { return cb(err); } else if (obj && obj.password) { if (pw === obj.password) { - log.print('DB', "User \"" + obj.username + "\" logged in!"); + log.print('DB', "User '" + obj.username + "' logged in!"); return cb(null, obj); } else { return cb(new Error('Wrong credentials!')); @@ -620,6 +984,46 @@ DB Interface return _this.db.hgetall("user:" + userId, fCheck(password)); }; + /* + Deletes a user and all his associated linked and active rules. + + @public deleteUser( *userId* ) + @param {String} userId + */ + + + exports.deleteUser = function(userId) { + log.print('DB', "deleteUser: '" + userId + "'"); + _this.db.srem("users", userId, replyHandler("Deleting user key '" + userId + "'")); + _this.db.del("user:" + userId, replyHandler("Deleting user '" + userId + "'")); + _this.db.smembers("user:" + userId + ":rules", function(err, obj) { + var delLinkedRuleUser, id, _i, _len, _results; + delLinkedRuleUser = function(ruleId) { + return _this.db.srem("rule:" + ruleId + ":users", userId, replyHandler("Deleting user key '" + userId + "' in linked rule '" + ruleId + "'")); + }; + _results = []; + for (_i = 0, _len = obj.length; _i < _len; _i++) { + id = obj[_i]; + _results.push(delLinkedRuleUser(id)); + } + return _results; + }); + _this.db.del("user:" + userId + ":rules", replyHandler("Deleting user '" + userId + "' rules")); + _this.db.smembers("user:" + userId + ":rules", function(err, obj) { + var delActivatedRuleUser, id, _i, _len, _results; + delActivatedRuleUser = function(ruleId) { + return _this.db.srem("rule:" + ruleId + ":active-users", userId, replyHandler("Deleting user key '" + userId + "' in active rule '" + ruleId + "'")); + }; + _results = []; + for (_i = 0, _len = obj.length; _i < _len; _i++) { + id = obj[_i]; + _results.push(delActivatedRuleUser(id)); + } + return _results; + }); + return _this.db.del("user:" + userId + ":active-rules", replyHandler("Deleting user '" + userId + "' rules")); + }; + /* Shuts down the db link. diff --git a/js-coffee/engine.js b/js-coffee/engine.js index 0090eb6..4ea45d2 100644 --- a/js-coffee/engine.js +++ b/js-coffee/engine.js @@ -29,34 +29,34 @@ exports = module.exports = function(args) { */ exports.addDBLinkAndLoadActionsAndRules = function(db_link) { db = db_link; - if(ml && db) db.getActionModules(function(err, obj) { - if(err) log.error('EN', 'retrieving Action Modules from DB!'); - else { - if(!obj) { - log.print('EN', 'No Action Modules found in DB!'); - loadRulesFromDB(); - } else { - var m; - for(var el in obj) { - log.print('EN', 'Loading Action Module from DB: ' + el); - try{ - m = ml.requireFromString(obj[el], el); - db.getActionModuleAuth(el, function(mod) { - return function(err, obj) { - if(obj && mod.loadCredentials) mod.loadCredentials(JSON.parse(obj)); - }; - }(m)); - listActionModules[el] = m; - } catch(e) { - e.addInfo = 'error in action module "' + el + '"'; - log.error('EN', e); - } - } - loadRulesFromDB(); - } - } - }); - else log.severe('EN', new Error('Module Loader or DB not defined!')); + // if(ml && db) db.getActionModules(function(err, obj) { + // if(err) log.error('EN', 'retrieving Action Modules from DB!'); + // else { + // if(!obj) { + // log.print('EN', 'No Action Modules found in DB!'); + // loadRulesFromDB(); + // } else { + // var m; + // for(var el in obj) { + // log.print('EN', 'Loading Action Module from DB: ' + el); + // try{ + // m = ml.requireFromString(obj[el], el); + // db.getActionModuleAuth(el, function(mod) { + // return function(err, obj) { + // if(obj && mod.loadCredentials) mod.loadCredentials(JSON.parse(obj)); + // }; + // }(m)); + // listActionModules[el] = m; + // } catch(e) { + // e.addInfo = 'error in action module "' + el + '"'; + // log.error('EN', e); + // } + // } + // loadRulesFromDB(); + // } + // } + // }); + // else log.severe('EN', new Error('Module Loader or DB not defined!')); }; function loadRulesFromDB() { diff --git a/js-coffee/request_handler.js b/js-coffee/request_handler.js index 35d063d..c66e5ac 100644 --- a/js-coffee/request_handler.js +++ b/js-coffee/request_handler.js @@ -8,7 +8,7 @@ Request Handler (function() { - var answerHandler, crypto, db, exports, fs, getHandlerFileAsString, getHandlerPath, log, mm, mustache, objAdminCmds, objUserCmds, path, qs, renderPage, sendLoginOrPage, + var answerHandler, crypto, db, exports, fs, getHandlerFileAsString, getHandlerPath, getIncludeFileAsString, log, mm, mustache, objAdminCmds, objUserCmds, path, qs, renderPage, sendLoginOrPage, _this = this; log = require('./logging'); @@ -189,6 +189,20 @@ Request Handler return fs.readFileSync(getHandlerPath(name), 'utf8'); }; + /* + Fetches an include file. + + @private getIncludeFileAsString( *name* ) + @param {String} name + */ + + + getIncludeFileAsString = function(name) { + var pth; + pth = path.resolve(__dirname, '..', 'webpages', 'handlers', 'includes', name + '.html'); + return fs.readFileSync(pth, 'utf8'); + }; + /* Renders a page depending on the user session and returns it. @@ -201,8 +215,8 @@ Request Handler renderPage = function(name, sess, msg) { var menubar, requires, template, view; template = getHandlerFileAsString(name); - menubar = getHandlerFileAsString('part_menubar'); - requires = getHandlerFileAsString('part_requires'); + menubar = getIncludeFileAsString('menubar'); + requires = getIncludeFileAsString('requires'); view = { user: sess.user, head_requires: requires, @@ -226,11 +240,13 @@ Request Handler sendLoginOrPage = function(pagename, req, resp) { - if (req.session && req.session.user) { - return resp.send(renderPage(pagename, req.session)); - } else { - return resp.sendfile(getHandlerPath('login')); + if (!req.session) { + req.session = {}; } + if (!req.session.user) { + pagename = 'login'; + } + return resp.send(renderPage(pagename, req.session)); }; /* diff --git a/testing/jsonWrongConfig.json b/testing/files/jsonWrongConfig.json similarity index 100% rename from testing/jsonWrongConfig.json rename to testing/files/jsonWrongConfig.json diff --git a/testing/js/test_config.js b/testing/js/test_config.js index e2806c2..aafa0ae 100644 --- a/testing/js/test_config.js +++ b/testing/js/test_config.js @@ -31,7 +31,7 @@ exports.testDifferentConfigFile = function(test) { test.expect(1); _this.conf({ - configPath: 'testing/jsonWrongConfig.json' + configPath: path.join('testing', 'files', 'jsonWrongConfig.json') }); test.ok(_this.conf.isReady(), 'Different path not loaded!'); return test.done(); diff --git a/testing/js/test_db_interface.js b/testing/js/test_db_interface.js index 5d43fd0..f808905 100644 --- a/testing/js/test_db_interface.js +++ b/testing/js/test_db_interface.js @@ -4,7 +4,6 @@ __indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }; exports.setUp = function(cb) { - _this.log = require('../js-coffee/logging'); _this.db = require('../js-coffee/db_interface'); _this.db({ logType: 2 @@ -47,11 +46,11 @@ }, testPurgeQueue: function(test) { var evt; + test.expect(2); evt = { eventid: '1', event: 'mail' }; - test.expect(2); _this.db.pushEvent(evt); _this.db.purgeEventQueue(); return _this.db.popEvent(function(err, obj) { @@ -128,68 +127,435 @@ } }; - exports.action_modules = { - testModule: function(test) { - var action1, action1name, fCheckModuleExists, fCheckModuleNotExists, fCheckModuleNotExistsInSet, fCheckSetEntry; - test.expect(4); - action1name = 'test-action-module_1'; - action1 = 'unit-test action module 1 content'; - fCheckSetEntry = function(err, obj) { - test.ok(__indexOf.call(obj, action1name) >= 0, 'Expected key not in action-modules set'); - return _this.db.getActionModule(action1name, fCheckModuleExists); - }; - fCheckModuleExists = function(err, obj) { - test.strictEqual(obj, action1, 'Retrieved Action Module is not what we expected'); - _this.log.print('delete action module'); - _this.db.deleteActionModule(action1name); - _this.log.print('tried to delete action module'); - return _this.db.getActionModule(action1name, fCheckModuleNotExists); - }; - fCheckModuleNotExists = function(err, obj) { - _this.log.print('got action module'); - test.strictEqual(obj, null, 'Action module still exists'); - _this.log.print('compared action module'); - return _this.db.getActionModuleIds(fCheckModuleNotExistsInSet); - }; - fCheckModuleNotExistsInSet = function(err, obj) { - test.ok(__indexOf.call(obj, action1name) < 0, 'Action module key still exists in set'); - return test.done(); - }; - _this.db.storeActionModule(action1name, action1); - return _this.db.getActionModuleIds(fCheckSetEntry); - }, - testFetchSeveralModules: function(test) { - var action1, action1name, action2, action2name, fCheckModule, fCheckSetEntries, forkEnds, semaphore; - semaphore = 2; - forkEnds = function() { - if (--semaphore === 0) { - return test.done(); - } - }; + exports.action_invoker = { + testCreateAndRead: function(test) { + var action, id; test.expect(3); - action1name = 'test-action-module_1'; - action2name = 'test-action-module_2'; - action1 = 'unit-test action module 1 content'; - action2 = 'unit-test action module 2 content'; - fCheckModule = function(mod) { - var myTest; + id = 'test-action-invoker'; + action = 'unit-test action invoker content'; + _this.db.storeActionInvoker(id, action); + return _this.db.getActionInvokerIds(function(err, obj) { + test.ok(__indexOf.call(obj, id) >= 0, 'Expected key not in action-invokers set'); + return _this.db.getActionInvoker(id, function(err, obj) { + test.strictEqual(obj, action, 'Retrieved Action Invoker is not what we expected'); + return _this.db.getActionInvokers(function(err, obj) { + test.deepEqual(action, obj[id], 'Action Invoker ist not in result set'); + _this.db.deleteActionInvoker(id); + return test.done(); + }); + }); + }); + }, + testUpdate: function(test) { + var action, actionNew, id; + test.expect(2); + id = 'test-action-invoker'; + action = 'unit-test action invoker content'; + actionNew = 'unit-test action invoker new content'; + _this.db.storeActionInvoker(id, action); + _this.db.storeActionInvoker(id, actionNew); + return _this.db.getActionInvoker(id, function(err, obj) { + test.strictEqual(obj, actionNew, 'Retrieved Action Invoker is not what we expected'); + return _this.db.getActionInvokers(function(err, obj) { + test.deepEqual(actionNew, obj[id], 'Action Invoker ist not in result set'); + _this.db.deleteActionInvoker(id); + return test.done(); + }); + }); + }, + testDelete: function(test) { + var action, id; + test.expect(2); + id = 'test-action-invoker'; + action = 'unit-test action invoker content'; + _this.db.storeActionInvoker(id, action); + _this.db.deleteActionInvoker(id); + return _this.db.getActionInvoker(id, function(err, obj) { + test.strictEqual(obj, null, 'Action Invoker still exists'); + return _this.db.getActionInvokerIds(function(err, obj) { + test.ok(__indexOf.call(obj, id) < 0, 'Action Invoker key still exists in set'); + return test.done(); + }); + }); + }, + testFetchSeveral: function(test) { + var action1, action1name, action2, action2name, fCheckInvoker, semaphore; + test.expect(3); + semaphore = 2; + action1name = 'test-action-invoker_1'; + action2name = 'test-action-invoker_2'; + action1 = 'unit-test action invoker 1 content'; + action2 = 'unit-test action invoker 2 content'; + fCheckInvoker = function(modname, mod) { + var forkEnds, myTest; myTest = test; - console.log('check module'); + forkEnds = function() { + if (--semaphore === 0) { + return myTest.done(); + } + }; return function(err, obj) { - console.log('db answered'); - myTest.strictEqual(mod, obj, "Module does not equal the expected one"); + myTest.strictEqual(mod, obj, "Invoker " + modname + " does not equal the expected one"); + _this.db.deleteActionInvoker(modname); return forkEnds(); }; }; - fCheckSetEntries = function(err, obj) { - test.ok(__indexOf.call(obj, action1name) >= 0 && __indexOf.call(obj, action2name) >= 0, 'Not all action module Ids in set'); - console.log('setentries fetched'); - this.db.getActionModule(action1name, fCheckModule(action1)); - return this.db.getActionModule(action2name, fCheckModule(action2)); + _this.db.storeActionInvoker(action1name, action1); + _this.db.storeActionInvoker(action2name, action2); + return _this.db.getActionInvokerIds(function(err, obj) { + test.ok(__indexOf.call(obj, action1name) >= 0 && __indexOf.call(obj, action2name) >= 0, 'Not all action invoker Ids in set'); + _this.db.getActionInvoker(action1name, fCheckInvoker(action1name, action1)); + return _this.db.getActionInvoker(action2name, fCheckInvoker(action2name, action2)); + }); + } + }; + + exports.action_invoker_params = { + testCreateAndRead: function(test) { + var actionId, params, userId; + test.expect(2); + userId = 'tester1'; + actionId = 'test-action-invoker_1'; + params = 'shouldn\'t this be an object?'; + _this.db.storeActionParams(actionId, userId, params); + return _this.db.getActionParamsIds(function(err, obj) { + var _ref; + test.ok((_ref = actionId + ':' + userId, __indexOf.call(obj, _ref) >= 0), 'Expected key not in action-params set'); + return _this.db.getActionParams(actionId, userId, function(err, obj) { + test.strictEqual(obj, params, 'Retrieved action params is not what we expected'); + _this.db.deleteActionParams(actionId, userId); + return test.done(); + }); + }); + }, + testUpdate: function(test) { + var actionId, params, paramsNew, userId; + test.expect(1); + userId = 'tester1'; + actionId = 'test-action-invoker_1'; + params = 'shouldn\'t this be an object?'; + paramsNew = 'shouldn\'t this be a new object?'; + _this.db.storeActionParams(actionId, userId, params); + _this.db.storeActionParams(actionId, userId, paramsNew); + return _this.db.getActionParams(actionId, userId, function(err, obj) { + test.strictEqual(obj, paramsNew, 'Retrieved action params is not what we expected'); + _this.db.deleteActionParams(actionId, userId); + return test.done(); + }); + }, + testDelete: function(test) { + var actionId, params, userId; + test.expect(2); + userId = 'tester1'; + actionId = 'test-action-invoker_1'; + params = 'shouldn\'t this be an object?'; + _this.db.storeActionParams(actionId, userId, params); + _this.db.deleteActionParams(actionId, userId); + return _this.db.getActionParams(actionId, userId, function(err, obj) { + test.strictEqual(obj, null, 'Action params still exists'); + return _this.db.getActionParamsIds(function(err, obj) { + var _ref; + test.ok((_ref = actionId + ':' + userId, __indexOf.call(obj, _ref) < 0), 'Action Params key still exists in set'); + return test.done(); + }); + }); + } + }; + + exports.event_poller = { + testCreateAndRead: function(test) { + var event, id; + test.expect(3); + id = 'test-event-poller'; + event = 'unit-test event poller content'; + _this.db.storeEventPoller(id, event); + return _this.db.getEventPollerIds(function(err, obj) { + test.ok(__indexOf.call(obj, id) >= 0, 'Expected key not in event-pollers set'); + return _this.db.getEventPoller(id, function(err, obj) { + test.strictEqual(obj, event, 'Retrieved Event Poller is not what we expected'); + return _this.db.getEventPollers(function(err, obj) { + test.deepEqual(event, obj[id], 'Event Poller ist not in result set'); + _this.db.deleteEventPoller(id); + return test.done(); + }); + }); + }); + }, + testUpdate: function(test) { + var event, eventNew, id; + test.expect(2); + id = 'test-event-poller'; + event = 'unit-test event poller content'; + eventNew = 'unit-test event poller new content'; + _this.db.storeEventPoller(id, event); + _this.db.storeEventPoller(id, eventNew); + return _this.db.getEventPoller(id, function(err, obj) { + test.strictEqual(obj, eventNew, 'Retrieved Event Poller is not what we expected'); + return _this.db.getEventPollers(function(err, obj) { + test.deepEqual(eventNew, obj[id], 'Event Poller ist not in result set'); + _this.db.deleteEventPoller(id); + return test.done(); + }); + }); + }, + testDelete: function(test) { + var event, id; + test.expect(2); + id = 'test-event-poller'; + event = 'unit-test event poller content'; + _this.db.storeEventPoller(id, event); + _this.db.deleteEventPoller(id); + return _this.db.getEventPoller(id, function(err, obj) { + test.strictEqual(obj, null, 'Event Poller still exists'); + return _this.db.getEventPollerIds(function(err, obj) { + test.ok(__indexOf.call(obj, id) < 0, 'Event Poller key still exists in set'); + return test.done(); + }); + }); + }, + testFetchSeveral: function(test) { + var event1, event1name, event2, event2name, fCheckPoller, semaphore; + test.expect(3); + semaphore = 2; + event1name = 'test-event-poller_1'; + event2name = 'test-event-poller_2'; + event1 = 'unit-test event poller 1 content'; + event2 = 'unit-test event poller 2 content'; + fCheckPoller = function(modname, mod) { + var forkEnds, myTest; + myTest = test; + forkEnds = function() { + if (--semaphore === 0) { + return myTest.done(); + } + }; + return function(err, obj) { + myTest.strictEqual(mod, obj, "Invoker " + modname + " does not equal the expected one"); + _this.db.deleteEventPoller(modname); + return forkEnds(); + }; }; - _this.db.storeActionModule(action1name, action1); - _this.db.storeActionModule(action2name, action2); - return _this.db.getActionModuleIds(fCheckSetEntries); + _this.db.storeEventPoller(event1name, event1); + _this.db.storeEventPoller(event2name, event2); + return _this.db.getEventPollerIds(function(err, obj) { + test.ok(__indexOf.call(obj, event1name) >= 0 && __indexOf.call(obj, event2name) >= 0, 'Not all event poller Ids in set'); + _this.db.getEventPoller(event1name, fCheckPoller(event1name, event1)); + return _this.db.getEventPoller(event2name, fCheckPoller(event2name, event2)); + }); + } + }; + + exports.event_poller_params = { + testCreateAndRead: function(test) { + var eventId, params, userId; + test.expect(2); + userId = 'tester1'; + eventId = 'test-event-poller_1'; + params = 'shouldn\'t this be an object?'; + _this.db.storeEventParams(eventId, userId, params); + return _this.db.getEventParamsIds(function(err, obj) { + var _ref; + test.ok((_ref = eventId + ':' + userId, __indexOf.call(obj, _ref) >= 0), 'Expected key not in event-params set'); + return _this.db.getEventParams(eventId, userId, function(err, obj) { + test.strictEqual(obj, params, 'Retrieved event params is not what we expected'); + _this.db.deleteEventParams(eventId, userId); + return test.done(); + }); + }); + }, + testUpdate: function(test) { + var eventId, params, paramsNew, userId; + test.expect(1); + userId = 'tester1'; + eventId = 'test-event-poller_1'; + params = 'shouldn\'t this be an object?'; + paramsNew = 'shouldn\'t this be a new object?'; + _this.db.storeEventParams(eventId, userId, params); + _this.db.storeEventParams(eventId, userId, paramsNew); + return _this.db.getEventParams(eventId, userId, function(err, obj) { + test.strictEqual(obj, paramsNew, 'Retrieved event params is not what we expected'); + _this.db.deleteEventParams(eventId, userId); + return test.done(); + }); + }, + testDelete: function(test) { + var eventId, params, userId; + test.expect(2); + userId = 'tester1'; + eventId = 'test-event-poller_1'; + params = 'shouldn\'t this be an object?'; + _this.db.storeEventParams(eventId, userId, params); + _this.db.deleteEventParams(eventId, userId); + return _this.db.getEventParams(eventId, userId, function(err, obj) { + test.strictEqual(obj, null, 'Event params still exists'); + return _this.db.getEventParamsIds(function(err, obj) { + var _ref; + test.ok((_ref = eventId + ':' + userId, __indexOf.call(obj, _ref) < 0), 'Event Params key still exists in set'); + return test.done(); + }); + }); + } + }; + + exports.rules = { + setUp: function(cb) { + _this.db({ + logType: 1 + }); + _this.userId = 'tester-1'; + _this.ruleId = 'test-rule_1'; + _this.rule = { + "id": "rule_id", + "event": "custom", + "condition": { + "property": "yourValue" + }, + "actions": [] + }; + _this.ruleNew = { + "id": "rule_new", + "event": "custom", + "condition": { + "property": "yourValue" + }, + "actions": [] + }; + return cb(); + }, + tearDown: function(cb) { + _this.db.deleteRule(_this.ruleId); + return cb(); + }, + testCreateAndRead: function(test) { + test.expect(3); + _this.db.storeRule(_this.ruleId, JSON.stringify(_this.rule)); + return _this.db.getRuleIds(function(err, obj) { + var _ref; + test.ok((_ref = _this.ruleId, __indexOf.call(obj, _ref) >= 0), 'Expected key not in rule key set'); + return _this.db.getRule(_this.ruleId, function(err, obj) { + test.deepEqual(JSON.parse(obj), _this.rule, 'Retrieved rule is not what we expected'); + return _this.db.getRules(function(err, obj) { + test.deepEqual(_this.rule, JSON.parse(obj[_this.ruleId]), 'Rule not in result set'); + _this.db.deleteRule(_this.ruleId); + return test.done(); + }); + }); + }); + }, + testUpdate: function(test) { + test.expect(1); + _this.db.storeRule(_this.ruleId, JSON.stringify(_this.rule)); + _this.db.storeRule(_this.ruleId, JSON.stringify(_this.ruleNew)); + return _this.db.getRule(_this.ruleId, function(err, obj) { + test.deepEqual(JSON.parse(obj), _this.ruleNew, 'Retrieved rule is not what we expected'); + _this.db.deleteRule(_this.ruleId); + return test.done(); + }); + }, + testDelete: function(test) { + test.expect(2); + _this.db.storeRule(_this.ruleId, JSON.stringify(_this.rule)); + _this.db.deleteRule(_this.ruleId); + return _this.db.getRule(_this.ruleId, function(err, obj) { + test.strictEqual(obj, null, 'Rule still exists'); + return _this.db.getRuleIds(function(err, obj) { + var _ref; + test.ok((_ref = _this.ruleId, __indexOf.call(obj, _ref) < 0), 'Rule key still exists in set'); + return test.done(); + }); + }); + }, + testLink: function(test) { + test.expect(2); + _this.db.linkRule(_this.ruleId, _this.userId); + return _this.db.getRuleLinkedUsers(_this.ruleId, function(err, obj) { + var _ref; + test.ok((_ref = _this.userId, __indexOf.call(obj, _ref) >= 0), "Rule not linked to user " + _this.userId); + return _this.db.getUserLinkedRules(_this.userId, function(err, obj) { + var _ref1; + test.ok((_ref1 = _this.ruleId, __indexOf.call(obj, _ref1) >= 0), "User not linked to rule " + _this.ruleId); + return test.done(); + }); + }); + }, + testUnlink: function(test) { + test.expect(2); + _this.db.linkRule(_this.ruleId, _this.userId); + _this.db.unlinkRule(_this.ruleId, _this.userId); + return _this.db.getRuleLinkedUsers(_this.ruleId, function(err, obj) { + var _ref; + test.ok((_ref = _this.userId, __indexOf.call(obj, _ref) < 0), "Rule still linked to user " + _this.userId); + return _this.db.getUserLinkedRules(_this.userId, function(err, obj) { + var _ref1; + test.ok((_ref1 = _this.ruleId, __indexOf.call(obj, _ref1) < 0), "User still linked to rule " + _this.ruleId); + return test.done(); + }); + }); + }, + testActivate: function(test) { + var usr; + test.expect(3); + usr = { + username: "tester-1", + password: "tester-1" + }; + _this.db.storeUser(usr); + _this.db.activateRule(_this.ruleId, _this.userId); + return _this.db.getRuleActivatedUsers(_this.ruleId, function(err, obj) { + var _ref; + test.ok((_ref = _this.userId, __indexOf.call(obj, _ref) >= 0), "Rule not activated for user " + _this.userId); + return _this.db.getUserActivatedRules(_this.userId, function(err, obj) { + var _ref1; + test.ok((_ref1 = _this.ruleId, __indexOf.call(obj, _ref1) >= 0), "User not activated for rule " + _this.ruleId); + return _this.db.getAllActivatedRuleIdsPerUser(function(err, obj) { + var _ref2; + test.ok(obj[_this.userId], "User not found in activated set"); + test.ok((_ref2 = _this.ruleId, __indexOf.call(obj[_this.userId], _ref2) >= 0), "Rule " + _this.ruleId + " not in activated rules set"); + return test.done(); + }); + }); + }); + }, + testDeactivate: function(test) { + test.expect(3); + _this.db.activateRule(_this.ruleId, _this.userId); + _this.db.deactivateRule(_this.ruleId, _this.userId); + return _this.db.getRuleActivatedUsers(_this.ruleId, function(err, obj) { + var _ref; + test.ok((_ref = _this.userId, __indexOf.call(obj, _ref) < 0), "Rule still activated for user " + _this.userId); + return _this.db.getUserActivatedRules(_this.userId, function(err, obj) { + var _ref1; + test.ok((_ref1 = _this.ruleId, __indexOf.call(obj, _ref1) < 0), "User still activated for rule " + _this.ruleId); + return _this.db.getAllActivatedRuleIdsPerUser(function(err, obj) { + var _ref2; + test.ok((_ref2 = _this.ruleId, __indexOf.call(obj[_this.userId], _ref2) < 0), "Rule " + _this.ruleId + " still in activated rules set"); + return test.done(); + }); + }); + }); + }, + testUnlinkAndDeactivateAfterDeletion: function(test) { + var fWaitForDeletion, fWaitForTest; + test.expect(2); + _this.db.storeRule(_this.ruleId, JSON.stringify(_this.rule)); + _this.db.linkRule(_this.ruleId, _this.userId); + _this.db.activateRule(_this.ruleId, _this.userId); + fWaitForTest = function() { + return _this.db.getUserLinkedRules(_this.userId, function(err, obj) { + var _ref; + test.ok((_ref = _this.ruleId, __indexOf.call(obj, _ref) < 0), "Rule " + _this.ruleId + " still linked to user " + _this.userId); + return _this.db.getUserActivatedRules(_this.userId, function(err, obj) { + var _ref1; + test.ok((_ref1 = _this.ruleId, __indexOf.call(obj, _ref1) < 0), "Rule " + _this.ruleId + " still activated for user " + _this.userId); + return test.done(); + }); + }); + }; + fWaitForDeletion = function() { + _this.db.deleteRule(_this.ruleId); + return setTimeout(fWaitForTest, 100); + }; + return setTimeout(fWaitForDeletion, 100); } }; diff --git a/testing/test_config.coffee b/testing/test_config.coffee index bbafbc3..2e853c5 100644 --- a/testing/test_config.coffee +++ b/testing/test_config.coffee @@ -22,7 +22,7 @@ exports.testParameters = ( test ) => exports.testDifferentConfigFile = ( test ) => test.expect 1 @conf - configPath: 'testing/jsonWrongConfig.json' + configPath: path.join 'testing', 'files', 'jsonWrongConfig.json' test.ok @conf.isReady(), 'Different path not loaded!' test.done() diff --git a/testing/test_db_interface.coffee b/testing/test_db_interface.coffee index 90a7be3..00a5198 100644 --- a/testing/test_db_interface.coffee +++ b/testing/test_db_interface.coffee @@ -1,6 +1,5 @@ exports.setUp = ( cb ) => - @log = require '../js-coffee/logging' @db = require '../js-coffee/db_interface' @db logType: 2 cb() @@ -8,17 +7,20 @@ exports.setUp = ( cb ) => exports.availability = testRequire: ( test ) => test.expect 1 + test.ok @db, 'DB interface loaded' test.done() testConnect: ( test ) => test.expect 1 + @db.isConnected ( err ) -> test.ifError err, 'Connection failed!' test.done() testNoConfig: ( test ) => test.expect 1 + @db configPath: 'nonexistingconf.file' @db.isConnected ( err ) -> @@ -27,16 +29,18 @@ exports.availability = testWrongConfig: ( test ) => test.expect 1 + @db { configPath: 'testing/jsonWrongConfig.json' } @db.isConnected ( err ) -> test.ok err, 'Still connected!?' test.done() testPurgeQueue: ( test ) => + test.expect 2 + evt = eventid: '1' event: 'mail' - test.expect 2 @db.pushEvent evt @db.purgeEventQueue() @db.popEvent ( err, obj ) => @@ -57,30 +61,41 @@ exports.events = testEmptyPopping: ( test ) => test.expect 2 + @db.popEvent ( err, obj ) => - test.ifError err, 'Error during pop after purging!' - test.strictEqual obj, null, 'There was an event in the queue!?' + test.ifError err, + 'Error during pop after purging!' + test.strictEqual obj, null, + 'There was an event in the queue!?' test.done() testEmptyPushing: ( test ) => test.expect 2 + @db.pushEvent null @db.popEvent ( err, obj ) => - test.ifError err, 'Error during non-empty pushing!' - test.strictEqual obj, null, 'There was an event in the queue!?' + test.ifError err, + 'Error during non-empty pushing!' + test.strictEqual obj, null, + 'There was an event in the queue!?' test.done() testNonEmptyPopping: ( test ) => test.expect 3 + @db.pushEvent @evt1 @db.popEvent ( err, obj ) => - test.ifError err, 'Error during non-empty popping!' - test.notStrictEqual obj, null, 'There was no event in the queue!' - test.deepEqual @evt1, obj, 'Wrong event in queue!' + test.ifError err, + 'Error during non-empty popping!' + test.notStrictEqual obj, null, + 'There was no event in the queue!' + test.deepEqual @evt1, obj, + 'Wrong event in queue!' test.done() testMultiplePushAndPops: ( test ) => test.expect 6 + semaphore = 2 forkEnds = () -> test.done() if --semaphore is 0 @@ -89,109 +104,548 @@ exports.events = @db.pushEvent @evt2 # eventually it would be wise to not care about the order of events @db.popEvent ( err, obj ) => - test.ifError err, 'Error during multiple push and pop!' - test.notStrictEqual obj, null, 'There was no event in the queue!' - test.deepEqual @evt1, obj, 'Wrong event in queue!' + test.ifError err, + 'Error during multiple push and pop!' + test.notStrictEqual obj, null, + 'There was no event in the queue!' + test.deepEqual @evt1, obj, + 'Wrong event in queue!' forkEnds() @db.popEvent ( err, obj ) => - test.ifError err, 'Error during multiple push and pop!' - test.notStrictEqual obj, null, 'There was no event in the queue!' - test.deepEqual @evt2, obj, 'Wrong event in queue!' + test.ifError err, + 'Error during multiple push and pop!' + test.notStrictEqual obj, null, + 'There was no event in the queue!' + test.deepEqual @evt2, obj, + 'Wrong event in queue!' forkEnds() -exports.action_modules = - # setUp: ( cb ) => - # @db logType: 1 - # cb() - - testModule: ( test ) => - test.expect 4 - action1name = 'test-action-module_1' - action1 = 'unit-test action module 1 content' - - fCheckSetEntry = ( err , obj ) => - test.ok action1name in obj, 'Expected key not in action-modules set' - @db.getActionModule action1name, fCheckModuleExists - - fCheckModuleExists = ( err , obj ) => - test.strictEqual obj, action1, 'Retrieved Action Module is not what we expected' - @log.print 'delete action module' - @db.deleteActionModule action1name - @log.print 'tried to delete action module' - @db.getActionModule action1name, fCheckModuleNotExists - - fCheckModuleNotExists = ( err , obj ) => - @log.print 'got action module' - test.strictEqual obj, null, 'Action module still exists' - @log.print 'compared action module' - @db.getActionModuleIds fCheckModuleNotExistsInSet - - fCheckModuleNotExistsInSet = ( err , obj ) => - test.ok action1name not in obj, 'Action module key still exists in set' - test.done() - - @db.storeActionModule action1name, action1 - @db.getActionModuleIds fCheckSetEntry - - testFetchSeveralModules: ( test ) => - semaphore = 2 - +exports.action_invoker = + testCreateAndRead: ( test ) => test.expect 3 - action1name = 'test-action-module_1' - action2name = 'test-action-module_2' - action1 = 'unit-test action module 1 content' - action2 = 'unit-test action module 2 content' - fCheckModule = ( mod ) -> + id = 'test-action-invoker' + action = 'unit-test action invoker content' + + # store an entry to start with + @db.storeActionInvoker id, action + + # test that the ID shows up in the set + @db.getActionInvokerIds ( err , obj ) => + test.ok id in obj, + 'Expected key not in action-invokers set' + + # the retrieved object really is the one we expected + @db.getActionInvoker id, ( err , obj ) => + test.strictEqual obj, action, + 'Retrieved Action Invoker is not what we expected' + + # Ensure the action invoker is in the list of all existing ones + @db.getActionInvokers ( err , obj ) => + test.deepEqual action, obj[id], + 'Action Invoker ist not in result set' + @db.deleteActionInvoker id + test.done() + + testUpdate: ( test ) => + test.expect 2 + + id = 'test-action-invoker' + action = 'unit-test action invoker content' + actionNew = 'unit-test action invoker new content' + + # store an entry to start with + @db.storeActionInvoker id, action + @db.storeActionInvoker id, actionNew + + # the retrieved object really is the one we expected + @db.getActionInvoker id, ( err , obj ) => + test.strictEqual obj, actionNew, + 'Retrieved Action Invoker is not what we expected' + + # Ensure the action invoker is in the list of all existing ones + @db.getActionInvokers ( err , obj ) => + test.deepEqual actionNew, obj[id], + 'Action Invoker ist not in result set' + @db.deleteActionInvoker id + test.done() + + testDelete: ( test ) => + test.expect 2 + + id = 'test-action-invoker' + action = 'unit-test action invoker content' + + # store an entry to start with + @db.storeActionInvoker id, action + + # Ensure the action invoker has been deleted + @db.deleteActionInvoker id + @db.getActionInvoker id, ( err , obj ) => + test.strictEqual obj, null, + 'Action Invoker still exists' + + # Ensure the ID has been removed from the set + @db.getActionInvokerIds ( err , obj ) => + test.ok id not in obj, + 'Action Invoker key still exists in set' + test.done() + + + testFetchSeveral: ( test ) => + test.expect 3 + + semaphore = 2 + action1name = 'test-action-invoker_1' + action2name = 'test-action-invoker_2' + action1 = 'unit-test action invoker 1 content' + action2 = 'unit-test action invoker 2 content' + + fCheckInvoker = ( modname, mod ) => myTest = test - sem = semaphore forkEnds = () -> - console.log 'fork ends' - myTest.done() if --sem is 0 - console.log 'check module' - ( err, obj ) -> - console.log 'db answered' - myTest.strictEqual mod, obj, "Module does not equal the expected one" + myTest.done() if --semaphore is 0 + ( err, obj ) => + myTest.strictEqual mod, obj, + "Invoker #{ modname } does not equal the expected one" + @db.deleteActionInvoker modname forkEnds() - fCheckSetEntries = ( err, obj ) -> - test.ok action1name in obj and action2name in obj, 'Not all action module Ids in set' - console.log 'setentries fetched' - @db.getActionModule action1name, fCheckModule(action1) - @db.getActionModule action2name, fCheckModule(action2) - - @db.storeActionModule action1name, action1 - @db.storeActionModule action2name, action2 - @db.getActionModuleIds fCheckSetEntries + @db.storeActionInvoker action1name, action1 + @db.storeActionInvoker action2name, action2 + @db.getActionInvokerIds ( err, obj ) => + test.ok action1name in obj and action2name in obj, + 'Not all action invoker Ids in set' + @db.getActionInvoker action1name, fCheckInvoker action1name, action1 + @db.getActionInvoker action2name, fCheckInvoker action2name, action2 -# testFetchModules: ( test ) => -# test.expect 0 -# test.done() +exports.action_invoker_params = + testCreateAndRead: ( test ) => + test.expect 2 -# testStoreParams: ( test ) => -# test.expect 0 -# test.done() + userId = 'tester1' + actionId = 'test-action-invoker_1' + params = 'shouldn\'t this be an object?' -# testFetchParams: ( test ) => -# test.expect 0 -# test.done() + # store an entry to start with + @db.storeActionParams actionId, userId, params + + # test that the ID shows up in the set + @db.getActionParamsIds ( err, obj ) => + test.ok actionId+':'+userId in obj, + 'Expected key not in action-params set' + + # the retrieved object really is the one we expected + @db.getActionParams actionId, userId, ( err, obj ) => + test.strictEqual obj, params, + 'Retrieved action params is not what we expected' + @db.deleteActionParams actionId, userId + test.done() -# exports.event_modules = -# test: ( test ) => -# test.expect 0 -# test.done() + testUpdate: ( test ) => + test.expect 1 + + userId = 'tester1' + actionId = 'test-action-invoker_1' + params = 'shouldn\'t this be an object?' + paramsNew = 'shouldn\'t this be a new object?' + + # store an entry to start with + @db.storeActionParams actionId, userId, params + @db.storeActionParams actionId, userId, paramsNew + + # the retrieved object really is the one we expected + @db.getActionParams actionId, userId, ( err, obj ) => + test.strictEqual obj, paramsNew, + 'Retrieved action params is not what we expected' + @db.deleteActionParams actionId, userId + test.done() + + testDelete: ( test ) => + test.expect 2 + + userId = 'tester1' + actionId = 'test-action-invoker_1' + params = 'shouldn\'t this be an object?' + + # store an entry to start with and delte it right away + @db.storeActionParams actionId, userId, params + @db.deleteActionParams actionId, userId + + # Ensure the action params have been deleted + @db.getActionParams actionId, userId, ( err, obj ) => + test.strictEqual obj, null, + 'Action params still exists' + # Ensure the ID has been removed from the set + @db.getActionParamsIds ( err, obj ) => + test.ok actionId+':'+userId not in obj, + 'Action Params key still exists in set' + test.done() -# exports.rules = -# test: ( test ) => -# test.expect 0 -# test.done() +exports.event_poller = + testCreateAndRead: ( test ) => + test.expect 3 + + id = 'test-event-poller' + event = 'unit-test event poller content' + + # store an entry to start with + @db.storeEventPoller id, event + + # test that the ID shows up in the set + @db.getEventPollerIds ( err , obj ) => + test.ok id in obj, + 'Expected key not in event-pollers set' + + # the retrieved object really is the one we expected + @db.getEventPoller id, ( err , obj ) => + test.strictEqual obj, event, + 'Retrieved Event Poller is not what we expected' + + # Ensure the event poller is in the list of all existing ones + @db.getEventPollers ( err , obj ) => + test.deepEqual event, obj[id], + 'Event Poller ist not in result set' + @db.deleteEventPoller id + test.done() + + testUpdate: ( test ) => + test.expect 2 + + id = 'test-event-poller' + event = 'unit-test event poller content' + eventNew = 'unit-test event poller new content' + + # store an entry to start with + @db.storeEventPoller id, event + @db.storeEventPoller id, eventNew + + # the retrieved object really is the one we expected + @db.getEventPoller id, ( err , obj ) => + test.strictEqual obj, eventNew, + 'Retrieved Event Poller is not what we expected' + + # Ensure the event poller is in the list of all existing ones + @db.getEventPollers ( err , obj ) => + test.deepEqual eventNew, obj[id], + 'Event Poller ist not in result set' + @db.deleteEventPoller id + test.done() + + testDelete: ( test ) => + test.expect 2 + + id = 'test-event-poller' + event = 'unit-test event poller content' + + # store an entry to start with + @db.storeEventPoller id, event + + # Ensure the event poller has been deleted + @db.deleteEventPoller id + @db.getEventPoller id, ( err , obj ) => + test.strictEqual obj, null, + 'Event Poller still exists' + + # Ensure the ID has been removed from the set + @db.getEventPollerIds ( err , obj ) => + test.ok id not in obj, + 'Event Poller key still exists in set' + test.done() + + + testFetchSeveral: ( test ) => + test.expect 3 + + semaphore = 2 + event1name = 'test-event-poller_1' + event2name = 'test-event-poller_2' + event1 = 'unit-test event poller 1 content' + event2 = 'unit-test event poller 2 content' + + fCheckPoller = ( modname, mod ) => + myTest = test + forkEnds = () -> + myTest.done() if --semaphore is 0 + ( err, obj ) => + myTest.strictEqual mod, obj, + "Invoker #{ modname } does not equal the expected one" + @db.deleteEventPoller modname + forkEnds() + + @db.storeEventPoller event1name, event1 + @db.storeEventPoller event2name, event2 + @db.getEventPollerIds ( err, obj ) => + test.ok event1name in obj and event2name in obj, + 'Not all event poller Ids in set' + @db.getEventPoller event1name, fCheckPoller event1name, event1 + @db.getEventPoller event2name, fCheckPoller event2name, event2 + + +exports.event_poller_params = + testCreateAndRead: ( test ) => + test.expect 2 + + userId = 'tester1' + eventId = 'test-event-poller_1' + params = 'shouldn\'t this be an object?' + + # store an entry to start with + @db.storeEventParams eventId, userId, params + + # test that the ID shows up in the set + @db.getEventParamsIds ( err, obj ) => + test.ok eventId+':'+userId in obj, + 'Expected key not in event-params set' + + # the retrieved object really is the one we expected + @db.getEventParams eventId, userId, ( err, obj ) => + test.strictEqual obj, params, + 'Retrieved event params is not what we expected' + @db.deleteEventParams eventId, userId + test.done() + + testUpdate: ( test ) => + test.expect 1 + + userId = 'tester1' + eventId = 'test-event-poller_1' + params = 'shouldn\'t this be an object?' + paramsNew = 'shouldn\'t this be a new object?' + + # store an entry to start with + @db.storeEventParams eventId, userId, params + @db.storeEventParams eventId, userId, paramsNew + + # the retrieved object really is the one we expected + @db.getEventParams eventId, userId, ( err, obj ) => + test.strictEqual obj, paramsNew, + 'Retrieved event params is not what we expected' + @db.deleteEventParams eventId, userId + test.done() + + testDelete: ( test ) => + test.expect 2 + + userId = 'tester1' + eventId = 'test-event-poller_1' + params = 'shouldn\'t this be an object?' + + # store an entry to start with and delete it right away + @db.storeEventParams eventId, userId, params + @db.deleteEventParams eventId, userId + + # Ensure the event params have been deleted + @db.getEventParams eventId, userId, ( err, obj ) => + test.strictEqual obj, null, + 'Event params still exists' + # Ensure the ID has been removed from the set + @db.getEventParamsIds ( err, obj ) => + test.ok eventId+':'+userId not in obj, + 'Event Params key still exists in set' + test.done() + + +exports.rules = + setUp: ( cb ) => + @db logType: 1 + @userId = 'tester-1' + @ruleId = 'test-rule_1' + @rule = + "id": "rule_id", + "event": "custom", + "condition": + "property": "yourValue", + "actions": [] + @ruleNew = + "id": "rule_new", + "event": "custom", + "condition": + "property": "yourValue", + "actions": [] + cb() + + tearDown: ( cb ) => + @db.deleteRule @ruleId + cb() + + testCreateAndRead: ( test ) => + test.expect 3 + + # store an entry to start with + @db.storeRule @ruleId, JSON.stringify(@rule) + + # test that the ID shows up in the set + @db.getRuleIds ( err, obj ) => + test.ok @ruleId in obj, + 'Expected key not in rule key set' + + # the retrieved object really is the one we expected + @db.getRule @ruleId, ( err, obj ) => + test.deepEqual JSON.parse(obj), @rule, + 'Retrieved rule is not what we expected' + + # Ensure the rule is in the list of all existing ones + @db.getRules ( err , obj ) => + test.deepEqual @rule, JSON.parse(obj[@ruleId]), + 'Rule not in result set' + @db.deleteRule @ruleId + test.done() + + testUpdate: ( test ) => + test.expect 1 + + # store an entry to start with + @db.storeRule @ruleId, JSON.stringify(@rule) + @db.storeRule @ruleId, JSON.stringify(@ruleNew) + + # the retrieved object really is the one we expected + @db.getRule @ruleId, ( err, obj ) => + test.deepEqual JSON.parse(obj), @ruleNew, + 'Retrieved rule is not what we expected' + @db.deleteRule @ruleId + test.done() + + testDelete: ( test ) => + test.expect 2 + + # store an entry to start with and delete it right away + @db.storeRule @ruleId, JSON.stringify(@rule) + @db.deleteRule @ruleId + + # Ensure the event params have been deleted + @db.getRule @ruleId, ( err, obj ) => + test.strictEqual obj, null, + 'Rule still exists' + + # Ensure the ID has been removed from the set + @db.getRuleIds ( err, obj ) => + test.ok @ruleId not in obj, + 'Rule key still exists in set' + test.done() + + testLink: ( test ) => + test.expect 2 + + # link a rule to the user + @db.linkRule @ruleId, @userId + + # Ensure the user is linked to the rule + @db.getRuleLinkedUsers @ruleId, ( err, obj ) => + test.ok @userId in obj, + "Rule not linked to user #{ @userId }" + + # Ensure the rule is linked to the user + @db.getUserLinkedRules @userId, ( err, obj ) => + test.ok @ruleId in obj, + "User not linked to rule #{ @ruleId }" + test.done() + + testUnlink: ( test ) => + test.expect 2 + + # link and unlink immediately afterwards + @db.linkRule @ruleId, @userId + @db.unlinkRule @ruleId, @userId + + # Ensure the user is linked to the rule + @db.getRuleLinkedUsers @ruleId, ( err, obj ) => + test.ok @userId not in obj, + "Rule still linked to user #{ @userId }" + + # Ensure the rule is linked to the user + @db.getUserLinkedRules @userId, ( err, obj ) => + test.ok @ruleId not in obj, + "User still linked to rule #{ @ruleId }" + test.done() + + testActivate: ( test ) => + test.expect 3 + + usr = + username: "tester-1" + password: "tester-1" + @db.storeUser usr + @db.activateRule @ruleId, @userId + # activate a rule for a user + + # Ensure the user is activated to the rule + @db.getRuleActivatedUsers @ruleId, ( err, obj ) => + test.ok @userId in obj, + "Rule not activated for user #{ @userId }" + + # Ensure the rule is linked to the user + @db.getUserActivatedRules @userId, ( err, obj ) => + test.ok @ruleId in obj, + "User not activated for rule #{ @ruleId }" + + # Ensure the rule is showing up in all active rules + @db.getAllActivatedRuleIdsPerUser ( err, obj ) => + test.ok obj[@userId], + "User not found in activated set" + test.ok @ruleId in obj[@userId], + "Rule #{ @ruleId } not in activated rules set" + test.done() + + testDeactivate: ( test ) => + test.expect 3 + + # store an entry to start with and link it to te user + @db.activateRule @ruleId, @userId + @db.deactivateRule @ruleId, @userId + + # Ensure the user is linked to the rule + @db.getRuleActivatedUsers @ruleId, ( err, obj ) => + test.ok @userId not in obj, + "Rule still activated for user #{ @userId }" + + # Ensure the rule is linked to the user + @db.getUserActivatedRules @userId, ( err, obj ) => + test.ok @ruleId not in obj, + "User still activated for rule #{ @ruleId }" + + # Ensure the rule is showing up in all active rules + @db.getAllActivatedRuleIdsPerUser ( err, obj ) => + test.ok @ruleId not in obj[@userId], + "Rule #{ @ruleId } still in activated rules set" + test.done() + + testUnlinkAndDeactivateAfterDeletion: ( test ) => + test.expect 2 + + # store an entry to start with and link it to te user + @db.storeRule @ruleId, JSON.stringify(@rule) + @db.linkRule @ruleId, @userId + @db.activateRule @ruleId, @userId + + # We need to wait here and there since these calls are asynchronous + fWaitForTest = () => + + # Ensure the user is unlinked to the rule + @db.getUserLinkedRules @userId, ( err, obj ) => + test.ok @ruleId not in obj, + "Rule #{ @ruleId } still linked to user #{ @userId }" + + # Ensure the rule is deactivated for the user + @db.getUserActivatedRules @userId, ( err, obj ) => + test.ok @ruleId not in obj, + "Rule #{ @ruleId } still activated for user #{ @userId }" + test.done() + + fWaitForDeletion = () => + @db.deleteRule @ruleId + setTimeout fWaitForTest, 100 + + setTimeout fWaitForDeletion, 100 + # exports.users = # test: ( test ) => # test.expect 0 # test.done() +# TODO on delete, remove all rules for the user if he's deleted exports.tearDown = ( cb ) => diff --git a/webpages/handlers/command_answer.html b/webpages/handlers/command_answer.html index 83eb5f1..00e1e55 100644 --- a/webpages/handlers/command_answer.html +++ b/webpages/handlers/command_answer.html @@ -12,5 +12,6 @@ {{message}}

+
\ No newline at end of file diff --git a/webpages/handlers/error.html b/webpages/handlers/error.html index fdd03cb..2c4f7fb 100644 --- a/webpages/handlers/error.html +++ b/webpages/handlers/error.html @@ -12,5 +12,6 @@ Error: {{message}}

+
\ No newline at end of file diff --git a/webpages/handlers/forge_modules.html b/webpages/handlers/forge_modules.html index 4ae8516..353c45b 100644 --- a/webpages/handlers/forge_modules.html +++ b/webpages/handlers/forge_modules.html @@ -73,6 +73,7 @@ exports.myOwnEventFunction = function( callback ) {

+
+ diff --git a/webpages/handlers/login.html b/webpages/handlers/login.html index 9b87db5..e3d9ebe 100644 --- a/webpages/handlers/login.html +++ b/webpages/handlers/login.html @@ -2,9 +2,11 @@ Login - + {{{head_requires}}} +
@@ -15,9 +17,10 @@
+
\ No newline at end of file diff --git a/webpages/handlers/push_event.html b/webpages/handlers/push_event.html index 0318075..36902e6 100644 --- a/webpages/handlers/push_event.html +++ b/webpages/handlers/push_event.html @@ -23,6 +23,7 @@

+