diff --git a/app/controllers/forms.server.controller.js b/app/controllers/forms.server.controller.js
index 8beb8c3e..f3092d9d 100644
--- a/app/controllers/forms.server.controller.js
+++ b/app/controllers/forms.server.controller.js
@@ -308,7 +308,7 @@ exports.create = function(req, res) {
});
}
- createdForm = helpers.removeSensitiveModelData('private_form', createdForm);
+ createdForm = helpers.removeSensitiveModelData('private_form', createdForm.toJSON());
return res.json(createdForm);
});
};
@@ -326,13 +326,8 @@ exports.read = function(req, res) {
});
}
- var newForm = req.form.toJSON();
-
- if(newForm.admin === req.user._id){
- return res.json(newForm);
- }
-
- newForm = helpers.removeSensitiveModelData('private_form', newForm);
+ newForm = helpers.removeSensitiveModelData('private_form', req.form.toJSON());
+
return res.json(newForm);
}
};
@@ -348,7 +343,7 @@ var readForRender = exports.readForRender = function(req, res) {
});
}
- newForm = helpers.removeSensitiveModelData('public_form', newForm);
+ newForm = helpers.removeSensitiveModelData('public_form', newForm.toJSON());
if(newForm.startPage && !newForm.startPage.showStart){
delete newForm.startPage;
@@ -413,7 +408,7 @@ exports.update = function(req, res) {
message: errorHandler.getErrorMessage(err)
});
} else {
- savedForm = helpers.removeSensitiveModelData('private_form', savedForm);
+ savedForm = helpers.removeSensitiveModelData('private_form', savedForm.toJSON());
res.json(savedForm);
}
});
@@ -526,7 +521,7 @@ exports.formByID = function(req, res, next, id) {
}
else {
//Remove sensitive information from User object
- req.form = helpers.removeSensitiveModelData('private_form', form);
+ req.form = helpers.removeSensitiveModelData('private_form', form.toJSON());
return next();
}
});
diff --git a/app/controllers/helpers.server.controller.js b/app/controllers/helpers.server.controller.js
index c25f6682..9b4c3792 100644
--- a/app/controllers/helpers.server.controller.js
+++ b/app/controllers/helpers.server.controller.js
@@ -1,6 +1,7 @@
'use strict';
const constants = require('../libs/constants');
+const _ = require('lodash');
module.exports = {
removeKeysFromDict: function(dict, keys){
@@ -10,29 +11,18 @@ module.exports = {
delete dict[curr_key];
}
}
+ return dict;
},
- removeSensitiveModelData: function(type, object){
- switch(type){
- case 'private_form':
- this.removeKeysFromDict(object, constants.privateFields[type]);
- if(object.admin){
- this.removeKeysFromDict(object.admin, constants.privateFields.private_user);
- }
- break;
+ removeSensitiveModelData: function(type, actual_object){
+ var object = _.cloneDeep(actual_object);
- case 'public_form':
- this.removeKeysFromDict(object, constants.privateFields[type]);
- if(object.admin){
- this.removeKeysFromDict(object.admin, constants.privateFields.public_user);
- }
- break;
-
- default:
- if(constants.privateFields.hasOwnProperty(type)){
- this.removeKeysFromDict(object, constants.privateFields[type]);
- }
- break;
- }
+ if(constants.privateFields.hasOwnProperty(type)) {
+ object = this.removeKeysFromDict(object, constants.privateFields[type]);
+ }
+ if(object.admin){
+ object.admin = this.removeKeysFromDict(object.admin, constants.privateFields.private_user);
+ }
+ debugger;
return object;
}
diff --git a/app/controllers/users/users.authentication.server.controller.js b/app/controllers/users/users.authentication.server.controller.js
index 852c20c7..4bb853f5 100755
--- a/app/controllers/users/users.authentication.server.controller.js
+++ b/app/controllers/users/users.authentication.server.controller.js
@@ -180,7 +180,7 @@ exports.signin = function(req, res, next) {
res.cookie('langCookie', user.language, { maxAge: 90000, httpOnly: true });
- user = helpers.removeSensitiveModelData('private_user', user);
+ user = helpers.removeSensitiveModelData('private_user', user.toJSON());
return res.json(user);
});
}
diff --git a/app/controllers/users/users.profile.server.controller.js b/app/controllers/users/users.profile.server.controller.js
index d6176f30..b03bcbc0 100755
--- a/app/controllers/users/users.profile.server.controller.js
+++ b/app/controllers/users/users.profile.server.controller.js
@@ -18,6 +18,8 @@ exports.update = function(req, res) {
// To improve security we remove the roles from the req.body object
delete req.body.roles;
+ debugger;
+
// Merge existing user
user = _.extend(user, req.body);
user.updated = Date.now();
@@ -32,7 +34,7 @@ exports.update = function(req, res) {
if (err) {
res.status(500).send(loginErr);
} else {
- user = helpers.removeSensitiveModelData('private_user', user);
+ user = helpers.removeSensitiveModelData('private_user', user.toJSON());
res.json(user);
}
});
@@ -44,7 +46,7 @@ exports.update = function(req, res) {
* Send User
*/
exports.getUser = function(req, res) {
- var user = helpers.removeSensitiveModelData('private_user', req.user);
+ var user = helpers.removeSensitiveModelData('private_user', req.user.toJSON());
return res.json(user);
};
diff --git a/app/libs/constants.js b/app/libs/constants.js
index f2bb9765..73ec3dbd 100644
--- a/app/libs/constants.js
+++ b/app/libs/constants.js
@@ -1,6 +1,7 @@
'use strict';
-module.exports = {
+var constants = module.exports = {
+
extraneousFormFieldProps: [
'validFieldTypes',
'disabled',
@@ -106,6 +107,7 @@ module.exports = {
userRoleTypes: ['user', 'admin', 'superuser'],
regex: {
+ username: /^[a-zA-Z0-9\-]+$/,
url: /((([A-Za-z]{3,9}:(?:\/\/)?)(?:[-;:&=\+\$,\w]+@)?[A-Za-z0-9.-]+|(?:www.|[-;:&=\+\$,\w]+@)[A-Za-z0-9.-]+)((?:\/[\+~%\/.\w-_]*)?\??(?:[-\+=&;%@.\w_]*)#?(?:[\w]*))?)/,
hexCode: /^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/,
email: /^(([^<>()\[\]\\.,;:\s@']+(\.[^<>()\[\]\\.,;:\s@']+)*)|('.+'))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/,
diff --git a/app/models/form.server.model.js b/app/models/form.server.model.js
index 3693a93f..471ab20a 100644
--- a/app/models/form.server.model.js
+++ b/app/models/form.server.model.js
@@ -241,3 +241,4 @@ FormSchema.index({created: 1});
mongoose.model('Form', FormSchema);
+module.exports = mongoose.model('Form');
\ No newline at end of file
diff --git a/app/models/form_submission.server.model.js b/app/models/form_submission.server.model.js
index 8c674818..e9620d84 100644
--- a/app/models/form_submission.server.model.js
+++ b/app/models/form_submission.server.model.js
@@ -81,3 +81,5 @@ FormSubmissionSchema.plugin(timeStampPlugin, {
});
mongoose.model('FormSubmission', FormSubmissionSchema);
+
+module.exports = mongoose.model('FormSubmission');
\ No newline at end of file
diff --git a/app/models/user.server.model.js b/app/models/user.server.model.js
index ab0a7cc6..d5484c72 100755
--- a/app/models/user.server.model.js
+++ b/app/models/user.server.model.js
@@ -38,7 +38,7 @@ var UserSchema = new Schema({
type: String,
unique: true,
lowercase: true,
- match: [/^[a-zA-Z0-9\-]+$/, 'Username can only contain alphanumeric characters and \'-\''],
+ match: [constants.regex.username, 'Username can only contain alphanumeric characters and \'-\''],
required: [true, 'Username is required']
},
passwordHash: {
@@ -165,4 +165,6 @@ UserSchema.methods.isAdmin = function() {
return false;
};
-module.exports = mongoose.model('User', UserSchema);
+mongoose.model('User', UserSchema);
+
+module.exports = mongoose.model('User');
\ No newline at end of file
diff --git a/app/tests/form.server.model.test.js b/app/tests/form.server.model.test.js
index 849415a5..c2c16a65 100644
--- a/app/tests/form.server.model.test.js
+++ b/app/tests/form.server.model.test.js
@@ -7,8 +7,8 @@ require('../../server.js');
*/
var should = require('should'),
mongoose = require('mongoose'),
- User = mongoose.model('User'),
- Form = mongoose.model('Form');
+ User = require('../models/user.server.model.js'),
+ Form = require('../models/form.server.model.js');
/**
* Globals
diff --git a/app/tests/form.server.routes.test.js b/app/tests/form.server.routes.test.js
index e55e35ea..b967a364 100644
--- a/app/tests/form.server.routes.test.js
+++ b/app/tests/form.server.routes.test.js
@@ -6,10 +6,10 @@ var should = require('should'),
request = require('supertest'),
Session = require('supertest-session'),
mongoose = require('mongoose'),
- User = mongoose.model('User'),
- Form = mongoose.model('Form'),
+ User = require('../models/user.server.model.js'),
+ Form = require('../models/form.server.model.js'),
+ FormSubmission = require('../models/form_submission.server.model.js'),
Field = mongoose.model('Field'),
- FormSubmission = mongoose.model('FormSubmission'),
async = require('async'),
_ = require('lodash');
diff --git a/app/tests/form_submission.model.test.js b/app/tests/form_submission.model.test.js
index 36935165..d08851a0 100644
--- a/app/tests/form_submission.model.test.js
+++ b/app/tests/form_submission.model.test.js
@@ -11,7 +11,7 @@ var should = require('should'),
_ = require('lodash'),
async = require('async'),
config = require('../../config/config'),
- FormSubmission = mongoose.model('FormSubmission');
+ FormSubmission = require('../models/form_submission.server.model.js');
var exampleDemo = {
address: '880-9650 Velit. St.',
diff --git a/app/tests/user.server.model.test.js b/app/tests/user.server.model.test.js
index 5a7cb9ad..b15fb3b1 100755
--- a/app/tests/user.server.model.test.js
+++ b/app/tests/user.server.model.test.js
@@ -5,8 +5,8 @@
*/
var should = require('should'),
mongoose = require('mongoose'),
- User = mongoose.model('User');
-
+ User = require('../models/user.server.model.js');
+
/**
* Globals
*/
diff --git a/app/tests/user.server.routes.test.js b/app/tests/user.server.routes.test.js
index 7198d449..7ed5e006 100644
--- a/app/tests/user.server.routes.test.js
+++ b/app/tests/user.server.routes.test.js
@@ -4,7 +4,7 @@ var should = require('should'),
app = require('../../server'),
Session = require('supertest-session'),
mongoose = require('mongoose'),
- User = mongoose.model('User'),
+ User = require('../models/user.server.model.js'),
config = require('../../config/config'),
tmpUser = mongoose.model(config.tempUserCollection),
async = require('async');
diff --git a/config/env/all.js b/config/env/all.js
index abeb7c33..ce66a168 100755
--- a/config/env/all.js
+++ b/config/env/all.js
@@ -13,12 +13,10 @@ module.exports = {
useMongoClient: true
}
},
-
-
admin: {
email: process.env.ADMIN_EMAIL || 'admin@admin.com',
- username: process.env.ADMIN_USERNAME || 'admin',
- password: process.env.ADMIN_PASSWORD || 'admin',
+ username: process.env.ADMIN_USERNAME || 'root',
+ password: process.env.ADMIN_PASSWORD || 'root',
roles: ['user', 'admin']
},
diff --git a/dump.rdb b/dump.rdb
deleted file mode 100644
index c6e61e2a..00000000
Binary files a/dump.rdb and /dev/null differ
diff --git a/package-lock.json b/package-lock.json
index 8516edc5..ebd0238c 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -9857,6 +9857,11 @@
"resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-4.0.1.tgz",
"integrity": "sha1-uVhksH+s7oKH6CMu/9bx1W7HWrI="
},
+ "nodemailer-wellknown": {
+ "version": "0.2.3",
+ "resolved": "https://registry.npmjs.org/nodemailer-wellknown/-/nodemailer-wellknown-0.2.3.tgz",
+ "integrity": "sha1-ZA7SBKAWYnZD+Yc5qU+O+dOcoKk="
+ },
"nodemon": {
"version": "1.12.1",
"resolved": "https://registry.npmjs.org/nodemon/-/nodemon-1.12.1.tgz",
diff --git a/public/modules/forms/tests/unit/directives/field-icon.client.directive.test.js b/public/modules/forms/tests/unit/directives/field-icon.client.directive.test.js
index 7dfc6823..728e16db 100644
--- a/public/modules/forms/tests/unit/directives/field-icon.client.directive.test.js
+++ b/public/modules/forms/tests/unit/directives/field-icon.client.directive.test.js
@@ -97,7 +97,9 @@
currType = FormFields.types[i];
currClass = faClasses[currType.name];
- var element = $compile('')(scope);
+ scope.currType = currType;
+
+ var element = $compile('')(scope);
scope.$digest();
expect(currClass).toBeDefined();
diff --git a/scripts/create_admin.js b/scripts/create_admin.js
index ea3b1469..1ce9a76c 100644
--- a/scripts/create_admin.js
+++ b/scripts/create_admin.js
@@ -7,9 +7,6 @@ exports.run = function(app, db, cb) {
var User = mongoose.model('User');
var username = config.admin.username;
-
- console.log('username: ' + config.admin.username);
- console.log('password: ' + config.admin.password);
var newUserObj = {
firstName: 'Admin',
diff --git a/scripts/setup.js b/scripts/setup.js
index d8e5350c..e91f29fa 100644
--- a/scripts/setup.js
+++ b/scripts/setup.js
@@ -3,239 +3,188 @@
/**
* Module dependencies.
*/
-process.env.NODE_ENV = 'production';
-var config = require('../config/config'),
- mongoose = require('mongoose'),
+var mongoose = require('mongoose'),
inquirer = require('inquirer'),
envfile = require('envfile'),
fs = require('fs-extra'),
- chalk = require('chalk');
+ chalk = require('chalk'),
+ constants = require('./setup_constants'),
+ _ = require('lodash');
-// Bootstrap db connection
-var db = mongoose.connect(config.db.uri, config.db.options, function(err) {
- if (err) {
- console.error(chalk.red('Could not connect to MongoDB!'));
- console.log(chalk.red(err));
+var exitSuccess = function(cb) {
+ console.log(chalk.green('TellForm has been successfully setup'));
+ console.log(chalk.green('Have fun using TellForm!'));
+
+ if(require.main === module){
+ process.exit(1);
+ } else if(cb && typeof cb === 'function'){
+ cb();
}
-});
-mongoose.connection.on('error', function(err) {
- console.error(chalk.red('MongoDB connection error: ' + err));
- process.exit(-1);
-});
-
-// Init the express application
-require('../config/express')(db);
-
-// Bootstrap passport config
-require('../config/passport')();
-
-var User = mongoose.model('User');
-require('../app/models/user.server.model.js');
-
-var nodemailer_providers = [
- '1und1',
- 'AOL',
- 'DebugMail.io',
- 'DynectEmail',
- 'FastMail',
- 'GandiMail',
- 'Gmail',
- 'Godaddy',
- 'GodaddyAsia',
- 'GodaddyEurope',
- 'hot.ee',
- 'Hotmail',
- 'iCloud',
- 'mail.ee',
- 'Mail.ru',
- 'Mailgun',
- 'Mailjet',
- 'Mandrill',
- 'Naver',
- 'OpenMailBox',
- 'Postmark',
- 'QQ',
- 'QQex',
- 'SendCloud',
- 'SendGrid',
- 'SES',
- 'SES-US-EAST-1',
- 'SES-US-WEST-1',
- 'SES-EU-WEST-1',
- 'Sparkpost',
- 'Yahoo',
- 'Yandex',
- 'Zoho'
-];
-
-var bool_options = [
- "TRUE",
- "FALSE"
-];
-
-var questions = [
- {
- type: 'confirm',
- name: 'shouldContinue',
- message: 'Do you wish to configure your deployment now?'
- },
- {
- type: 'input',
- name: 'APP_NAME',
- message: 'What do you want to name your TellForm deployment?'
- },
- {
- type: 'input',
- name: 'APP_DESC',
- message: 'Describe your project (for SEO) (optional)'
- },
- {
- type: 'input',
- name: 'APP_KEYWORDS',
- message: 'What keywords are relevant to your project (seperate by commas) (optional)'
- },
- {
- type: 'confirm',
- name: 'SIGNUP_DISABLED',
- message: 'Do you want to disable signups?',
- default: false
- },
- {
- type: 'list',
- name: 'SUBDOMAINS_DISABLED',
- message: 'Do you want to have subdomains? (i.e. are you using a custom domain)',
- choices: bool_options
- },
- {
- type: 'list',
- name: 'MAILER_SERVICE_PROVIDER',
- message: 'What email service provider are you using?',
- choices: nodemailer_providers
- },
- {
- type: 'input',
- name: 'MAILER_EMAIL_ID',
- message: 'What is your SMTP username?'
- },
- {
- type: 'password',
- name: 'MAILER_PASSWORD',
- message: 'What is your SMTP password?'
- },
- {
- type: 'input',
- name: 'MAILER_FROM',
- message: 'What do you want the default "from" email address to be?'
- },
- {
- type: 'input',
- name: 'BASE_URL',
- message: 'What is the url your TellForm will be hosted at?',
- default: 'localhost'
- },
- {
- type: 'input',
- name: 'PORT',
- message: 'What port should the TellForm server run on?',
- default: '3000'
- },
- {
- type: 'input',
- name: 'GOOGLE_ANALYTICS_ID',
- message: 'What is your Google Analytics Tag? (optional)'
- },
- {
- type: 'input',
- name: 'RAVEN_DSN',
- message: 'What is your Private Raven DSN key? (optional)'
- },
- {
- type: 'input',
- name: 'PRERENDER_TOKEN',
- message: 'What is your Prerender.io token? (optional)'
- },
- {
- type: 'input',
- name: 'COVERALLS_REPO_TOKEN',
- message: 'What is your Coveralls.io token? (optional)'
- },
- {
- type: 'input',
- name: 'COVERALLS_REPO_TOKEN',
- message: 'What is your reCAPTCHA token? (optional)'
- },
- {
- type: 'input',
- name: 'email',
- message: 'What should be the email for your admin account?'
- },
- {
- type: 'input',
- name: 'username',
- message: 'What should be the username for your admin account?'
- },
- {
- type: 'password',
- name: 'password',
- message: 'What should be the password for your admin account?'
- }
-];
-
-if(!fs.existsSync('./\.env')) {
- console.log(chalk.green('\n\nHi, welcome to TellForm Setup'));
-
- console.log(chalk.green('You should only run this the first time you run TellForm\n--------------------------------------------------\n\n'));
-
- inquirer.prompt([questions[0]]).then(function (confirmAns) {
- if (confirmAns['shouldContinue']) {
-
- inquirer.prompt(questions.slice(1)).then(function (answers) {
- answers['NODE_ENV'] = 'production';
-
- var email = answers['email'];
- var username = answers['username'];
- var pass = answers['password'];
- delete answers['email'];
- delete answers['password'];
-
- envfile.stringify(answers, function (err, str) {
- try {
- fs.outputFileSync('./\.env', str);
- } catch (fileErr) {
- return console.error(chalk.red(fileErr));
- }
-
- console.log(chalk.green('Successfully created .env file'));
-
- user = new User({
- firstName: 'Admin',
- lastName: 'Account',
- email: email,
- username: username,
- password: pass,
- provider: 'local',
- roles: ['admin', 'user']
- });
-
- user.save(function (userSaveErr) {
- if (err) {
- return console.error(chalk.red(userSaveErr));
- }
-
- console.log(chalk.green('Successfully created user'));
-
- console.log(chalk.green('Have fun using TellForm!'));
- process.exit(1);
- });
- });
- });
- } else {
- console.log(chalk.green('Have fun using TellForm!'));
- process.exit(1);
- }
- });
-} else {
- console.log(chalk.red('You already have a .env file'));
- process.exit(1);
+}
+
+var exitError = function(err, cb){
+ console.error(chalk.red(err.message || err));
+ if(require.main === module){
+ process.exit(-1);
+ } else if(cb && typeof cb === 'function'){
+ cb();
+ }
+}
+
+var removeENVFile = function() {
+ fs.unlinkSync('./\.env')
+}
+
+var createOrUpdateAdminUser = function(username, email, password, cb){
+ //Command Line Bootstrapping Code
+ if (require.main === module) {
+ var config = require('../config/config');
+
+ // Bootstrap db connection
+ var db = mongoose.connect(config.db.uri, config.db.options, function(err) {
+ if (err) {
+ console.error(chalk.red('Could not connect to MongoDB!'));
+ return cb(new Error(err));
+ }
+ });
+ mongoose.connection.on('error', function(err) {
+ return cb(new Error('MongoDB connection error: ' + err));
+ });
+
+ // Init the express application
+ require('../config/express')(db);
+
+ // Bootstrap passport config
+ require('../config/passport')();
+ }
+
+ var User = require('../app/models/user.server.model.js');
+
+ var updateObj = {
+ firstName: 'Admin',
+ lastName: 'Account',
+ username: username,
+ email: email,
+ provider: 'local',
+ roles: ['admin', 'user']
+ }
+
+ var options = {
+ upsert: true,
+ new: true,
+ setDefaultsOnInsert: true
+ }
+
+ User.findOneAndUpdate({ username: username }, updateObj, options, function (err, user) {
+ if (err) {
+ delete pass;
+ delete email;
+ delete username;
+ return cb(err);
+ }
+
+ if(!user){
+ delete pass;
+ delete email;
+ delete username;
+ return cb(new Error('Admin User could not be created'));
+ }
+
+ user.password = password
+ user.save(function(err) {
+ if(err){
+ delete pass;
+ delete email;
+ delete username;
+ return cb(err);
+ }
+
+ delete pass;
+ delete email;
+ delete username;
+
+ console.log(chalk.green('Successfully created user'));
+
+ cb();
+ });
+ });
+
+}
+
+var createENVFile = function(cb) {
+ inquirer.prompt(constants.questionsPart1).then(function (answersPart1) {
+ var nextQuestions = constants.mailerWellKnownQuestions.concat(constants.questionsPart2);
+ if(answersPart1['MAILER_SERVICE_PROVIDER'] === 'Custom Mailserver'){
+ nextQuestions = constants.mailerCustomQuestions.concat(constants.questionsPart2);
+ }
+
+ inquirer.prompt(nextQuestions).then(function (answersPart2) {
+ var answers = _.chain(anwsersPart1)._extend(answersPart2).mapValues(function(val){
+ if(_.isBoolean(val)){
+ return val ? 'TRUE' : 'FALSE';
+ }
+ return val;
+ }).values();
+
+ var email = answers['email'];
+ var username = answers['username'];
+ var pass = answers['password'];
+ delete answers['email'];
+ delete answers['username'];
+ delete answers['password'];
+
+ envfile.stringify(answers, function (err, str) {
+ try {
+ fs.outputFileSync('./\.env', str);
+ } catch (fileErr) {
+ console.error(chalk.red(fileErr));
+ process.exit(-1);
+ }
+
+ console.log(chalk.green('Successfully created .env file'));
+
+ createOrUpdateAdminUser(username, email, pass, function(err){
+ if(err) {
+ return exitError(err, cb);
+ }
+ exitSuccess(cb);
+ });
+
+ });
+ });
+ });
+}
+
+var checkENVAndRunSetup = function(cb) {
+ console.log(chalk.green(constants.asciiArt));
+ if(require.main === module){
+ console.log(chalk.green('Welcome to TellForm\'s Setup Tool'));
+ console.log(chalk.green('Follow the prompts to begin.\n-------------------------------------------\n\n'));
+ }
+
+ if(fs.existsSync('./\.env') && require.main === module) {
+ inquirer.prompt([constants.replaceENVQuestion]).then(function (envAnswer) {
+ if (envAnswer['replaceENVFile']) {
+ removeENVFile();
+ createENVFile(cb);
+ } else {
+ exitSuccess(cb);
+ }
+ });
+ } else {
+
+ if(require.main !== module){
+ console.log(chalk.green('Welcome to TellForm\'s Initial Setup\n'));
+ console.log(chalk.green('The following prompts will help you properly configure your TellForm instance.'));
+ console.log(chalk.green('If you want to run this tool after your inital setup, run `node scripts/setup.js`.\n---------------------------------------------------------------------\n\n'));
+ }
+ createENVFile();
+ }
+}
+
+module.exports.checkENVAndRunSetup = checkENVAndRunSetup;
+
+if(require.main === module) {
+ checkENVAndRunSetup();
}
diff --git a/scripts/setup_constants.js b/scripts/setup_constants.js
new file mode 100644
index 00000000..29397906
--- /dev/null
+++ b/scripts/setup_constants.js
@@ -0,0 +1,201 @@
+var constants = require('../app/libs/constants');
+
+var createRegexValidator = function(regex, message){
+ return function(value) {
+ var isValid = new RegExp(regex, 'g').test(value);
+
+ if(!isValid){
+ return message
+ } else {
+ return true;
+ }
+ }
+}
+
+var validateEmail = createRegexValidator(constants.regex.email, 'Please enter a valid email');
+var validateUsername = createRegexValidator(constants.regex.username, 'Usernames can only contain alphanumeric characters and \'-\'');
+
+module.exports = {
+ asciiArt: " _____ _ _______ \n" +
+ " |_ _| | | | ___| \n" +
+ " | | ___| | | |_ ___ _ __ _ __ ___ \n" +
+ " | |/ _ \\ | | _/ _ \\| '__| '_ ` _ \\ \n" +
+ " | | __/ | | || (_) | | | | | | | |\n" +
+ " \\_/\\___|_|_\\_| \\___/|_| |_| |_| |_|\n",
+
+
+ replaceENVQuestion: {
+ type: 'confirm',
+ name: 'replaceENVFile',
+ message: 'An older .env file already exists. Do you want to replace it?',
+ default: false
+ },
+
+ questionsPart1: [
+ {
+ type: 'list',
+ name: 'NODE_ENV',
+ message: 'What mode do you want to run TellForm in?',
+ choices: ['development', 'production', 'test'],
+ default: 'development'
+ },
+ {
+ type: 'input',
+ name: 'APP_NAME',
+ message: 'What do you want to name your TellForm deployment?'
+ },
+ {
+ type: 'input',
+ name: 'APP_DESC',
+ message: 'Describe your project (for SEO) (optional)'
+ },
+ {
+ type: 'confirm',
+ name: 'SIGNUP_DISABLED',
+ message: 'Do you want to disable signups?',
+ default: false
+ },
+ {
+ type: 'confirm',
+ name: 'SUBDOMAINS_DISABLED',
+ message: 'Do you want to disable subdomains? (i.e. are you using a custom domain)'
+ },
+ {
+ type: 'list',
+ name: 'MAILER_SERVICE_PROVIDER',
+ message: 'What email service provider are you using?',
+ choices: [
+ 'Custom Mailserver',
+ '1und1',
+ 'AOL',
+ 'DebugMail.io',
+ 'DynectEmail',
+ 'FastMail',
+ 'GandiMail',
+ 'Gmail',
+ 'Godaddy',
+ 'GodaddyAsia',
+ 'GodaddyEurope',
+ 'hot.ee',
+ 'Hotmail',
+ 'iCloud',
+ 'mail.ee',
+ 'Mail.ru',
+ 'Mailgun',
+ 'Mailjet',
+ 'Mandrill',
+ 'Naver',
+ 'OpenMailBox',
+ 'Postmark',
+ 'QQ',
+ 'QQex',
+ 'SendCloud',
+ 'SendGrid',
+ 'SES',
+ 'SES-US-EAST-1',
+ 'SES-US-WEST-1',
+ 'SES-EU-WEST-1',
+ 'Sparkpost',
+ 'Yahoo',
+ 'Yandex',
+ 'Zoho'
+ ]
+ }
+ ],
+
+ mailerWellKnownQuestions: [
+ {
+ type: 'input',
+ name: 'MAILER_EMAIL_ID',
+ message: 'What is your SMTP username?'
+ },
+ {
+ type: 'password',
+ name: 'MAILER_PASSWORD',
+ message: 'What is your SMTP password?'
+ }
+ ],
+
+ mailerCustomQuestions: [
+ {
+ type: 'input',
+ name: 'MAILER_SMTP_HOST',
+ message: 'What is your SMTP server url?'
+ },
+ {
+ type: 'input',
+ name: 'MAILER_SMTP_PORT',
+ message: 'What is your SMTP server port?'
+ },
+ {
+ type: 'confirm',
+ name: 'MAILER_SMTP_SECURE',
+ message: 'Is your SMTP server using SSL/TLS?'
+ },
+ {
+ type: 'input',
+ name: 'MAILER_SMTP_HOST',
+ message: 'What is your SMTP host domain?'
+ },
+ {
+ type: 'input',
+ name: 'MAILER_EMAIL_ID',
+ message: 'What is your SMTP username?'
+ },
+ {
+ type: 'password',
+ name: 'MAILER_PASSWORD',
+ message: 'What is your SMTP password?'
+ }
+ ],
+
+ questionsPart2: [
+ {
+ type: 'input',
+ name: 'MAILER_FROM',
+ message: 'What do you want the default "from" email address to be?',
+ validate: validateEmail
+ },
+ {
+ type: 'input',
+ name: 'MONGODB_URI',
+ message: 'What is the URI of your Mongo database?',
+ default: 'mongodb://localhost/mean'
+ },
+ {
+ type: 'input',
+ name: 'REDIS_URL',
+ message: 'What is the URI of your Redis installation?',
+ default: 'redis://127.0.0.1:6379'
+ },
+ {
+ type: 'input',
+ name: 'BASE_URL',
+ message: 'What is the (root) url your TellForm will be hosted at?',
+ default: 'localhost'
+ },
+ {
+ type: 'input',
+ name: 'PORT',
+ message: 'What port should the TellForm server run on?',
+ default: '3000'
+ },
+ {
+ type: 'input',
+ name: 'email',
+ message: 'What should be the email for your admin account?',
+ validate: validateEmail
+ },
+ {
+ type: 'input',
+ name: 'username',
+ message: 'What should be the username for your admin account?',
+ validate: validateUsername
+ },
+ {
+ type: 'password',
+ name: 'password',
+ message: 'What should be the password for your admin account?'
+ }
+ ]
+};
\ No newline at end of file
diff --git a/selenium/config.json b/selenium/config.json
index f382f84d..6a55c28d 100644
--- a/selenium/config.json
+++ b/selenium/config.json
@@ -5,8 +5,8 @@
"browsers": "chrome"
},
"vars": {
- "LoginUsername": "admin",
- "LoginPassword": "admin",
+ "LoginUsername": "root",
+ "LoginPassword": "root",
"ShortTextTitle": "SeleniumShortText",
"Profile_NewFirstName": "SeleniumUser_FirstName",
"Profile_NewLastName": "SeleniumUser_LastName",
diff --git a/selenium/package.json b/selenium/package.json
index 03727c90..ae2c41f2 100644
--- a/selenium/package.json
+++ b/selenium/package.json
@@ -12,8 +12,7 @@
"resemblejs-node": "1.0.0",
"selenium-standalone": "6.x.x"
},
- "devDependencies": {
- },
+ "devDependencies": {},
"scripts": {
"installdriver": "./node_modules/.bin/selenium-standalone install --drivers.firefox.baseURL=http://npm.taobao.org/mirrors/geckodriver --baseURL=http://npm.taobao.org/mirrors/selenium --drivers.chrome.baseURL=http://npm.taobao.org/mirrors/chromedriver --drivers.ie.baseURL=http://npm.taobao.org/mirrors/selenium",
"server": "./node_modules/.bin/selenium-standalone start",
diff --git a/selenium/test/loginAndChangeProfile.js b/selenium/test/loginAndChangeProfile.js
index 83e3fda8..fdf5c0d9 100644
--- a/selenium/test/loginAndChangeProfile.js
+++ b/selenium/test/loginAndChangeProfile.js
@@ -49,13 +49,8 @@ module.exports = function(){
});
it('click: Sign in ( button, 174, 18, 0 )', async function(){
- await driver.sleep(300).wait('button', 30000)
- .sleep(300).mouseMove(174, 18).click(0);
- });
-
- it('mouseDown: My Settings ( a > span.ng-binding, 41.375, 12, 0 )', async function(){
- await driver.sleep(300).wait('a > span.ng-binding', 30000)
- .sleep(300).mouseMove(41.375, 12).mouseDown(0);
+ await driver.sleep(300).wait('button.btn-signup', 30000)
+ .sleep(300).click();
});
it('expect: displayed, div.new-button, equal, true', async function(){
@@ -72,33 +67,28 @@ module.exports = function(){
.should.equal(_(true));
});
- it('click: My Settings ( a.dropdown-toggle, 95, 29, 0 )', async function(){
+ it('click: My Settings ( a.dropdown-toggle )', async function(){
await driver.sleep(300).wait('a.dropdown-toggle', 30000)
- .sleep(300).mouseMove(95, 29).click(0);
+ .sleep(300).click();
});
- it('× expect: display, li:nth-child(1) > a.ng-binding, equal, true', async function(){
- await driver.sleep(300).wait('li:nth-child(1) > a.ng-binding', 30000)
+ it('× expect: display, ul.dropdown-menu > li:nth-child(1) > a.ng-binding, equal, true', async function(){
+ await driver.sleep(300).wait('ul.dropdown-menu > li:nth-child(1) > a.ng-binding', 30000)
.displayed()
.should.not.be.a('error')
.should.equal(_(true));
});
- it('× expect: display, li:nth-child(3) > a.ng-binding, equal, true', async function(){
- await driver.sleep(300).wait('li:nth-child(3) > a.ng-binding', 30000)
+ it('× expect: display, ul.dropdown-menu > li:nth-child(3) > a.ng-binding, equal, true', async function(){
+ await driver.sleep(300).wait('ul.dropdown-menu > li:nth-child(3) > a.ng-binding', 30000)
.displayed()
.should.not.be.a('error')
.should.equal(_(true));
});
- it('mouseDown: Edit Profile ( li:nth-child(1) > a.ng-binding, 54.59375, 14, 0 )', async function(){
- await driver.sleep(300).wait('li:nth-child(1) > a.ng-binding', 30000)
- .sleep(300).mouseMove(54.59375, 14).mouseDown(0);
- });
-
- it('click: Edit Profile ( li:nth-child(1) > a.ng-binding, 52, 13, 0 )', async function(){
- await driver.sleep(300).wait('li:nth-child(1) > a.ng-binding', 30000)
- .sleep(300).mouseMove(52, 13).click(0);
+ it('click: Edit Profile ( ul.dropdown-menu > li:nth-child(1) > a.ng-binding )', async function(){
+ await driver.sleep(300).wait('ul.dropdown-menu > li:nth-child(1) > a.ng-binding', 30000)
+ .sleep(300).click();
});
it('waitBody: ', async function(){
@@ -117,14 +107,9 @@ module.exports = function(){
.val(_(`{{Profile_NewLastName}}`));
});
- it('× click: Save Changes ( button.btn-signup, 95, 10, 0 )', async function(){
+ it('× click: Save Changes ( button.btn-signup )', async function(){
await driver.sleep(300).wait('button.btn-signup', 30000)
- .sleep(300).mouseMove(95, 10).click(0);
- });
-
- it('× mouseUp: Profile saved succes... ( section.row, 333, 78, 0 )', async function(){
- await driver.sleep(300).wait('section.row', 30000)
- .sleep(300).mouseMove(333, 78).mouseMove(333, 78).mouseUp(0);
+ .sleep(300).click();
});
it('× expect: displayed, div.text-success, equal, true', async function(){
@@ -157,7 +142,7 @@ module.exports = function(){
it('× click: Save Changes ( button.btn-signup, 95, 10, 0 )', async function(){
await driver.sleep(300).wait('button.btn-signup', 30000)
- .sleep(300).mouseMove(95, 10).click(0);
+ .sleep(300).click();
});
it('× expect: displayed, .text-danger, notEqual, true', async function(){
@@ -174,13 +159,9 @@ module.exports = function(){
.val(_(`{{Profile_NewInvalidEmail}}`));
});
- it('× click: Save Changes ( button.btn-signup, 90, 16, 0 )', async function(){
+ it('× click: Save Changes ( button.btn-signup )', async function(){
await driver.sleep(300).wait('button.btn-signup', 30000)
- .sleep(300).mouseMove(90, 16).click(0);
- });
-
- it('url: http://localhost:5000/#!/settings/profile', async function(){
- await driver.url(_(`http://localhost:5000/#!/settings/profile`));
+ .sleep(300).click();
});
it('url: http://localhost:5000/#!/settings/profile', async function(){
@@ -193,20 +174,6 @@ module.exports = function(){
});
});
- it('scrollTo: 0, 114', async function(){
- await driver.scrollTo(0, 114);
- });
-
- it('click: Email ( div:nth-child(8) > div.field-title, 352, 0, 0 )', async function(){
- await driver.sleep(300).wait('div:nth-child(8) > div.field-title', 30000)
- .sleep(300).mouseMove(352, 0).click(0);
- });
-
- it('click: Email ( //h4[text()="Email"], 323, 5, 0 )', async function(){
- await driver.sleep(300).wait('//h4[text()="Email"]', 30000)
- .sleep(300).mouseMove(323, 5).click(0);
- });
-
it('expect: text, #email, notEqual, {{Profile_NewInvalidEmail}}', async function(){
await driver.sleep(300).wait('#email', 300)
.text()
diff --git a/selenium_config.json b/selenium_config.json
new file mode 100644
index 00000000..6a55c28d
--- /dev/null
+++ b/selenium_config.json
@@ -0,0 +1,23 @@
+{
+ "webdriver": {
+ "host": "127.0.0.1",
+ "port": "4444",
+ "browsers": "chrome"
+ },
+ "vars": {
+ "LoginUsername": "root",
+ "LoginPassword": "root",
+ "ShortTextTitle": "SeleniumShortText",
+ "Profile_NewFirstName": "SeleniumUser_FirstName",
+ "Profile_NewLastName": "SeleniumUser_LastName",
+ "Profile_OldFirstName": "Admin",
+ "Profile_OldLastName": "Account",
+ "Profile_NewInvalidEmail": "SeleniumInvalidEmail"
+ },
+ "recorder": {
+ "pathAttrs": "data-id,data-name,type,data-type,role,data-role,data-value",
+ "attrValueBlack": "",
+ "classValueBlack": "",
+ "hideBeforeExpect": ""
+ }
+}
\ No newline at end of file
diff --git a/selenium_test/loginAndChangeProfile.js b/selenium_test/loginAndChangeProfile.js
new file mode 100644
index 00000000..f2282dfe
--- /dev/null
+++ b/selenium_test/loginAndChangeProfile.js
@@ -0,0 +1,398 @@
+const fs = require('fs');
+const path = require('path');
+const chai = require("chai");
+const should = chai.should();
+const JWebDriver = require('jwebdriver');
+chai.use(JWebDriver.chaiSupportChainPromise);
+const resemble = require('resemblejs-node');
+resemble.outputSettings({
+ errorType: 'flatDifferenceIntensity'
+});
+
+const rootPath = getRootPath();
+
+module.exports = function(){
+
+ let driver, testVars;
+
+ before(function(){
+ let self = this;
+ driver = self.driver;
+ testVars = self.testVars;
+ });
+
+ it('url: http://localhost:5000', async function(){
+ await driver.url(_(`http://localhost:5000`));
+ });
+
+ it('waitBody: ', async function(){
+ await driver.sleep(500).wait('body', 30000).html().then(function(code){
+ isPageError(code).should.be.false;
+ });
+ });
+
+ it('insertVar: username ( #username, {{LoginUsername}} )', async function(){
+ await driver.sleep(300).wait('#username', 30000)
+ .val(_(`{{LoginUsername}}`));
+ });
+
+ it('insertVar: password ( #password, {{LoginUsername}} )', async function(){
+ await driver.sleep(300).wait('#password', 30000)
+ .val(_(`{{LoginUsername}}`));
+ });
+
+ it('expect: displayed, .btn-signup, equal, true', async function(){
+ await driver.sleep(300).wait('.btn-signup', 30000)
+ .displayed()
+ .should.not.be.a('error')
+ .should.equal(_(true));
+ });
+
+ it('click: Sign in ( button, 174, 18, 0 )', async function(){
+ await driver.sleep(300).wait('button.btn-signup', 30000)
+ .sleep(300).click();
+ });
+
+ it('expect: displayed, div.new-button, equal, true', async function(){
+ await driver.sleep(300).wait('div.new-button', 30000)
+ .displayed()
+ .should.not.be.a('error')
+ .should.equal(_(true));
+ });
+
+ it('expect: displayed, a.dropdown-toggle, equal, true', async function(){
+ await driver.sleep(300).wait('a.dropdown-toggle', 30000)
+ .displayed()
+ .should.not.be.a('error')
+ .should.equal(_(true));
+ });
+
+ it('click: My Settings ( a.dropdown-toggle )', async function(){
+ await driver.sleep(300).wait('a.dropdown-toggle', 30000)
+ .sleep(300).click();
+ });
+
+ it('× expect: display, li:nth-child(1) > a.ng-binding, equal, true', async function(){
+ await driver.sleep(300).wait('li:nth-child(1) > a.ng-binding', 30000)
+ .displayed()
+ .should.not.be.a('error')
+ .should.equal(_(true));
+ });
+
+ it('× expect: display, li:nth-child(3) > a.ng-binding, equal, true', async function(){
+ await driver.sleep(300).wait('li:nth-child(3) > a.ng-binding', 30000)
+ .displayed()
+ .should.not.be.a('error')
+ .should.equal(_(true));
+ });
+
+ it('click: Edit Profile ( li:nth-child(1) > a.ng-binding)', async function(){
+ await driver.sleep(300).wait('li:nth-child(1) > a.ng-binding', 30000)
+ .sleep(300).mouseMove(54.59375, 14).mouseDown(0);
+ });
+
+ it('click: Edit Profile ( li:nth-child(1) > a.ng-binding, 52, 13, 0 )', async function(){
+ await driver.sleep(300).wait('li:nth-child(1) > a.ng-binding', 30000)
+ .sleep(300).mouseMove(52, 13).click(0);
+ });
+
+ it('waitBody: ', async function(){
+ await driver.sleep(500).wait('body', 30000).html().then(function(code){
+ isPageError(code).should.be.false;
+ });
+ });
+
+ it('× insertVar: firstName ( #firstName, {{Profile_NewFirstName}} )', async function(){
+ await driver.sleep(300).wait('#firstName', 30000)
+ .val(_(`{{Profile_NewFirstName}}`));
+ });
+
+ it('× insertVar: lastName ( #lastName, {{Profile_NewLastName}} )', async function(){
+ await driver.sleep(300).wait('#lastName', 30000)
+ .val(_(`{{Profile_NewLastName}}`));
+ });
+
+ it('× click: Save Changes ( button.btn-signup, 95, 10, 0 )', async function(){
+ await driver.sleep(300).wait('button.btn-signup', 30000)
+ .sleep(300).mouseMove(95, 10).click(0);
+ });
+
+ it('× mouseUp: Profile saved succes... ( section.row, 333, 78, 0 )', async function(){
+ await driver.sleep(300).wait('section.row', 30000)
+ .sleep(300).mouseMove(333, 78).mouseMove(333, 78).mouseUp(0);
+ });
+
+ it('× expect: displayed, div.text-success, equal, true', async function(){
+ await driver.sleep(300).wait('div.text-success', 30000)
+ .displayed()
+ .should.not.be.a('error')
+ .should.equal(_(true));
+ });
+
+ it('× expect: displayed, .text-danger, notEqual, true', async function(){
+ await driver.sleep(300).wait('.text-danger', 300)
+ .displayed()
+ .should.not.be.a('error')
+ .should.not.equal(_(true));
+ });
+
+ /*
+ ** Revert back to expected names
+ */
+
+ it('× insertVar: firstName ( #firstName, {{Profile_OldFirstName}} )', async function(){
+ await driver.sleep(300).wait('#firstName', 30000)
+ .val(_(`{{Profile_OldFirstName}}`));
+ });
+
+ it('× insertVar: lastName ( #lastName, {{Profile_OldLastName}} )', async function(){
+ await driver.sleep(300).wait('#lastName', 30000)
+ .val(_(`{{Profile_OldLastName}}`));
+ });
+
+ it('× click: Save Changes ( button.btn-signup, 95, 10, 0 )', async function(){
+ await driver.sleep(300).wait('button.btn-signup', 30000)
+ .sleep(300).click(0);
+ });
+
+ it('× expect: displayed, .text-danger, notEqual, true', async function(){
+ await driver.sleep(300).wait('.text-danger', 300)
+ .displayed()
+ .should.not.be.a('error')
+ .should.not.equal(_(true));
+ });
+
+
+ //Check that we can't save an invalid email
+ it('× insertVar: email ( #email, {{Profile_NewInvalidEmail}} )', async function(){
+ await driver.sleep(300).wait('#email', 30000)
+ .val(_(`{{Profile_NewInvalidEmail}}`));
+ });
+
+ it('× click: Save Changes ( button.btn-signup, 90, 16, 0 )', async function(){
+ await driver.sleep(300).wait('button.btn-signup', 30000)
+ .sleep(300).click(0);
+ });
+
+ it('url: http://localhost:5000/#!/settings/profile', async function(){
+ await driver.url(_(`http://localhost:5000/#!/settings/profile`));
+ });
+
+ it('waitBody: ', async function(){
+ await driver.sleep(500).wait('body', 30000).html().then(function(code){
+ isPageError(code).should.be.false;
+ });
+ });
+
+ it('click: Email ( div:nth-child(8) > div.field-title, 352, 0, 0 )', async function(){
+ await driver.sleep(300).wait('div:nth-child(8) > div.field-title', 30000)
+ .sleep(300).click(0);
+ });
+
+ it('click: Email ( //h4[text()="Email"], 323, 5, 0 )', async function(){
+ await driver.sleep(300).wait('//h4[text()="Email"]', 30000)
+ .sleep(300).click(0);
+ });
+
+ it('expect: text, #email, notEqual, {{Profile_NewInvalidEmail}}', async function(){
+ await driver.sleep(300).wait('#email', 300)
+ .text()
+ .should.not.be.a('error')
+ .should.not.equal(_(`{{Profile_NewInvalidEmail}}`));
+ });
+
+
+ /*
+ ** Logout
+ */
+ it('click: Signout ( //a[text()="Signout"], 31, 31, 0 )', async function(){
+ await driver.sleep(300).wait('//a[text()="Signout"]', 30000)
+ .sleep(300).mouseMove(31, 31).click(0);
+ });
+
+ it('expect: displayed, button.btn-signup, equal, true', async function(){
+ await driver.sleep(300).wait('button.btn-signup', 30000)
+ .displayed()
+ .should.not.be.a('error')
+ .should.equal(_(true));
+ });
+
+ function _(str){
+ if(typeof str === 'string'){
+ return str.replace(/\{\{(.+?)\}\}/g, function(all, key){
+ return testVars[key] || '';
+ });
+ }
+ else{
+ return str;
+ }
+ }
+
+};
+
+if(module.parent && /mocha\.js/.test(module.parent.id)){
+ runThisSpec();
+}
+
+function runThisSpec(){
+ // read config
+ let webdriver = process.env['webdriver'] || '';
+ let proxy = process.env['wdproxy'] || '';
+ let config = require(rootPath + '/config.json');
+ let webdriverConfig = Object.assign({},config.webdriver);
+ let host = webdriverConfig.host;
+ let port = webdriverConfig.port || 4444;
+ let match = webdriver.match(/([^\:]+)(?:\:(\d+))?/);
+ if(match){
+ host = match[1] || host;
+ port = match[2] || port;
+ }
+ let testVars = config.vars;
+ let browsers = webdriverConfig.browsers;
+ browsers = browsers.replace(/^\s+|\s+$/g, '');
+ delete webdriverConfig.host;
+ delete webdriverConfig.port;
+ delete webdriverConfig.browsers;
+
+ // read hosts
+ let hostsPath = rootPath + '/hosts';
+ let hosts = '';
+ if(fs.existsSync(hostsPath)){
+ hosts = fs.readFileSync(hostsPath).toString();
+ }
+ let specName = path.relative(rootPath, __filename).replace(/\\/g,'/').replace(/\.js$/,'');
+
+ browsers.split(/\s*,\s*/).forEach(function(browserName){
+ let caseName = specName + ' : ' + browserName;
+
+ let browserInfo = browserName.split(' ');
+ browserName = browserInfo[0];
+ let browserVersion = browserInfo[1];
+
+ describe(caseName, function(){
+
+ this.timeout(600000);
+ this.slow(1000);
+
+ let driver;
+ before(function(){
+ let self = this;
+ let driver = new JWebDriver({
+ 'host': host,
+ 'port': port
+ });
+ let sessionConfig = Object.assign({}, webdriverConfig, {
+ 'browserName': browserName,
+ 'version': browserVersion,
+ 'ie.ensureCleanSession': true,
+ 'chromeOptions': {
+ 'args': ['--enable-automation']
+ }
+ });
+ if(proxy){
+ sessionConfig.proxy = {
+ 'proxyType': 'manual',
+ 'httpProxy': proxy,
+ 'sslProxy': proxy
+ }
+ }
+ else if(hosts){
+ sessionConfig.hosts = hosts;
+ }
+ self.driver = driver.session(sessionConfig).maximize().config({
+ pageloadTimeout: 30000, // page onload timeout
+ scriptTimeout: 5000, // sync script timeout
+ asyncScriptTimeout: 10000 // async script timeout
+ });
+ self.testVars = testVars;
+ let casePath = path.dirname(caseName);
+ self.screenshotPath = rootPath + '/screenshots/' + casePath;
+ self.diffbasePath = rootPath + '/diffbase/' + casePath;
+ self.caseName = caseName.replace(/.*\//g, '').replace(/\s*[:\.\:\-\s]\s*/g, '_');
+ mkdirs(self.screenshotPath);
+ mkdirs(self.diffbasePath);
+ self.stepId = 0;
+ return self.driver;
+ });
+
+ module.exports();
+
+ beforeEach(function(){
+ let self = this;
+ self.stepId ++;
+ if(self.skipAll){
+ self.skip();
+ }
+ });
+
+ afterEach(async function(){
+ let self = this;
+ let currentTest = self.currentTest;
+ let title = currentTest.title;
+ if(currentTest.state === 'failed' && /^(url|waitBody|switchWindow|switchFrame):/.test(title)){
+ self.skipAll = true;
+ }
+ if(!/^(closeWindow):/.test(title)){
+ let filepath = self.screenshotPath + '/' + self.caseName + '_' + self.stepId;
+ let driver = self.driver;
+ try{
+ // catch error when get alert msg
+ await driver.getScreenshot(filepath + '.png');
+ let url = await driver.url();
+ let html = await driver.source();
+ html = '\n' + html;
+ fs.writeFileSync(filepath + '.html', html);
+ let cookies = await driver.cookies();
+ fs.writeFileSync(filepath + '.cookie', JSON.stringify(cookies));
+ }
+ catch(e){}
+ }
+ });
+
+ after(function(){
+ return this.driver.close();
+ });
+
+ });
+ });
+}
+
+function getRootPath(){
+ let rootPath = path.resolve(__dirname);
+ while(rootPath){
+ if(fs.existsSync(rootPath + '/config.json')){
+ break;
+ }
+ rootPath = rootPath.substring(0, rootPath.lastIndexOf(path.sep));
+ }
+ return rootPath;
+}
+
+function mkdirs(dirname){
+ if(fs.existsSync(dirname)){
+ return true;
+ }else{
+ if(mkdirs(path.dirname(dirname))){
+ fs.mkdirSync(dirname);
+ return true;
+ }
+ }
+}
+
+function callSpec(name){
+ try{
+ require(rootPath + '/' + name)();
+ }
+ catch(e){
+ console.log(e)
+ process.exit(1);
+ }
+}
+
+function isPageError(code){
+ return code == '' || / jscontent="errorCode" jstcache="\d+"|diagnoseConnectionAndRefresh|dnserror_unavailable_header|id="reportCertificateErrorRetry"|400 Bad Request|403 Forbidden|404 Not Found|500 Internal Server Error|502 Bad Gateway|503 Service Temporarily Unavailable|504 Gateway Time-out/i.test(code);
+}
+
+function catchError(error){
+
+}
diff --git a/selenium/test/loginAndCreateForm.spec.js b/selenium_test/loginAndCreateForm.spec.js
similarity index 100%
rename from selenium/test/loginAndCreateForm.spec.js
rename to selenium_test/loginAndCreateForm.spec.js
diff --git a/server.js b/server.js
index 725a6842..042b26ae 100755
--- a/server.js
+++ b/server.js
@@ -1,22 +1,9 @@
'use strict';
+
/**
* Module dependencies.
*/
-
-if(!process.env.NODE_ENV){
- process.env.NODE_ENV = 'development';
-}
-
-//Don't check .env file if we are in travis-ci
-if(!process.env.TRAVIS){
- require('dotenv').config({path: './.env'});
-}
-
-
-require('events').EventEmitter.prototype._maxListeners = 0;
-
-var config = require('./config/config'),
- mongoose = require('mongoose'),
+var mongoose = require('mongoose'),
chalk = require('chalk'),
nodemailer = require('nodemailer');
@@ -24,62 +11,79 @@ var config = require('./config/config'),
* Main application entry file.
* Please note that the order of loading is important.
*/
-
-// Bootstrap db connection
-var db = mongoose.connect(config.db.uri, config.db.options, function (err) {
- if (err) {
- console.error(chalk.red('Could not connect to MongoDB!'));
- console.log(chalk.red(err));
+var bootstrap = function() {
+ //Don't check .env file if we are in travis-ci
+ if(!process.env.TRAVIS) {
+ require('dotenv').config({path: './.env'});
}
-});
-mongoose.connection.on('error', function (err) {
- console.error(chalk.red('MongoDB connection error: ' + err));
- process.exit(-1);
-});
-
-const smtpTransport = nodemailer.createTransport(config.mailer.options);
-
-// verify connection configuration on startup
-smtpTransport.verify(function(error, success) {
- if (error) {
- console.error(chalk.red('Your mail configuration is incorrect: ' + error));
- process.exit(-1);
+
+ if(!process.env.NODE_ENV) {
+ process.env.NODE_ENV = 'development';
}
-});
-// Init the express application
-var app = require('./config/express')(db);
+ var config = require('./config/config');
-//Create admin account
-if (process.env.CREATE_ADMIN_ACCOUNT === 'TRUE') {
- var create_admin = require('./scripts/create_admin');
-
- create_admin.run(app, db, function(err){
- if(err){
- console.error(chalk.red('Could not create Admin Account: ' + err));
+ // Bootstrap db connection
+ var db = mongoose.connect(config.db.uri, config.db.options, function (err) {
+ if (err) {
+ console.error(chalk.red('Could not connect to MongoDB!'));
+ console.log(chalk.red(err));
}
});
+ mongoose.connection.on('error', function (err) {
+ console.error(chalk.red('MongoDB connection error: ' + err));
+ process.exit(-1);
+ });
+
+ const smtpTransport = nodemailer.createTransport(config.mailer.options);
+
+ // verify connection configuration on startup
+ smtpTransport.verify(function(error, success) {
+ if (error) {
+ console.error(chalk.red('Your mail configuration is incorrect: ' + error));
+ process.exit(-1);
+ }
+ });
+
+ // Init the express application
+ var app = require('./config/express')(db);
+
+ //Create admin account
+ if (process.env.CREATE_ADMIN_ACCOUNT === 'TRUE' && process.env.NODE_ENV !== 'test') {
+ var create_admin = require('./scripts/create_admin');
+
+ create_admin.run(app, db, function(err){
+ if(err){
+ console.error(chalk.red('Could not create Admin Account: ' + err));
+ }
+ });
+ }
+
+ // Bootstrap passport config
+ require('./config/passport')();
+
+ // Start the app by listening on
+ app.listen(config.port);
+
+ // Logging initialization
+ console.log('--');
+ console.log(chalk.green('Environment:\t\t\t' + process.env.NODE_ENV));
+ console.log(chalk.green('Port:\t\t\t\t' + config.port));
+ console.log(chalk.green('Database:\t\t\t' + config.db.uri));
+ console.log('--');
+
+ process.on('uncaughtException', function (err) {
+ console.error((new Date()).toUTCString() + ' uncaughtException:', err.message);
+ console.error(err.stack);
+ process.exit(1);
+ });
+
+ return app;
}
-
-// Bootstrap passport config
-require('./config/passport')();
-
-// Start the app by listening on
-app.listen(config.port);
-
-// Expose app
-exports = module.exports = app;
-
-// Logging initialization
-console.log('--');
-console.log(chalk.green('Environment:\t\t\t' + process.env.NODE_ENV));
-console.log(chalk.green('Port:\t\t\t\t' + config.port));
-console.log(chalk.green('Database:\t\t\t' + config.db.uri));
-console.log('--');
-
-process.on('uncaughtException', function (err) {
- console.error((new Date()).toUTCString() + ' uncaughtException:', err.message);
- console.error(err.stack);
- process.exit(1);
-});
+// To maintain backwards compatibility, run bootstrap when called as a file
+if(require.main === module) {
+ bootstrap();
+} else {
+ module.exports = bootstrap();
+}
\ No newline at end of file
diff --git a/start.js b/start.js
new file mode 100644
index 00000000..d1458d0e
--- /dev/null
+++ b/start.js
@@ -0,0 +1,15 @@
+var fs = require('fs'),
+ setup = require('./scripts/setup');
+
+//Set this to infinity to increase server capacity
+require('events').EventEmitter.prototype._maxListeners = 0;
+
+
+//Run setup script if no .env file is detected
+if(process.stdout.isTTY) {
+ setup.checkENVAndRunSetup(function() {
+ require('./server');
+ });
+} else {
+ require('./server');
+}