diff --git a/.editorconfig b/.editorconfig index ed90a068..ad92ba39 100755 --- a/.editorconfig +++ b/.editorconfig @@ -8,7 +8,7 @@ root = true # Unix-style newlines with a newline ending every file [*] end_of_line = lf -indent_style = tab +indent_style = space insert_final_newline = true [{Dockerfile,Procfile}] diff --git a/app/controllers/forms.server.controller.js b/app/controllers/forms.server.controller.js index 34032727..3eadee81 100644 --- a/app/controllers/forms.server.controller.js +++ b/app/controllers/forms.server.controller.js @@ -34,7 +34,7 @@ exports.deleteSubmissions = function(req, res) { }); return; } - + res.status(200).send('Form submissions successfully deleted'); }); }; @@ -77,7 +77,7 @@ exports.createSubmission = function(req, res) { } else { form.selfNotifications.fromEmails = config.mailer.options.from; } - + emailNotifications.send(form.selfNotifications, formFieldDict, smtpTransport, function(err){ if(err){ return callback({ @@ -89,7 +89,7 @@ exports.createSubmission = function(req, res) { }); } else { callback(); - } + } }, function(callback) { if (form.respondentNotifications && form.respondentNotifications.enabled && form.respondentNotifications.toField) { @@ -106,7 +106,7 @@ exports.createSubmission = function(req, res) { }); } else { callback(); - } + } } ], function (err) { if(err){ @@ -138,10 +138,12 @@ exports.listSubmissions = function(req, res) { * Get Visitor Analytics Data for a given Form */ exports.getVisitorData = function(req, res) { + var results = []; + Form.aggregate([ { $match: { - _id: mongoose.Types.ObjectId(req.params.formIdNoMiddleware), + _id: mongoose.Types.ObjectId(req.form.id), admin: mongoose.Types.ObjectId(req.user.id) } }, @@ -156,26 +158,26 @@ exports.getVisitorData = function(req, res) { _id: 0, deviceType: '$analytics.visitors.deviceType', SubmittedTimeElapsed: { - $cond: [ + $cond: [ { $eq: ['$analytics.visitors.isSubmitted', true] - }, - '$analytics.visitors.timeElapsed', + }, + '$analytics.visitors.timeElapsed', 0 ] }, SubmittedResponses: { - $cond: [ + $cond: [ { $eq: ['$analytics.visitors.isSubmitted', true] - }, - 1, + }, + 1, 0 ] } } }, - { + { $group: { _id: '$deviceType', total_time: { $sum: '$SubmittedTimeElapsed' }, @@ -189,21 +191,21 @@ exports.getVisitorData = function(req, res) { responses: '$responses', visits: '$visits', average_time: { - $cond: [ - { $eq: [ '$responses', 0 ] }, - 0, - { $divide: ['$total_time', '$responses'] } - ] + $cond: [ + { $eq: [ '$responses', 0 ] }, + 0, + { $divide: ['$total_time', '$responses'] } + ] }, conversion_rate: { $multiply: [ 100, - { - $cond: [ - { $eq: [ '$visits', 0 ] }, - 0, - { $divide: ['$responses', '$visits'] } - ] + { + $cond: [ + { $eq: [ '$visits', 0 ] }, + 0, + { $divide: ['$responses', '$visits'] } + ] } ] } @@ -219,26 +221,26 @@ exports.getVisitorData = function(req, res) { _id: 0, deviceType: '$analytics.visitors.deviceType', SubmittedTimeElapsed: { - $cond: [ + $cond: [ { $eq: ['$analytics.visitors.isSubmitted', true] - }, - '$analytics.visitors.timeElapsed', + }, + '$analytics.visitors.timeElapsed', 0 ] }, SubmittedResponses: { - $cond: [ + $cond: [ { $eq: ['$analytics.visitors.isSubmitted', true] - }, - 1, + }, + 1, 0 ] } } }, - { + { $group: { _id: null, total_time: { $sum: '$SubmittedTimeElapsed' }, @@ -253,21 +255,21 @@ exports.getVisitorData = function(req, res) { responses: '$responses', visits: '$visits', average_time: { - $cond: [ - { $eq: [ '$responses', 0 ] }, - 0, - { $divide: ['$total_time', '$responses'] } - ] + $cond: [ + { $eq: [ '$responses', 0 ] }, + 0, + { $divide: ['$total_time', '$responses'] } + ] }, conversion_rate: { $multiply: [ 100, - { - $cond: [ - { $eq: [ '$visits', 0 ] }, - 0, - { $divide: ['$responses', '$visits'] } - ] + { + $cond: [ + { $eq: [ '$visits', 0 ] }, + 0, + { $divide: ['$responses', '$visits'] } + ] } ] } @@ -276,16 +278,15 @@ exports.getVisitorData = function(req, res) { ], } } - ], function(err, results){ - if (err) { - console.error(err); - return res.status(500).send({ - message: errorHandler.getErrorMessage(err) - }); - } - - return res.json(results); - }); + ]) + .cursor() + .exec() + .on('end', function() { + res.json(results); + }) + .on('data', function(entry){ + results.push(entry); + }); }; /** @@ -297,7 +298,7 @@ exports.create = function(req, res) { message: 'Invalid Input' }); } - + var form = new Form(req.body.form); form.admin = req.user._id; @@ -327,7 +328,7 @@ exports.read = function(req, res) { } var newForm = helpers.removeSensitiveModelData('private_form', req.form.toJSON()); - + return res.json(newForm); } }; @@ -343,7 +344,7 @@ var readForRender = exports.readForRender = function(req, res) { }); } - newForm = helpers.removeSensitiveModelData('public_form', newForm.toJSON()); + newForm = helpers.removeSensitiveModelData('public_form', newForm); if(newForm.startPage && !newForm.startPage.showStart){ delete newForm.startPage; @@ -380,8 +381,8 @@ exports.update = function(req, res) { }); } - delete updatedForm.lastModified; - delete updatedForm.created; + delete updatedForm.lastModified; + delete updatedForm.created; delete updatedForm.id; delete updatedForm._id; delete updatedForm.__v; @@ -448,53 +449,45 @@ exports.list = function(req, res) { message: errorHandler.getErrorMessage(err) }); } - + var form_ids = forms.map(function(form){ return form._id; }); //Get number of submissions for each form - FormSubmission.aggregate([ - { - $match: { - form: { - $in: form_ids - } - } - }, - { - $group: { - _id: '$form', - responses: { $sum: 1 } - } - }, - ], function(err, results){ - if (err) { - console.error(err); - return res.status(500).send({ - message: errorHandler.getErrorMessage(err) - }); - } + FormSubmission + .aggregate() + .match({ + form: { + $in: form_ids + } + }) + .group({ + _id: '$form', + responses: { $sum: 1 } + }) + .cursor() + .exec() + .on('end', function() { + forms = forms.map(function (form) { + if (!form.submissionNum) { + form.submissionNum = 0; + } - const result_ids = results.map(function(result){ - return ''+result._id; - }); - - var currIndex = -1; + return helpers.removeSensitiveModelData('private_form', form); + }); - for(var i=0; i -1){ - forms[i].submissionNum = results[currIndex].responses; - } else { - forms[i].submissionNum = 0; - } - } - - res.json(forms); - }); + return form; + }); + }); }); }; @@ -557,11 +550,13 @@ exports.formByIDFast = function(req, res, next, id) { /** * Form authorization middleware + * + * reject access if the owner of the form is not the current user and the user is not an admin */ exports.hasAuthorization = function(req, res, next) { var form = req.form; - if (req.form.admin.id !== req.user.id || req.user.roles.indexOf('admin') > -1) { - res.status(403).send({ + if (req.form.admin.id !== req.user.id && req.user.roles.indexOf('admin') < 0) { + return res.status(403).send({ message: 'User '+req.user.username+' is not authorized to edit Form: '+form.title }); } diff --git a/app/controllers/helpers.server.controller.js b/app/controllers/helpers.server.controller.js index 9b4c3792..493ca3d1 100644 --- a/app/controllers/helpers.server.controller.js +++ b/app/controllers/helpers.server.controller.js @@ -14,6 +14,10 @@ module.exports = { return dict; }, removeSensitiveModelData: function(type, actual_object){ + if (typeof actual_object.toJSON === 'function') { + actual_object = actual_object.toJSON(); + } + var object = _.cloneDeep(actual_object); if(constants.privateFields.hasOwnProperty(type)) { @@ -26,4 +30,4 @@ module.exports = { return object; } -}; \ No newline at end of file +}; diff --git a/app/models/form.server.model.js b/app/models/form.server.model.js index b7992478..3b7e9513 100644 --- a/app/models/form.server.model.js +++ b/app/models/form.server.model.js @@ -241,4 +241,4 @@ FormSchema.index({created: 1}); mongoose.model('Form', FormSchema); -module.exports = mongoose.model('Form'); \ No newline at end of file +module.exports = mongoose.model('Form'); diff --git a/app/sockets/analytics_service.js b/app/sockets/analytics_service.js index 0021f60f..2ed100ca 100644 --- a/app/sockets/analytics_service.js +++ b/app/sockets/analytics_service.js @@ -13,48 +13,45 @@ module.exports = function (io, socket) { var visitorsData = {}; var saveVisitorData = function (data, socket, cb){ - Form.findById(data.formId, function(err, form) { - if (err) { - console.error(err); - throw new Error(errorHandler.getErrorMessage(err)); - } + Form.findByIdAndUpdate( + data.formId, + { + $push: { + 'analytics.visitors': { + socketId: data.socketId, + referrer: data.referrer, + timeElapsed: data.timeElapsed, + isSubmitted: data.isSubmitted, + language: data.language, + ipAddr: '', + deviceType: data.deviceType + } + } + }, + function(err, form) { + if (err) { + console.error(err); + throw new Error(errorHandler.getErrorMessage(err)); + } - var newVisitor = { - socketId: data.socketId, - referrer: data.referrer, - timeElapsed: data.timeElapsed, - isSubmitted: data.isSubmitted, - language: data.language, - ipAddr: '', - deviceType: data.deviceType - }; + console.log('update form to', form) - form.analytics.visitors.push(newVisitor); - - - form.form_fields = form.form_fields.map(v => Object.assign({}, v, { fieldValue: null })); - - form.save(function (formSaveErr) { - if (err) { - console.error(err); - throw new Error(errorHandler.getErrorMessage(formSaveErr)); - } - - if(cb){ - return cb(); - } - }); + if(cb){ + return cb(); + } }); }; io.on('connection', function(current_socket) { + console.log('CONNECTED CLIENT'); + // a user has visited our page - add them to the visitorsData object current_socket.on('form-visitor-data', function(data) { visitorsData[current_socket.id] = data; visitorsData[current_socket.id].socketId = current_socket.id; visitorsData[current_socket.id].isSaved = false; - + console.log('received data', data); if (data.isSubmitted && !data.isSaved) { visitorsData[current_socket.id].isSaved = true; saveVisitorData(data, function() { diff --git a/app/views/form.server.view.pug b/app/views/form.server.view.pug index 8893954d..d66ce5fe 100644 --- a/app/views/form.server.view.pug +++ b/app/views/form.server.view.pug @@ -46,7 +46,7 @@ html(lang='en', xmlns='http://www.w3.org/1999/xhtml') script(type='text/javascript'). var signupDisabled = !{signupDisabled}; var socketPort = false; - var socketUrl = "ws.tellform.com"; + var socketUrl = false; var subdomainsDisabled = !{subdomainsDisabled}; //Embedding socketPort diff --git a/app/views/index.server.view.pug b/app/views/index.server.view.pug index 1c08be19..0bb5ca1f 100644 --- a/app/views/index.server.view.pug +++ b/app/views/index.server.view.pug @@ -14,7 +14,7 @@ block content //Embedding The signupDisabled Boolean script(type='text/javascript'). var signupDisabled = !{signupDisabled}; - var socketPort = false; + var socketPort = false; var socketUrl = false; var subdomainsDisabled = !{subdomainsDisabled}; var locale = "en"; @@ -45,7 +45,7 @@ block content script(type='text/javascript', src='https://cdnjs.cloudflare.com/ajax/libs/angular-strap/2.3.8/angular-strap.min.js') script(src='https://cdnjs.cloudflare.com/ajax/libs/quill/1.3.4/quill.min.js') - script(src='https://cdnjs.cloudflare.com/ajax/libs/ng-quill/3.5.1/ng-quill.js') + script(src='https://cdnjs.cloudflare.com/ajax/libs/ng-quill/3.5.2/ng-quill.js') script(src='https://unpkg.com/quill-placeholder-module@0.2.0/dist/placeholder-module.js') //Application JavaScript Files @@ -55,7 +55,7 @@ block content if process.env.NODE_ENV === 'development' script(type='text/javascript', src='http://#{request.hostname}:35729/livereload.js') - + script(src='https://cdn.ravenjs.com/2.3.0/angular/raven.min.js') - - script Raven.config('https://825fefd6b4ed4a4da199c1b832ca845c@sentry.tellform.com/2').install(); \ No newline at end of file + + script Raven.config('https://825fefd6b4ed4a4da199c1b832ca845c@sentry.tellform.com/2').install(); diff --git a/bower.json b/bower.json index 68349a13..90c1f70f 100755 --- a/bower.json +++ b/bower.json @@ -11,7 +11,7 @@ "appPath": "public/modules", "dependencies": { "bootstrap": "^3.3.7", - "angular-resource": "~1.4.7", + "angular-resource": "~1.7.8", "angular-cache-buster": "~0.4.3", "angular-bootstrap": "~0.14.3", "angular-ui-utils": "~3.0.0", @@ -23,13 +23,13 @@ "file-saver.js": "~1.20150507.2", "angular-bootstrap-colorpicker": "~3.0.19", "angular-scroll": "^1.0.0", - "angular-sanitize": "1.4.14", + "angular-sanitize": "^1.7.8", "v-button": "^1.1.1", - "angular-input-stars": "https://github.com/tellform/angular-input-stars.git#master", + "angular-input-stars": "^1.8.0", "raven-js": "^3.0.4", "tableExport.jquery.plugin": "^1.5.1", "js-yaml": "^3.6.1", - "angular-translate": "~2.11.0", + "angular-translate": "^2.18.1", "ng-translate": "*", "deep-diff": "^0.3.4", "jsep": "0.3.1", @@ -41,21 +41,10 @@ "angular-ui-select": "^0.19.8", "angular-bootstrap-switch": "^0.5.2", "jquery": "^3.2.1", - "ng-quill": "https://github.com/KillerCodeMonkey/ng-quill.git#master", + "ng-quill": "^4.5.0", "angular-ui-router": "^1.0.11", "angular-permission": "^5.3.2", - "angular-mocks": "^1.6.6", - "quill": "https://github.com/quilljs/quill/releases/download/v1.3.4/quill.tar.gz", - "jspdf": "^1.3.5" - }, - "resolutions": { - "angular-bootstrap": "^0.14.0", - "jquery": "^3.2.1", - "angular-ui-router": "^1.0.11", - "angular": "1.6", - "angular-mocks": "^1.6.6", - "quill": "e-tag:792062a8d", - "jspdf": "1.1.239 || 1.3.2" + "angular-mocks": "^1.7.8" }, "overrides": { "BOWER-PACKAGE": { diff --git a/config/config.js b/config/config.js index 7a32033c..3dfca31d 100755 --- a/config/config.js +++ b/config/config.js @@ -64,7 +64,7 @@ module.exports.removeRootDir = function(files, removeRoot, addRoot) { */ module.exports.getBowerFormJSAssets = function() { if(process.env.NODE_ENV === 'production'){ - return ['/static/lib/angular/angular.min.js', '/static/dist/vendor.min.js', '/static/lib/angular-ui-date/src/date.js'] + return ['/static/lib/angular/angular.min.js', '/static/dist/vendor.min.js', '/static/lib/angular-ui-date/src/date.js']; } return this.removeRootDir(minBowerFiles('**/**.js'), 'public/', 'static/'); }; diff --git a/config/env/all.js b/config/env/all.js index 15ca1f6a..9dd2fb16 100755 --- a/config/env/all.js +++ b/config/env/all.js @@ -8,10 +8,7 @@ module.exports = { keywords: process.env.APP_KEYWORDS || 'typeform, pdfs, forms, opensource, formbuilder, google forms, nodejs' }, db: { - uri: process.env.MONGOLAB_URI || process.env.MONGODB_URI || 'mongodb://'+ (process.env.DB_PORT_27017_TCP_ADDR || '127.0.0.1') + '/mean', - options: { - useMongoClient: true - } + uri: process.env.MONGOLAB_URI || process.env.MONGODB_URI || 'mongodb://'+ (process.env.DB_PORT_27017_TCP_ADDR || '127.0.0.1') + '/mean' }, admin: { email: process.env.ADMIN_EMAIL || 'admin@admin.com', @@ -19,7 +16,7 @@ module.exports = { password: process.env.ADMIN_PASSWORD || 'root', roles: ['user', 'admin'] }, - + redisUrl: process.env.REDIS_URL || 'redis://127.0.0.1:6379', port: process.env.PORT || 3000, diff --git a/config/env/development.js b/config/env/development.js index 7335664b..bd19d48d 100755 --- a/config/env/development.js +++ b/config/env/development.js @@ -4,10 +4,7 @@ module.exports = { baseUrl: process.env.BASE_URL || 'http://localhost:5000', port: process.env.PORT || 5000, db: { - uri: process.env.MONGODB_URI || 'mongodb://'+( process.env.DB_PORT_27017_TCP_ADDR || '127.0.0.1') +'/mean', - options: { - useMongoClient: true - } + uri: process.env.MONGODB_URI || 'mongodb://'+( process.env.DB_PORT_27017_TCP_ADDR || '127.0.0.1') +'/mean' }, log: { // Can specify one of 'combined', 'common', 'dev', 'short', 'tiny' diff --git a/config/env/production.js b/config/env/production.js index 5dfc8ee0..98a93f27 100755 --- a/config/env/production.js +++ b/config/env/production.js @@ -3,10 +3,7 @@ module.exports = { baseUrl: process.env.BASE_URL || process.env.HEROKU_APP_NAME + '.herokuapp.com' || 'tellform.com', db: { - uri: process.env.MONGODB_URI || process.env.MONGOHQ_URL || process.env.MONGOLAB_URI || 'mongodb://' + (process.env.DB_PORT_27017_TCP_ADDR || '127.0.0.1') + '/mean', - options: { - useMongoClient: true - } + uri: process.env.MONGODB_URI || process.env.MONGOHQ_URL || process.env.MONGOLAB_URI || 'mongodb://' + (process.env.DB_PORT_27017_TCP_ADDR || '127.0.0.1') + '/mean' }, port: process.env.PORT || 5000, socketUrl: process.env.SOCKET_URL || 'ws.tellform.com', diff --git a/config/env/test.js b/config/env/test.js index cddd377a..651685f1 100755 --- a/config/env/test.js +++ b/config/env/test.js @@ -3,10 +3,7 @@ module.exports = { baseUrl: '127.0.0.1:3001', db: { - uri: 'mongodb://localhost/mean-test', - options: { - useMongoClient: true - } + uri: 'mongodb://localhost/mean-test' }, port: 3001, log: { diff --git a/config/express.js b/config/express.js index 5b87f8e0..26f71bf7 100755 --- a/config/express.js +++ b/config/express.js @@ -76,7 +76,7 @@ module.exports = function(db) { if(config.socketUrl){ app.locals.socketUrl = config.socketUrl; - } + } app.locals.bowerFormJSFiles = config.getBowerFormJSAssets(); app.locals.bowerJSFiles = config.getBowerJSAssets(); @@ -93,7 +93,7 @@ module.exports = function(db) { var User = mongoose.model('User'); var subdomainPath = '/subdomain/'; var subdomains = req.subdomains; - + if (subdomains.slice(0, 4).join('.') + '' === '1.0.0.127') { subdomains = subdomains.slice(4); } @@ -102,7 +102,7 @@ module.exports = function(db) { if (!subdomains.length) { return next(); } - + urlPath = url.parse(req.url).path.split('/'); if (urlPath.indexOf('static') > -1) { urlPath.splice(1, 1); diff --git a/gruntfile.js b/gruntfile.js index 75868a9f..f50e0223 100755 --- a/gruntfile.js +++ b/gruntfile.js @@ -143,7 +143,7 @@ module.exports = function(grunt) { dev: { script: 'server.js', options: { - nodeArgs: ['--debug'], + nodeArgs: ['--inspect'], ext: 'js,html', watch: watchFiles.serverViews.concat(watchFiles.serverJS) } @@ -250,7 +250,7 @@ module.exports = function(grunt) { }, main: { options: { - module: 'TellForm.templates' + module: 'app.templates' }, src: ['public/modules/**/views/**.html', 'public/modules/**/views/**/*.html', 'public/form_modules/forms/base/**/*.html'], dest: 'public/dist/populate_template_cache.js' @@ -297,7 +297,7 @@ module.exports = function(grunt) { // Debug task. grunt.registerTask('debug', ['lint', 'html2js:main', 'html2js:forms', 'concurrent:debug']); - + // Lint task(s). grunt.registerTask('lint', ['jshint', 'csslint']); grunt.registerTask('lint:tests', ['jshint:allTests']); diff --git a/package-lock.json b/package-lock.json index 6608d690..54607dd7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17,6 +17,11 @@ "@types/babel-types": "*" } }, + "abab": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.0.tgz", + "integrity": "sha512-sY5AXXVZv4Y1VACTtR11UJCPHHudgY5i26Qj5TypE6DKlIApbwb5uqhXcJ5UUGbvZNRh7EeIoW+LrJumBsKp7w==" + }, "abbrev": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", @@ -66,6 +71,11 @@ } } }, + "acorn-walk": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-6.2.0.tgz", + "integrity": "sha512-7evsyfH1cLOCdAzZAd43Cic04yKydNx0cF+7tiA19p1XnLLPU4dpCQOqpjqwokFe//vS0QqfqqjCS2JkiIs0cA==" + }, "after": { "version": "0.8.2", "resolved": "https://registry.npmjs.org/after/-/after-0.8.2.tgz", @@ -344,6 +354,11 @@ "resolved": "https://registry.npmjs.org/array-differ/-/array-differ-1.0.0.tgz", "integrity": "sha1-7/UuN1gknTO+QCuLuOVkuytdQDE=" }, + "array-equal": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-equal/-/array-equal-1.0.0.tgz", + "integrity": "sha1-jCpe8kcv2ep0KwTHenUJO6J1fJM=" + }, "array-find-index": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", @@ -436,8 +451,7 @@ "async-limiter": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz", - "integrity": "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg==", - "dev": true + "integrity": "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg==" }, "asynckit": { "version": "0.4.0", @@ -824,6 +838,11 @@ "repeat-element": "^1.1.2" } }, + "browser-process-hrtime": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-0.1.3.tgz", + "integrity": "sha512-bRFnI4NnjO6cnyLmOV/7PVoDEMJChlcfN0z4s1YMBY989/SvlfMI1lgCnkFUs53e9gQF+w7qu7XdllSTiSl8Aw==" + }, "browser-stdout": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.0.tgz", @@ -1678,6 +1697,19 @@ "parserlib": "~0.2.2" } }, + "cssom": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", + "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==" + }, + "cssstyle": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-1.3.0.tgz", + "integrity": "sha512-wXsoRfsRfsLVNaVzoKdqvEmK/5PFaEXNspVT22Ots6K/cnJdpoDKuQFw+qlMiXnmaif1OgeC466X1zISgAOcGg==", + "requires": { + "cssom": "~0.3.6" + } + }, "currently-unhandled": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz", @@ -1716,6 +1748,16 @@ "integrity": "sha512-vKQ9DTQPN1FLYiiEEOQ6IBGFqvjCa5rSK3cWMy/Nespm5d/x3dGFT9UBZnkLxCwua/IXBi2TYnwTEpsOvhC4UQ==", "dev": true }, + "data-urls": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-1.1.0.tgz", + "integrity": "sha512-YTWYI9se1P55u58gL5GkQHW4P6VJBJ5iBT+B5a7i2Tjadhv52paJG0qHX4A0OR6/t52odI64KP2YvFpkDOi3eQ==", + "requires": { + "abab": "^2.0.0", + "whatwg-mimetype": "^2.2.0", + "whatwg-url": "^7.0.0" + } + }, "date-format": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/date-format/-/date-format-2.0.0.tgz", @@ -1773,8 +1815,7 @@ "deep-is": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", - "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", - "dev": true + "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=" }, "define-property": { "version": "2.0.2", @@ -1948,6 +1989,14 @@ "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.0.tgz", "integrity": "sha1-sXrtguirWeUt2cGbF1bg/BhyBMI=" }, + "domexception": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/domexception/-/domexception-1.0.1.tgz", + "integrity": "sha512-raigMkn7CJNNo6Ihro1fzG7wr3fHuYVytzquZKX5n0yizGsTcYgzdIUwj1X9pK0VvjeihV+XiclP+DjwbsSKug==", + "requires": { + "webidl-conversions": "^4.0.2" + } + }, "domhandler": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.3.0.tgz", @@ -2746,8 +2795,7 @@ "fast-levenshtein": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", - "dev": true + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=" }, "faye-websocket": { "version": "0.4.4", @@ -5066,8 +5114,7 @@ "commander": "^2.0.0", "glob": "^5.0.0", "htmlparser2": "^3.0.0", - "lodash": "^3.0.0", - "node.extend": "^1.0.0" + "lodash": "^3.0.0" } }, "lodash": { @@ -5521,11 +5568,6 @@ "resolved": "https://registry.npmjs.org/hooks/-/hooks-0.2.1.tgz", "integrity": "sha1-D1kbGzRL3LPfWXc/Yvu6+Fv0Aos=" }, - "hooks-fixed": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/hooks-fixed/-/hooks-fixed-1.1.0.tgz", - "integrity": "sha1-DowVM2cI5mERhf45C0RofdUjDbs=" - }, "hosted-git-info": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.5.0.tgz", @@ -5551,6 +5593,14 @@ } } }, + "html-encoding-sniffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-1.0.2.tgz", + "integrity": "sha512-71lZziiDnsuabfdYiUeWdCVyKuqwWi23L8YeIgV9jSSZHCtb6wB1BKWooH7L3tn4/FuZJMVWyNaIDr4RGmaSYw==", + "requires": { + "whatwg-encoding": "^1.0.1" + } + }, "html-minifier": { "version": "3.5.21", "resolved": "https://registry.npmjs.org/html-minifier/-/html-minifier-3.5.21.tgz", @@ -5893,6 +5943,11 @@ "integrity": "sha1-x+NWzeoiWucbNtcPLnGpK6TkJZA=", "dev": true }, + "ip-regex": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-2.1.0.tgz", + "integrity": "sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk=" + }, "ipaddr.js": { "version": "1.9.0", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.0.tgz", @@ -6379,6 +6434,106 @@ "integrity": "sha512-xYuhvQ7I9PDJIGBWev9xm0+SMSed3ZDBAmvVjbFR1ZRLAF+vlXcQu6cRI9uAlj81rzikElRVteehwV7DuX2ZmQ==", "dev": true }, + "jsdom": { + "version": "15.1.1", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-15.1.1.tgz", + "integrity": "sha512-cQZRBB33arrDAeCrAEWn1U3SvrvC8XysBua9Oqg1yWrsY/gYcusloJC3RZJXuY5eehSCmws8f2YeliCqGSkrtQ==", + "requires": { + "abab": "^2.0.0", + "acorn": "^6.1.1", + "acorn-globals": "^4.3.2", + "array-equal": "^1.0.0", + "cssom": "^0.3.6", + "cssstyle": "^1.2.2", + "data-urls": "^1.1.0", + "domexception": "^1.0.1", + "escodegen": "^1.11.1", + "html-encoding-sniffer": "^1.0.2", + "nwsapi": "^2.1.4", + "parse5": "5.1.0", + "pn": "^1.1.0", + "request": "^2.88.0", + "request-promise-native": "^1.0.7", + "saxes": "^3.1.9", + "symbol-tree": "^3.2.2", + "tough-cookie": "^3.0.1", + "w3c-hr-time": "^1.0.1", + "w3c-xmlserializer": "^1.1.2", + "webidl-conversions": "^4.0.2", + "whatwg-encoding": "^1.0.5", + "whatwg-mimetype": "^2.3.0", + "whatwg-url": "^7.0.0", + "ws": "^7.0.0", + "xml-name-validator": "^3.0.0" + }, + "dependencies": { + "acorn": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.2.0.tgz", + "integrity": "sha512-8oe72N3WPMjA+2zVG71Ia0nXZ8DpQH+QyyHO+p06jT8eg8FGG3FbcUIi8KziHlAfheJQZeoqbvq1mQSQHXKYLw==" + }, + "acorn-globals": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-4.3.2.tgz", + "integrity": "sha512-BbzvZhVtZP+Bs1J1HcwrQe8ycfO0wStkSGxuul3He3GkHOIZ6eTqOkPuw9IP1X3+IkOo4wiJmwkobzXYz4wewQ==", + "requires": { + "acorn": "^6.0.1", + "acorn-walk": "^6.0.1" + } + }, + "escodegen": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.11.1.tgz", + "integrity": "sha512-JwiqFD9KdGVVpeuRa68yU3zZnBEOcPs0nKW7wZzXky8Z7tffdYUHbe11bPCV5jYlK6DVdKLWLm0f5I/QlL0Kmw==", + "requires": { + "esprima": "^3.1.3", + "estraverse": "^4.2.0", + "esutils": "^2.0.2", + "optionator": "^0.8.1", + "source-map": "~0.6.1" + } + }, + "esprima": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-3.1.3.tgz", + "integrity": "sha1-/cpRzuYTOJXjyI1TXOSdv/YqRjM=" + }, + "estraverse": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz", + "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=" + }, + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "optional": true + }, + "tough-cookie": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-3.0.1.tgz", + "integrity": "sha512-yQyJ0u4pZsv9D4clxO69OEjLWYw+jbgspjTue4lTQZLfV0c5l1VmK2y1JK8E9ahdpltPOaAThPcp5nKPUgSnsg==", + "requires": { + "ip-regex": "^2.1.0", + "psl": "^1.1.28", + "punycode": "^2.1.1" + } + }, + "ws": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.1.0.tgz", + "integrity": "sha512-Swie2C4fs7CkwlHu1glMePLYJJsWjzhl1vm3ZaLplD0h7OMkZyZ6kLTB/OagiU923bZrPFXuDTeEqaEN4NWG4g==", + "requires": { + "async-limiter": "^1.0.0" + } + } + } + }, "jshint": { "version": "2.9.7", "resolved": "https://registry.npmjs.org/jshint/-/jshint-2.9.7.tgz", @@ -6491,11 +6646,6 @@ "promise": "^7.0.1" } }, - "kareem": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/kareem/-/kareem-1.0.1.tgz", - "integrity": "sha1-eAXSFbtTIU7Dr5aaHQsfF+PnuVw=" - }, "karma": { "version": "0.13.22", "resolved": "https://registry.npmjs.org/karma/-/karma-0.13.22.tgz", @@ -8143,7 +8293,6 @@ "version": "0.3.0", "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", - "dev": true, "requires": { "prelude-ls": "~1.1.2", "type-check": "~0.3.2" @@ -8351,6 +8500,11 @@ "integrity": "sha1-lU73UEkmIDjJbR/Jiyj9r58Hcqo=", "dev": true }, + "lodash.sortby": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", + "integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=" + }, "log-driver": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/log-driver/-/log-driver-1.2.5.tgz", @@ -8951,123 +9105,6 @@ "bson": "~0.4.20" } }, - "mongoose": { - "version": "4.4.20", - "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-4.4.20.tgz", - "integrity": "sha1-6XT/tq6MUPQJgBqEl6mOnztR8t0=", - "requires": { - "async": "1.5.2", - "bson": "~0.4.23", - "hooks-fixed": "1.1.0", - "kareem": "1.0.1", - "mongodb": "2.1.18", - "mpath": "0.2.1", - "mpromise": "0.5.5", - "mquery": "1.11.0", - "ms": "0.7.1", - "muri": "1.1.0", - "regexp-clone": "0.0.1", - "sliced": "1.0.1" - }, - "dependencies": { - "bluebird": { - "version": "2.10.2", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-2.10.2.tgz", - "integrity": "sha1-AkpVFylTCIV/FPkfEQb8O1VfRGs=" - }, - "debug": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz", - "integrity": "sha1-+HBX6ZWxofauaklgZkE3vFbwOdo=", - "requires": { - "ms": "0.7.1" - } - }, - "es6-promise": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-3.0.2.tgz", - "integrity": "sha1-AQ1YWEI6XxGJeWZfRkhqlcbuK7Y=" - }, - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" - }, - "mongodb": { - "version": "2.1.18", - "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-2.1.18.tgz", - "integrity": "sha1-KNQLUVsr5NWmn/3UxTXw30MuQJc=", - "requires": { - "es6-promise": "3.0.2", - "mongodb-core": "1.3.18", - "readable-stream": "1.0.31" - } - }, - "mongodb-core": { - "version": "1.3.18", - "resolved": "https://registry.npmjs.org/mongodb-core/-/mongodb-core-1.3.18.tgz", - "integrity": "sha1-kGhLO3xzVtZa41Y5HTCw8kiATHo=", - "requires": { - "bson": "~0.4.23", - "require_optional": "~1.0.0" - } - }, - "mpath": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/mpath/-/mpath-0.2.1.tgz", - "integrity": "sha1-Ok6Ck1mAHeljCcJ6ay4QLon56W4=" - }, - "mpromise": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/mpromise/-/mpromise-0.5.5.tgz", - "integrity": "sha1-9bJCWddjrMIlewoMjG2Gb9UXMuY=" - }, - "mquery": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/mquery/-/mquery-1.11.0.tgz", - "integrity": "sha1-4MZd7bEDftv2z7iCYud3/uI1Udk=", - "requires": { - "bluebird": "2.10.2", - "debug": "2.2.0", - "regexp-clone": "0.0.1", - "sliced": "0.0.5" - }, - "dependencies": { - "sliced": { - "version": "0.0.5", - "resolved": "https://registry.npmjs.org/sliced/-/sliced-0.0.5.tgz", - "integrity": "sha1-XtwETKTrb3gW1Qui/GPiXY/kcH8=" - } - } - }, - "ms": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz", - "integrity": "sha1-nNE8A62/8ltl7/3nzoZO6VIBcJg=" - }, - "readable-stream": { - "version": "1.0.31", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.31.tgz", - "integrity": "sha1-jyUC4LyeOw2huUUgqrtOJgPsr64=", - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" - } - }, - "sliced": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/sliced/-/sliced-1.0.1.tgz", - "integrity": "sha1-CzpmK10Ewxd7GSa+qCsD+Dei70E=" - }, - "string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" - } - } - }, "morgan": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.9.1.tgz", @@ -10451,6 +10488,11 @@ "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=" }, + "nwsapi": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.1.4.tgz", + "integrity": "sha512-iGfd9Y6SFdTNldEy2L0GUhcarIutFmk+MPWIn9dmj8NMIup03G08uUF2KGbbmv/Ux4RT0VZJoP/sVbWA6d/VIw==" + }, "oauth-sign": { "version": "0.8.2", "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz", @@ -10569,7 +10611,6 @@ "version": "0.8.2", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz", "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", - "dev": true, "requires": { "deep-is": "~0.1.3", "fast-levenshtein": "~2.0.4", @@ -10582,8 +10623,7 @@ "wordwrap": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", - "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", - "dev": true + "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=" } } }, @@ -10753,6 +10793,11 @@ "error-ex": "^1.2.0" } }, + "parse5": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.0.tgz", + "integrity": "sha512-fxNG2sQjHvlVAYmzBZS9YlDp6PTSSDwa98vkD4QgVDDCAo84z5X1t5XyJQ62ImdLXx5NdIIfihey6xpum9/gRQ==" + }, "parsejson": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/parsejson/-/parsejson-0.0.3.tgz", @@ -11209,6 +11254,11 @@ "resolved": "https://registry.npmjs.org/platform/-/platform-1.3.5.tgz", "integrity": "sha512-TuvHS8AOIZNAlE77WUDiR4rySV/VMptyMfcfeoMgs4P8apaZM3JrnbzBiixKUv+XR6i+BXrQh8WAnjaSPFO65Q==" }, + "pn": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/pn/-/pn-1.1.0.tgz", + "integrity": "sha512-2qHaIQr2VLRFoxe2nASzsV6ef4yOOH+Fi9FBOVH6cqeSgUnoyySPZkxzLuzd+RYOQTRpROA0ztTMqxROKSb/nA==" + }, "posix-character-classes": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", @@ -11217,8 +11267,7 @@ "prelude-ls": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", - "dev": true + "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=" }, "prepend-http": { "version": "1.0.4", @@ -12324,6 +12373,24 @@ "throttleit": "^1.0.0" } }, + "request-promise-core": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.2.tgz", + "integrity": "sha512-UHYyq1MO8GsefGEt7EprS8UrXsm1TxEvFUX1IMTuSLU2Rh7fTIdFtl8xD7JiEYiWU2dl+NYAjCTksTehQUxPag==", + "requires": { + "lodash": "^4.17.11" + } + }, + "request-promise-native": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/request-promise-native/-/request-promise-native-1.0.7.tgz", + "integrity": "sha512-rIMnbBdgNViL37nZ1b3L/VfPOpSi0TqVDQPAvO6U14lMzOLrt5nilxCQqtDKhZeDiW0/hkCXGoQjhgJd/tCh6w==", + "requires": { + "request-promise-core": "1.1.2", + "stealthy-require": "^1.1.1", + "tough-cookie": "^2.3.3" + } + }, "require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -12336,15 +12403,6 @@ "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=", "dev": true }, - "require_optional": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/require_optional/-/require_optional-1.0.1.tgz", - "integrity": "sha512-qhM/y57enGWHAe3v/NcwML6a3/vfESLe/sGM2dII+gEO0BpKRUkWZow/tyloNqJyN6kXSl3RyyM8Ll5D/sJP8g==", - "requires": { - "resolve-from": "^2.0.0", - "semver": "^5.1.0" - } - }, "requires-port": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", @@ -12359,11 +12417,6 @@ "path-parse": "^1.0.6" } }, - "resolve-from": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-2.0.0.tgz", - "integrity": "sha1-lICrIOlP+h2egKgEx+oUdhGWa1c=" - }, "resolve-url": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", @@ -12453,6 +12506,14 @@ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, + "saxes": { + "version": "3.1.11", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-3.1.11.tgz", + "integrity": "sha512-Ydydq3zC+WYDJK1+gRxRapLIED9PWeSuuS41wqyoRmzvhhh9nc+QQrVMKJYzJFULazeGhzSV0QleN2wD3boh2g==", + "requires": { + "xmlchars": "^2.1.1" + } + }, "scandirectory": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/scandirectory/-/scandirectory-2.5.0.tgz", @@ -13131,6 +13192,11 @@ "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" }, + "stealthy-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz", + "integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=" + }, "stream-shift": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.0.tgz", @@ -13409,6 +13475,11 @@ } } }, + "symbol-tree": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", + "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==" + }, "taskgroup": { "version": "4.3.1", "resolved": "https://registry.npmjs.org/taskgroup/-/taskgroup-4.3.1.tgz", @@ -13602,6 +13673,21 @@ "punycode": "^1.4.1" } }, + "tr46": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz", + "integrity": "sha1-qLE/1r/SSJUZZ0zN5VujaTtwbQk=", + "requires": { + "punycode": "^2.1.0" + }, + "dependencies": { + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" + } + } + }, "trim-newlines": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz", @@ -13629,7 +13715,6 @@ "version": "0.3.2", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", - "dev": true, "requires": { "prelude-ls": "~1.1.2" } @@ -14032,6 +14117,24 @@ "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-2.0.1.tgz", "integrity": "sha1-wGavtYK7HLQSjWDqkjkulNXp2+w=" }, + "w3c-hr-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.1.tgz", + "integrity": "sha1-gqwr/2PZUOqeMYmlimViX+3xkEU=", + "requires": { + "browser-process-hrtime": "^0.1.2" + } + }, + "w3c-xmlserializer": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-1.1.2.tgz", + "integrity": "sha512-p10l/ayESzrBMYWRID6xbuCKh2Fp77+sA0doRuGn4tTIMrrZVeqfpKjXHY+oDh3K4nLdPgNwMTVP6Vp4pvqbNg==", + "requires": { + "domexception": "^1.0.1", + "webidl-conversions": "^4.0.2", + "xml-name-validator": "^3.0.0" + } + }, "watchr": { "version": "2.4.13", "resolved": "https://registry.npmjs.org/watchr/-/watchr-2.4.13.tgz", @@ -14047,6 +14150,44 @@ "typechecker": "^2.0.8" } }, + "webidl-conversions": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz", + "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==" + }, + "whatwg-encoding": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz", + "integrity": "sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==", + "requires": { + "iconv-lite": "0.4.24" + }, + "dependencies": { + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + } + } + }, + "whatwg-mimetype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz", + "integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==" + }, + "whatwg-url": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.0.0.tgz", + "integrity": "sha512-37GeVSIJ3kn1JgKyjiYNmSLP1yzbpb29jdmwBSgkD9h40/hyrR/OifpVUndji3tmwGgD8qpw7iQu3RSbCrBpsQ==", + "requires": { + "lodash.sortby": "^4.7.0", + "tr46": "^1.0.1", + "webidl-conversions": "^4.0.2" + } + }, "which": { "version": "1.0.9", "resolved": "https://registry.npmjs.org/which/-/which-1.0.9.tgz", @@ -14197,6 +14338,16 @@ "integrity": "sha1-SWsswQnsqNus/i3HK2A8F8WHCtQ=", "dev": true }, + "xml-name-validator": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz", + "integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==" + }, + "xmlchars": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.1.1.tgz", + "integrity": "sha512-7hew1RPJ1iIuje/Y01bGD/mXokXxegAgVS+e+E0wSi2ILHQkYAH1+JXARwTjZSM4Z4Z+c73aKspEcqj+zPPL/w==" + }, "xmlhttprequest-ssl": { "version": "1.5.3", "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.3.tgz", diff --git a/package.json b/package.json index 9d4298e3..2a35745f 100644 --- a/package.json +++ b/package.json @@ -49,11 +49,12 @@ "helmet": "^3.16.0", "i18n": "^0.8.3", "jit-grunt": "^0.9.1", + "jsdom": "^15.1.1", "lodash": "^4.17.13", "main-bower-files": "^2.13.1", "method-override": "~2.3.0", "mkdirp": "^0.5.1", - "mongoose": "~4.4.19", + "mongoose": "^5.6.4", "morgan": "^1.9.1", "nodemailer": "~4.0.0", "passport": "~0.3.0", diff --git a/public/config.js b/public/config.js index dde967a4..326670cf 100755 --- a/public/config.js +++ b/public/config.js @@ -2,22 +2,29 @@ // Init the application configuration module for AngularJS application var ApplicationConfiguration = (function() { - // Init module configuration options - var applicationModuleName = 'TellForm'; - var applicationModuleVendorDependencies = ['duScroll', 'ui.select', 'ngSanitize', 'vButton', 'ngResource', 'TellForm.templates', 'ui.router', 'ui.bootstrap', 'ui.utils', 'pascalprecht.translate']; - // Add a new vertical module var registerModule = function(moduleName, dependencies) { // Create angular module angular.module(moduleName, dependencies || []); // Add the module to the AngularJS configuration file - angular.module(applicationModuleName).requires.push(moduleName); + angular.module('app').requires.push(moduleName); }; return { - applicationModuleName: applicationModuleName, - applicationModuleVendorDependencies: applicationModuleVendorDependencies, + applicationModuleName: 'app', + applicationModuleVendorDependencies: [ + 'duScroll', + 'ui.select', + 'ngSanitize', + 'vButton', + 'ngResource', + 'app.templates', + 'ui.router', + 'ui.bootstrap', + 'ui.utils', + 'pascalprecht.translate' + ], registerModule: registerModule }; })(); diff --git a/public/form_modules/forms/base/directives/submit-form.client.directive.js b/public/form_modules/forms/base/directives/submit-form.client.directive.js index 244f8226..0c9b4254 100644 --- a/public/form_modules/forms/base/directives/submit-form.client.directive.js +++ b/public/form_modules/forms/base/directives/submit-form.client.directive.js @@ -20,7 +20,7 @@ angular.module('view-form').directive('submitFormDirective', ['$http', 'TimeCoun controller: function($document, $window, $scope){ var FORM_ACTION_ID = 'submit_field'; $scope.forms = {}; - + var form_fields_count = $scope.myform.visible_form_fields.filter(function(field){ return field.fieldType !== 'statement'; }).length; @@ -145,8 +145,8 @@ angular.module('view-form').directive('submitFormDirective', ['$http', 'TimeCoun if(!field_id && field_index === null) { return; } - - if(field_id === FORM_ACTION_ID){ + + if(field_id === FORM_ACTION_ID){ field_index = $scope.myform.visible_form_fields.length; } else if(!field_id) { field_id = $scope.myform.visible_form_fields[field_index]._id; @@ -171,7 +171,7 @@ angular.module('view-form').directive('submitFormDirective', ['$http', 'TimeCoun if($scope.selected._id === field_id){ return; } - + $scope.selected._id = field_id; $scope.selected.index = field_index; @@ -199,7 +199,7 @@ angular.module('view-form').directive('submitFormDirective', ['$http', 'TimeCoun //Handle case for dropdown input angular.element('#'+field_id+'.selectize-input')[0].focus(); } - } + } }; $rootScope.$on('duScrollspy:becameActive', function($event, $element, $target){ @@ -215,7 +215,7 @@ angular.module('view-form').directive('submitFormDirective', ['$http', 'TimeCoun if($scope.selected && $scope.selected.index > -1){ if($scope.selected._id !== FORM_ACTION_ID){ var currField = $scope.myform.visible_form_fields[$scope.selected.index]; - + //Jump to logicJump's destination if it is true if(currField.logicJump && currField.logicJump.jumpTo && evaluateLogicJump(currField)){ $scope.setActiveField(currField.logicJump.jumpTo, null, true); @@ -312,10 +312,10 @@ angular.module('view-form').directive('submitFormDirective', ['$http', 'TimeCoun form.timeElapsed = _timeElapsed; form.percentageComplete = $filter('formValidity')($scope.myform) / $scope.myform.visible_form_fields.length * 100; - delete form.endPage - delete form.isLive - delete form.provider - delete form.startPage + delete form.endPage; + delete form.isLive; + delete form.provider; + delete form.startPage; delete form.visible_form_fields; delete form.analytics; delete form.design; @@ -332,7 +332,7 @@ angular.module('view-form').directive('submitFormDirective', ['$http', 'TimeCoun .then(function (data, status) { $scope.myform.submitted = true; $scope.loading = false; - SendVisitorData.send(form, $rootScope.getActiveField(), _timeElapsed); + SendVisitorData.send($scope.myform, $rootScope.getActiveField(), _timeElapsed); }, function (error) { $scope.loading = false; console.error(error); diff --git a/public/form_modules/forms/base/services/socket.io.client.service.js b/public/form_modules/forms/base/services/socket.io.client.service.js index 74c388e0..ecfdc829 100644 --- a/public/form_modules/forms/base/services/socket.io.client.service.js +++ b/public/form_modules/forms/base/services/socket.io.client.service.js @@ -20,6 +20,7 @@ } else { url = window.location.protocol + '//' + window.location.hostname; } + url = url.replace(/^http/, 'ws'); service.socket = io(url, {'transports': ['websocket', 'polling']}); } diff --git a/public/form_modules/forms/directives/analytics-service.client.directive.js b/public/form_modules/forms/directives/analytics-service.client.directive.js index 39165c63..d3622c4c 100644 --- a/public/form_modules/forms/directives/analytics-service.client.directive.js +++ b/public/form_modules/forms/directives/analytics-service.client.directive.js @@ -12,7 +12,6 @@ // Create a controller method for sending visitor data function send(form, lastActiveId, timeElapsed) { - var lang = window.navigator.userLanguage || window.navigator.language; lang = lang.slice(0,2); @@ -49,7 +48,7 @@ if (!Socket.socket) { Socket.connect(); } - + Socket.on('disconnect', function(){ Socket.connect(); }); diff --git a/public/modules/forms/admin/controllers/list-forms.client.controller.js b/public/modules/forms/admin/controllers/list-forms.client.controller.js index e7dc77e8..f702d1fe 100644 --- a/public/modules/forms/admin/controllers/list-forms.client.controller.js +++ b/public/modules/forms/admin/controllers/list-forms.client.controller.js @@ -1,13 +1,13 @@ 'use strict'; // Forms controller -angular.module('forms').controller('ListFormsController', ['$rootScope', '$scope', '$stateParams', '$state', 'GetForms', 'CurrentForm', '$http', '$uibModal', 'myForms', '$window', '$location', - function($rootScope, $scope, $stateParams, $state, GetForms, CurrentForm, $http, $uibModal, myForms, $window, $location) { +angular.module('forms').controller('ListFormsController', ['$rootScope', '$scope', '$stateParams', '$state', 'GetForms', 'CurrentForm', '$http', '$uibModal', 'myForms', '$window', + function($rootScope, $scope, $stateParams, $state, GetForms, CurrentForm, $http, $uibModal, myForms, $window) { $scope = $rootScope; $scope.forms = {}; $scope.showCreateModal = false; - $scope.myforms = myForms + $scope.myforms = myForms; $scope.formLanguage = $window.$locale; $rootScope.languageRegExp = { diff --git a/public/modules/users/config/users.client.routes.js b/public/modules/users/config/users.client.routes.js index 14b061d8..ac8f6ff9 100755 --- a/public/modules/users/config/users.client.routes.js +++ b/public/modules/users/config/users.client.routes.js @@ -5,6 +5,7 @@ angular.module('users').config(['$stateProvider', function($stateProvider) { var checkLoggedin = function($q, $timeout, $state, User, Auth) { + var deferred = $q.defer(); if (Auth.currentUser && Auth.currentUser.email) { return; @@ -40,7 +41,7 @@ angular.module('users').config(['$stateProvider', $stateProvider. state('profile', { resolve: { - currentUser: ['$q', '$state', 'User', 'Auth', checkCurrentUser] + currentUser: ['$q', '$timeout', '$state', 'User', 'Auth', checkLoggedin] }, url: '/settings/profile', templateUrl: 'modules/users/views/settings/edit-profile.client.view.html', @@ -48,7 +49,7 @@ angular.module('users').config(['$stateProvider', }). state('password', { resolve: { - currentUser: ['$q', '$state', 'User', 'Auth', checkCurrentUser] + currentUser: ['$q', '$timeout', '$state', 'User', 'Auth', checkLoggedin] }, url: '/settings/password', templateUrl: 'modules/users/views/settings/change-password.client.view.html', diff --git a/public/modules/users/controllers/authentication.client.controller.js b/public/modules/users/controllers/authentication.client.controller.js index 8940db47..22dbaee5 100755 --- a/public/modules/users/controllers/authentication.client.controller.js +++ b/public/modules/users/controllers/authentication.client.controller.js @@ -1,7 +1,7 @@ 'use strict'; -angular.module('users').controller('AuthenticationController', ['$scope', '$location', '$state', '$rootScope', 'User', 'Auth', '$translate', '$window', - function($scope, $location, $state, $rootScope, User, Auth, $translate, $window) { +angular.module('users').controller('AuthenticationController', ['$scope', '$location', '$state', '$rootScope', 'User', 'Auth', + function($scope, $location, $state, $rootScope, User, Auth) { //This helps us test the controller by allowing tests to inject their own scope variables if(!$scope.credentials) $scope.credentials = {}; diff --git a/public/modules/users/controllers/change_password.client.controller.js b/public/modules/users/controllers/change_password.client.controller.js index e4114bf8..4d2152e3 100644 --- a/public/modules/users/controllers/change_password.client.controller.js +++ b/public/modules/users/controllers/change_password.client.controller.js @@ -2,13 +2,12 @@ angular.module('users').controller('ChangePasswordController', ['$scope', '$rootScope', '$http', '$state', 'Users', 'Auth', function($scope, $rootScope, $http, $state, Users, Auth) { - $scope.user = Auth.currentUser; - console.log($scope.user) + console.log($scope.user); $scope.cancel = function(){ $scope.user = Auth.currentUser; - } + }; // Change user password $scope.changeUserPassword = function() { @@ -24,6 +23,5 @@ angular.module('users').controller('ChangePasswordController', ['$scope', '$root $scope.error = response.message; }); }; - */ } ]); diff --git a/public/modules/users/controllers/password.client.controller.js b/public/modules/users/controllers/password.client.controller.js index 5797ce3f..d66b369e 100755 --- a/public/modules/users/controllers/password.client.controller.js +++ b/public/modules/users/controllers/password.client.controller.js @@ -1,7 +1,7 @@ 'use strict'; -angular.module('users').controller('PasswordController', ['$scope', '$stateParams', '$state', 'User', '$window', - function($scope, $stateParams, $state, User, $window) { +angular.module('users').controller('PasswordController', ['$scope', '$stateParams', '$state', 'User', + function($scope, $stateParams, $state, User) { $scope.error = ''; if(!$scope.forms) $scope.forms = {}; diff --git a/public/modules/users/controllers/settings.client.controller.js b/public/modules/users/controllers/settings.client.controller.js index 1404cddf..3b26c04b 100755 --- a/public/modules/users/controllers/settings.client.controller.js +++ b/public/modules/users/controllers/settings.client.controller.js @@ -7,7 +7,7 @@ angular.module('users').controller('SettingsController', ['$scope', '$rootScope' $scope.cancel = function(){ $scope.user = Auth.currentUser; - } + }; // Update a user profile $scope.updateUserProfile = function(isValid) { diff --git a/public/modules/users/controllers/verify.client.controller.js b/public/modules/users/controllers/verify.client.controller.js index b07e1cae..80ca6e90 100644 --- a/public/modules/users/controllers/verify.client.controller.js +++ b/public/modules/users/controllers/verify.client.controller.js @@ -1,7 +1,7 @@ 'use strict'; -angular.module('users').controller('VerifyController', ['$scope', '$state', '$rootScope', 'User', 'Auth', '$stateParams', '$translate', '$window', - function($scope, $state, $rootScope, User, Auth, $stateParams, $translate, $window) { +angular.module('users').controller('VerifyController', ['$scope', '$state', '$rootScope', 'User', 'Auth', '$stateParams', + function($scope, $state, $rootScope, User, Auth, $stateParams) { $scope.isResetSent = false; if(!$scope.credentials) $scope.credentials = {}; $scope.error = ''; @@ -46,4 +46,4 @@ angular.module('users').controller('VerifyController', ['$scope', '$state', '$ro } }; } -]); \ No newline at end of file +]); diff --git a/scripts/create_admin.js b/scripts/create_admin.js index 7c5a91ee..53b83103 100644 --- a/scripts/create_admin.js +++ b/scripts/create_admin.js @@ -1,6 +1,6 @@ var config = require('../config/config'), mongoose = require('mongoose'), - chalk = require('chalk'); + chalk = require('chalk'); exports.run = function(app, db, cb) { console.log(chalk.green('Creating the Admin Account')); @@ -16,21 +16,21 @@ exports.run = function(app, db, cb) { password: config.admin.password || 'root', provider: 'local', roles: ['admin', 'user'] - }); + }; var options = { upsert: true, new: true, setDefaultsOnInsert: true - } + }; - User.findOneAndUpdate({username: username}, newUserObj, options, function (err, currUser1) { + User.findOneAndUpdate({username: newUserObj.username}, newUserObj, options, function (err, currUser1) { if (err) { return cb(err); } if(!currUser1){ - return cb(new Error('Couldn\'t create admin account')) + return cb(new Error('Couldn\'t create admin account')); } else { currUser1.password = config.admin.password; @@ -44,4 +44,4 @@ exports.run = function(app, db, cb) { }); } }); -} +}; diff --git a/server.js b/server.js index 9caf04d8..4edc6fed 100755 --- a/server.js +++ b/server.js @@ -80,7 +80,7 @@ if (process.env.CREATE_ADMIN === 'TRUE') { }); return app; -} +}; // To maintain backwards compatibility, run bootstrap when called as a file if(require.main === module) {