UNPKG

jive-sdk

Version:

Node.js SDK for Jive Software to assist with the development of add-ons

523 lines (418 loc) 16.1 kB
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <title>Jive SDK Source: jive-sdk-service/lib/definitionSetup.js</title> <!--[if lt IE 9]> <script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script> <![endif]--> <link type="text/css" rel="stylesheet" href="styles/sunlight.default.css"> <link type="text/css" rel="stylesheet" href="styles/site.spacelab.css"> </head> <body> <div class="container-fluid"> <div class="navbar navbar-fixed-top navbar-inverse"> <div class="navbar-inner"> <a class="brand" href="index.html">Jive SDK</a> <ul class="nav"> <li class="dropdown"> <a href="modules.list.html" class="dropdown-toggle" data-toggle="dropdown">Modules<b class="caret"></b></a> <ul class="dropdown-menu "> <li> <a href="module-abstractDefinitions.html">abstractDefinitions</a> </li> <li> <a href="module-abstractInstances.html">abstractInstances</a> </li> <li> <a href="module-addOnRoutes.html">addOnRoutes</a> </li> <li> <a href="module-api.html">api</a> </li> <li> <a href="module-community.html">community</a> </li> <li> <a href="module-constants.html">constants</a> </li> <li> <a href="module-devRoutes.html">devRoutes</a> </li> <li> <a href="module-events.html">events</a> </li> <li> <a href="module-extensions.html">extensions</a> </li> <li> <a href="module-extstreamsInstances.html">extstreamsInstances</a> </li> <li> <a href="module-jiveutil.html">jiveutil</a> </li> <li> <a href="module-oauthRoutes.html">oauthRoutes</a> </li> <li> <a href="module-request.html">request</a> </li> <li> <a href="module-security.html">security</a> </li> <li> <a href="module-service.html">service</a> </li> <li> <a href="module-tasks.html">tasks</a> </li> <li> <a href="module-tileInstances.html">tileInstances</a> </li> <li> <a href="module-tileRoutes.html">tileRoutes</a> </li> <li> <a href="module-tilesDefinitions.html">tilesDefinitions</a> </li> <li> <a href="module-webhooks.html">webhooks</a> </li> </ul> </li> <li class="dropdown"> <a href="classes.list.html" class="dropdown-toggle" data-toggle="dropdown">Classes<b class="caret"></b></a> <ul class="dropdown-menu "> <li> <a href="extstreamsDefinitions.html">extstreamsDefinitions</a> </li> <li> <a href="filePersistence.html">filePersistence</a> </li> <li> <a href="memoryPersistence.html">memoryPersistence</a> </li> <li> <a href="memoryScheduler.html">memoryScheduler</a> </li> <li> <a href="oauthHandler.html">oauthHandler</a> </li> </ul> </li> </ul> </div> </div> <div class="row-fluid"> <div class="span12"> <div id="main"> <h1 class="page-title">Source: jive-sdk-service/lib/definitionSetup.js</h1> <section> <article> <pre class="sunlight-highlight-javascript linenums">/* * Copyright 2013 Jive Software * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ var fs = require('fs'), q = require('q'), path = require('path'), jive = require('../api'), service = require('./service'); var express = require('express'); var consolidate = require('consolidate'); var baseSetup = require('./baseSetup'); var definitionSetup = Object.create(baseSetup); module.exports = definitionSetup; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Private function isValidFile(file ) { return !(file.indexOf('.') == 0) } function fsexists(path) { var deferred = q.defer(); var method = fs.exists ? fs.exists : require('path').exists; method( path, function(exists ) { deferred.resolve(exists); }); return deferred.promise; } var tileLifeCycleEvents = [ jive.constants.globalEventNames.NEW_INSTANCE, jive.constants.globalEventNames.INSTANCE_UPDATED, jive.constants.globalEventNames.INSTANCE_REMOVED ]; var tileDataPushEvents = [ jive.constants.globalEventNames.DATA_PUSHED, jive.constants.globalEventNames.ACTIVITY_PUSHED, jive.constants.globalEventNames.COMMENT_PUSHED ]; function buildHandlerFunction(handlerInfo) { if ( handlerInfo['globalListener'] ) { // if explicitly marked as a globalListener, then there are no conditions for handling, just pass it to the // event handler return handlerInfo['handler']; } else { // otherwise its a 'protected' handler return function(context, event ) { var definitionName = handlerInfo['definitionName']; var eventListener; if ( context['eventListener'] ) { eventListener = context['eventListener']; } else if ( event ) { if ( tileLifeCycleEvents.indexOf(event) > -1 ) { eventListener = context['name']; } if ( tileDataPushEvents.indexOf(event) > -1 ) { if ( context['theInstance'] ) { eventListener = context['theInstance']['name']; } } } if ( !eventListener || eventListener === definitionName ) { return handlerInfo['handler'](context); } } } } function tileDefinitionStupEventListener(handlerInfo, _definitionName, setupContext) { var definitionJson; if ( setupContext ) { definitionJson = setupContext['definitionJson']; } var definitionName = definitionJson ? definitionJson['name'] : _definitionName; handlerInfo['definitionName'] = definitionName; if (!handlerInfo['event']) { throw new Error('Event handler "' + definitionName + '" must specify an event name.'); } if (!handlerInfo['handler']) { throw new Error('Event handler "' + definitionName + '" must specify a function handler.'); } var eventListener = handlerInfo['eventListener'] || definitionName; if (jive.events.globalEvents.indexOf(handlerInfo['event']) != -1) { jive.events.registerEventListener(handlerInfo['event'], buildHandlerFunction(handlerInfo) ); } else { jive.events.registerEventListener( handlerInfo['event'], buildHandlerFunction(handlerInfo), { 'eventListener' : eventListener, 'description' : handlerInfo['description'] || 'Unique to definition' }); } } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////// // public /** * Returns a promise when defintion tasks, life cycle events, * and other things in the service directory have been processed. * @param definitionName * @param svcDir * @return {*} */ definitionSetup.setupDefinitionServices = function( app, definitionName, svcDir, definitionJson ) { ///////////////////////////////////////////////////// // apply definition specific tasks, life cycle events, etc. var next; if ( !definitionJson ) { // set it up var definitionLocation = require('path').dirname( svcDir ) + '/definition.json'; next = definitionSetup.setupDefinitionMetadata(definitionLocation); } else { next = q.resolve(definitionJson); } var setupContext = { 'definitionJson' : definitionJson }; return next.then( function(definition) { return definitionSetup.setupServices(app, definitionName, svcDir, tileDefinitionStupEventListener, setupContext ); }); }; /** * Returns a promise when all the routes have been calculated for a particular definition directory. */ definitionSetup.setupDefinitionRoutes = function(app, definitionName, routesPath){ return definitionSetup.setupRoutes( app, definitionName, routesPath ); }; definitionSetup.setupDefinitionMetadata = function(definitionPath) { // if a definition exists, read it from disk and save it return fsexists(definitionPath).then( function(exists) { if ( exists ) { return q.nfcall( fs.readFile, definitionPath).then( function(data ) { var definitionDirName = path.basename( path.dirname( definitionPath ) ); var definition = JSON.parse(data); definition.id = definition.id === '{{{definition_id}}}' ? null : definition.id; definition['definitionDirName'] = definitionDirName; return definition; }).then( function( definition ) { var apiToUse = definition['style'] === 'ACTIVITY' ? jive.extstreams.definitions : jive.tiles.definitions; return apiToUse.save(definition); }); } }); }; /** * Returns a promise for detecting when the definition directory has been autowired. * Assumes that the definintion directory is exactly the same as the definition name, eg.: * * /tiles/my-twitter-definition * * In this case the definition name is my-twitter-definition. * @param definitionDir */ definitionSetup.setupOneDefinition = function( app, definitionDir, definitionName ) { return q.nfcall( fs.stat, definitionDir ).then( function( stat ) { if ( stat.isDirectory() ) { definitionName = definitionName || (definitionDir.substring( definitionDir.lastIndexOf('/') + 1, definitionDir.length ) ); /// xxx todo this might not always work! use path var definitionPath = definitionDir + '/definition.json'; var routesPath = definitionDir + '/backend/routes'; var servicesPath = definitionDir + '/backend'; app.use( '/' + definitionName, express.static( definitionDir + '/public' ) ); // setup tile public directory var definitionApp = express(); definitionApp.engine('html', consolidate.mustache); definitionApp.set('view engine', 'html'); definitionApp.set('views', definitionDir + '/public'); app.use( definitionApp ); // if a definition exists, read it from disk and save it var definitionPromise = definitionSetup.setupDefinitionMetadata(definitionPath); // wire up service and routes return definitionPromise.then( function(definitionJson) { var promises = []; promises.push( fsexists(routesPath).then( function(exists) { if ( exists ) { return definitionSetup.setupDefinitionRoutes( definitionApp, definitionName, routesPath ); } })); promises.push( fsexists(definitionDir).then( function(exists) { if ( exists ) { return definitionSetup.setupDefinitionServices( app, definitionName, servicesPath, definitionJson ); } })); return q.all(promises); }); } else { return q.resolve(); } }).catch( function(e) { jive.logger.error("Failed to setup tile at " + definitionName + "; " + e.stack); process.exit(-1); }); }; /** * Autowires each definition discovered in the provided definitions directory. * @param definitionsRootDir * @return {*} */ definitionSetup.setupAllDefinitions = function( app, definitionsRootDir ) { return jive.util.fsexists( definitionsRootDir).then( function(exists) { if ( exists ) { return q.nfcall(fs.readdir, definitionsRootDir).then(function(dirContents){ return setupDefinitionsSequentially(app,definitionsRootDir, dirContents); }); } else { return q.resolve(); } }).then( function () { // make sure that all definitions in the db actually still exist var remove = function(libraryToUse) { return libraryToUse.findAll().then( function (allDefinitions) { var proms = []; allDefinitions.forEach(function (tile) { var definitionDir = tile['definitionDirName']; if ( definitionDir ) { proms.push( jive.util.fsexists( definitionsRootDir + '/' + definitionDir).then( function(exists) { return !exists ? libraryToUse.remove( tile['id']) : q.resolve(); }) ); } return q.resolve(); }); return q.all(proms); }); }; return remove( jive.tiles.definitions).then( function() { return remove( jive.extstreams.definitions ); }); }); }; /** * This will setup tiledefinition persistence by having one tile insert at a time. * Tested on jive-persistence-postgres and jive-persistence-mongo * @param app * @param definitionsRootDir * @param directoryContents * @returns {*} */ function setupDefinitionsSequentially(app,definitionsRootDir, directoryContents) { if (directoryContents.length == 0) { return q.resolve(); } else { var item = directoryContents.shift(); if (!isValidFile(item)) { return setupDefinitionsSequentially(app,definitionsRootDir, directoryContents); } var dirPath = definitionsRootDir + '/' + item; return definitionSetup.setupOneDefinition(app, dirPath) .then(function () { return setupDefinitionsSequentially(app,definitionsRootDir, directoryContents); }); } } </pre> </article> </section> </div> <div class="clearfix"></div> <footer> <span class="copyright"> Jive Software, Inc </span> <br /> <span class="jsdoc-message"> Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.3.0-dev</a> on Wed Jan 22 2014 12:29:37 GMT-0800 (PST) using the <a href="https://github.com/terryweiss/docstrap">DocStrap template</a>. </span> </footer> </div> <br clear="both"> </div> </div> <script src="scripts/sunlight.js"></script> <script src="scripts/sunlight.javascript.js"></script> <script src="scripts/sunlight-plugin.doclinks.js"></script> <script src="scripts/sunlight-plugin.linenumbers.js"></script> <script src="scripts/sunlight-plugin.menu.js"></script> <script src="scripts/jquery.min.js"></script> <script src="scripts/jquery.scrollTo.js"></script> <script src="scripts/jquery.localScroll.js"></script> <script src="scripts/bootstrap-dropdown.js"></script> <script src="scripts/toc.js"></script> <script> Sunlight.highlightAll({lineNumbers:true, showMenu: true, enableDoclinks :true}); </script> <script> $( function () { $( "#toc" ).toc( { selectors : "h1,h2,h3,h4", showAndHide : false, scrollTo : 60 } ); $( "#toc>ul" ).addClass( "nav nav-pills nav-stacked" ); $( "#main span[id^='toc']" ).addClass( "toc-shim" ); } ); </script> </body> </html>