<commit_before>/*
 * 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.
 */

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Private

var fs = require('fs');
var path = require('path');
var express = require('express');
var q = require('q');
var bootstrap = require('./bootstrap');
var definitionConfigurator = require('./definitionSetup');
var osAppConfigurator = require('./appSetup');
var serviceConfigurator = require('./serviceSetup');
var jive = require('../api');
var log4js = require('log4js');
var mustache = require('mustache');

var app;
var rootDir = process.cwd();
var tilesDir = rootDir + '/tiles';
var osAppsDir = rootDir + '/apps';
var cartridgesDir = rootDir + '/cartridges';
var storagesDir = rootDir + '/storages';

var _dir = function(theDir, defaultDir ) {
    theDir = theDir || defaultDir;

    if ( theDir.indexOf('/') == 0 ) {
        return rootDir + theDir;
    } else {
        return process.cwd() + '/' + theDir;
    }
};

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Public

/**
 * For managing jive communities registered with this service
 */
exports.community = jive.community;

/**
 * For managing service webhooks
 */
exports.webhooks = jive.webhooks;

/**
 * Configuration options
 */
exports.options = {};

var persistence;
/**
 * Retrieves or sets current persistence strategy, defaults to file.
 * @type {undefined}
 */
exports.persistence = function(_persistence) {

    if ( _persistence ) {
        // set persistence
        if ( !_persistence['find'] || !_persistence['findByID'] || !_persistence['remove'] || !_persistence['save'] ) {
            throw 'Unsupported persistence strategy - must implement find, findByID, remove, save methods.';
        }
        persistence = _persistence;
        jive.context['persistence'] = persistence;
    }

    // retrieve persistence
    return {
        save: function() {
            return persistence ? persistence.save(
                arguments.length > 0 ? arguments[0] : undefined,
                arguments.length > 1 ? arguments[1] : undefined,
                arguments.length > 2 ? arguments[2] : undefined,
                arguments.length > 3 ? arguments[3] : undefined,
                arguments.length > 4 ? arguments[4] : undefined,
                arguments.length > 5 ? arguments[5] : undefined
            ) : function() {
                return q.reject( new Error("persistence not defined") );
            }
        },

        find: function() {
            return persistence ? persistence.find(
                arguments.length > 0 ? arguments[0] : undefined,
                arguments.length > 1 ? arguments[1] : undefined,
                arguments.length > 2 ? arguments[2] : undefined,
                arguments.length > 3 ? arguments[3] : undefined,
                arguments.length > 4 ? arguments[4] : undefined,
                arguments.length > 5 ? arguments[5] : undefined
            ) : function() {
                return q.reject( new Error("persistence not defined") );
            }
        },

        findByID: function() {
            return persistence ? persistence.find(
                arguments.length > 0 ? arguments[0] : undefined,
                arguments.length > 1 ? arguments[1] : undefined,
                arguments.length > 2 ? arguments[2] : undefined,
                arguments.length > 3 ? arguments[3] : undefined,
                arguments.length > 4 ? arguments[4] : undefined,
                arguments.length > 5 ? arguments[5] : undefined
            ) : function() {
                return q.reject( new Error("persistence not defined") );
            }
        },

        remove: function() {
            return persistence ? persistence.remove(
                arguments.length > 0 ? arguments[0] : undefined,
                arguments.length > 1 ? arguments[1] : undefined,
                arguments.length > 2 ? arguments[2] : undefined,
                arguments.length > 3 ? arguments[3] : undefined,
                arguments.length > 4 ? arguments[4] : undefined,
                arguments.length > 5 ? arguments[5] : undefined
            ) : function() {
                return q.reject( new Error("persistence not defined") );
            }
        },

        close: function() {
            return persistence ? persistence.close() :  function() {
                return q.reject( new Error("persistence not defined") );
            }
        }
    }
};

var scheduler;
/**
 * Retrieves or sets the scheduling strategy. Defaults to memory (single node). todo
 * @param _scheduler
 * @returns {*}
 */
exports.scheduler = function( _scheduler ) {
    if ( _scheduler ) {
        if ( !_scheduler['schedule'] || !_scheduler['unschedule'] || !_scheduler['getTasks'] ) {
            throw 'Unsupported scheduler strategy - must implement schedule, unschedule, isScheduled, getTasks.';
        }
        scheduler = _scheduler;

        if ( !scheduler ) {
            scheduler = new jive.scheduler.memory();
        }
        jive.context.scheduler = scheduler;
    }
    scheduler = jive.context.scheduler;
    return scheduler;
};

/**
 * @param _app
 * @param options JSON or path to options file
 * @param definitionsToAutowire optional arraylist of tile names under [app root]/tiles to autowire
 */
exports.init = function(_app, options ) {
    if (_app) {
        app = _app;
    }
    else {
        app = express();
    }
    rootDir =  rootDir || process.cwd();
    tilesDir = rootDir + '/tiles';

    // for some reason this needs to be configured earlier than later
    app.use(express.bodyParser());
    app.use(express.logger('dev'));
    app.use(express.methodOverride());
    app.use(app.router);
    app.use(express.errorHandler());

    var applyDefaults = function(config) {
        if ( !config['persistence'] ) {
            config['persistence'] = 'file';
        }
        if ( !config['scheduler'] ) {
            config['scheduler'] = 'memory';
        }
    };

   var applyOverrides = function(config) {
        // override role
        var roleFromEnv = process.env['jive_sdk_service_role'];
        if ( roleFromEnv ) {
            config['role'] = roleFromEnv;
        }
    };

    var initialPromise;
    if ( typeof options === 'object' ) {
        applyDefaults(options);
        applyOverrides(options);
        exports.options = options;
        jive.context.config = exports.options;

        initialPromise = q.fcall( function() {
            return options;
        });
    } else {
        // if no options are provided, then try getting them from
        // cmd line arguments, or from environemnt
        if ( !options ) {
            var configFileFromEnv = process.env['jive_sdk_config_file'];
            var configFilePathFromArgs = undefined;

            process.argv.forEach(function (val, index, array) {
                if ( val.indexOf('=') > -1 ) {
                    var arg = val.split(/=/);

                    if ( arg[0] == 'configFile' ) {
                        jive.logger.debug("Command line argument:"  + arg[0] + "=" + arg[1]);
                        configFilePathFromArgs = arg[1];
                    }
                }
            });

            options = configFilePathFromArgs || configFileFromEnv;

            if( !options ) {
                // assume its a file in the rootdir
                options = rootDir + "/jiveclientconfiguration.json";
            }
        }

        initialPromise = q.nfcall( fs.readFile, options, 'utf8').then( function (data) {
            var jiveConfig = JSON.parse(data);
            applyDefaults(jiveConfig);
            applyOverrides(jiveConfig);

            exports.options = jiveConfig;
            jive.context.config = exports.options;

            jive.logger.debug('Startup configuration from', options);
            jive.logger.debug(jiveConfig);

            return jiveConfig;
        });
    }

    return initialPromise
            .then(initLogger)
            .then(initPersistence)
            .then(initScheduler);
};

function initLogger(options) {
    var logfile = options['logFile'] || options['logfile'];
    var logLevel = process.env['jive_logging_level'] || options['logLevel'] || options['loglevel'] || 'INFO';
    logLevel = logLevel.toUpperCase();

    if (logfile) {
        if (logfile.indexOf('logs/') === 0) {
            if (!fs.existsSync('logs')) {
                jive.logger.warn('logs subdirectory does not exist. Creating directory now.');
                fs.mkdirSync('logs');
            }
        }
        log4js.loadAppender('file');
        log4js.addAppender(log4js.appenders.file(logfile), 'jive-sdk');
    }

    jive.logger.setLevel(logLevel);

    return options;
}

function initPersistence(options) {
    var persistence = options['persistence'];
    if ( typeof persistence === 'object' ) {
        // set persistence if the object is provided
        exports.persistence( options['persistence'] );
    }
    else if ( typeof persistence === 'string' ) {
        //If a string is provided, and it's a valid type exported in jive.persistence, then use that.
        if (jive.persistence[persistence]) {
            exports.persistence(new jive.persistence[persistence](options)); //pass options, such as location of DB for mongoDB.
        }
        else {
            jive.logger.warn('Invalid persistence option given "' + persistence + '". Must be one of ' + Object.keys(jive.persistence));
            jive.logger.warn('Defaulting to file persistence');
        }
    }
    return options;
}

function initScheduler(options) {
    var scheduler = options['scheduler'];
    if ( typeof scheduler === 'object' ) {
        // set scheduler if the object is provided
        exports.scheduler(scheduler);
    }
    else if ( typeof scheduler === 'string' ) {
        //If a string is provided, and it's a valid type exported in jive.scheduler, then use that.
        if (jive.scheduler[scheduler]) {
            exports.scheduler(new jive.scheduler[scheduler](options)); //pass options, such as location of redis for Kue.
        }
        else {
            jive.logger.warn('Invalid scheduler option given "' + scheduler + '". Must be one of ' + Object.keys(jive.scheduler));
            jive.logger.warn('Defaulting to memory scheduler');
        }
    }
    return options;
}

/**
 *
 */
exports.autowire = function(definitionsToAutowire) {
    if( definitionsToAutowire ) {

        if (definitionsToAutowire['forEach'] ) {
            var promises = [];
            definitionsToAutowire.forEach( function( definition ) {
                promises.push( definitionConfigurator.setupOneDefinition(
                    app, _dir( '/tiles/' + definition), definition
                ) );
            });
            return q.all(promises);
        } else {
            return definitionConfigurator.setupOneDefinition(
                app, _dir( '/tiles/' + definitionsToAutowire), definitionsToAutowire
            );
        }
    } else {
        // assume autowiring everything
        return definitionConfigurator.setupAllDefinitions(app, _dir( '/tiles', '/tiles'))
        .then( function () {
            return osAppConfigurator.setupAllApps( app, _dir( '/apps', '/apps'));
        })
        .then( function () {
            return serviceConfigurator.setupAllServices( app, _dir( '/services', '/services'));
        })
        .then( function () {
            return serviceConfigurator.setupAllServices( app, _dir( '/storages', '/storages'));
        });
    }
};

/**
 * Autowire a routes directory for a given definition
 * @param definitionName
 * @param definitionRouteDirectory
 */
exports.autowireDefinitionRoutes = function( definitionName, definitionRouteDirectory ) {
    return definitionConfigurator.setupDefinitionRoutes(
        app, definitionName, _dir(definitionRouteDirectory, '/tiles/' + definitionName + '/routes' )
    );
};

/**
 * Autowire a services directory for a given definition
 * @param definitionName
 * @param definitionServicesDirectory
 */
exports.autowireDefinitionServices = function( definitionName, definitionServicesDirectory ) {
    return definitionConfigurator.setupDefinitionServices(
        definitionName, _dir( definitionServicesDirectory, '/tiles/' + definitionName + '/services' )
    );
};

