Skip to content

Commit

Permalink
Closes #78 Add support to specify seeds to be created at server start…
Browse files Browse the repository at this point in the history
… up (#80)

* WIP adding new util function for creating seeds at startup

* WIP project creation implemented

* WIP adding authorization and fixing eslint errors.

* WIP - added config validation and tests.

* WIP - adding logging of creation and authorization.

* #80 Fixing review comments

* #80 Fixing review comments.

* #80 Fix eslint errors.
  • Loading branch information
kecso authored and Patrik Meijer committed Apr 3, 2018
1 parent 0dc9983 commit 95fdb36
Show file tree
Hide file tree
Showing 8 changed files with 492 additions and 7 deletions.
3 changes: 2 additions & 1 deletion config/config.default.js
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,8 @@ var path = require('path'),
enable: true,
allowDuplication: true, //requires mongodb >= 2.6
defaultProject: 'EmptyProject',
basePaths: [path.join(__dirname, '../seeds')]
basePaths: [path.join(__dirname, '../seeds')],
createAtStartup: []
},

server: {
Expand Down
17 changes: 17 additions & 0 deletions config/validator.js
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,23 @@ function validateConfig(configOrFileName) {
assertBoolean('config.seedProjects.enable', config.seedProjects.enable);
assertString('config.seedProjects.defaultProject', config.seedProjects.defaultProject);
assertArray('config.seedProjects.basePaths', config.seedProjects.basePaths);
assertArray('config.seedProjects.createAtStartup', config.seedProjects.createAtStartup);
config.seedProjects.createAtStartup.forEach(function (seedInfo, index) {
assertObject('config.seedProjects.createAtStartup[' + index + ']', config.seedProjects.createAtStartup[index]);
assertString('config.seedProjects.createAtStartup[' + index + '].seedId',
config.seedProjects.createAtStartup[index].seedId);
assertString('config.seedProjects.createAtStartup[' + index + '].projectName', seedInfo.projectName);
assertObject('config.seedProjects.createAtStartup[' + index + '].rights', seedInfo.rights);
if (seedInfo.creatorId) {
assertString('config.seedProjects.createAtStartup[' + index + '].creatorId', seedInfo.creatorId);
} else if (typeof config.authentication.adminAccount !== 'string') {
throw new Error('Either config.seedProjects.createAtStartup[' + index +
'].creatorId or config.authentication.adminAccount should exists!');
}
if (seedInfo.ownerId) {
assertString('config.seedProjects.createAtStartup[' + index + '].ownerId', seedInfo.ownerId);
}
});

// server configuration
expectedKeys.push('server');
Expand Down
4 changes: 3 additions & 1 deletion index.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ var requirejs = require('requirejs'),
path = require('path'),
requireJsBase = path.join(__dirname, 'src'),
fs = require('fs'),
webgmeUtils = require('./src/utils'),
webgmeUtils,
_core,
_canon,
_Logger,
Expand All @@ -36,6 +36,8 @@ requirejs.config({
}
});

webgmeUtils = require('./src/utils');

function addToRequireJsPaths(gmeConfig) {

function addFromBasePath(basepaths, componentName, componentNames) {
Expand Down
3 changes: 3 additions & 0 deletions src/server/standalone.js
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,9 @@ function StandAloneServer(gmeConfig) {

return serverDeferred.promise;
})
.then(function () {
return webgmeUtils.createStartUpProjects(gmeConfig, __gmeAuth, __storage, logger, getUrl());
})
.nodeify(function (err) {
self.isRunning = true;
if (err) {
Expand Down
92 changes: 90 additions & 2 deletions src/utils.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/*globals*/
/*globals requireJS*/
/*eslint-env node*/

/**
Expand All @@ -13,6 +13,7 @@ var fs = require('fs'),
Q = require('q'),
path = require('path'),
requireUncached = require('require-uncached'),
storageUtils = requireJS('common/storage/util'),
SVGMapDeffered;

function walkDir(dir, done) {
Expand Down Expand Up @@ -416,6 +417,92 @@ function getComponentsJson(logger, callback) {
return deferred.promise.nodeify(callback);
}

function createStartUpProjects(gmeConfig, gmeAuth, storage, logger, url) {
var deferred = Q.defer(),
WorkerRequest = require('./server/worker/workerrequests'),
worker = new WorkerRequest(logger.fork('worker'), gmeConfig, url),
configArray = JSON.parse(JSON.stringify(gmeConfig.seedProjects.createAtStartup)),
promises = [],
creators = [],
tokens = [],
createdProjects = [],
isProjectExists = function (projectId, list) {
var exists = false;

list.forEach(function (projectInfo) {
if (projectInfo._id === projectId) {
exists = true;
}
});
return exists;
};


configArray.forEach(function (projectInfo) {
projectInfo.creatorId = projectInfo.creatorId || gmeConfig.authentication.admin;
projectInfo.ownerId = projectInfo.ownerId || projectInfo.creatorId;

if (creators.indexOf(projectInfo.creatorId) === -1) {
creators.push(projectInfo.creatorId);
promises.push(gmeAuth.generateJWTokenForAuthenticatedUser(projectInfo.creatorId));
}
});

Q.all(promises)
.then(function (tokens_) {
var promises = [];

tokens = tokens_;
creators.forEach(function (owner) {
promises.push(storage.getProjects({username: owner}));
});

return Q.all(promises);
})
.then(function (projectLists) {
promises = [];
configArray.forEach(function (projectInfo) {
var index = creators.indexOf(projectInfo.creatorId),
id = storageUtils.getProjectIdFromOwnerIdAndProjectName(projectInfo.ownerId,
projectInfo.projectName);

if (isProjectExists(id, projectLists[index]) === false) {
createdProjects.push(projectInfo);
logger.info('Creating \'' + projectInfo.projectName + '\' for \'' + projectInfo.ownerId +
'\' from seed[' + projectInfo.seedId + '].');
promises.push(Q.ninvoke(worker, 'seedProject', tokens[index], projectInfo.projectName,
projectInfo.ownerId, {seedName: projectInfo.seedId, type: 'file'}));
}
});

return Q.all(promises);
})
.then(function () {
var authorizationRequests = [],
projectAuthParams = {
entityType: gmeAuth.authorizer.ENTITY_TYPES.PROJECT
};

createdProjects.forEach(function (projectInfo) {
var userOrOrg,
id = storageUtils.getProjectIdFromOwnerIdAndProjectName(projectInfo.ownerId,
projectInfo.projectName);

for (userOrOrg in projectInfo.rights) {
logger.info('Authorizing \'' + userOrOrg + '\' to use \'' + projectInfo.projectName +
'\' of \'' + projectInfo.ownerId + '.');
authorizationRequests.push(gmeAuth.authorizer.setAccessRights(userOrOrg,
id, projectInfo.rights[userOrOrg], projectAuthParams));
}
});

return Q.all(authorizationRequests);
})
.then(deferred.resolve)
.catch(deferred.reject);
return deferred.promise;
}

module.exports = {
isGoodExtraAsset: isGoodExtraAsset,
getComponentNames: getComponentNames,
Expand All @@ -430,5 +517,6 @@ module.exports = {
getRedirectUrlParameter: getRedirectUrlParameter,
getSeedDictionary: getSeedDictionary,
getSeedDictionarySync: getSeedDictionarySync,
getComponentsJson: getComponentsJson
getComponentsJson: getComponentsJson,
createStartUpProjects: createStartUpProjects,
};
49 changes: 49 additions & 0 deletions test/config/config.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,55 @@ describe('configuration and components', function () {
}
});

it('should throw if projectSeeds.createAtStartup is malformed',
function () {
var config;
process.env.NODE_ENV = 'test';
config = require('../../config');
unloadConfigs();
validateConfig = require('../../config/validator').validateConfig;

(function () {
var myConf = JSON.parse(JSON.stringify(config));
myConf.seedProjects.createAtStartup = [{seedId: 'EmptyProjecct', projectName: 'One', rights: {}}];
validateConfig(myConf);
}).should.throw(Error);
(function () {
var myConf = JSON.parse(JSON.stringify(config));
myConf.seedProjects.createAtStartup = 'fault';
validateConfig(myConf);
}).should.throw(Error);

(function () {
var myConf = JSON.parse(JSON.stringify(config));
myConf.seedProjects.createAtStartup = [{projectName: 'One', ownerId: 'admin', rights: {}}];
validateConfig(myConf);
}).should.throw(Error);

(function () {
var myConf = JSON.parse(JSON.stringify(config));
myConf.seedProjects.createAtStartup = [{
seedId: 'EmptyProjecct',
projectName: 'One',
creatorId: 'admin',
rights: {}
}];
validateConfig(myConf);
}).should.not.throw(Error);

(function () {
var myConf = JSON.parse(JSON.stringify(config));
myConf.authentication.adminAccount = 'admin';
myConf.seedProjects.createAtStartup = [{
seedId: 'EmptyProjecct',
projectName: 'One',
rights: {}
}];
validateConfig(myConf);
}).should.not.throw(Error);
}
);

it('clientconfig should not expose mongo', function () {
var config,
clientConfig;
Expand Down
3 changes: 0 additions & 3 deletions test/server/standalone.auth.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,6 @@ describe('standalone http server with authentication turned on', function () {
});
});


it('should log in', function (done) {
logIn(function (err) {
if (err) {
Expand Down Expand Up @@ -196,7 +195,6 @@ describe('standalone http server with authentication turned on', function () {
});
});


it('should be able to export an authorized project /worker/simpleResult/:id/exported_branch', function (done) {
var projectName = 'project',
projectId = testFixture.projectName2Id(projectName),
Expand Down Expand Up @@ -246,7 +244,6 @@ describe('standalone http server with authentication turned on', function () {
.nodeify(done);
});


it('should return a readable error', function (done) {
var projectName = 'DoesntExist';
openSocketIo()
Expand Down
Loading

0 comments on commit 95fdb36

Please sign in to comment.