diff --git a/app/controllers/forms.server.controller.js b/app/controllers/forms.server.controller.js index f1b1c750..d800f827 100644 --- a/app/controllers/forms.server.controller.js +++ b/app/controllers/forms.server.controller.js @@ -19,12 +19,12 @@ var mongoose = require('mongoose'), */ exports.uploadPDF = function(req, res, next) { - console.log('inside uploadPDF'); + //console.log('inside uploadPDF'); // console.log('\n\nProperty Descriptor\n-----------'); // console.log(Object.getOwnPropertyDescriptor(req.files.file, 'path')); - console.log(req.file); + //console.log(req.file); if(req.file){ var pdfFile = req.file; @@ -159,9 +159,20 @@ exports.deleteSubmissions = function(req, res) { res.status(400).send({ message: errorHandler.getErrorMessage(err) }); + return; } - res.status(200).send('Form submissions successfully deleted'); + form.analytics.visitors = []; + form.save(function(err){ + if(err){ + res.status(400).send({ + message: errorHandler.getErrorMessage(err) + }); + return; + } + res.status(200).send('Form submissions successfully deleted'); + + }); }); }; @@ -171,8 +182,6 @@ exports.deleteSubmissions = function(req, res) { exports.createSubmission = function(req, res) { var form = req.form; - // console.log('in createSubmission()'); - // console.log(req.body); var submission = new FormSubmission({ admin: req.form.admin._id, @@ -212,7 +221,7 @@ exports.createSubmission = function(req, res) { submission.save(function(err, submission){ if(err){ console.log(err.message); - res.status(400).send({ + res.status(500).send({ message: errorHandler.getErrorMessage(err) }); } @@ -280,8 +289,9 @@ exports.create = function(req, res) { exports.read = function(req, res) { var validUpdateTypes= Form.schema.path('plugins.oscarhost.settings.updateType').enumValues; - var newForm = JSON.parse(JSON.stringify(req.form)); + var newForm = req.form.toJSON({virtuals : true}); newForm.plugins.oscarhost.settings.validUpdateTypes = validUpdateTypes; + res.json(newForm); }; @@ -376,11 +386,12 @@ exports.formByID = function(req, res, next, id) { } else { //Remove sensitive information from User object - form.admin.password = undefined; - form.admin.salt = undefined; - form.provider = undefined; + var _form = form; + _form.admin.password = undefined; + _form.admin.salt = undefined; + _form.provider = undefined; - req.form = form; + req.form = _form; return next(); } }); diff --git a/app/models/form.server.model.js b/app/models/form.server.model.js index e32f2966..0be5d656 100644 --- a/app/models/form.server.model.js +++ b/app/models/form.server.model.js @@ -46,6 +46,21 @@ var ButtonSchema = new Schema({ } }); +var VisitorDataSchema = new Schema({ + referrer: { + type: String + }, + lastActiveField: { + type: Schema.Types.ObjectId + }, + timeElapsed: { + type: Number + }, + isSubmitted: { + type: Boolean + } +}); + /** * Form Schema */ @@ -66,6 +81,13 @@ var FormSchema = new Schema({ default: '' }, + analytics:{ + gaCode: { + type: String + }, + visitors: [VisitorDataSchema] + }, + form_fields: [FieldSchema], submissions: [{ type: Schema.Types.ObjectId, @@ -193,16 +215,91 @@ var FormSchema = new Schema({ }, auth: { user: { - type: String, + type: String }, pass: { - type: String, + type: String } } } } }); +/* +** In-Form Analytics Virtual Attributes + */ +FormSchema.virtual('analytics.views').get(function () { + return this.analytics.visitors.length; +}); + +FormSchema.virtual('analytics.submissions').get(function () { + return this.submissions.length; +}); + +FormSchema.virtual('analytics.conversionRate').get(function () { + return this.submissions.length/this.analytics.visitors.length*100; +}); + +FormSchema.virtual('analytics.fields').get(function () { + var fieldDropoffs = []; + var visitors = this.analytics.visitors; + var that = this; + + for(var i=0; i i){ + return sum + 1; + } + return sum; + }, 0); + }else { + continueViews = _.reduce(visitors, function(sum, visitorObj){ + if(visitorObj.lastActiveField+'' === field._id+'' && visitorObj.isSubmitted){ + return sum + 1; + } + return sum; + }, 0); + + } + + var totalViews = dropoffViews+continueViews; + var continueRate = continueViews/totalViews*100; + var dropoffRate = dropoffViews/totalViews*100; + + fieldDropoffs[i] = { + dropoffViews: dropoffViews, + continueViews: continueViews, + totalViews: totalViews, + continueRate: continueRate, + dropoffRate: dropoffRate, + field: field + }; + + } + } + + return fieldDropoffs; +}); + FormSchema.plugin(mUtilities.timestamp, { createdPath: 'created', modifiedPath: 'lastModified', diff --git a/app/models/form_field.server.model.js b/app/models/form_field.server.model.js index c7f669bd..1a0452bf 100644 --- a/app/models/form_field.server.model.js +++ b/app/models/form_field.server.model.js @@ -193,15 +193,11 @@ FormFieldSchema.pre('validate', function(next) { //Submission fieldValue correction FormFieldSchema.pre('save', function(next) { - console.log('pre save'); - console.log(this.isSubmission); - console.log(this._id); - console.log(this.submissionId); - console.log(this.fieldType); - - if(this.isSubmission && this.fieldType === 'dropdown'){ + if(this.fieldType === 'dropdown' && this.isSubmission){ + //console.log(this); this.fieldValue = this.fieldValue.option_value; + //console.log(this.fieldValue); } return next(); diff --git a/app/models/form_submission.server.model.js b/app/models/form_submission.server.model.js index dc1403cc..a02c9568 100644 --- a/app/models/form_submission.server.model.js +++ b/app/models/form_submission.server.model.js @@ -51,6 +51,7 @@ function formFieldsSetter(form_fields){ form_fields[i].submissionId = form_fields[i]._id; form_fields[i]._id = new mongoose.mongo.ObjectID(); } + //console.log(form_fields) return form_fields; } @@ -127,7 +128,6 @@ var FormSubmissionSchema = new Schema({ default: false } } - }); FormSubmissionSchema.path('form_fields').set(formFieldsSetter); @@ -267,7 +267,6 @@ FormSubmissionSchema.pre('save', function (next) { self = this, _form = this.form; - if(this.pdf && this.pdf.path){ dest_filename = self.title.replace(/ /g,'')+'_submission_'+Date.now()+'.pdf'; var __path = this.pdf.path.split('/').slice(0,this.pdf.path.split('/').length-1).join('/'); diff --git a/app/sockets/analytics_service.js b/app/sockets/analytics_service.js new file mode 100644 index 00000000..a231bb87 --- /dev/null +++ b/app/sockets/analytics_service.js @@ -0,0 +1,80 @@ +'use strict'; + + +/** + * Module dependencies. + */ +var mongoose = require('mongoose'), + config = require('../../config/config'), + errorHandler = require('../controllers/errors.server.controller'), + Form = mongoose.model('Form'); + +// Create the chat configuration +module.exports = function (io, socket) { + var visitorsData = {}; + + var saveVisitorData = function (data, cb){ + + Form.findById(data.formId, function(err, form) { + if (err) { + console.log(err); + throw new Error(errorHandler.getErrorMessage(err)); + } + + var newVisitor = { + referrer: data.referrer, + lastActiveField: data.lastActiveField, + timeElapsed: data.timeElapsed, + isSubmitted: data.isSubmitted + }; + + form.analytics.visitors.push(newVisitor); + + form.save(function (err) { + if (err) { + console.log(err); + throw new Error(errorHandler.getErrorMessage(err)); + } + console.log('\n\nVisitor data successfully added!'); + + delete visitorsData[socket.id]; + + if(cb) cb(); + }); + }); + + socket.disconnect(0); + }; + + io.on('connection', function(socket) { + + + // a user has visited our page - add them to the visitorsData object + socket.on('form-visitor-data', function(data) { + + console.log('\n\nuser has visited our page'); + + visitorsData[socket.id] = data; + + console.log(data); + + if (data.isSubmitted) { + saveVisitorData(data, function () { + console.log('\n\n user submitted form'); + + socket.disconnect(0); + }); + } + }); + + socket.on('disconnect', function() { + var data = visitorsData[socket.id]; + + if(data){ + if(!data.isSubmitted) { + saveVisitorData(data); + } + } + }); + }); +}; diff --git a/app/views/layout.server.view.html b/app/views/layout.server.view.html index f90b12b5..0a4a367c 100755 --- a/app/views/layout.server.view.html +++ b/app/views/layout.server.view.html @@ -80,8 +80,12 @@ + + + {% for bowerJSFile in bowerJSFiles %} @@ -103,7 +107,7 @@ + +
+
+
Google Analytics Tracking Code
+
+ +
+ +
+
Language
diff --git a/public/modules/forms/views/directiveViews/form/edit-submissions-form.client.view.html b/public/modules/forms/views/directiveViews/form/edit-submissions-form.client.view.html index 1df5d80c..68b35c52 100644 --- a/public/modules/forms/views/directiveViews/form/edit-submissions-form.client.view.html +++ b/public/modules/forms/views/directiveViews/form/edit-submissions-form.client.view.html @@ -1,5 +1,47 @@
+
+
+ Total Views: {{myform.analytics.views}} +
+
+ Submissions: {{myform.analytics.submissions}} +
+ +
+ Conversion Rate: {{myform.analytics.conversionRate}}% +
+
+
+
+
+ +
+ Field Title +
+
+ Field Views +
+ +
+ User dropoff rate at this field +
+
+
+ +
+ {{fieldStats.field.title}} +
+
+ {{fieldStats.totalViews}} +
+ +
+ {{fieldStats.dropoffRate}}% +
+
+
+