/**
 * Autowire definition metadata file for a given definition
 * @param definitionMetadataFile
 */
exports.autowireDefinitionMetadata = function( definitionMetadataFile ) {
    return definitionConfigurator.setupDefinitionMetadata(definitionMetadataFile);
};

/**
 * Return promise - fail or succeed
 */
exports.start = function() {
    return bootstrap.start( app, exports.options, rootDir, tilesDir, osAppsDir, cartridgesDir, storagesDir).then( function() {
        jive.logger.info("Service started in " + app['settings']['env'] + " mode");
    });
};

/**
 * Computes the full service URL for this service, taking into account
 * jiveclientconfiguration.json (clientUrl & port)
 */
exports.serviceURL = function() {
    var conf = jive.service.options;
    var url = conf['clientUrl'];

    var port = conf['port'];
    if ( port && port != 443 && port != 80 ) {
        url += ':' + port;
    }

    return url;
};

/**
 * Public service routes
 */
exports.routes = {
    'tiles' : require('../routes/tiles'),
    'jive' : require('../routes/jive'),
    'dev' : require('../routes/dev'),
    'oauth' : require('../routes/oauth')
};

/**
 * Interrogate the role of this node
 */
exports.role = {
    'isWorker' : function() {
        return !exports.options['role'] || exports.options['role'] === jive.constants.roles.WORKER;
    },
    'isPusher' : function() {
        return !exports.options['role'] || exports.options['role'] === jive.constants.roles.PUSHER;
    },
    'isHttp' : function() {
        return !exports.options['role'] || exports.options['role'] === jive.constants.roles.HTTP_HANDLER;
    }
};

exports.extensions = function() {
    return require('./extension/extension');
};

exports.getExpandedTileDefinitions = function(all) {
    var conf = exports.options;
    var host = exports.serviceURL();
    var processed = [];

    all.forEach( function( tile ) {
        if ( !tile ) {
            return;
        }
        var name = tile.name;
        var stringified = JSON.stringify(tile);
        stringified =  mustache.render(stringified, {
            host: host,
            tile_public: host + '/' + name,
            tile_route: host + '/' + name,
            clientId: conf.clientId
        });

        var processedTile = JSON.parse(stringified);

        // defaults
        if ( !processedTile['published'] ) {
            processedTile['published'] = "2013-02-28T15:12:16.768-0800";
        }
        if ( !processedTile['updated'] ) {
            processedTile['updated'] = "2013-02-28T15:12:16.768-0800";
        }
        if ( processedTile['action'] ) {
            if ( processedTile['action'].indexOf('http') != 0 ) {
                // assume its relative to host then
                processedTile['action'] = host + ( processedTile['action'].indexOf('/') == 0 ? "" : "/" ) + processedTile['action'];
            }
        }
        if ( !processedTile['config'] ) {
            processedTile['config'] = host + '/' + processedTile['definitionDirName'] + '/configure';
        } else {
            if ( processedTile['config'].indexOf('http') != 0 ) {
                // assume its relative to host then
                processedTile['config'] = host + ( processedTile['config'].indexOf('/') == 0 ? "" : "/" ) + processedTile['config'];
            }
        }
        if ( !processedTile['register'] ) {
            processedTile['register'] = host + '/registration';
        } else {
            if ( processedTile['register'].indexOf('http') != 0 ) {
                // assume its relative to host then
                processedTile['register'] = host + ( processedTile['register'].indexOf('/') == 0 ? "" : "/" ) + processedTile['register'];
            }
        }
        if ( processedTile['unregister'] && processedTile['unregister'].indexOf('http') != 0 ) {
            // assume its relative to host then
            processedTile['unregister'] = host + ( processedTile['unregister'].indexOf('/') == 0 ? "" : "/" ) + processedTile['unregister'];
        }
        if ( !processedTile['client_id'] ) {
            processedTile['client_id'] = conf.clientId;
        }
        if ( !processedTile['id'] ) {
            processedTile['id'] = '{{{definition_id}}}';
        }

        if (conf.clientId) {
            processedTile.description += ' for ' + conf.clientId;
        }
        processed.push( processedTile );
    });
    return processed;
};
<commit_msg>findById was calling find in the implementation.<commit_after>/*
 * 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.
 */

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Private

var fs = require('fs');
var path = require('path');
var express = require('express');
var q = require('q');
var bootstrap = require('./bootstrap');
var definitionConfigurator = require('./definitionSetup');
var osAppConfigurator = require('./appSetup');
var serviceConfigurator = require('./serviceSetup');
var jive = require('../api');
var log4js = require('log4js');
var mustache = require('mustache');

var app;
var rootDir = process.cwd();
var tilesDir = rootDir + '/tiles';
var osAppsDir = rootDir + '/apps';
var cartridgesDir = rootDir + '/cartridges';
var storagesDir = rootDir + '/storages';

var _dir = function(theDir, defaultDir ) {
    theDir = theDir || defaultDir;

    if ( theDir.indexOf('/') == 0 ) {
        return rootDir + theDir;
    } else {
        return process.cwd() + '/' + theDir;
    }
};

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Public

/**
 * For managing jive communities registered with this service
 */
exports.community = jive.community;

/**
 * For managing service webhooks
 */
exports.webhooks = jive.webhooks;

/**
 * Configuration options
 */
exports.options = {};

var persistence;
/**
 * Retrieves or sets current persistence strategy, defaults to file.
 * @type {undefined}
 */
exports.persistence = function(_persistence) {

    if ( _persistence ) {
        // set persistence
        if ( !_persistence['find'] || !_persistence['findByID'] || !_persistence['remove'] || !_persistence['save'] ) {
            throw 'Unsupported persistence strategy - must implement find, findByID, remove, save methods.';
        }
        persistence = _persistence;
        jive.context['persistence'] = persistence;
    }

    // retrieve persistence
    return {
        save: function() {
            return persistence ? persistence.save(
                arguments.length > 0 ? arguments[0] : undefined,
                arguments.length > 1 ? arguments[1] : undefined,
                arguments.length > 2 ? arguments[2] : undefined,
                arguments.length > 3 ? arguments[3] : undefined,
                arguments.length > 4 ? arguments[4] : undefined,
                arguments.length > 5 ? arguments[5] : undefined
            ) : function() {
                return q.reject( new Error("persistence not defined") );
            }
        },

        find: function() {
            return persistence ? persistence.find(
                arguments.length > 0 ? arguments[0] : undefined,
                arguments.length > 1 ? arguments[1] : undefined,
                arguments.length > 2 ? arguments[2] : undefined,
                arguments.length > 3 ? arguments[3] : undefined,
                arguments.length > 4 ? arguments[4] : undefined,
                arguments.length > 5 ? arguments[5] : undefined
            ) : function() {
                return q.reject( new Error("persistence not defined") );
            }
        },

        findByID: function() {
            return persistence ? persistence.findByID(
                arguments.length > 0 ? arguments[0] : undefined,
                arguments.length > 1 ? arguments[1] : undefined,
                arguments.length > 2 ? arguments[2] : undefined,
                arguments.length > 3 ? arguments[3] : undefined,
                arguments.length > 4 ? arguments[4] : undefined,
                arguments.length > 5 ? arguments[5] : undefined
            ) : function() {
                return q.reject( new Error("persistence not defined") );
            }
        },

        remove: function() {
            return persistence ? persistence.remove(
                arguments.length > 0 ? arguments[0] : undefined,
                arguments.length > 1 ? arguments[1] : undefined,
                arguments.length > 2 ? arguments[2] : undefined,
                arguments.length > 3 ? arguments[3] : undefined,
                arguments.length > 4 ? arguments[4] : undefined,
                arguments.length > 5 ? arguments[5] : undefined
            ) : function() {
                return q.reject( new Error("persistence not defined") );
            }
        },

        close: function() {
            return persistence ? persistence.close() :  function() {
                return q.reject( new Error("persistence not defined") );
            }
        }
    }
};

var scheduler;
/**
 * Retrieves or sets the scheduling strategy. Defaults to memory (single node). todo
 * @param _scheduler
 * @returns {*}
 */
exports.scheduler = function( _scheduler ) {
    if ( _scheduler ) {
        if ( !_scheduler['schedule'] || !_scheduler['unschedule'] || !_scheduler['getTasks'] ) {
            throw 'Unsupported scheduler strategy - must implement schedule, unschedule, isScheduled, getTasks.';
        }
        scheduler = _scheduler;

        if ( !scheduler ) {
            scheduler = new jive.scheduler.memory();
        }
        jive.context.scheduler = scheduler;
    }
    scheduler = jive.context.scheduler;
    return scheduler;
};

/**
 * @param _app
 * @param options JSON or path to options file
 * @param definitionsToAutowire optional arraylist of tile names under [app root]/tiles to autowire
 */
exports.init = function(_app, options ) {
    if (_app) {
        app = _app;
    }
    else {
        app = express();
    }
    rootDir =  rootDir || process.cwd();
    tilesDir = rootDir + '/tiles';

    // for some reason this needs to be configured earlier than later
    app.use(express.bodyParser());
    app.use(express.logger('dev'));
    app.use(express.methodOverride());
    app.use(app.router);
    app.use(express.errorHandler());

    var applyDefaults = function(config) {
        if ( !config['persistence'] ) {
            config['persistence'] = 'file';
        }
        if ( !config['scheduler'] ) {
            config['scheduler'] = 'memory';
        }
    };

   var applyOverrides = function(config) {
        // override role
        var roleFromEnv = process.env['jive_sdk_service_role'];
        if ( roleFromEnv ) {
            config['role'] = roleFromEnv;
        }
    };

    var initialPromise;
    if ( typeof options === 'object' ) {
        applyDefaults(options);
        applyOverrides(options);
        exports.options = options;
        jive.context.config = exports.options;

        initialPromise = q.fcall( function() {
            return options;
        });
    } else {
        // if no options are provided, then try getting them from
        // cmd line arguments, or from environemnt
        if ( !options ) {
            var configFileFromEnv = process.env['jive_sdk_config_file'];
            var configFilePathFromArgs = undefined;

            process.argv.forEach(function (val, index, array) {
                if ( val.indexOf('=') > -1 ) {
                    var arg = val.split(/=/);

                    if ( arg[0] == 'configFile' ) {
                        jive.logger.debug("Command line argument:"  + arg[0] + "=" + arg[1]);
                        configFilePathFromArgs = arg[1];
                    }
                }
            });

            options = configFilePathFromArgs || configFileFromEnv;

            if( !options ) {
                // assume its a file in the rootdir
                options = rootDir + "/jiveclientconfiguration.json";
            }
        }

        initialPromise = q.nfcall( fs.readFile, options, 'utf8').then( function (data) {
            var jiveConfig = JSON.parse(data);
            applyDefaults(jiveConfig);
            applyOverrides(jiveConfig);

            exports.options = jiveConfig;
            jive.context.config = exports.options;

            jive.logger.debug('Startup configuration from', options);
            jive.logger.debug(jiveConfig);

            return jiveConfig;
        });
    }

    return initialPromise
            .then(initLogger)
            .then(initPersistence)
            .then(initScheduler);
};

