Merge branch 'master' into emailNotifications

This commit is contained in:
David Baldwynn 2017-10-05 21:27:57 -07:00
commit ae946bd619
18 changed files with 1511 additions and 2762 deletions

View File

@ -46,17 +46,16 @@ exports.deleteSubmissions = function(req, res) {
* Submit a form entry
*/
exports.createSubmission = function(req, res) {
var form = req.form;
var timeElapsed = 0;
console.log(req.body);
if(typeof req.body.timeElapsed === 'number'){
timeElapsed = req.body.timeElapsed;
}
var submission = new FormSubmission({
admin: form.admin._id,
form: form._id,
title: form.title,
form: req.body._id,
title: req.body.title,
form_fields: req.body.form_fields,
timeElapsed: timeElapsed,
percentageComplete: req.body.percentageComplete,
@ -73,18 +72,7 @@ exports.createSubmission = function(req, res) {
message: errorHandler.getErrorMessage(err)
});
}
form.submissions.push(submission);
form.save(function (err) {
if (err) {
console.error(err);
return res.status(500).send({
message: errorHandler.getErrorMessage(err)
});
}
res.status(200).send('Form submission successfully saved');
});
res.status(200).send('Form submission successfully saved');
});
};
@ -94,10 +82,10 @@ exports.createSubmission = function(req, res) {
exports.listSubmissions = function(req, res) {
var _form = req.form;
FormSubmission.find({ form: _form._id }).exec(function(err, _submissions) {
FormSubmission.find({ form: _form._id }).sort('-created').lean().exec(function(err, _submissions) {
if (err) {
console.error(err);
res.status(400).send({
res.status(500).send({
message: errorHandler.getErrorMessage(err)
});
}
@ -172,7 +160,9 @@ var readForRender = exports.readForRender = function(req, res) {
});
}
delete newForm.admin;
delete newForm.lastModified;
delete newForm.__v;
delete newForm.created;
if(!newForm.startPage.showStart){
delete newForm.startPage;
@ -185,7 +175,7 @@ var readForRender = exports.readForRender = function(req, res) {
* Update a form
*/
exports.update = function(req, res) {
var form = req.form;
var form = req.form;
var updatedForm = req.body.form;
delete updatedForm.__v;
@ -250,24 +240,28 @@ exports.delete = function(req, res) {
* Get All of Users' Forms
*/
exports.list = function(req, res) {
Form.aggregate([
{ $match: { admin: req.user._id } },
{
$project: {
admin: 1,
_id: 1,
language: 1,
isLive: 1,
title: 1,
numberOfResponses: { $size: "$submissions" }
}
}
]).exec(function(err, forms) {
//Allow 'admin' user to view all forms
var searchObj = {admin: req.user};
if(req.user.isAdmin()) searchObj = {};
Form.find(searchObj)
.sort('-created')
.select('title language submissions admin isLive')
.populate('admin.username', 'admin._id')
.lean()
.exec(function(err, forms) {
if (err) {
res.status(400).send({
message: errorHandler.getErrorMessage(err)
});
} else {
for(var i=0; i<forms.length; i++){
forms[i].numberOfResponses = 0;
if(forms[i].submissions){
forms[i].numberOfResponses = forms[i].submissions.length;
delete forms[i].submissions;
}
}
res.json(forms);
}
});
@ -316,10 +310,9 @@ exports.formByIDFast = function(req, res, next, id) {
});
}
Form.findById(id)
.select('title language form_fields startPage endPage hideFooter isLive design admin analytics.gaCode')
.populate('admin.roles', 'admin.id')
.lean()
.cache()
.select('title language form_fields startPage endPage hideFooter isLive design analytics.gaCode')
.exec(function(err, form) {
if (err) {
return next(err);
@ -329,7 +322,14 @@ exports.formByIDFast = function(req, res, next, id) {
});
}
else {
req.form = form;
//Remove sensitive information from User object
var _form = form;
if(_form.admin){
_form.admin.password = null;
_form.admin.salt = null;
_form.provider = null;
}
req.form = _form;
return next();
}
});

View File

@ -16,12 +16,6 @@ var FormSubmissionSchema = new Schema({
type: String
},
admin: {
type: Schema.Types.ObjectId,
ref: 'User',
required: true
},
form_fields: [FieldSchema],
form: {
@ -59,20 +53,19 @@ var FormSubmissionSchema = new Schema({
});
FormSubmissionSchema.pre('save', function (next) {
//Iterate through form fields and format data
//Iterate through form fields and format data
for(var i = 0; i < this.form_fields.length; i++){
if(this.form_fields[i].fieldType === 'dropdown'){
this.form_fields[i].fieldValue = this.form_fields[i].fieldValue.option_value;
}
}
next();
next();
});
FormSubmissionSchema.path('form_fields', {
set: function(form_fields){
for (var i = 0; i < form_fields.length; i++) {
form_fields[i].isSubmission = true;
form_fields[i].submissionId = form_fields[i]._id;
form_fields[i]._id = new mongoose.mongo.ObjectID();
delete form_fields[i].deletePreserved;

View File

@ -14,21 +14,22 @@ module.exports = function(app) {
app.route('/subdomain/:userSubdomain((?!api$)[A-Za-z0-9]+)/')
.get(core.form);
app.route('/subdomain/:userSubdomain((?!api$)[A-Za-z0-9]+)/forms/:formId([a-zA-Z0-9]+)')
app.route('/subdomain/:userSubdomain((?!api$)[A-Za-z0-9]+)/forms/([a-zA-Z0-9]+)')
.post(forms.createSubmission);
app.route('/subdomain/:userSubdomain((?!api$)[A-Za-z0-9]+)/forms/:formIdFast([a-zA-Z0-9]+)/render')
.get(forms.readForRender);
app.route('/forms/:formIdFast([a-zA-Z0-9]+)/render')
app.route('/forms/:formId([a-zA-Z0-9]+)/render')
.get(auth.isAuthenticatedOrApiKey, forms.hasAuthorization, forms.readForRender);
} else {
app.route('/view/')
.get(core.form);
app.route('/forms/:formIdFast([a-zA-Z0-9]+)/render')
app.route('/forms/:formIdFast([a-zA-Z0-9]+)/render')
.get(forms.readForRender);
}
app.route('/forms/:formIdFast([a-zA-Z0-9]+)')
.post(forms.createSubmission)
app.route('/forms')
.get(auth.isAuthenticatedOrApiKey, forms.list)
.post(auth.isAuthenticatedOrApiKey, forms.create);
@ -48,4 +49,5 @@ module.exports = function(app) {
// Fast formId middleware
app.param('formIdFast', forms.formByIDFast);
};

View File

@ -43,34 +43,9 @@
}
</style>
<script src="https://code.jquery.com/jquery-3.1.1.min.js" type="text/javascript"></script>
<script type="text/javascript">
$(window).ready(function() {
$(".loader").fadeOut("slow");
});
</script>
<!-- Fav Icon -->
<link href="/static/modules/core/img/brand/favicon.ico" rel="shortcut icon" type="image/x-icon">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
<!--Bower CSS dependencies-->
{% for bowerCssFile in bowerCssFiles %}
<link rel="stylesheet" href="{{bowerCssFile}}">
{% endfor %}
<link rel="stylesheet" href="/static/lib/angular-input-stars/angular-input-stars.css">
<link rel="stylesheet" href="/static/lib/jquery-ui/themes/flick/jquery-ui.min.css"/>
<!-- end Bower CSS dependencies-->
<!--Application CSS Files-->
{% for cssFile in cssFiles %}
<link rel="stylesheet" href="{{cssFile}}">
{% endfor %}
<!-- end Application CSS Files-->
<!-- HTML5 Shim -->
<!--[if lt IE 9]>
@ -86,9 +61,8 @@
<section ui-view></section>
</section>
<!--
Embedding The User Object signupDisabled, socketPort and socketUrl Boolean
-->
<!--Embedding The User Object signupDisabled, socketPort and socketUrl Boolean -->
<script type="text/javascript">
var user = {{ user | json | safe }};
var signupDisabled = {{signupDisabled | safe}};
@ -100,14 +74,39 @@
var subdomainsDisabled = {{subdomainsDisabled | safe}};
</script>
<script src="/static/lib/jquery/dist/jquery.min.js" type="text/javascript"></script>
<script type="text/javascript">
$(window).on("load", function() {
$(".loader").fadeOut("slow");
});
</script>
<link rel="stylesheet" href="/static/lib/font-awesome/css/font-awesome.min.css">
<link rel="stylesheet" href="/static/lib/bootstrap/dist/css/bootstrap.min.css">
<!--Bower CSS dependencies-->
{% for bowerCssFile in bowerCssFiles %}
<link rel="stylesheet" href="{{bowerCssFile}}">
{% endfor %}
<link rel="stylesheet" href="/static/lib/angular-input-stars/angular-input-stars.css">
<link rel="stylesheet" href="/static/lib/jquery-ui/themes/flick/jquery-ui.min.css"/>
<!-- end Bower CSS dependencies-->
<!--Application CSS Files-->
{% for cssFile in cssFiles %}
<link rel="stylesheet" href="{{cssFile}}">
{% endfor %}
<!-- end Application CSS Files-->
<!--Socket.io Client Dependency-->
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/2.0.3/socket.io.slim.js" async></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.min.js" type="text/javascript"></script>
<script src="/static/lib/socket.io-client/dist/socket.io.min.js"></script>
<script src="/static/lib/jquery-ui/jquery-ui.js" type="text/javascript"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script>
<script src="/static/dist/vendor.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-date/1.0.1/date.min.js" type="text/javascript"></script>
<script src="/static/lib/angular-ui-date/src/date.js" type="text/javascript"></script>
<!--Application JavaScript Files-->
{% for jsFile in formJSFiles %}
<script type="text/javascript" src="{{jsFile}}"></script>
@ -119,15 +118,27 @@
<script async type="text/javascript" src="http://{{request.hostname}}:35729/livereload.js"></script>
{% endif %}
<script defer>
<script>
Raven.config('https://825fefd6b4ed4a4da199c1b832ca845c@sentry.tellform.com/2').install();
</script>
<script >
window.ga=function(){ga.q.push(arguments)};ga.q=[];ga.l=+new Date;
ga('create','{{google_analytics_id}}','auto');ga('send','pageview')
{% if google_analytics_id %}
<script>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','https://www.google-analytics.com/analytics.js','ga');
ga('create', '{{google_analytics_id}}', 'auto');
ga('send', 'pageview');
</script>
<script src="https://www.google-analytics.com/analytics.js" async defer></script>
{% endif %}
<script type="text/javascript">
window.heap=window.heap||[],heap.load=function(e,t){window.heap.appid=e,window.heap.config=t=t||{};var r=t.forceSSL||"https:"===document.location.protocol,a=document.createElement("script");a.type="text/javascript",a.async=!0,a.src=(r?"https:":"http:")+"//cdn.heapanalytics.com/js/heap-"+e+".js";var n=document.getElementsByTagName("script")[0];n.parentNode.insertBefore(a,n);for(var o=function(e){return function(){heap.push([e].concat(Array.prototype.slice.call(arguments,0)))}},p=["addEventProperties","addUserProperties","clearEventProperties","identify","removeEventProperty","setEventProperties","track","unsetEventProperty"],c=0;c<p.length;c++)heap[p[c]]=o(p[c])};
heap.load("2213510609");
</script>
</body>
</html>

View File

@ -125,7 +125,11 @@
</script>
<script src="https://www.google-analytics.com/analytics.js" async defer></script>
<script type="text/javascript">
window.heap=window.heap||[],heap.load=function(e,t){window.heap.appid=e,window.heap.config=t=t||{};var r=t.forceSSL||"https:"===document.location.protocol,a=document.createElement("script");a.type="text/javascript",a.async=!0,a.src=(r?"https:":"http:")+"//cdn.heapanalytics.com/js/heap-"+e+".js";var n=document.getElementsByTagName("script")[0];n.parentNode.insertBefore(a,n);for(var o=function(e){return function(){heap.push([e].concat(Array.prototype.slice.call(arguments,0)))}},p=["addEventProperties","addUserProperties","clearEventProperties","identify","removeEventProperty","setEventProperties","track","unsetEventProperty"],c=0;c<p.length;c++)heap[p[c]]=o(p[c])};
heap.load("2213510609");
</script>
</body>
</html>

12
config/env/all.js vendored
View File

@ -14,11 +14,6 @@ module.exports = {
pass: ''
}
},
aws: {
'accessKeyId': process.env.AWS_ACCESS_ID,
'secretAccessKey': process.env.AWS_SECRET_KEY,
'region': process.env.AWS_REGION
},
port: process.env.PORT || 3000,
socketPort: process.env.SOCKET_PORT || 20523,
@ -32,11 +27,6 @@ module.exports = {
baseUrl: '',
tempUserCollection: 'temporary_users',
mailosaur: {
key: process.env.MAILOSAUR_KEY || '',
mailbox_id: process.env.MAILOSAUR_MAILBOX || ''
},
subdomainsDisabled: (process.env.SUBDOMAINS_DISABLED === 'TRUE'),
//Sentry DSN Client Key
@ -44,7 +34,7 @@ module.exports = {
// The secret should be set to a non-guessable string that
// is used to compute a session hash
sessionSecret: 'MEAN',
sessionSecret: process.env.SESSION_SECRET || 'CHANGE_ME_PLEASE',
// The name of the MongoDB collection to store sessions in
sessionCollection: 'sessions',
// The session cookie settings

View File

@ -27,8 +27,8 @@ var fs = require('fs-extra'),
var mongoose = require('mongoose');
var cacheOpts = {
max:10000,
maxAge:1000*60*2
max:100000,
maxAge:1000*60
};
require('mongoose-cache').install(mongoose, cacheOpts);
@ -184,8 +184,6 @@ module.exports = function(db) {
level: 9
}));
// Showing stack errors
app.set('showStackError', true);
// Set swig as the template engine
app.engine('server.view.html', consolidate[config.templateEngine]);
@ -203,6 +201,7 @@ module.exports = function(db) {
app.set('view cache', false);
} else if (process.env.NODE_ENV === 'production') {
app.locals.cache = 'memory';
app.set('view cache', true);
}
// Request body parsing middleware should be above methodOverride
@ -296,10 +295,16 @@ module.exports = function(db) {
// Log it
client.captureError(err);
// Error page
res.status(500).render('500', {
error: err.stack
});
/*if(process.env.NODE_ENV === 'production'){
res.status(500).render('500', {
error: 'Internal Server Error'
});
} else {*/
// Error page
res.status(500).render('500', {
error: err.stack
});
//}
});
// Assume 404 since no middleware responded

View File

@ -120,10 +120,10 @@ module.exports = function(grunt) {
productionForms: {
options: {
mangled: true,
beautify: true
compress: true
},
files: {
'public/dist/vendor_forms_uglified.js': bowerArray
'public/dist/vendor.min.js': bowerArray
}
}
},
@ -367,7 +367,7 @@ module.exports = function(grunt) {
grunt.registerTask('lint:tests', ['jshint:allTests']);
// Build task(s).
grunt.registerTask('build', ['lint', 'loadConfig', 'cssmin', 'ngAnnotate', 'uglify', 'closure-compiler', 'html2js:main', 'html2js:forms']);
grunt.registerTask('build', ['lint', 'loadConfig', 'cssmin', 'ngAnnotate', 'uglify', 'html2js:main', 'html2js:forms']);
//Setup task(s).
grunt.registerTask('setup', ['execute']);

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -335,12 +335,30 @@ 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.visible_form_fields;
delete form.analytics;
delete form.design;
delete form.submissions;
delete form.submitted;
for(var i=0; i < $scope.myform.form_fields.length; i++){
if($scope.myform.form_fields[i].fieldType === 'dropdown' && !$scope.myform.form_fields[i].deletePreserved){
$scope.myform.form_fields[i].fieldValue = $scope.myform.form_fields[i].fieldValue.option_value;
}
//Get rid of unnessecary attributes for each form field
delete form.form_fields[i].submissionId;
delete form.form_fields[i].disabled;
delete form.form_fields[i].ratingOptions;
delete form.form_fields[i].fieldOptions;
delete form.form_fields[i].logicJump;
delete form.form_fields[i].description;
delete form.form_fields[i].validFieldTypes;
delete form.form_fields[i].fieldType;
}
setTimeout(function () {
@ -348,7 +366,7 @@ angular.module('view-form').directive('submitFormDirective', ['$http', 'TimeCoun
.success(function (data, status) {
$scope.myform.submitted = true;
$scope.loading = false;
SendVisitorData.send($scope.myform, getActiveField(), _timeElapsed);
SendVisitorData.send(form, getActiveField(), _timeElapsed);
})
.error(function (error) {
$scope.loading = false;

View File

@ -5,12 +5,12 @@
<div ng-show="!myform.submitted && myform.startPage.showStart" class="form-submitted" style="padding-top: 35vh;">
<div class="row">
<div class="col-xs-12 text-center" style="overflow-wrap: break-word;">
<h1 style="font-weight: 400; nont-size: 25px;">
<h1 style="font-weight: 400; nont-size: 25px;" ng-style="{'color': form.design.colors.questionColor}">
{{myform.startPage.introTitle}}
</h1>
</div>
<div class="col-xs-10 col-xs-offset-1 text-center" style="overflow-wrap: break-word;">
<p style="color: grey; font-weight: 100; font-size: 16px;">
<p style="font-weight: 100; font-size: 16px;" ng-style="{'color': form.design.colors.questionColor}">
{{myform.startPage.introParagraph}}
</p>
</div>
@ -102,7 +102,7 @@
<!-- Default End Page View -->
<div ng-if="myform.submitted && !loading && !myform.endPage.showEnd" class="form-submitted" ng-style="{'color':myform.design.colors.buttonTextColor}" style="padding-top: 5vh;">
<div class="field row text-center">
<div class="field row text-center" ng-style="{'color': myform.design.colors.questionColor}">
<div class="col-xs-12 col-sm-12 col-md-6 col-md-offset-3 text-center">{{ 'FORM_SUCCESS' | translate }}</div>
</div>
<div class="row form-actions">
@ -118,12 +118,12 @@
<div ng-if="myform.submitted && !loading && myform.endPage.showEnd" class="form-submitted" ng-style="{'color':myform.design.colors.buttonTextColor}" style="padding-top: 5vh;">
<div class="row">
<div class="col-xs-12 text-center" style="overflow-wrap: break-word;">
<h1 style="font-weight: 400; nont-size: 25px;">
<h1 style="font-weight: 400; font-size: 25px;" ng-style="{'color': myform.design.colors.questionColor}">
{{myform.endPage.title}}
</h1>
</div>
<div class="col-xs-10 col-xs-offset-1 text-center" style="overflow-wrap: break-word;">
<p style="color: grey; font-weight: 100; font-size: 16px;">
<p style="font-weight: 100; font-size: 16px;" ng-style="{'color': myform.design.colors.questionColor}">
{{myform.endPage.paragraph}}
</p>
</div>
@ -147,4 +147,4 @@
</button>
</p>
</div>
</div>
</div>

View File

@ -16,7 +16,7 @@ angular.module('forms').directive('editSubmissionsFormDirective', ['$rootScope',
rows: []
};
var submissions = $scope.myform.submissions || [];
var submissions = $scope.myform.submissions || [];
//Iterate through form's submissions
for(var i = 0; i < submissions.length; i++){
@ -181,7 +181,7 @@ angular.module('forms').directive('editSubmissionsFormDirective', ['$rootScope',
//Export selected submissions of Form
$scope.exportSubmissions = function(type){
angular.element('#table-submission-data').tableExport({type: type, escape:false});
angular.element('#table-submission-data').tableExport({type: type, escape:false, ignoreColumn: [0]});
};
}