fixed analytics service
This commit is contained in:
parent
faa306302b
commit
f464deb959
|
@ -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) {
|
||||
|
|
|
@ -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++){
|
||||
|
|
|
@ -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');
|
||||
|
|
|
@ -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",
|
||||
|
|
170
public/dist/application.js
vendored
170
public/dist/application.js
vendored
File diff suppressed because one or more lines are too long
6
public/dist/application.min.js
vendored
6
public/dist/application.min.js
vendored
File diff suppressed because one or more lines are too long
27
public/dist/form-application.js
vendored
27
public/dist/form-application.js
vendored
File diff suppressed because one or more lines are too long
6
public/dist/form-application.min.js
vendored
6
public/dist/form-application.min.js
vendored
File diff suppressed because one or more lines are too long
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
*/
|
||||
|
|
|
@ -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">
|
||||
|
|
|
@ -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',
|
||||
|
|
Loading…
Reference in a new issue