function initLogger(options) {
    var logfile = options['logFile'] || options['logfile'];
    var logLevel = process.env['jive_logging_level'] || options['logLevel'] || options['loglevel'] || 'INFO';
    logLevel = logLevel.toUpperCase();

    if (logfile) {
        if (logfile.indexOf('logs/') === 0) {
            if (!fs.existsSync('logs')) {
                jive.logger.warn('logs subdirectory does not exist. Creating directory now.');
                fs.mkdirSync('logs');
            }
        }
        log4js.loadAppender('file');
        log4js.addAppender(log4js.appenders.file(logfile), 'jive-sdk');
    }

    jive.logger.setLevel(logLevel);

    return options;
}

function initPersistence(options) {
    var persistence = options['persistence'];
    if ( typeof persistence === 'object' ) {
        // set persistence if the object is provided
        exports.persistence( options['persistence'] );
    }
    else if ( typeof persistence === 'string' ) {
        //If a string is provided, and it's a valid type exported in jive.persistence, then use that.
        if (jive.persistence[persistence]) {
            exports.persistence(new jive.persistence[persistence](options)); //pass options, such as location of DB for mongoDB.
        }
        else {
            jive.logger.warn('Invalid persistence option given "' + persistence + '". Must be one of ' + Object.keys(jive.persistence));
            jive.logger.warn('Defaulting to file persistence');
        }
    }
    return options;
}

function initScheduler(options) {
    var scheduler = options['scheduler'];
    if ( typeof scheduler === 'object' ) {
        // set scheduler if the object is provided
        exports.scheduler(scheduler);
    }
    else if ( typeof scheduler === 'string' ) {
        //If a string is provided, and it's a valid type exported in jive.scheduler, then use that.
        if (jive.scheduler[scheduler]) {
            exports.scheduler(new jive.scheduler[scheduler](options)); //pass options, such as location of redis for Kue.
        }
        else {
            jive.logger.warn('Invalid scheduler option given "' + scheduler + '". Must be one of ' + Object.keys(jive.scheduler));
            jive.logger.warn('Defaulting to memory scheduler');
        }
    }
    return options;
}

/**
 *
 */
exports.autowire = function(definitionsToAutowire) {
    if( definitionsToAutowire ) {

        if (definitionsToAutowire['forEach'] ) {
            var promises = [];
            definitionsToAutowire.forEach( function( definition ) {
                promises.push( definitionConfigurator.setupOneDefinition(
                    app, _dir( '/tiles/' + definition), definition
                ) );
            });
            return q.all(promises);
        } else {
            return definitionConfigurator.setupOneDefinition(
                app, _dir( '/tiles/' + definitionsToAutowire), definitionsToAutowire
            );
        }
    } else {
        // assume autowiring everything
        return definitionConfigurator.setupAllDefinitions(app, _dir( '/tiles', '/tiles'))
        .then( function () {
            return osAppConfigurator.setupAllApps( app, _dir( '/apps', '/apps'));
        })
        .then( function () {
            return serviceConfigurator.setupAllServices( app, _dir( '/services', '/services'));
        })
        .then( function () {
            return serviceConfigurator.setupAllServices( app, _dir( '/storages', '/storages'));
        });
    }
};

/**
 * Autowire a routes directory for a given definition
 * @param definitionName
 * @param definitionRouteDirectory
 */
exports.autowireDefinitionRoutes = function( definitionName, definitionRouteDirectory ) {
    return definitionConfigurator.setupDefinitionRoutes(
        app, definitionName, _dir(definitionRouteDirectory, '/tiles/' + definitionName + '/routes' )
    );
};

/**
 * Autowire a services directory for a given definition
 * @param definitionName
 * @param definitionServicesDirectory
 */
exports.autowireDefinitionServices = function( definitionName, definitionServicesDirectory ) {
    return definitionConfigurator.setupDefinitionServices(
        definitionName, _dir( definitionServicesDirectory, '/tiles/' + definitionName + '/services' )
    );
};

/**
 * Autowire definition metadata file for a given definition
 * @param definitionMetadataFile
 */
exports.autowireDefinitionMetadata = function( definitionMetadataFile ) {
    return definitionConfigurator.setupDefinitionMetadata(definitionMetadataFile);
};

/**
 * Return promise - fail or succeed
 */
exports.start = function() {
    return bootstrap.start( app, exports.options, rootDir, tilesDir, osAppsDir, cartridgesDir, storagesDir).then( function() {
        jive.logger.info("Service started in " + app['settings']['env'] + " mode");
    });
};

/**
 * Computes the full service URL for this service, taking into account
 * jiveclientconfiguration.json (clientUrl & port)
 */
exports.serviceURL = function() {
    var conf = jive.service.options;
    var url = conf['clientUrl'];

    var port = conf['port'];
    if ( port && port != 443 && port != 80 ) {
        url += ':' + port;
    }

    return url;
};

/**
 * Public service routes
 */
exports.routes = {
    'tiles' : require('../routes/tiles'),
    'jive' : require('../routes/jive'),
    'dev' : require('../routes/dev'),
    'oauth' : require('../routes/oauth')
};

/**
 * Interrogate the role of this node
 */
exports.role = {
    'isWorker' : function() {
        return !exports.options['role'] || exports.options['role'] === jive.constants.roles.WORKER;
    },
    'isPusher' : function() {
        return !exports.options['role'] || exports.options['role'] === jive.constants.roles.PUSHER;
    },
    'isHttp' : function() {
        return !exports.options['role'] || exports.options['role'] === jive.constants.roles.HTTP_HANDLER;
    }
};

exports.extensions = function() {
    return require('./extension/extension');
};

exports.getExpandedTileDefinitions = function(all) {
    var conf = exports.options;
    var host = exports.serviceURL();
    var processed = [];

    all.forEach( function( tile ) {
        if ( !tile ) {
            return;
        }
        var name = tile.name;
        var stringified = JSON.stringify(tile);
        stringified =  mustache.render(stringified, {
            host: host,
            tile_public: host + '/' + name,
            tile_route: host + '/' + name,
            clientId: conf.clientId
        });

        var processedTile = JSON.parse(stringified);

        // defaults
        if ( !processedTile['published'] ) {
            processedTile['published'] = "2013-02-28T15:12:16.768-0800";
        }
        if ( !processedTile['updated'] ) {
            processedTile['updated'] = "2013-02-28T15:12:16.768-0800";
        }
        if ( processedTile['action'] ) {
            if ( processedTile['action'].indexOf('http') != 0 ) {
                // assume its relative to host then
                processedTile['action'] = host + ( processedTile['action'].indexOf('/') == 0 ? "" : "/" ) + processedTile['action'];
            }
        }
        if ( !processedTile['config'] ) {
            processedTile['config'] = host + '/' + processedTile['definitionDirName'] + '/configure';
        } else {
            if ( processedTile['config'].indexOf('http') != 0 ) {
                // assume its relative to host then
                processedTile['config'] = host + ( processedTile['config'].indexOf('/') == 0 ? "" : "/" ) + processedTile['config'];
            }
        }
        if ( !processedTile['register'] ) {
            processedTile['register'] = host + '/registration';
        } else {
            if ( processedTile['register'].indexOf('http') != 0 ) {
                // assume its relative to host then
                processedTile['register'] = host + ( processedTile['register'].indexOf('/') == 0 ? "" : "/" ) + processedTile['register'];
            }
        }
        if ( processedTile['unregister'] && processedTile['unregister'].indexOf('http') != 0 ) {
            // assume its relative to host then
            processedTile['unregister'] = host + ( processedTile['unregister'].indexOf('/') == 0 ? "" : "/" ) + processedTile['unregister'];
        }
        if ( !processedTile['client_id'] ) {
            processedTile['client_id'] = conf.clientId;
        }
        if ( !processedTile['id'] ) {
            processedTile['id'] = '{{{definition_id}}}';
        }

        if (conf.clientId) {
            processedTile.description += ' for ' + conf.clientId;
        }
        processed.push( processedTile );
    });
    return processed;
};

exports.security = security;
<|endoftext|>


<commit_before>import React, { Component, PropTypes } from 'react';
import './DemoPage.less';
import ComponentRenderer from '../ComponentRenderer';
import FilterSidebar from '../FilterSidebar';
import DemoPageComponentShortInfo from '../DemoPageComponentShortInfo';
import Rcslider from 'rc-slider';
import ToolApplicationHeader from '../ToolApplicationHeader';
import queryString from 'query-string';
import { spring, Motion } from 'react-motion';
import find from 'lodash/find';

export default
class DemoPage extends Component {
  constructor(props) {
    super(props);
    let query = queryString.parse(location.search);
    this.state = {
      showSidebar: (query.showSidebar === 'true') && !props.isScreenSmall,
      packagesInfo: [],
      componentsInfo: [],
      currentComponentId: '',
      currentComponent: null,
      options: {
        maxContainerWidth: (query.maxContainerWidth) || '40%',
        isShowContainerBorders: false,
        isContentCentered: query.forceCentering === 'true',
        isUseScope: typeof query.isUseScope === 'undefined' ? true : query.isUseScope
      }
    };
    this.handleHistoryPopState = this.handleHistoryPopState.bind(this);
  }

  componentWillMount() {
    this.getComponentsInfo();
    this.getPackagesInfo();
    window.addEventListener('popstate', this.handleHistoryPopState);
  }

  componentDidUpdate(prevProps, prevState) {
    if (this.state.componentsInfo !== prevState.componentsInfo) {
      this.initCurrentComponentId();
    }
  }

  componentWillUnmount() {
    clearTimeout(this._getComponentTimeout);
    window.removeEventListener('popstate', this.handleHistoryPopState);
  }

  initCurrentComponentId() {
    let idFromQueryString = queryString.parse(location.search).currentComponentId;
    let id = idFromQueryString ?
      idFromQueryString :
      (this.state.componentsInfo[0] && this.state.componentsInfo[0].id);
    this.handleComponentSelection(this.state.componentsInfo, id || 0);
  }

  handleHistoryPopState(event) {
    this.initCurrentComponentId();
    this.initOptions();
  }

  parseQueryParameters() {
    return queryString.parse(location.search);
  }

  getPackagesInfo() {
    this.props.loader.getPackagesInfo(data => {
      this.setState({ packagesInfo: data });
    });
  }

  getCurrentComponentInfo() {
    return this.state.componentsInfo.filter(componentInfo =>
      componentInfo.id === this.state.currentComponentId
    )[0]
  }

