fixed analytics geolocation

This commit is contained in:
David Baldwynn 2017-03-06 13:45:11 -08:00
parent 00054c9440
commit 8a12f4d65c
No known key found for this signature in database
GPG key ID: 15D1C13202224A9B
14 changed files with 194 additions and 322 deletions

View file

@ -54,26 +54,19 @@ exports.createSubmission = function(req, res) {
timeElapsed = req.body.timeElapsed; timeElapsed = req.body.timeElapsed;
} }
var submission = new FormSubmission({ var submission = new FormSubmission({
admin: req.form.admin._id, admin: form.admin._id,
form: req.form._id, form: form._id,
title: req.form.title, title: form.title,
form_fields: req.body.form_fields, form_fields: req.body.form_fields,
timeElapsed: timeElapsed, timeElapsed: timeElapsed,
percentageComplete: req.body.percentageComplete percentageComplete: req.body.percentageComplete,
ipAddr: req.body.ipAddr,
geoLocation: req.body.geoLocation,
device: req.body.device
}); });
//Save submitter's IP Address
if(req.headers['x-forwarded-for'] || req.connection.remoteAddress){
var ip = req.headers['x-forwarded-for'] || req.connection.remoteAddress;
if(ip && process.env.NODE_ENV !== 'development') submission.ipAddr = ip;
}
if (req.device) {
submission.device = req.device;
}
submission.save(function(err, submission){ submission.save(function(err, submission){
if (err) { if (err) {
console.error(err.message); console.error(err.message);
return res.status(500).send({ return res.status(500).send({
@ -185,6 +178,7 @@ exports.readForRender = function(req, res) {
delete newForm.submissions; delete newForm.submissions;
delete newForm.analytics; delete newForm.analytics;
delete newForm.isLive; delete newForm.isLive;
delete newForm.admin;
return res.json(newForm); return res.json(newForm);
}; };
@ -234,7 +228,6 @@ exports.update = function(req, res) {
*/ */
exports.delete = function(req, res) { exports.delete = function(req, res) {
var form = req.form; var form = req.form;
// console.log('deleting form');
Form.remove({_id: form._id}, function(err) { Form.remove({_id: form._id}, function(err) {
if (err) { if (err) {
res.status(400).send({ res.status(400).send({

View file

@ -234,8 +234,8 @@ FormSchema.virtual('analytics.fields').get(function () {
var totalViews = dropoffViews+continueViews; var totalViews = dropoffViews+continueViews;
var responses = continueViews; var responses = continueViews;
var continueRate = continueViews/totalViews*100; var continueRate = (continueViews/totalViews*100).toFixed(0);
var dropoffRate = dropoffViews/totalViews*100; var dropoffRate = (dropoffViews/totalViews*100).toFixed(0);
fieldDropoffs[i] = { fieldDropoffs[i] = {
dropoffViews: dropoffViews, dropoffViews: dropoffViews,

View file

@ -5,7 +5,6 @@
*/ */
var mongoose = require('mongoose'), var mongoose = require('mongoose'),
Schema = mongoose.Schema, Schema = mongoose.Schema,
freegeoip = require('node-freegeoip'),
_ = require('lodash'), _ = require('lodash'),
config = require('../../config/config'), config = require('../../config/config'),
path = require('path'), path = require('path'),
@ -53,9 +52,6 @@ var FormSubmissionSchema = new Schema({
Country: { Country: {
type: String type: String
}, },
Region: {
type: String
},
City: { City: {
type: String type: String
} }
@ -69,29 +65,11 @@ var FormSubmissionSchema = new Schema({
} }
}, },
pdfFilePath: {
type: Schema.Types.Mixed
},
pdf: {
type: Schema.Types.Mixed
},
fdfData: {
type: Schema.Types.Mixed
},
timeElapsed: { timeElapsed: {
type: Number type: Number
}, },
percentageComplete: { percentageComplete: {
type: Number type: Number
},
hasPlugins: {
oscarhost: {
type: Boolean,
default: false
}
} }
}); });
@ -112,19 +90,4 @@ FormSubmissionSchema.plugin(mUtilities.timestamp, {
useVirtual: false useVirtual: false
}); });
//Check for IP Address of submitting person
FormSubmissionSchema.pre('save', function (next) {
var self = this;
if (this.ipAddr) {
if (this.isModified('ipAddr') || !this.geoLocation) {
freegeoip.getLocation(this.ipAddr, function (err, location) {
if (err) return next(err);
self.geoLocation = location;
return next();
});
}
}
return next();
});
module.exports = FormSubmissionSchema; module.exports = FormSubmissionSchema;

10
config/env/test.js vendored
View file

@ -56,15 +56,5 @@ module.exports = {
pass: process.env.MAILER_PASSWORD || '' pass: process.env.MAILER_PASSWORD || ''
} }
} }
},
oscarhost: {
baseUrl: process.env.OSCARHOST_BASEURL || 'OSCARHOST_BASEURL',
settings: {
updateType: process.env.OSCARHOST_UPDATETYPE || 'OSCARHOST_UPDATETYPE',
},
auth:{
user: process.env.OSCARHOST_USER || 'process.env.OSCARHOST_USER',
pass: process.env.OSCARHOST_PASS || 'process.env.OSCARHOST_PASS',
}
} }
}; };

View file

@ -74,7 +74,6 @@
"mongoose-utilities": "~0.1.1", "mongoose-utilities": "~0.1.1",
"morgan": "~1.6.1", "morgan": "~1.6.1",
"multer": "~1.1.0", "multer": "~1.1.0",
"node-freegeoip": "0.0.1",
"nodemailer": "~1.10.0", "nodemailer": "~1.10.0",
"nodemailer-sendgrid-transport": "^0.2.0", "nodemailer-sendgrid-transport": "^0.2.0",
"nodemailer-sparkpost-transport": "^1.0.0", "nodemailer-sparkpost-transport": "^1.0.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

@ -260,8 +260,6 @@ angular.module('view-form').directive('submitFormDirective', ['$http', 'TimeCoun
}); });
} }
console.log("time elapsed: ");
console.log(TimeCounter.getTimeElapsed());
SendVisitorData.send($scope.myform, getActiveField(), TimeCounter.getTimeElapsed()); SendVisitorData.send($scope.myform, getActiveField(), TimeCounter.getTimeElapsed());
}; };
@ -310,6 +308,39 @@ angular.module('view-form').directive('submitFormDirective', ['$http', 'TimeCoun
document.querySelectorAll('.ng-invalid.focusOn')[0].focus(); document.querySelectorAll('.ng-invalid.focusOn')[0].focus();
}; };
var getDeviceData = function(){
var md = new MobileDetect(window.navigator.userAgent);
var deviceType = 'other';
if (md.tablet()){
deviceType = 'tablet';
} else if (md.mobile()) {
deviceType = 'mobile';
} else if (!md.is('bot')) {
deviceType = 'desktop';
}
return {
type: deviceType,
name: window.navigator.platform
}
};
var getIpAndGeo = function(){
//Get Ip Address and GeoLocation Data
$.ajaxSetup( { "async": false } );
var geoData = $.getJSON('//freegeoip.net/json/').responseJSON;
$.ajaxSetup( { "async": true } );
return {
ipAddr: geoData.ip,
geoLocation: {
City: geoData.city,
Country: geoData.country_name
}
}
};
$rootScope.submitForm = $scope.submitForm = function() { $rootScope.submitForm = $scope.submitForm = function() {
var _timeElapsed = TimeCounter.stopClock(); var _timeElapsed = TimeCounter.stopClock();
@ -317,8 +348,15 @@ angular.module('view-form').directive('submitFormDirective', ['$http', 'TimeCoun
var form = _.cloneDeep($scope.myform); var form = _.cloneDeep($scope.myform);
form.timeElapsed = _timeElapsed; var deviceData = getDeviceData();
form.device = deviceData;
var geoData = getIpAndGeo();
form.ipAddr = geoData.ipAddr;
form.geoLocation = geoData.geoLocation;
console.log(geoData);
form.timeElapsed = _timeElapsed;
form.percentageComplete = $filter('formValidity')($scope.myform) / $scope.myform.visible_form_fields.length * 100; form.percentageComplete = $filter('formValidity')($scope.myform) / $scope.myform.visible_form_fields.length * 100;
delete form.visible_form_fields; delete form.visible_form_fields;
@ -331,7 +369,6 @@ angular.module('view-form').directive('submitFormDirective', ['$http', 'TimeCoun
setTimeout(function () { setTimeout(function () {
$scope.submitPromise = $http.post('/forms/' + $scope.myform._id, form) $scope.submitPromise = $http.post('/forms/' + $scope.myform._id, form)
.success(function (data, status, headers) { .success(function (data, status, headers) {
console.log($scope.myform.form_fields[0]);
$scope.myform.submitted = true; $scope.myform.submitted = true;
$scope.loading = false; $scope.loading = false;
SendVisitorData.send($scope.myform, getActiveField(), _timeElapsed); SendVisitorData.send($scope.myform, getActiveField(), _timeElapsed);

View file

@ -41,7 +41,11 @@
timeElapsed: timeElapsed, timeElapsed: timeElapsed,
language: lang, language: lang,
deviceType: deviceType, deviceType: deviceType,
ipAddr: geoData.ip ipAddr: geoData.ip,
geoLocation: {
city: geoData.city,
country: geoData.country_name
}
}; };
Socket.emit('form-visitor-data', visitorData); Socket.emit('form-visitor-data', visitorData);
} }

View file

@ -12,82 +12,12 @@ angular.module('forms').directive('configureFormDirective', ['$rootScope', '$htt
formFields:'@' formFields:'@'
}, },
controller: function($scope){ controller: function($scope){
console.log($scope.myform);
if( CurrentForm.getForm().plugins){
if(CurrentForm.getForm().plugins.oscarhost.baseUrl) $scope.oscarhostAPI = true;
}else{
$scope.oscarhostAPI = false;
}
$scope.log = ''; $scope.log = '';
$scope.pdfLoading = false;
$scope.languages = $rootScope.languages; $scope.languages = $rootScope.languages;
this._current_upload = null;
$scope.resetForm = $rootScope.resetForm; $scope.resetForm = $rootScope.resetForm;
$scope.update = $rootScope.update; $scope.update = $rootScope.update;
this._unbindedPdfFields = $scope.pdfFields;
//DAVID: TODO: finish this so we can create a Form.pdfFieldMap
// $scope.getUnbindedPdfFields = function(fieldType){
// this._unbindedPdfFields = $scope.pdfFields
// }
//PDF Functions
$scope.cancelUpload = function(){
this._current_upload.abort();
$scope.pdfLoading = false;
$scope.removePDF();
};
$scope.removePDF = function(){
$scope.myform.pdf = null;
$scope.myform.isGenerated = false;
$scope.myform.autofillPDFs = false;
console.log('form.pdf: '+$scope.myform.pdf+' REMOVED');
};
$scope.uploadPDF = function(file) {
if (file) {
console.log(file);
Upload.upload({
url: '/upload/pdf',
data: {
'user': $scope.user,
file: file
}
}).then(function (resp) {
var data = resp.data;
$scope.log = 'file ' + data.originalname + ' uploaded as ' + data.filename + '. JSON: ' + JSON.stringify(data) + '\n' + $scope.log;
$scope.myform.pdf = angular.fromJson(angular.toJson(data));
//console.log($scope.myform.pdf);
$scope.pdfLoading = false;
console.log($scope.log);
if (!$scope.$$phase && !$scope.$digest) {
$scope.$apply();
}
}, function(resp){
$scope.pdfLoading = false;
console.log('Error occured during upload.\n');
console.log(resp.status);
}, function (evt) {
var progressPercentage = parseInt(100.0 * evt.loaded / evt.total, 10);
$scope.log = 'progress: ' + progressPercentage + '% ' +
evt.config.data.file.name + '\n' + $scope.log;
console.log($scope.log);
$scope.pdfLoading = true;
});
}
};
} }
}; };
} }

View file

@ -39,7 +39,7 @@ angular.module('forms').directive('editSubmissionsFormDirective', ['$rootScope',
} }
$scope.table.rows = submissions; $scope.table.rows = submissions;
console.log(submissions);
/* /*
** Analytics Functions ** Analytics Functions
@ -55,7 +55,7 @@ angular.module('forms').directive('editSubmissionsFormDirective', ['$rootScope',
if(numSubmissions == 0) return 0; if(numSubmissions == 0) return 0;
return totalTime/numSubmissions; return (totalTime/numSubmissions).toFixed(0);
})(); })();
$scope.DeviceStatistics = (function(){ $scope.DeviceStatistics = (function(){
@ -86,12 +86,12 @@ angular.module('forms').directive('editSubmissionsFormDirective', ['$rootScope',
stats[deviceType].total_time = stats[deviceType].total_time + visitor.timeElapsed; stats[deviceType].total_time = stats[deviceType].total_time + visitor.timeElapsed;
stats[deviceType].average_time = stats[deviceType].total_time / stats[deviceType].visits; stats[deviceType].average_time = (stats[deviceType].total_time / stats[deviceType].visits).toFixed(0);
if(!stats[deviceType].average_time) stats[deviceType].average_time = 0; if(!stats[deviceType].average_time) stats[deviceType].average_time = 0;
if (visitor.isSubmitted) stats[deviceType].responses++; if (visitor.isSubmitted) stats[deviceType].responses++;
stats[deviceType].completion = stats[deviceType].responses / stats[deviceType].visits; stats[deviceType].completion = (stats[deviceType].responses / stats[deviceType].visits).toFixed(0);
if(!stats[deviceType].completion) stats[deviceType].completion = 0; if(!stats[deviceType].completion) stats[deviceType].completion = 0;
} }
console.log("stats"); console.log("stats");
@ -139,7 +139,7 @@ angular.module('forms').directive('editSubmissionsFormDirective', ['$rootScope',
/* /*
* Form Submission Methods * Form Submission Methods
*/ */
//Delete selected submissions of Form //Delete selected submissions of Form
$scope.deleteSelectedSubmissions = function(){ $scope.deleteSelectedSubmissions = function(){

View file

@ -134,7 +134,7 @@
{{ 'COMPLETION_RATE' | translate }} {{ 'COMPLETION_RATE' | translate }}
</div> </div>
<div class="row"> <div class="row">
{{DeviceStatistics.desktop.completion}} {{DeviceStatistics.desktop.completion}}%
</div> </div>
</div> </div>
@ -143,7 +143,7 @@
{{ 'COMPLETION_RATE' | translate }} {{ 'COMPLETION_RATE' | translate }}
</div> </div>
<div class="row"> <div class="row">
{{DeviceStatistics.tablet.completion}} {{DeviceStatistics.tablet.completion}}%
</div> </div>
</div> </div>
@ -152,7 +152,7 @@
{{ 'COMPLETION_RATE' | translate }} {{ 'COMPLETION_RATE' | translate }}
</div> </div>
<div class="row"> <div class="row">
{{DeviceStatistics.phone.completion}} {{DeviceStatistics.phone.completion}}%
</div> </div>
</div> </div>
@ -161,7 +161,7 @@
{{ 'COMPLETION_RATE' | translate }} {{ 'COMPLETION_RATE' | translate }}
</div> </div>
<div class="row"> <div class="row">
{{DeviceStatistics.other.completion}} {{DeviceStatistics.other.completion}}%
</div> </div>
</div> </div>
</div> </div>
@ -245,17 +245,17 @@
</button> </button>
</div> </div>
<div class="col-xs-2 col-xs-offset-4 text-right"> <div class="col-xs-2 col-xs-offset-4 text-right">
<button class="btn btn-default" ng-click="exportSubmissions('xml')"> <button class="btn btn-gray" ng-click="exportSubmissions('xml')">
<small>{{ 'EXPORT_TO_EXCEL' | translate }}</small> <small>{{ 'EXPORT_TO_EXCEL' | translate }}</small>
</button> </button>
</div> </div>
<div class="col-md-2 text-right"> <div class="col-md-2 text-right">
<button class="btn btn-default" ng-click="exportSubmissions('csv')"> <button class="btn btn-gray" ng-click="exportSubmissions('csv')">
<small>{{ 'EXPORT_TO_CSV' | translate }}</small> <small>{{ 'EXPORT_TO_CSV' | translate }}</small>
</button> </button>
</div> </div>
<div class="col-md-2 text-right"> <div class="col-md-2 text-right">
<button class="btn btn-default" ng-click="exportSubmissions('json')"> <button class="btn btn-gray" ng-click="exportSubmissions('json')">
<small>{{ 'EXPORT_TO_JSON' | translate }}</small> <small>{{ 'EXPORT_TO_JSON' | translate }}</small>
</button> </button>
</div> </div>
@ -290,9 +290,6 @@
<th> <th>
{{ 'DATE_SUBMITTED' | translate }} (UTC) {{ 'DATE_SUBMITTED' | translate }} (UTC)
</th> </th>
<th ng-if="myform.autofillPDFs">
{{ 'GENERATED_PDF' | translate }}
</th>
</tr> </tr>
</thead> </thead>
@ -318,7 +315,7 @@
{{row.device.name}}, {{row.device.type}} {{row.device.name}}, {{row.device.type}}
</td> </td>
<td> <td>
{{row.geoLocation.city}}, {{row.geoLocation.country_name}} {{row.geoLocation.City}}, {{row.geoLocation.Country}}
</td> </td>
<td> <td>
{{row.ipAddr}} {{row.ipAddr}}
@ -326,9 +323,6 @@
<td> <td>
{{row.created | date:'yyyy-MM-dd HH:mm:ss'}} {{row.created | date:'yyyy-MM-dd HH:mm:ss'}}
</td> </td>
<td ng-if="row.pdf">
<a href="{{row.pdfFilePath}}" download="{{row.pdf.name}}" target="_self">{{ 'GENERATED_PDF' | translate }}</a>
</td>
</tr> </tr>
</tbody> </tbody>
</table> </table>