fixed analytics service

This commit is contained in:
David Baldwynn 2016-11-09 11:04:47 -08:00
parent faa306302b
commit f464deb959
12 changed files with 209 additions and 287 deletions

View file

@ -151,7 +151,8 @@ exports.read = function(req, res) {
}
var newForm = req.form.toJSON({virtuals : true});
var newForm = req.form.toJSON();
console.log(newForm.analytics);
newForm.submissions = _submissions;
if (req.userId) {

View file

@ -270,17 +270,6 @@ FormSchema.plugin(mUtilities.timestamp, {
useVirtual: false
});
//Delete template PDF of current Form
FormSchema.pre('remove', function (next) {
if(this.pdf && process.env.NODE_ENV === 'development'){
//Delete template form
fs.unlink(this.pdf.path, function(err){
if (err) throw err;
console.log('successfully deleted', this.pdf.path);
});
}
});
var _original;
function getDeletedIndexes(needle, haystack){
@ -296,7 +285,6 @@ function getDeletedIndexes(needle, haystack){
return deletedIndexes;
}
//Move PDF to permanent location after new template is uploaded
FormSchema.pre('save', function (next) {
var that = this;
@ -316,120 +304,6 @@ FormSchema.pre('save', function (next) {
}, function(cb) {
return cb(null);
},
function(cb) {
if (that.pdf) {
async.series([
function (callback) {
if (that.isModified('pdf') && that.pdf.path) {
var new_filename = that.title.replace(/ /g, '') + '_template.pdf';
var newDestination = path.join(config.pdfUploadPath, that.admin.username.replace(/ /g, ''), that.title.replace(/ /g, '')),
stat = null;
try {
stat = fs.statSync(newDestination);
} catch (err) {
mkdirp.sync(newDestination);
}
if (stat && !stat.isDirectory()) {
return callback(new Error('Directory cannot be created because an inode of a different type exists at "' + config.pdfUploadPath + '"'), null);
}
var old_path = that.pdf.path;
fs.move(old_path, path.join(newDestination, new_filename), {clobber: true}, function (err) {
if (err) {
console.error(err);
return callback(new Error(err.message), 'task1');
} else {
that.pdf.path = path.join(newDestination, new_filename);
that.pdf.name = new_filename;
return callback(null, 'task1');
}
});
} else {
return callback(null, 'task1');
}
},
function (callback) {
if (that.isGenerated) {
that.pdf.path = config.pdfUploadPath + that.admin.username.replace(/ /g, '') + '/' + that.title.replace(/ /g, '') + '/' + that.title.replace(/ /g, '') + '_template.pdf';
that.pdf.name = that.title.replace(/ /g, '') + '_template.pdf';
var _typeConvMap = {
'Multiline': 'textarea',
'Text': 'textfield',
'Button': 'checkbox',
'Choice': 'radio',
'Password': 'password',
'FileSelect': 'filefield',
'Radio': 'radio'
};
pdfFiller.generateFieldJson(that.pdf.path, '', function (err, _form_fields) {
//console.log(that.pdf.path);
if (err) {
return callback(new Error(err.message), null);
} else if (!_form_fields.length || _form_fields === undefined || _form_fields === null) {
return callback(new Error('Generated formfields is empty'), null);
}
console.log('autogenerating form');
//Map PDF field names to FormField field names
for (var i = 0; i < _form_fields.length; i++) {
var _field = _form_fields[i];
//Convert types from FDF to 'FormField' types
if (_typeConvMap[_field.fieldType + '']) {
_field.fieldType = _typeConvMap[_field.fieldType + ''];
}
var new_field = {};
new_field.title = _field.fieldType + ' ' + Math.abs(mt());
new_field.fieldValue = '';
new_field.disabled = false;
new_field.fieldType = _field.fieldType;
new_field.deletePreserved = false;
new_field.required = false;
_form_fields[i] = new_field;
}
that.form_fields = _form_fields;
that.isGenerated = false;
return callback(null, 'task2');
});
} else {
return callback(null, 'task2');
}
}
], function (err, results) {
if (err) {
return cb(new Error({
message: err.message
}));
} else {
//console.log('ending form save1');
return cb();
}
});
}
else if (_original) {
if (_original.hasOwnProperty('pdf')) {
fs.remove(_original.pdf.path, function (err) {
if (err) return cb(err);
console.log('file at ' + _original.pdf.path + ' successfully deleted');
return cb();
});
}
else return cb();
}
else return cb();
},
function(cb) {
var hasIds = true;
for(var i=0; i<that.form_fields.length; i++){

View file

@ -31,6 +31,7 @@ module.exports = function (io, socket) {
deviceType: data.deviceType
};
form.analytics.visitors.push(newVisitor);
form.save(function (err) {
@ -39,6 +40,7 @@ module.exports = function (io, socket) {
throw new Error(errorHandler.getErrorMessage(err));
}
console.log('\n\nVisitor data successfully added!');
console.log(newVisitor);
delete visitorsData[socket.id];
@ -56,7 +58,7 @@ module.exports = function (io, socket) {
socket.on('form-visitor-data', function(data) {
visitorsData[socket.id] = data;
if (data.isSubmitted) {
saveVisitorData(data, function () {
console.log('\n\n user submitted form');

View file

@ -41,7 +41,8 @@
"deep-diff": "^0.3.4",
"mathjs": "^3.4.1",
"jsep": "^0.3.1",
"ngclipboard": "^1.1.1"
"ngclipboard": "^1.1.1",
"mobile-detect": "^1.3.3"
},
"resolutions": {
"angular-bootstrap": "^0.14.0",

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

@ -13,13 +13,36 @@
// Create a controller method for sending visitor data
function send(form, lastActiveIndex, timeElapsed) {
var lang = window.navigator.userLanguage || window.navigator.language;
lang = lang.slice(0,2);
var userAgentString = navigator.userAgent;
var md = new MobileDetect(userAgentString);
var deviceType = 'other';
if (md.tablet()){
deviceType = 'tablet';
} else if (md.mobile()) {
deviceType = 'mobile';
} else if (window.screenX != 0) {
deviceType = 'desktop';
}
$.ajaxSetup( { "async": false } );
var result = $.getJSON('myUrl');
var geoData = $.getJSON('//freegeoip.net/json/?callback=?');
$.ajaxSetup( { "async": true } );
// Create a new message object
var visitorData = {
referrer: document.referrer,
isSubmitted: form.submitted,
formId: form._id,
lastActiveField: form.form_fields[lastActiveIndex]._id,
timeElapsed: timeElapsed
timeElapsed: timeElapsed,
language: lang,
deviceType: deviceType,
ipAddr: geoData.ip
};
Socket.emit('form-visitor-data', visitorData);
}

View file

@ -7,7 +7,7 @@ angular.module('forms').directive('editSubmissionsFormDirective', ['$rootScope',
restrict: 'E',
scope: {
user:'=',
myform: '@'
myform: '='
},
controller: function($scope){
@ -23,8 +23,6 @@ angular.module('forms').directive('editSubmissionsFormDirective', ['$rootScope',
Forms.get({
formId: $stateParams.formId
}, function(form){
console.log('running init controller');
console.log(form);
$scope.myform = form;
var defaultFormFields = _.cloneDeep($scope.myform.form_fields);
@ -42,12 +40,69 @@ angular.module('forms').directive('editSubmissionsFormDirective', ['$rootScope',
$scope.table.rows = submissions;
/*
** Analytics Functions
*/
$scope.AverageTimeElapsed = (function(){
var totalTime = 0;
var numSubmissions = $scope.table.rows.length;
console.log("AverageTimeElapsed");
console.log($scope.table.rows);
for(var i=0; i<$scope.table.rows.length; i++){
totalTime += $scope.table.rows[i].timeElapsed;
}
return totalTime/numSubmissions;
})();
$scope.DeviceStatistics = (function(){
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($scope.myform.analytics && $scope.myform.analytics.visitors) {
var visitors = $scope.myform.analytics.visitors;
for (var i = 0; i < visitors.length; i++) {
var visitor = visitors[i];
var deviceType = visitor.deviceType;
stats[deviceType].visits++;
stats[deviceType].total_time = stats[deviceType].total_time + visitor.timeElapsed;
stats[deviceType].average_time = stats[deviceType].total_time / stats[deviceType].visits || 0;
if (visitor.isSubmitted) stats[deviceType].responses++;
stats[deviceType].completion = stats[deviceType].response / stats[deviceType].visits || 0;
}
}
return stats;
})();
});
};
initController();
var updateFields = $interval(initController, 500);
var updateFields = $interval(initController, 2000);
$scope.$on("$destroy", function() {
if (updateFields) {
@ -55,57 +110,6 @@ angular.module('forms').directive('editSubmissionsFormDirective', ['$rootScope',
}
});
/*
** Analytics Functions
*/
$scope.AverageTimeElapsed = (function(){
var totalTime = 0;
var numSubmissions = $scope.table.rows.length;
for(var i=0; i<$scope.table.rows.length; i++){
totalTime += $scope.table.rows[i].timeElapsed;
}
return totalTime/numSubmissions;
})();
$scope.DeviceStatistics = (function(){
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($scope.myform.analytics && $scope.myform.analytics.visitors) {
for (var i = 0; i < visitors.length; i++) {
var visitor = visitors[i];
var deviceType = visitor.deviceType;
stats[deviceType].visits++;
stats[deviceType].total_time = +visitor.timeElapsed;
stats[deviceType].average_time = stats[deviceType].total_time / stats[deviceType].visits || 0;
if (visitor.isSubmitted) stats[deviceType].responses++;
stats[deviceType].completion = stats[deviceType].response / stats[deviceType].visits || 0;
}
}
return stats;
})();
/*
** Table Functions
*/

View file

@ -31,7 +31,7 @@
</div>
<div class="col-xs-3">
{{AverageTimeElapsed | secondsToDateTime | date:'mm:ss'}}
{{ AverageTimeElapsed | secondsToDateTime | date:'mm:ss'}}
</div>
</div>
<div class="col-xs-12 detailed-title">

View file

@ -9,16 +9,6 @@ angular.module('forms').factory('Forms', ['$resource', 'FORM_URL',
'query' : {
method: 'GET',
isArray: true
//DAVID: TODO: Do we really need to get visible_form_fields for a Query?
// transformResponse: function(data, header) {
// var forms = angular.fromJson(data);
// angular.forEach(forms, function(form, idx) {
// form.visible_form_fields = _.filter(form.form_fields, function(field){
// return (field.deletePreserved === false);
// });
// });
// return forms;
// }
},
'get' : {
method: 'GET',