  getComponentsInfo() {
    this.props.loader.getComponentsInfo(data => {
      let preparedComponentsInfo = this.prepareComponentsInfo(data);
      let idFromQueryString = queryString.parse(location.search).currentComponentId;
      let id = idFromQueryString || preparedComponentsInfo[0].id;
      this.handleComponentSelection(preparedComponentsInfo, id);
      this.setState({ componentsInfo: preparedComponentsInfo });
    });
  }

  prepareComponentsInfo(components) {
    let preparedComponentsInfo = components.map(component => ({
      ...component,
      id: `${component.package}/${component.version}/${component.name}`
    }));
    return preparedComponentsInfo;
  }

  setQueryStringParam(name, value) {
    let prevQueryString = this.parseQueryParameters();
    let nextQueryString = queryString.stringify({ ...prevQueryString, [name]: value });
    history.pushState({}, '', `${location.origin}${location.path || ''}?${nextQueryString}`);
  }

  getComponent(componentInfo) {
    this.props.loader.getComponent(componentInfo, this.onComponentReady.bind(this));
  }

  onComponentReady(componentData) {
    let componentInfo = this.state.componentsInfo.filter(
      componentInfo => componentInfo.id === this.state.currentComponentId
    )[0];
    this.setState({ currentComponent: { ...componentData, componentInfo } });
  }

  handleToggleSidebar(show) {
    this.setQueryStringParam('showSidebar', !this.state.showSidebar);
    this.setState({ showSidebar: typeof show !== 'undefined' ? show : !this.state.showSidebar });
  }

  handleToggleForceCentering() {
    let { options } = this.state;
    this.setOption('isContentCentered', !options.isContentCentered);
    this.setQueryStringParam('forceCentering', !options.isContentCentered);
  }

  handleToggleUseScope() {
    let { options } = this.state;
    this.setOption('isUseScope', !options.isUseScope);
    this.setQueryStringParam('isUseScope', !options.isUseScope);
  }

  setOption(name, value) {
    this.setState({
      options: {
        ...this.state.options,
        [name]: value
      }
    });
  }

  handleComponentSelection(componentsInfo, id) {
    let componentInfo = componentsInfo.filter(info => info.id === id)[0];
    this.setState({ currentComponentId: id });
    /* this._getComponentTimeout: ugly hack to resolve problems with component selection with synchronous loaders.
    *   if you fix it in normal way, don't forget to remove timeout clear within componentWillUnmount.
    *   Not 0 because IE */
    this._getComponentTimeout = setTimeout(() => this.getComponent(componentInfo), 16);
    this.setQueryStringParam('currentComponentId', id);
  }

  handleContainerWidthChange(value) {
    let nextMaxContainerWidth = `${value}%`;
    this.setOption('maxContainerWidth', nextMaxContainerWidth);
    this.setQueryStringParam('maxContainerWidth', nextMaxContainerWidth);
  }

  render() {
    let { isScreenSmall } = this.props;
    let { options, packagesInfo } = this.state;
    let isMobileScreen = window.innerWidth <= 1200;
    let currentComponentInfo = this.getCurrentComponentInfo();
    let componentRenderer = this.state.currentComponent ? (
      <ComponentRenderer
        component={this.state.currentComponent}
        componentInfo={currentComponentInfo}
        maxContainerWidth={options.maxContainerWidth}
        isScreenSmall={this.props.isScreenSmall}
        isUseScope={options.isUseScope}
        options={options}
      />
    ) : null;

    let sidebar = (
      <Motion
        defaultStyle={{ x: this.state.showSidebar ? 0 : 100 }}
        style={{ x: this.state.showSidebar ? (isMobileScreen ? spring(0) : 0) : (isMobileScreen ? spring(100) : 100) }}
      >
        {interpolatedStyle =>
          <div
            className={`demo-page__filter-sidebar ${isMobileScreen ? 'demo-page__filter-sidebar--mobile' : ' '}`}
            style={{
              boxShadow: this.props.isScreenSmall ? '0 0 12px rgba(0, 0, 0, 0.65)' : '',
              transform: `translate(-${interpolatedStyle.x}%, 0)`
            }}
          >
            <FilterSidebar
              componentsInfo={this.state.componentsInfo}
              currentComponent={this.state.currentComponent}
              onComponentChange={this.handleComponentSelection.bind(this, this.state.componentsInfo)}
              hideOnOutsideClick={this.props.isScreenSmall}
              onHide={() => this.handleToggleSidebar.call(this, false)}
            />

        }
      </Motion>
    );

    let toggleSidebarBtn = (
      <button
        className="demo-page__primary-btn"
        onClick={() => this.handleToggleSidebar.call(this)}
        type="button"
      >
        SIDEBAR
      </button>
    );

    let maxWidthSlider = !isMobileScreen ? (

          Max width:

        <Rcslider
          className="demo-page__max-container-width-slider"
          onChange={this.handleContainerWidthChange.bind(this)}
          defaultValue={parseInt(options.maxContainerWidth, 10)}
          tipFormatter={null}
        />

          {options.maxContainerWidth}

    ) : null;

    let componentPackage = find(
      packagesInfo,
      packageInfo => packageInfo.info.name === currentComponentInfo.package
    ) || {};

    let forceCenteringToggler = (

        Force Centering

    );

    let useScopeToggler = (

        Use scope

    );

    return (

        {sidebar}

              <ToolApplicationHeader
                applicationName="Showroom"
                repositoryUrl="https://github.com/OpusCapitaBES/js-react-showroom-client"
                contacts={[
                  { name: 'alexey.sergeev@jcatalog.com', email: 'alexey.sergeev@jcatalog.com' },
                  { name: 'kirill.volkovich@jcatalog.com', email: 'kirill.volkovich@jcatalog.com' }
                ]}
              />

                {toggleSidebarBtn}

 this.setOption('isShowContainerBorders', true)}
                onMouseLeave={() => this.setOption('isShowContainerBorders', false)}
              >
                {maxWidthSlider}
                {forceCenteringToggler}
                {useScopeToggler}

            <DemoPageComponentShortInfo
              packageName={currentComponentInfo && currentComponentInfo.package}
              packageJson={componentPackage.info}
              componentName={currentComponentInfo && currentComponentInfo.name}
              version={currentComponentInfo && currentComponentInfo.version}
              repositoryUrl={
                componentPackage.info &&
                componentPackage.info.repository &&
                (componentPackage.info.repository.url || componentPackage.info.repository)
              }
              gitHead={componentPackage.info && componentPackage.info.gitHead}
              isMobileScreen={isMobileScreen}
            />

            {componentRenderer}

    )
  }
}

DemoPage.propTypes = {
  loader: PropTypes.object.isRequired,
  isScreenSmall: PropTypes.bool
};
<commit_msg>Fix bug with wrong browser urls/history navigation<commit_after>import React, { Component, PropTypes } from 'react';
import './DemoPage.less';
import ComponentRenderer from '../ComponentRenderer';
import FilterSidebar from '../FilterSidebar';
import DemoPageComponentShortInfo from '../DemoPageComponentShortInfo';
import Rcslider from 'rc-slider';
import ToolApplicationHeader from '../ToolApplicationHeader';
import queryString from 'query-string';
import { spring, Motion } from 'react-motion';
import find from 'lodash/find';

export default
class DemoPage extends Component {
  constructor(props) {
    super(props);
    let query = queryString.parse(location.search);
    this.state = {
      showSidebar: (query.showSidebar === 'true') && !props.isScreenSmall,
      packagesInfo: [],
      componentsInfo: [],
      currentComponentId: '',
      currentComponent: null,
      options: {
        maxContainerWidth: (query.maxContainerWidth) || '40%',
        isShowContainerBorders: false,
        isContentCentered: query.forceCentering === 'true',
        isUseScope: typeof query.isUseScope === 'undefined' ? true : query.isUseScope
      }
    };
    this.handleHistoryPopState = this.handleHistoryPopState.bind(this);
  }

  componentWillMount() {
    this.getComponentsInfo();
    this.getPackagesInfo();
    window.addEventListener('popstate', this.handleHistoryPopState);
  }

  componentDidUpdate(prevProps, prevState) {
    if (this.state.componentsInfo !== prevState.componentsInfo) {
      this.initCurrentComponentId();
    }
  }

  componentWillUnmount() {
    clearTimeout(this._getComponentTimeout);
    window.removeEventListener('popstate', this.handleHistoryPopState);
  }

  initCurrentComponentId() {
    let idFromQueryString = queryString.parse(location.search).currentComponentId;
    let id = idFromQueryString ?
      idFromQueryString :
      (this.state.componentsInfo[0] && this.state.componentsInfo[0].id);
    this.handleComponentSelection(this.state.componentsInfo, id || 0);
  }

  handleHistoryPopState(event) {
    this.initCurrentComponentId();
    this.initOptions();
  }

  parseQueryParameters() {
    return queryString.parse(location.search);
  }

  getPackagesInfo() {
    this.props.loader.getPackagesInfo(data => {
      this.setState({ packagesInfo: data });
    });
  }

  getCurrentComponentInfo() {
    return this.state.componentsInfo.filter(componentInfo =>
      componentInfo.id === this.state.currentComponentId
    )[0]
  }

  getComponentsInfo() {
    this.props.loader.getComponentsInfo(data => {
      let preparedComponentsInfo = this.prepareComponentsInfo(data);
      let idFromQueryString = queryString.parse(location.search).currentComponentId;
      let id = idFromQueryString || preparedComponentsInfo[0].id;
      this.handleComponentSelection(preparedComponentsInfo, id);
      this.setState({ componentsInfo: preparedComponentsInfo });
    });
  }

  prepareComponentsInfo(components) {
    let preparedComponentsInfo = components.map(component => ({
      ...component,
      id: `${component.package}/${component.version}/${component.name}`
    }));
    return preparedComponentsInfo;
  }

  setQueryStringParam(name, value) {
    let prevQueryString = this.parseQueryParameters();
    let nextQueryString = queryString.stringify({ ...prevQueryString, [name]: value });
    history.pushState({}, '', `${location.origin}${location.pathname || ''}?${nextQueryString}`);
  }

  getComponent(componentInfo) {
    this.props.loader.getComponent(componentInfo, this.onComponentReady.bind(this));
  }

  onComponentReady(componentData) {
    let componentInfo = this.state.componentsInfo.filter(
      componentInfo => componentInfo.id === this.state.currentComponentId
    )[0];
    this.setState({ currentComponent: { ...componentData, componentInfo } });
  }

  handleToggleSidebar(show) {
    this.setQueryStringParam('showSidebar', !this.state.showSidebar);
    this.setState({ showSidebar: typeof show !== 'undefined' ? show : !this.state.showSidebar });
  }

  handleToggleForceCentering() {
    let { options } = this.state;
    this.setOption('isContentCentered', !options.isContentCentered);
    this.setQueryStringParam('forceCentering', !options.isContentCentered);
  }

