'use strict'; /** * Module dependencies. */ var mongoose = require('mongoose'), Schema = mongoose.Schema, _ = require('lodash'), timeStampPlugin = require('../libs/timestamp.server.plugin'), async = require('async'), Random = require('random-js'), mt = Random.engines.mt19937(); mt.autoSeed(); //Mongoose Models var FieldSchema = require('./form_field.server.model.js'); var FormSubmissionSchema = require('./form_submission.server.model.js'), FormSubmission = mongoose.model('FormSubmission', FormSubmissionSchema); var ButtonSchema = new Schema({ url: { type: String, match: [/((([A-Za-z]{3,9}:(?:\/\/)?)(?:[-;:&=\+\$,\w]+@)?[A-Za-z0-9.-]+|(?:www.|[-;:&=\+\$,\w]+@)[A-Za-z0-9.-]+)((?:\/[\+~%\/.\w-_]*)?\??(?:[-\+=&;%@.\w_]*)#?(?:[\w]*))?)/], }, action: String, text: String, bgColor: { type: String, match: [/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/], default: '#5bc0de' }, color: { type: String, match: [/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/], default: '#ffffff' } }); var VisitorDataSchema = new Schema({ socketId: { type: String }, referrer: { type: String }, lastActiveField: { type: Schema.Types.ObjectId }, timeElapsed: { type: Number }, isSubmitted: { type: Boolean }, language: { type: String }, ipAddr: { type: String, default: '' }, deviceType: { type: String, enum: ['desktop', 'phone', 'tablet', 'other'], default: 'other' }, userAgent: { type: String } }); var formSchemaOptions = { toJSON: { virtuals: true } }; /** * Form Schema */ var FormSchema = new Schema({ title: { type: String, trim: true, required: 'Form Title cannot be blank' }, language: { type: String, enum: ['en', 'fr', 'es', 'it', 'de'], default: 'en', required: 'Form must have a language' }, analytics:{ gaCode: { type: String }, visitors: [VisitorDataSchema] }, form_fields: [FieldSchema], submissions: [{ type: Schema.Types.ObjectId, ref: 'FormSubmission' }], admin: { type: Schema.Types.ObjectId, ref: 'User', required: 'Form must have an Admin' }, startPage: { showStart:{ type: Boolean, default: false }, introTitle:{ type: String, default: 'Welcome to Form' }, introParagraph:{ type: String }, introButtonText:{ type: String, default: 'Start' }, buttons:[ButtonSchema] }, endPage: { showEnd:{ type: Boolean, default: false }, title:{ type: String, default: 'Thank you for filling out the form' }, paragraph:{ type: String }, buttonText:{ type: String, default: 'Go back to Form' }, buttons:[ButtonSchema] }, hideFooter: { type: Boolean, default: false }, isLive: { type: Boolean, default: true }, design: { colors:{ backgroundColor: { type: String, match: [/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/], default: '#fff' }, questionColor: { type: String, match: [/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/], default: '#333' }, answerColor: { type: String, match: [/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/], default: '#333' }, buttonColor: { type: String, match: [/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/], default: '#fff' }, buttonTextColor: { type: String, match: [/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/], default: '#333' } }, font: String } }, formSchemaOptions); /* ** In-Form Analytics Virtual Attributes */ FormSchema.virtual('analytics.views').get(function () { if(this.analytics && this.analytics.visitors && this.analytics.visitors.length > 0){ return this.analytics.visitors.length; } else { return 0; } }); function getDeviceStatistics(visitors){ var newStatItem = function(){ return { visits: 0, responses: 0, completion: 0, average_time: 0, total_time: 0 }; }; var stats = { desktop: newStatItem(), tablet: newStatItem(), phone: newStatItem(), other: newStatItem() }; if(visitors) { for (var i = 0; i < visitors.length; i++) { var visitor = visitors[i]; var deviceType = visitor.deviceType; stats[deviceType].visits++; if (visitor.isSubmitted) { stats[deviceType].total_time = stats[deviceType].total_time + visitor.timeElapsed; stats[deviceType].responses++; } if(stats[deviceType].visits) { stats[deviceType].completion = 100*(stats[deviceType].responses / stats[deviceType].visits).toFixed(2); } if(stats[deviceType].responses){ stats[deviceType].average_time = (stats[deviceType].total_time / stats[deviceType].responses).toFixed(0); } } } return stats; } function getFieldAnalytics(form){ var fieldDropoffs = []; var visitors = form.analytics.visitors; var that = form; if(!form.form_fields || form.form_fields.length === 0) { return null; } for(var i=0; i