  handleToggleUseScope() {
    let { options } = this.state;
    this.setOption('isUseScope', !options.isUseScope);
    this.setQueryStringParam('isUseScope', !options.isUseScope);
  }

  setOption(name, value) {
    this.setState({
      options: {
        ...this.state.options,
        [name]: value
      }
    });
  }

  handleComponentSelection(componentsInfo, id) {
    let componentInfo = componentsInfo.filter(info => info.id === id)[0];
    this.setState({ currentComponentId: id });
    /* this._getComponentTimeout: ugly hack to resolve problems with component selection with synchronous loaders.
    *   if you fix it in normal way, don't forget to remove timeout clear within componentWillUnmount.
    *   Not 0 because IE */
    this._getComponentTimeout = setTimeout(() => this.getComponent(componentInfo), 16);
    this.setQueryStringParam('currentComponentId', id);
  }

  handleContainerWidthChange(value) {
    let nextMaxContainerWidth = `${value}%`;
    this.setOption('maxContainerWidth', nextMaxContainerWidth);
    this.setQueryStringParam('maxContainerWidth', nextMaxContainerWidth);
  }

  render() {
    let { isScreenSmall } = this.props;
    let { options, packagesInfo } = this.state;
    let isMobileScreen = window.innerWidth <= 1200;
    let currentComponentInfo = this.getCurrentComponentInfo();
    let componentRenderer = this.state.currentComponent ? (
      <ComponentRenderer
        component={this.state.currentComponent}
        componentInfo={currentComponentInfo}
        maxContainerWidth={options.maxContainerWidth}
        isScreenSmall={this.props.isScreenSmall}
        isUseScope={options.isUseScope}
        options={options}
      />
    ) : null;

    let sidebar = (
      <Motion
        defaultStyle={{ x: this.state.showSidebar ? 0 : 100 }}
        style={{ x: this.state.showSidebar ? (isMobileScreen ? spring(0) : 0) : (isMobileScreen ? spring(100) : 100) }}
      >
        {interpolatedStyle =>
          <div
            className={`demo-page__filter-sidebar ${isMobileScreen ? 'demo-page__filter-sidebar--mobile' : ' '}`}
            style={{
              boxShadow: this.props.isScreenSmall ? '0 0 12px rgba(0, 0, 0, 0.65)' : '',
              transform: `translate(-${interpolatedStyle.x}%, 0)`
            }}
          >
            <FilterSidebar
              componentsInfo={this.state.componentsInfo}
              currentComponent={this.state.currentComponent}
              onComponentChange={this.handleComponentSelection.bind(this, this.state.componentsInfo)}
              hideOnOutsideClick={this.props.isScreenSmall}
              onHide={() => this.handleToggleSidebar.call(this, false)}
            />

        }
      </Motion>
    );

    let toggleSidebarBtn = (
      <button
        className="demo-page__primary-btn"
        onClick={() => this.handleToggleSidebar.call(this)}
        type="button"
      >
        SIDEBAR
      </button>
    );

    let maxWidthSlider = !isMobileScreen ? (

          Max width:

        <Rcslider
          className="demo-page__max-container-width-slider"
          onChange={this.handleContainerWidthChange.bind(this)}
          defaultValue={parseInt(options.maxContainerWidth, 10)}
          tipFormatter={null}
        />

          {options.maxContainerWidth}

    ) : null;

    let componentPackage = find(
      packagesInfo,
      packageInfo => packageInfo.info.name === currentComponentInfo.package
    ) || {};

    let forceCenteringToggler = (

        Force Centering

    );

    let useScopeToggler = (

        Use scope

    );

    return (

        {sidebar}

              <ToolApplicationHeader
                applicationName="Showroom"
                repositoryUrl="https://github.com/OpusCapitaBES/js-react-showroom-client"
                contacts={[
                  { name: 'alexey.sergeev@jcatalog.com', email: 'alexey.sergeev@jcatalog.com' },
                  { name: 'kirill.volkovich@jcatalog.com', email: 'kirill.volkovich@jcatalog.com' }
                ]}
              />

                {toggleSidebarBtn}

 this.setOption('isShowContainerBorders', true)}
                onMouseLeave={() => this.setOption('isShowContainerBorders', false)}
              >
                {maxWidthSlider}
                {forceCenteringToggler}
                {useScopeToggler}

            <DemoPageComponentShortInfo
              packageName={currentComponentInfo && currentComponentInfo.package}
              packageJson={componentPackage.info}
              componentName={currentComponentInfo && currentComponentInfo.name}
              version={currentComponentInfo && currentComponentInfo.version}
              repositoryUrl={
                componentPackage.info &&
                componentPackage.info.repository &&
                (componentPackage.info.repository.url || componentPackage.info.repository)
              }
              gitHead={componentPackage.info && componentPackage.info.gitHead}
              isMobileScreen={isMobileScreen}
            />

            {componentRenderer}

    )
  }
}

DemoPage.propTypes = {
  loader: PropTypes.object.isRequired,
  isScreenSmall: PropTypes.bool
};
<|endoftext|>


<commit_before>
module.exports = {
  // Bedecked default options
  engine: 'markdown',
  protocol: 'https:',
  revealjsVersion: '2.6.2',
  theme: 'default',
  title: 'Just Another Bedecked Presentation',

  // Reveal.js default init options
  optAutoSlide: 0,
  optAutoSlideStoppable: true,
  optCenter: true,
  optControls: true,
  optEmbedded: false,
  optFragments: true,
  optHideAddressBar: true,
  optHistory: false,
  optKeyboard: true,
  optLoop: false,
  optMouseWheel: false,
  optOverview: true,
  optPreviewLinks: false,
  optProgress: true,
  optRtl: false,
  optSlideNumber: false,
  optTouch: true,
  optViewDistance: 3
};
<commit_msg>feature(cli): Add --pack flag<commit_after>
module.exports = {
  // Bedecked default options
  engine: 'markdown',
  pack: false,
  protocol: 'https:',
  revealjsVersion: '2.6.2',
  theme: 'default',
  title: 'Just Another Bedecked Presentation',

  // Reveal.js default init options
  optAutoSlide: 0,
  optAutoSlideStoppable: true,
  optCenter: true,
  optControls: true,
  optEmbedded: false,
  optFragments: true,
  optHideAddressBar: true,
  optHistory: false,
  optKeyboard: true,
  optLoop: false,
  optMouseWheel: false,
  optOverview: true,
  optPreviewLinks: false,
  optProgress: true,
  optRtl: false,
  optSlideNumber: false,
  optTouch: true,
  optViewDistance: 3
};
<|endoftext|>


<commit_before>import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { agreementType, personType, thesisType } from '../../util/types';

class AgreementView extends Component {

    constructor(props) {
        super(props);
        this.state = {
            showAgreements: [],
        }
    }

    renderOne(agreement) {
        const index = this.props.agreements.findIndex(x => x.agreementId === agreement.agreementId);
        return (

                {this.state.showAgreements[index] ?

{agreement.thesisTitle}

                        {/*
                        atm doesn't get the information from back end. Is it needed?

Gradun tekijän tiedot

                                Gradun tekijän nimi: {agreement.firstname + " " + agreement.lastname + "\t"}|
                                Gradun ala: {agreement.studyfieldName}

                                Opiskelijanumero: {agreement.studentNumber + "\t"}|
                        Lähiosoite: {agreement.address}

                                Sähköpostiosoite: {agreement.email + "\t"}|
                        Puhelinnumero: {agreement.phone}

*/}

Opinnäytetyön tiedot

                            Aloitusajankohta: {agreement.startDate}

                            Arvioitu valmistumisajankohta: {agreement.completionEta}

                            Suorituspaikka: {agreement.performancePlace}

Ohjausvastuut

                            {/* TODO: pass other supervisors as a list from backend with other
                            agreement info. */}
                            Vastuuohjaaja: {agreement.title} {agreement.firstname} {agreement.lastname}

                            Muu ohjaaja: the be shown here

                            2. ohjaaja: to be shown here

Työskentelyn tavoitteet ja ajankäyttö

                            Viikoittainen työaika: {agreement.studentWorkTime}

                            Ohjaajien varmaama ohjausaika: {agreement.supervisorWorkTime}

                            Välitavoitteet: {agreement.intermediateGoal}

                            Sopimus tapaamistiheydestä, yhteydenpitotavoista ja keskusteluun käytettävissä olevasta ajasta: {agreement.meetingAgreement}

                            Tavoitearvosana: {agreement.studentGradeGoal}

                            Muuta: {agreement.other}

                    : undefined}

        );
    }

    changeShowing(e, agreement) {
        const index = this.props.agreements.findIndex((x => x.agreementId === agreement.agreementId));
        const newState = Object.assign({}, this.state);
        if (newState.showAgreements[index]) { //can't use x = !x since x is at first undefined
            newState.showAgreements[index] = false; //if is visible, hide
        } else {
            newState.showAgreements[index] = true;
        }
        this.setState({
            showAgreements: newState.showAgreements
        });
    }

    handleEdit= (e, agreement) => {
        this.props.handleEditAgreement(agreement);

    }

    getSupervisor(agreement) {
        const supervisor = this.props.persons.find(person => person.personId === agreement.responsibleSupervisorId);
        if (supervisor)
            return `${supervisor.firstname} ${supervisor.lastname}`;

        return '';
    }

    getThesis(agreement) {
        return this.props.theses.find(thesis => thesis.thesisId === agreement.thesisId) || {};
    }

    renderList() {
        const data = this.props.agreements;
        return (

                {data.map((agreement, index) =>

Opinnäytetyön otsikko (työnimi): {this.getThesis(agreement).title}

                        Ohjausvastuut:

                        Vastuuohjaaja: {agreement.title} {this.getSupervisor(agreement)}

                        Muuohjaaja: to be shown here

                        2. ohjaaja: to be shown here

                        <button key={agreement.agreementId} className="ui primary button" onClick={(e) => this.changeShowing(e, agreement)}>Show/hide agreement information</button>
                        <button className="ui primary button" onClick={(e) => this.handleEdit(e, agreement)}>Edit agreement</button>
                        {this.renderOne(agreement)}

                )}

        );
    }

    render() {
        if (this.props.agreements.length > 0) return
{this.renderList()}

        return (

{this.renderOne(this.props.agreements)}

        );
    }
}

const { arrayOf, func } = PropTypes;
AgreementView.propTypes = {
    agreements: arrayOf(agreementType).isRequired,
    persons: arrayOf(personType).isRequired,
    theses: arrayOf(thesisType).isRequired,
    handleEditAgreement: func.isRequired
};

export default AgreementView;
<commit_msg>Show author name on header<commit_after>import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { agreementType, personType, thesisType } from '../../util/types';

class AgreementView extends Component {

    constructor(props) {
        super(props);
        this.state = {
            showAgreements: [],
        }
    }

    getAuthorName(agreement) {
        const author = this.props.persons.find(person => person.personId === agreement.authorId);
        return author ? `${author.firstname} ${author.lastname}` : '';
    }

    renderOne(agreement) {
        const index = this.props.agreements.findIndex(x => x.agreementId === agreement.agreementId);
        return (

                {this.state.showAgreements[index] ?

{agreement.thesisTitle}

                        {/*
                        atm doesn't get the information from back end. Is it needed?

Gradun tekijän tiedot

                                Gradun tekijän nimi: {agreement.firstname + " " + agreement.lastname + "\t"}|
                                Gradun ala: {agreement.studyfieldName}

                                Opiskelijanumero: {agreement.studentNumber + "\t"}|
                        Lähiosoite: {agreement.address}

                                Sähköpostiosoite: {agreement.email + "\t"}|
                        Puhelinnumero: {agreement.phone}

*/}

Opinnäytetyön tiedot

                            Aloitusajankohta: {agreement.startDate}

                            Arvioitu valmistumisajankohta: {agreement.completionEta}

                            Suorituspaikka: {agreement.performancePlace}

Ohjausvastuut

                            {/* TODO: pass other supervisors as a list from backend with other
                            agreement info. */}
                            Vastuuohjaaja: {agreement.title} {agreement.firstname} {agreement.lastname}

                            Muu ohjaaja: the be shown here

                            2. ohjaaja: to be shown here

Työskentelyn tavoitteet ja ajankäyttö

                            Viikoittainen työaika: {agreement.studentWorkTime}

                            Ohjaajien varmaama ohjausaika: {agreement.supervisorWorkTime}

                            Välitavoitteet: {agreement.intermediateGoal}

                            Sopimus tapaamistiheydestä, yhteydenpitotavoista ja keskusteluun käytettävissä olevasta ajasta: {agreement.meetingAgreement}

                            Tavoitearvosana: {agreement.studentGradeGoal}

                            Muuta: {agreement.other}

                    : undefined}

        );
    }

    changeShowing(e, agreement) {
        const index = this.props.agreements.findIndex((x => x.agreementId === agreement.agreementId));
        const newState = Object.assign({}, this.state);
        if (newState.showAgreements[index]) { //can't use x = !x since x is at first undefined
            newState.showAgreements[index] = false; //if is visible, hide
        } else {
            newState.showAgreements[index] = true;
        }
        this.setState({
            showAgreements: newState.showAgreements
        });
    }

    handleEdit= (e, agreement) => {
        this.props.handleEditAgreement(agreement);

    }

    getSupervisor(agreement) {
        const supervisor = this.props.persons.find(person => person.personId === agreement.responsibleSupervisorId);
        if (supervisor)
            return `${supervisor.firstname} ${supervisor.lastname}`;

        return '';
    }

    getThesis(agreement) {
        return this.props.theses.find(thesis => thesis.thesisId === agreement.thesisId) || {};
    }

    renderList() {
        const data = this.props.agreements;
        return (

                {data.map((agreement, index) =>

{this.getAuthorName(agreement)}: {this.getThesis(agreement).title}

                        Ohjausvastuut:

                        Vastuuohjaaja: {agreement.title} {this.getSupervisor(agreement)}

                        Muuohjaaja: to be shown here

                        2. ohjaaja: to be shown here

                        <button key={agreement.agreementId} className="ui primary button" onClick={(e) => this.changeShowing(e, agreement)}>Show/hide agreement information</button>
                        <button className="ui primary button" onClick={(e) => this.handleEdit(e, agreement)}>Edit agreement</button>
                        {this.renderOne(agreement)}

                )}

        );
    }

    render() {
        if (this.props.agreements.length > 0) return
{this.renderList()}

        return (

{this.renderOne(this.props.agreements)}

        );
    }
}

const { arrayOf, func } = PropTypes;
AgreementView.propTypes = {
    agreements: arrayOf(agreementType).isRequired,
    persons: arrayOf(personType).isRequired,
    theses: arrayOf(thesisType).isRequired,
    handleEditAgreement: func.isRequired
};

export default AgreementView;
<|endoftext|>


<commit_before>import React, { Component, PropTypes } from 'react';
import { findDOMNode } from 'react-dom';
import Overlay from 'react-overlays/lib/Overlay';
import Transition from 'react-overlays/lib/Transition';
import styled, { injectGlobal } from 'styled-components';
import { colors } from '../../theme';

injectGlobal(`
  .transition-out {
    opacity: 0;
    transition: opacity 200ms linear;
  }

  .transition-in {
    opacity: .9;
  }
`);

const TooltipBase = styled.div`
  position: absolute;
`;

const TooltipInner = styled.div`
  background-color: ${colors.black};
  border-radius: 2px;
  color: ${colors.white};
  font-family: sans-serif;
  font-size: 12px;
  padding: 3px 8px;
  text-align: center;
`;

const TooltipArrowBase = styled.div`
  border-color: transparent;
  border-style: solid;
  height: 0;
  position: absolute;
  width: 0;
`;

const TooltipTop = styled(TooltipBase)`
  margin-top: -3px;
  padding: 5px 0;
`;

const TooltipRight = styled(TooltipBase)`
  margin-right: 3px;
  padding: 0 5px;
`;

const TooltipBottom = styled(TooltipBase)`
  margin-bottom: 3px;
  padding: 5px 0;
`;

const TooltipLeft = styled(TooltipBase)`
  margin-left: -3px;
  padding: 0 5px;
`;

const TooltipArrowTop = styled(TooltipArrowBase)`
  border-top-color: ${colors.black};
  border-width: 5px 5px 0;
  bottom: 0;
  left: 50%;
  margin-left: -5px;
`;

const TooltipArrowRight = styled(TooltipArrowBase)`
  border-right-color: ${colors.black};
  border-width: 5px 5px 5px 0;
  left: 0;
  margin-top: -5px;
  top: 50%;
`;

const TooltipArrowBottom = styled(TooltipArrowBase)`
  border-bottom-color: ${colors.black};
  border-width: 0 5px 5px;
  left: 50%;
  margin-left: -5px;
  top: 0;
`;

const TooltipArrowLeft = styled(TooltipArrowBase)`
  border-left-color: ${colors.black};
  border-width: 5px 0 5px 5px;
  margin-top: -5px;
  right: 0;
  top: 50%;
`;

const Fade = (props) => (
  <Transition
    className="transition-out"
    enteredClassName="transition-in"
    enteringClassName="transition-in"
    in={props.in}
    mountOnEnter="true"
    unmountOnExit="false"
    timeout="200"
    transitionAppear="true"
  >
    {props.children}
  </Transition>
);

Fade.propTypes = {
  children: PropTypes.any.isRequired,
  in: PropTypes.boolean
};

const Popup = (props) => {
  const { className, children, position, style } = props;
  let TooltipStyled;
  let TooltipArrow;

  switch (position) {
    case 'right':
      TooltipStyled = TooltipRight;
      TooltipArrow = TooltipArrowRight;
      break;
    case 'bottom':
      TooltipStyled = TooltipBottom;
      TooltipArrow = TooltipArrowBottom;
      break;
    case 'left':
      TooltipStyled = TooltipLeft;
      TooltipArrow = TooltipArrowLeft;
      break;
    default:
      TooltipStyled = TooltipTop;
      TooltipArrow = TooltipArrowTop;
      break;
  }

  return (
    <TooltipStyled className={className} style={{ ...style }}>
      <TooltipArrow />
      <TooltipInner>
        {children}
      </TooltipInner>
    </TooltipStyled>
  );
};

Popup.propTypes = {
  children: PropTypes.any.isRequired,
  className: PropTypes.string,
  position: PropTypes.oneOf(['top', 'right', 'bottom', 'left']),
  style: PropTypes.object
};

class Tooltip extends Component {
  constructor(props) {
    super(props);

    this.state = { show: false };
  }

  show() {
    return this.setState({ show: true });
  }

  hide() {
    return this.setState({ show: false });
  }

  render() {
    return (

         this.show()} onMouseLeave={() => this.hide()}>
          {this.props.children}

        <Overlay
          show={this.state.show}
          onHide={() => this.setState({ show: false })}
          placement={this.props.position}
          container={document.body}
          target={ props => findDOMNode(this.refs.target)}
          transition={Fade}
        >
          <Popup position={this.props.position}>
            {this.props.content}
          </Popup>
        </Overlay>

    );
  }
}

Tooltip.propTypes = {
  children: PropTypes.any.isRequired,
  /** The text the tooltip displays */
  content: PropTypes.node.isRequired,
  /** Set the position of the tooltip over the content */
  position: PropTypes.oneOf(['top', 'right', 'bottom', 'left'])
};

Tooltip.defaultProps = {
  position: 'top'
};

export default Tooltip;
<commit_msg>fixed some lint errors<commit_after>import React, { Component, PropTypes } from 'react';
import { findDOMNode } from 'react-dom';
import Overlay from 'react-overlays/lib/Overlay';
import Transition from 'react-overlays/lib/Transition';
import styled, { injectGlobal } from 'styled-components';
import { colors } from '../../theme';

/* eslint-disable no-unused-expressions */
injectGlobal`
  .transition-out {
    opacity: 0;
    transition: opacity 200ms linear;
  }

  .transition-in {
    opacity: .9;
  }
`;
/* eslint-enable no-unused-expressions */

const TooltipBase = styled.div`
  position: absolute;
`;

const TooltipInner = styled.div`
  background-color: ${colors.black};
  border-radius: 2px;
  color: ${colors.white};
  font-family: sans-serif;
  font-size: 12px;
  padding: 3px 8px;
  text-align: center;
`;

const TooltipArrowBase = styled.div`
  border-color: transparent;
  border-style: solid;
  height: 0;
  position: absolute;
  width: 0;
`;

const TooltipTop = styled(TooltipBase)`
  margin-top: -3px;
  padding: 5px 0;
`;

const TooltipRight = styled(TooltipBase)`
  margin-right: 3px;
  padding: 0 5px;
`;

const TooltipBottom = styled(TooltipBase)`
  margin-bottom: 3px;
  padding: 5px 0;
`;

const TooltipLeft = styled(TooltipBase)`
  margin-left: -3px;
  padding: 0 5px;
`;

const TooltipArrowTop = styled(TooltipArrowBase)`
  border-top-color: ${colors.black};
  border-width: 5px 5px 0;
  bottom: 0;
  left: 50%;
  margin-left: -5px;
`;

const TooltipArrowRight = styled(TooltipArrowBase)`
  border-right-color: ${colors.black};
  border-width: 5px 5px 5px 0;
  left: 0;
  margin-top: -5px;
  top: 50%;
`;

const TooltipArrowBottom = styled(TooltipArrowBase)`
  border-bottom-color: ${colors.black};
  border-width: 0 5px 5px;
  left: 50%;
  margin-left: -5px;
  top: 0;
`;

const TooltipArrowLeft = styled(TooltipArrowBase)`
  border-left-color: ${colors.black};
  border-width: 5px 0 5px 5px;
  margin-top: -5px;
  right: 0;
  top: 50%;
`;

const Fade = (props) => (
  <Transition
    className="transition-out"
    enteredClassName="transition-in"
    enteringClassName="transition-in"
    in={props.in}
    mountOnEnter
    unmountOnExit={false}
    timeout={200}
    transitionAppear
  >
    {props.children}
  </Transition>
);

Fade.propTypes = {
  children: PropTypes.any.isRequired,
  in: PropTypes.bool
};

const Popup = (props) => {
  const { className, children, position, style } = props;
  let TooltipStyled;
  let TooltipArrow;

  switch (position) {
    case 'right':
      TooltipStyled = TooltipRight;
      TooltipArrow = TooltipArrowRight;
      break;
    case 'bottom':
      TooltipStyled = TooltipBottom;
      TooltipArrow = TooltipArrowBottom;
      break;
    case 'left':
      TooltipStyled = TooltipLeft;
      TooltipArrow = TooltipArrowLeft;
      break;
    default:
      TooltipStyled = TooltipTop;
      TooltipArrow = TooltipArrowTop;
      break;
  }

  return (
    <TooltipStyled className={className} style={{ ...style }}>
      <TooltipArrow />
      <TooltipInner>
        {children}
      </TooltipInner>
    </TooltipStyled>
  );
};

Popup.propTypes = {
  children: PropTypes.any.isRequired,
  className: PropTypes.string,
  position: PropTypes.oneOf(['top', 'right', 'bottom', 'left']),
  style: PropTypes.object
};

class Tooltip extends Component {
  constructor(props) {
    super(props);

    this.state = { show: false };
  }

  show() {
    return this.setState({ show: true });
  }

  hide() {
    return this.setState({ show: false });
  }

  render() {
    return (

         this.show()} onMouseLeave={() => this.hide()}>
          {this.props.children}

        <Overlay
          show={this.state.show}
          onHide={() => this.setState({ show: false })}
          placement={this.props.position}
          container={document.body}
          target={ props => findDOMNode(this.refs.target)}
          transition={Fade}
        >
          <Popup position={this.props.position}>
            {this.props.content}
          </Popup>
        </Overlay>

    );
  }
}

Tooltip.propTypes = {
  children: PropTypes.any.isRequired,
  /** The text the tooltip displays */
  content: PropTypes.node.isRequired,
  /** Set the position of the tooltip over the content */
  position: PropTypes.oneOf(['top', 'right', 'bottom', 'left'])
};

Tooltip.defaultProps = {
  position: 'top'
};

export default Tooltip;
<|endoftext|>


<commit_before>/**
 * Nextcloud - passman
 *
 * @copyright Copyright (c) 2016, Sander Brand (brantje@gmail.com)
 * @copyright Copyright (c) 2016, Marcos Zuriaga Miguel (wolfi@wolfi.es)
 * @license GNU AGPL version 3 or any later version
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

(function () {
	'use strict';

	/**
	 * @ngdoc service
	 * @name passmanApp.ShareService
	 * @description
	 * # ShareService
	 * Service in the passmanApp.
	 */
	angular.module('passmanApp')
		.service('ShareService', ['$http', 'VaultService', 'EncryptService', 'CredentialService', function ($http, VaultService, EncryptService, CredentialService) {
			// Setup sjcl random engine to max paranoia level and start collecting data
			var paranoia_level = 10;
			/** global: sjcl */
			sjcl.random.setDefaultParanoia(paranoia_level);
			sjcl.random.startCollectors();

			return {
				search: function (string) {
					var queryUrl = OC.generateUrl('apps/passman/api/v2/sharing/search');
					return $http.post(queryUrl, {search: string}).then(function (response) {
						if (response.data) {
							return response.data;
						} else {
							return response;
						}
					});
				},
				shareWithUser: function (credential, target_user_data) {
					var queryUrl = OC.generateUrl('apps/passman/api/v2/sharing/share');
					return $http.post(queryUrl,
						{
							item_id: credential.credential_id,
							item_guid: credential.guid,
							permissions: target_user_data.accessLevel,
							vaults: target_user_data.vaults,
						}
					);
				},
				getVaultsByUser: function (userId) {
					var queryUrl = OC.generateUrl('apps/passman/api/v2/sharing/vaults/' + userId);
					return $http.get(queryUrl, {search: userId}).then(function (response) {
						if (response.data) {
							for (var i = 0; i < response.data.length; i++) {
								/** global: forge */
								response.data[i].public_sharing_key = forge.pki.publicKeyFromPem(response.data[i].public_sharing_key);
							}
							return response.data;
						} else {
							return response;
						}
					});
				},
				getPendingRequests: function () {
					var queryUrl = OC.generateUrl('apps/passman/api/v2/sharing/pending');
					return $http.get(queryUrl).then(function (response) {
						if (response.data) {
							return response.data;
						}
					});
				},
				saveSharingRequest: function (request, crypted_shared_key) {
					var queryUrl = OC.generateUrl('apps/passman/api/v2/sharing/save');
					return $http.post(queryUrl, {
						item_guid: request.item_guid,
						target_vault_guid: request.target_vault_guid,
						final_shared_key: crypted_shared_key
					}).then(function (response) {
						return response.data;
					});
				},
				declineSharingRequest: function (request) {
					var queryUrl = OC.generateUrl('apps/passman/api/v2/sharing/decline/' + request.req_id);
					return $http.delete(queryUrl).then(function (response) {
						return response.data;
					});
				},
				unshareCredential: function (credential) {
					var queryUrl = OC.generateUrl('apps/passman/api/v2/sharing/credential/' + credential.guid);
					return $http.delete(queryUrl).then(function (response) {
						return response.data;
					});
				},

				unshareCredentialFromUser: function (credential, user_id) {
					var queryUrl = OC.generateUrl('apps/passman/api/v2/sharing/credential/' + credential.guid + '/' + user_id);
					return $http.delete(queryUrl).then(function (response) {
						return response.data;
					});
				},

				createPublicSharedCredential: function (shareObj) {
					var queryUrl = OC.generateUrl('apps/passman/api/v2/sharing/public');
					return $http.post(queryUrl, shareObj).then(function (response) {
						return response.data;
					});
				},
				getPublicSharedCredential: function (credential_guid) {
					var queryUrl = OC.generateUrl('apps/passman/api/v2/sharing/credential/' + credential_guid + '/public');
					return $http.get(queryUrl).then(function (response) {
							if (response.data) {
								return response;
							} else {
								return response;
							}
						},
						function (result) {
							return result;
						});
				},
				getSharedCredentialACL: function (credential) {
					var queryUrl = OC.generateUrl('apps/passman/api/v2/sharing/credential/' + credential.guid + '/acl');
					return $http.get(queryUrl).then(function (response) {
							if (response.data) {
								return response.data;
							} else {
								return response;
							}
						},
						function (result) {
							return result;
						});
				},
				updateCredentialAcl: function (credential, acl) {
					var queryUrl = OC.generateUrl('apps/passman/api/v2/sharing/credential/' + credential.guid + '/acl');
					return $http.patch(queryUrl, acl).then(function (response) {
						return response.data;
					});
				},
				getCredendialsSharedWithUs: function (vault_guid) {
					var queryUrl = OC.generateUrl('apps/passman/api/v2/sharing/vault/' + vault_guid + '/get');
					return $http.get(queryUrl).then(function (response) {
						if (response.data) {
							return response.data;
						}
					});
				},
				downloadSharedFile: function (credential, file) {
					var queryUrl = OC.generateUrl('apps/passman/api/v2/sharing/credential/' + credential.guid + '/file/' + file.guid);
					return $http.get(queryUrl).then(function (response) {
						if (response.data) {
							return response.data;
						}
					});
				},
				encryptSharedCredential: function (credential, sharedKey) {
					var _credential = angular.copy(credential);
					_credential.shared_key = EncryptService.encryptString(sharedKey);
					var encrypted_fields = CredentialService.getEncryptedFields();
					for (var i = 0; i < encrypted_fields.length; i++) {
						var field = encrypted_fields[i];
						var fieldValue = angular.copy(credential[field]);
						_credential[field] = EncryptService.encryptString(JSON.stringify(fieldValue), sharedKey);
					}
					return _credential;
				},
				decryptSharedCredential: function (credential, sharedKey) {
					var _credential = angular.copy(credential);
					var encrypted_fields = CredentialService.getEncryptedFields();
					for (var i = 0; i < encrypted_fields.length; i++) {
						var field = encrypted_fields[i];
						var fieldValue = angular.copy(_credential[field]);
						var field_decrypted_value;
						if (_credential.hasOwnProperty(field)) {
							try {
								field_decrypted_value = EncryptService.decryptString(fieldValue, sharedKey);
							} catch (e) {
								throw e;
							}
							try {
								_credential[field] = JSON.parse(field_decrypted_value);
							} catch (e) {
								console.warn('Field' + field + ' in ' + _credential.label + ' could not be parsed! Value:' + fieldValue);
								throw e;
							}
						}
					}
					return _credential;
				},

				generateRSAKeys: function (key_length) {
					/** global: C_Promise */
					var p = new C_Promise(function () {
						/** global: forge */
						var state = forge.pki.rsa.createKeyPairGenerationState(key_length, 0x10001);
						var step = function () {
							// run for 100 ms
							/** global: forge */
							if (!forge.pki.rsa.stepKeyPairGenerationState(state, 100)) {
								if (state.p !== null) {
									// progress(50);
									this.call_progress(50);
								}
								else {
									// progress(0);
									this.call_progress(0);
								}
								setTimeout(step.bind(this), 1);
							}
							else {
								// callback(state.keys);
								this.call_then(state.keys);
							}
						};
						setTimeout(step.bind(this), 100);
					});
					return p;
				},
				generateSharedKey: function (size) {
					size = size || 20;
					/** global: C_Promise */
					return new C_Promise(function () {
						var t = this;
						/** global: CRYPTO */
						CRYPTO.PASSWORD.generate(size,
							function (pass) {
								t.call_then(pass);
							},
							function (progress) {
								t.call_progress(progress);
							}
						);
					});
				},
				rsaKeyPairToPEM: function (keypair) {
					return {
						'publicKey': forge.pki.publicKeyToPem(keypair.publicKey),
						'privateKey': forge.pki.privateKeyToPem(keypair.privateKey)
					};
				},
				getSharingKeys: function () {
					var vault = VaultService.getActiveVault();
					return {
						'private_sharing_key': EncryptService.decryptString(angular.copy(vault.private_sharing_key)),
						'public_sharing_key': vault.public_sharing_key
					};
				},
				rsaPrivateKeyFromPEM: function (private_pem) {
					/** global: forge */
					return forge.pki.privateKeyFromPem(private_pem);
				},
				rsaPublicKeyFromPEM: function (public_pem) {
					/** global: forge */
					return forge.pki.publicKeyFromPem(public_pem);
				},
				/**
				 * Cyphers an array of string in a non-blocking way
				 * @param vaults[]    An array of vaults with the processed public keys
				 * @param string    The string to cypher
				 */
				cypherRSAStringWithPublicKeyBulkAsync: function (vaults, string) {
					var workload = function () {
						if (this.current_index < this.vaults.length > 0 && this.vaults.length > 0) {
							var _vault = angular.copy(this.vaults[this.current_index]);
							/** global: forge */
							_vault.key = forge.util.encode64(
								_vault.public_sharing_key.encrypt(this.string)
							);
							this.data.push(
								_vault
							);
							this.current_index++;

							this.call_progress(this.current_index);
							setTimeout(workload.bind(this), 1);
						}
						else {
							this.call_then(this.data);
						}
					};
					/** global: C_Promise */
					return new C_Promise(function () {
						this.data = [];
						this.vaults = vaults;
						this.string = string;
						this.current_index = 0;

						setTimeout(workload.bind(this), 0);
					});
				}
			};
		}]);
}());<commit_msg>Fix error where compromised beeing null would disable shares<commit_after>/**
 * Nextcloud - passman
 *
 * @copyright Copyright (c) 2016, Sander Brand (brantje@gmail.com)
 * @copyright Copyright (c) 2016, Marcos Zuriaga Miguel (wolfi@wolfi.es)
 * @license GNU AGPL version 3 or any later version
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

(function () {
	'use strict';

	/**
	 * @ngdoc service
	 * @name passmanApp.ShareService
	 * @description
	 * # ShareService
	 * Service in the passmanApp.
	 */
	angular.module('passmanApp')
		.service('ShareService', ['$http', 'VaultService', 'EncryptService', 'CredentialService', function ($http, VaultService, EncryptService, CredentialService) {
			// Setup sjcl random engine to max paranoia level and start collecting data
			var paranoia_level = 10;
			/** global: sjcl */
			sjcl.random.setDefaultParanoia(paranoia_level);
			sjcl.random.startCollectors();

			return {
				search: function (string) {
					var queryUrl = OC.generateUrl('apps/passman/api/v2/sharing/search');
					return $http.post(queryUrl, {search: string}).then(function (response) {
						if (response.data) {
							return response.data;
						} else {
							return response;
						}
					});
				},
				shareWithUser: function (credential, target_user_data) {
					var queryUrl = OC.generateUrl('apps/passman/api/v2/sharing/share');
					return $http.post(queryUrl,
						{
							item_id: credential.credential_id,
							item_guid: credential.guid,
							permissions: target_user_data.accessLevel,
							vaults: target_user_data.vaults,
						}
					);
				},
				getVaultsByUser: function (userId) {
					var queryUrl = OC.generateUrl('apps/passman/api/v2/sharing/vaults/' + userId);
					return $http.get(queryUrl, {search: userId}).then(function (response) {
						if (response.data) {
							for (var i = 0; i < response.data.length; i++) {
								/** global: forge */
								response.data[i].public_sharing_key = forge.pki.publicKeyFromPem(response.data[i].public_sharing_key);
							}
							return response.data;
						} else {
							return response;
						}
					});
				},
				getPendingRequests: function () {
					var queryUrl = OC.generateUrl('apps/passman/api/v2/sharing/pending');
					return $http.get(queryUrl).then(function (response) {
						if (response.data) {
							return response.data;
						}
					});
				},
				saveSharingRequest: function (request, crypted_shared_key) {
					var queryUrl = OC.generateUrl('apps/passman/api/v2/sharing/save');
					return $http.post(queryUrl, {
						item_guid: request.item_guid,
						target_vault_guid: request.target_vault_guid,
						final_shared_key: crypted_shared_key
					}).then(function (response) {
						return response.data;
					});
				},
				declineSharingRequest: function (request) {
					var queryUrl = OC.generateUrl('apps/passman/api/v2/sharing/decline/' + request.req_id);
					return $http.delete(queryUrl).then(function (response) {
						return response.data;
					});
				},
				unshareCredential: function (credential) {
					var queryUrl = OC.generateUrl('apps/passman/api/v2/sharing/credential/' + credential.guid);
					return $http.delete(queryUrl).then(function (response) {
						return response.data;
					});
				},

				unshareCredentialFromUser: function (credential, user_id) {
					var queryUrl = OC.generateUrl('apps/passman/api/v2/sharing/credential/' + credential.guid + '/' + user_id);
					return $http.delete(queryUrl).then(function (response) {
						return response.data;
					});
				},

				createPublicSharedCredential: function (shareObj) {
					var queryUrl = OC.generateUrl('apps/passman/api/v2/sharing/public');
					return $http.post(queryUrl, shareObj).then(function (response) {
						return response.data;
					});
				},
				getPublicSharedCredential: function (credential_guid) {
					var queryUrl = OC.generateUrl('apps/passman/api/v2/sharing/credential/' + credential_guid + '/public');
					return $http.get(queryUrl).then(function (response) {
							if (response.data) {
								return response;
							} else {
								return response;
							}
						},
						function (result) {
							return result;
						});
				},
				getSharedCredentialACL: function (credential) {
					var queryUrl = OC.generateUrl('apps/passman/api/v2/sharing/credential/' + credential.guid + '/acl');
					return $http.get(queryUrl).then(function (response) {
							if (response.data) {
								return response.data;
							} else {
								return response;
							}
						},
						function (result) {
							return result;
						});
				},
				updateCredentialAcl: function (credential, acl) {
					var queryUrl = OC.generateUrl('apps/passman/api/v2/sharing/credential/' + credential.guid + '/acl');
					return $http.patch(queryUrl, acl).then(function (response) {
						return response.data;
					});
				},
				getCredendialsSharedWithUs: function (vault_guid) {
					var queryUrl = OC.generateUrl('apps/passman/api/v2/sharing/vault/' + vault_guid + '/get');
					return $http.get(queryUrl).then(function (response) {
						if (response.data) {
							return response.data;
						}
					});
				},
				downloadSharedFile: function (credential, file) {
					var queryUrl = OC.generateUrl('apps/passman/api/v2/sharing/credential/' + credential.guid + '/file/' + file.guid);
					return $http.get(queryUrl).then(function (response) {
						if (response.data) {
							return response.data;
						}
					});
				},
				encryptSharedCredential: function (credential, sharedKey) {
					var _credential = angular.copy(credential);
					_credential.shared_key = EncryptService.encryptString(sharedKey);
					var encrypted_fields = CredentialService.getEncryptedFields();
					for (var i = 0; i < encrypted_fields.length; i++) {
						var field = encrypted_fields[i];
						var fieldValue = angular.copy(credential[field]);
						_credential[field] = EncryptService.encryptString(JSON.stringify(fieldValue), sharedKey);
					}
					return _credential;
				},
				decryptSharedCredential: function (credential, sharedKey) {

					var _credential = angular.copy(credential);
					var encrypted_fields = CredentialService.getEncryptedFields();
					for (var i = 0; i < encrypted_fields.length; i++) {

						var field = encrypted_fields[i];
						var fieldValue = angular.copy(_credential[field]);
						var field_decrypted_value;
						if (_credential.hasOwnProperty(field)) {
							try {
								field_decrypted_value = EncryptService.decryptString(fieldValue, sharedKey);
							} catch (e) {
								if(field === 'compromised'){
									//old shares do not have compromised set, so we need to make sure that it will be set for version 2.3.0
									//credentials from 2.3.0 onwards have compromised already set, and don't need to worry about that.
									//if compromised is not the issue, break and throw an error
									field_decrypted_value=0;
								}else{
									throw e;
								}
							}
							try {
								_credential[field] = JSON.parse(field_decrypted_value);
							} catch (e) {
								console.warn('Field' + field + ' in ' + _credential.label + ' could not be parsed! Value:' + fieldValue);
								throw e;
							}
						}
					}
					return _credential;
				},

				generateRSAKeys: function (key_length) {
					/** global: C_Promise */
					var p = new C_Promise(function () {
						/** global: forge */
						var state = forge.pki.rsa.createKeyPairGenerationState(key_length, 0x10001);
						var step = function () {
							// run for 100 ms
							/** global: forge */
							if (!forge.pki.rsa.stepKeyPairGenerationState(state, 100)) {
								if (state.p !== null) {
									// progress(50);
									this.call_progress(50);
								}
								else {
									// progress(0);
									this.call_progress(0);
								}
								setTimeout(step.bind(this), 1);
							}
							else {
								// callback(state.keys);
								this.call_then(state.keys);
							}
						};
						setTimeout(step.bind(this), 100);
					});
					return p;
				},
				generateSharedKey: function (size) {
					size = size || 20;
					/** global: C_Promise */
					return new C_Promise(function () {
						var t = this;
						/** global: CRYPTO */
						CRYPTO.PASSWORD.generate(size,
							function (pass) {
								t.call_then(pass);
							},
							function (progress) {
								t.call_progress(progress);
							}
						);
					});
				},
				rsaKeyPairToPEM: function (keypair) {
					return {
						'publicKey': forge.pki.publicKeyToPem(keypair.publicKey),
						'privateKey': forge.pki.privateKeyToPem(keypair.privateKey)
					};
				},
				getSharingKeys: function () {
					var vault = VaultService.getActiveVault();
					return {
						'private_sharing_key': EncryptService.decryptString(angular.copy(vault.private_sharing_key)),
						'public_sharing_key': vault.public_sharing_key
					};
				},
				rsaPrivateKeyFromPEM: function (private_pem) {
					/** global: forge */
					return forge.pki.privateKeyFromPem(private_pem);
				},
				rsaPublicKeyFromPEM: function (public_pem) {
					/** global: forge */
					return forge.pki.publicKeyFromPem(public_pem);
				},
				/**
				 * Cyphers an array of string in a non-blocking way
				 * @param vaults[]    An array of vaults with the processed public keys
				 * @param string    The string to cypher
				 */
				cypherRSAStringWithPublicKeyBulkAsync: function (vaults, string) {
					var workload = function () {
						if (this.current_index < this.vaults.length > 0 && this.vaults.length > 0) {
							var _vault = angular.copy(this.vaults[this.current_index]);
							/** global: forge */
							_vault.key = forge.util.encode64(
								_vault.public_sharing_key.encrypt(this.string)
							);
							this.data.push(
								_vault
							);
							this.current_index++;

							this.call_progress(this.current_index);
							setTimeout(workload.bind(this), 1);
						}
						else {
							this.call_then(this.data);
						}
					};
					/** global: C_Promise */
					return new C_Promise(function () {
						this.data = [];
						this.vaults = vaults;
						this.string = string;
						this.current_index = 0;

						setTimeout(workload.bind(this), 0);
					});
				}
			};
		}]);
}());<|endoftext|>