got submission deletion working

This commit is contained in:
David Baldwynn 2015-07-27 11:11:43 -07:00
parent 79dfbbc8a7
commit 6983440113
50 changed files with 1213 additions and 1217 deletions

View file

@ -20,6 +20,10 @@ var mongoose = require('mongoose'),
exports.uploadPDF = function(req, res, next) {
console.log('inside uploadPDF');
// console.log(req.files.file);
// console.log('\n\nProperty Descriptor\n-----------');
// console.log(Object.getOwnPropertyDescriptor(req.files.file, 'path'));
if(req.files){
var pdfFile = req.files.file;
var _user = req.user;
@ -50,7 +54,7 @@ exports.uploadPDF = function(req, res, next) {
}
pdfFile.path = path.join(newDestination, pdfFile.name);
console.log(pdfFile.name + ' uploaded to ' + pdfFile.path);
res.status(200).send('pdf file successfully uploaded');
res.json(pdfFile);
});
} else {
@ -63,22 +67,46 @@ exports.uploadPDF = function(req, res, next) {
}
};
/**
* Delete a forms submissions
*/
exports.deleteSubmissions = function(req, res) {
console.log(req.body);
var submission_id_list = req.body.deleted_submissions,
form = req.form;
FormSubmission.remove({ form: req.form, admin: req.user, _id: {$in: submission_id_list} }, function(err){
if(err){
res.status(400).send({
message: errorHandler.getErrorMessage(err)
});
}
res.status(200).send('Form submissions successfully deleted');
});
};
/**
* Submit a form entry
*/
exports.createSubmission = function(req, res) {
var submission = new FormSubmission(),
var submission,
form = req.form,
fdfData,
fdfTemplate,
that = this;
submission = new FormSubmission({
admin: req.user,
form_fields: req.body.form_fields,
timeElapsed: req.body.timeElapsed
});
submission.form = form;
submission.admin = req.user;
submission.form_fields = req.body.form_fields;
submission.title = req.body.title;
submission.timeElapsed = req.body.timeElapsed;
submission.pdf = form.pdf;
submission.title = form.title;
// submission.ipAddr = req.headers['x-forwarded-for'] || req.connection.remoteAddress;
if(form.autofillPDFs){
@ -93,42 +121,23 @@ exports.createSubmission = function(req, res) {
});
}
}
fdfData = pdfFiller.fillFdfTemplate(fdfTemplate, submission.form_fields, null);
fdfData = pdfFiller.convFieldJson2FDF(submission.form_fields);
submission.fdfData = fdfData;
}else{
submission.fdfData = undefined;
}
async.series([
function(callback){
submission.save(function(err){
if (err) {
callback(err);
} else {
callback(null);
}
});
},
function(callback){
//Add submission to Form.submissionns
form.submissions.push(submission);
form.save(function(err){
if (err) {
callback(err);
} else {
callback(null);
}
});
},
], function(err, results) {
if(err){
res.status(400).send({
message: errorHandler.getErrorMessage(err)
});
}
// console.log(results);
// console.log(that.form_fields);
res.status(200).send('Form submission successfully saved');
});
submission.save(function(err){
if(err){
res.status(400).send({
message: errorHandler.getErrorMessage(err)
});
}
// console.log(results);
// console.log(that.form_fields);
res.status(200).send('Form submission successfully saved');
});
};
/**
@ -172,8 +181,8 @@ exports.create = function(req, res) {
var form = new Form(req.body.form);
form.admin = req.user;
console.log(form);
console.log(req.user);
// console.log(form);
// console.log(req.user);
form.save(function(err) {
if (err) {
@ -182,7 +191,7 @@ exports.create = function(req, res) {
message: errorHandler.getErrorMessage(err)
});
} else {
res.status(200).send('form created');
res.json(form);
}
});
};
@ -201,13 +210,16 @@ exports.read = function(req, res) {
exports.update = function(req, res) {
console.log('in form.update()');
console.log(req.body.form.form_fields);
// console.log(req.body.form.form_fields);
var form = req.form;
delete req.body.form.__v;
delete req.body.form._id;
delete req.body.form.created;
delete req.body.form.lastModified;
delete req.body.form.admin;
// console.log(form.admin);
//Unless we have 'admin' priviledges, updating form admin is disabled
if(req.user.roles.indexOf('admin') === -1) delete req.body.form.admin;
@ -216,7 +228,7 @@ exports.update = function(req, res) {
// console.log(req.body.form);
// form.form_fields = req.body.form.form_fields;
form.save(function(err) {
form.save(function(err, form) {
if (err) {
console.log(err);
res.status(400).send({
@ -224,7 +236,7 @@ exports.update = function(req, res) {
});
} else {
console.log('updated form');
res.status(200).send('updated form');
res.json(form);
}
});
};
@ -287,6 +299,11 @@ exports.formByID = function(req, res, next, id) {
});
}
else {
if(!form.username){
form.admin = req.user;
}
// console.log(creaform.admin);
//Remove sensitive information from User object
form.admin.password = null;
form.admin.created = null;

View file

@ -4,6 +4,7 @@
* Module dependencies.
*/
var _ = require('lodash'),
nev = require('email-verification'),
errorHandler = require('../errors.server.controller'),
mongoose = require('mongoose'),
passport = require('passport'),
@ -11,89 +12,36 @@ var _ = require('lodash'),
config = require('../../../config/config'),
nodemailer = require('nodemailer'),
crypto = require('crypto'),
nev = require('email-verification'),
User = mongoose.model('User');
var smtpTransport = nodemailer.createTransport(config.mailer.options);
// NEV configuration =====================
nev.configure({
persistentUserModel: User,
expirationTime: 600, // 10 minutes
/**
* Reset password GET from email token
*/
exports.validateResetToken = function(req, res) {
User.findOne({
resetPasswordToken: req.params.token,
resetPasswordExpires: {
$gt: Date.now()
}
}, function(err, user) {
if (!user) {
return res.redirect('/#!/password/reset/invalid');
}
verificationURL: config.baseUrl+'/#!/verify/${URL}',
transportOptions: config.mailer.options,
verifyMailOptions: {
from: config.mailer.from,
subject: 'Confirm your account',
html: '<p>Please verify your account by clicking <a href="${URL}">this link</a>. If you are unable to do so, copy and ' +
'paste the following link into your browser:</p><p>${URL}</p>',
text: 'Please verify your account by clicking the following link, or by copying and pasting it into your browser: ${URL}'
},
res.redirect('/#!/password/reset/' + req.params.token);
});
};
confirmMailOptions: {
from: config.mailer.from,
subject: 'Successfully verified!',
html: '<p>Your account has been successfully verified.</p>',
text: 'Your account has been successfully verified.'
},
/**
* Send verification email
*/
var sendVerificationEmail = function(req, res, next) {
// Init Variables
var passwordDetails = req.body;
});
async.waterfall([
// Generate random token
function(done) {
crypto.randomBytes(20, function(err, buffer) {
var token = buffer.toString('hex');
done(err, token);
});
},
function(token, done) {
// For security measurement we remove the roles from the req.body object
delete req.body.roles;
// Init Variables
var user = new User(req.body);
user.resetPasswordToken = token;
user.resetPasswordExpires = Date.now() + 3600000; // 1 hour
// Add missing user fields
user.provider = 'local';
user.displayName = user.firstName + ' ' + user.lastName;
// Then save the user
user.save(function(err) {
done(err, token, user);
});
},
function(token, user, done) {
res.render('templates/verify-account-email', {
name: user.displayName,
url: 'http://' + req.headers.host + '/auth/activate/' + token,
appName: config.app.title
}, function(err, emailHTML) {
done(err, emailHTML, user);
});
},
// If valid email, send reset email using service
function(emailHTML, user, done) {
var mailOptions = {
to: user.email,
from: config.mailer.from,
subject: 'Please verify your email',
html: emailHTML
};
smtpTransport.sendMail(mailOptions, function(err) {
done(err, 'done');
});
}
], function(err) {
if (err) return next(err);
res.status(200).send('new user successfully registered');
});
};
nev.generateTempUserModel(User);
/**
* Signup
@ -104,32 +52,44 @@ exports.signup = function(req, res) {
// Init Variables
var user = new User(req.body);
var message = null;
// Add missing user fields
user.provider = 'local';
user.username = user.email;
user.displayName = user.firstName + ' ' + user.lastName;
// Then save the user
user.save(function(err) {
if (err) {
return res.status(400).send({
message: errorHandler.getErrorMessage(err)
});
} else {
// Remove sensitive data before login
user.password = undefined;
user.salt = undefined;
res.status(200).send('new user successfully registered');
// Then save the temporary user
nev.createTempUser(user, function(newTempUser) {
// new user created
if (newTempUser) {
nev.registerTempUser(newTempUser);
res.status(200).send('An email has been sent to you. Please check it to verify your account.');
} else {
res.status(400).send('Error: Temp user could NOT be created!');
}
});
};
// req.login(user, function(err) {
// if (err) {
// res.status(400).send(err);
// } else {
// res.status(200).send('new user successfully registered');
// }
// });
}
exports.validateVerificationToken = function(req, res, next){
nev.confirmTempUser(req.params.token, function(user) {
if (user){
res.status(200).send('User successfully verified');
}else {
// redirect to resend verification email
res.status(401).send('Verification token is invalid or has expired');
}
});
};
exports.resendVerificationEmail = function(req, res, next){
nev.resendVerificationEmail(req.body.email, function(user) {
if (user){
res.status(200).send('User successfully verified');
}else {
// user hasn't been found yet
res.status(400).send( {message: 'Error: User could NOT be verified'} );
}
});
};

View file

@ -0,0 +1,45 @@
'use strict';
angular.module('users').controller('VerifyController', ['$scope', '$location', '$state', '$rootScope', 'User', 'Auth',
function($scope, $location, $state, $rootScope, User, Auth) {
$scope = $rootScope;
$scope.credentials = {};
$scope.error = null;
$scope.success = null;
// If user is signed in then redirect back home
if ($scope.authentication.isAuthenticated()) $state.go('home');
$scope.validateVerifyToken = function(){
$scope.success = $scope.error = null;
User.validateVerifyToken($stateParams.token).then(
function(response){
// If successful show success message and clear form
$scope.success = response.message;
$scope.passwordDetails = null;
},
function(error){
$scope.error = error.message || error;
$scope.passwordDetails = null;
}
);
}
// Submit forgotten password account id
$scope.resendVerifyEmail = function() {
User.resendVerifyEmail($scope.email).then(
function(response){
$scope.success = response.message;
$scope.credentials = null;
},
function(error){
$scope.error = error;
$scope.credentials = null;
}
);
};
}
]);

View file

@ -12,9 +12,10 @@ var mongoose = require('mongoose'),
config = require('../../config/config'),
path = require('path'),
fs = require('fs-extra'),
async = require('async');
var Field = mongoose.model('Field', FieldSchema);
var FormSubmission = mongoose.model('FormSubmission', FormSubmissionSchema);
async = require('async'),
Field = mongoose.model('Field', FieldSchema),
FormSubmission = mongoose.model('FormSubmission', FormSubmissionSchema),
_original;
/**
@ -33,7 +34,7 @@ var FormSchema = new Schema({
type: String,
trim: true,
unique: true,
required: 'Title cannot be blank'
required: 'Title cannot be blank',
},
language: {
type: String,
@ -47,10 +48,6 @@ var FormSchema = new Schema({
},
form_fields: {
type: [FieldSchema],
set: function(form_fields) {
this._previousFormFields = this.form_fields;
return form_fields;
}
},
submissions: [{
@ -89,10 +86,6 @@ var FormSchema = new Schema({
},
});
FormSchema.post('init', function() {
this._original = this.toObject();
});
//Delete template PDF of current Form
FormSchema.pre('remove', function (next) {
if(this.pdf){
@ -104,6 +97,21 @@ FormSchema.pre('remove', function (next) {
}
});
//Set _original
FormSchema.pre('save', function (next) {
this.constructor // ≈ mongoose.model('…', FieldSchema).findById
.findOne({title: this.title}, function(err, original){
if(err) next(err);
else {
_original = original;
next();
}
});
});
//Update lastModified and created everytime we save
FormSchema.pre('save', function (next) {
var now = new Date();
@ -114,29 +122,12 @@ FormSchema.pre('save', function (next) {
next();
});
//Concatenate submission and form's form_fields
// FormSchema.pre('save', function (next) {
// if(this.isModified('form_fields')){
// if(this.submissions.length){
// for(var i=0; i<this.submissions.length; i++){
// var submission = this.submissions[i];
// console.log(submission.form_fields);
// this.submissions[i].form_fields = submission.form_fields.concat(_.difference(this.form_fields, this._previousFormFields));
// }
// }
// this.form_fields = this._previousFormFields.concat(_.difference(this.form_fields, this._previousFormFields));
// }
// next();
// });
function getDeletedIndexes(needle, haystack){
var deletedIndexes = [];
if(haystack.length > 0){
for(var i = 0; i < needle.length; i++){
if(haystack.indexOf(needle[i]) <= -1){
if(haystack.indexOf(needle[i]) === -1){
deletedIndexes.push(i);
}
}
@ -144,100 +135,6 @@ function getDeletedIndexes(needle, haystack){
return deletedIndexes;
}
FormSchema.pre('save', function (next) {
if(this.isModified('form_fields')){
var old_form_fields = this._original.form_fields,
old_ids = _.pluck(this.form_fields, '_id'),
new_ids = _.pluck(old_form_fields, '_id'),
deletedIds = getDeletedIndexes(old_ids, new_ids),
that = this;
// console.log(deletedIds);
// console.log('old_ids\n--------');
// console.log(old_ids);
// console.log('new_ids\n--------');
// console.log(new_ids);
//Preserve fields that have at least one submission
if( deletedIds.length > 0 ){
var modifiedSubmissions;
async.forEachOfSeries(deletedIds, function (deletedIdIndex, key, callback) {
var deleted_id = old_ids[deletedIdIndex];
//Search for submissions with deleted form_field
FormSubmission.
find({ form: that, admin: that.admin, form_fields: {$elemMatch: {_id: deleted_id} } }).
exec(function(err, submissions){
if(err){
console.error(err);
return callback(err);
}
//Delete field if there are no submission(s) found
if(submissions.length > 0) {
//Push old form_field to start of array
that.form_fields.unshift(old_form_fields[deletedIdIndex]);
modifiedSubmissions.push.apply(modifiedSubmissions, submissions);
console.log(modifiedSubmissions);
}
callback(null, modifiedSubmissions);
}
);
}, function (err, submissions) {
if(err){
console.error(err.message);
next(err);
}
console.log('preserved deleted fields');
console.log(submissions);
async.forEachOfSeries(modifiedSubmissions, function (submission, key, callback) {
for(var i = 0; i < deletedIds.length; i++){
var tmpField = _.find(submission.form_fields, function(field){
return field._id === deletedIds[i];
});
var index = submission.form_fields.indexOf(tmpField);
if(tmpField){
//Delete old form_field
submission.form_fields.splice(index, 1);
//Move old form_field to start
submission.form_fields.unshift(tmpField);
}
}
submission.save(function (err) {
if (err) callback(err);
callback();
});
}, function (err) {
if(err){
console.error(err.message);
next(err);
}
next();
});
});
}
}
next();
});
//Move PDF to permanent location after new template is uploaded
FormSchema.pre('save', function (next) {
@ -245,7 +142,7 @@ FormSchema.pre('save', function (next) {
var that = this;
async.series([
function(callback){
if(that.isModified('pdf')){
if(that.isModified('pdf') && that.pdf.path){
var new_filename = that.title.replace(/ /g,'')+'_template.pdf';
@ -258,21 +155,25 @@ FormSchema.pre('save', function (next) {
fs.mkdirSync(newDestination);
}
if (stat && !stat.isDirectory()) {
callback( new Error('Directory cannot be created because an inode of a different type exists at "' + config.pdfUploadPath + '"'), null);
return callback( new Error('Directory cannot be created because an inode of a different type exists at "' + config.pdfUploadPath + '"'), null);
}
fs.move(that.pdf.path, path.join(newDestination, new_filename), function (err) {
var old_path = that.pdf.path;
fs.move(old_path, path.join(newDestination, new_filename), {clobber: true}, function (err) {
if (err) {
console.error(err);
callback( new Error(err.message), null);
}
that.pdf.path = path.join(newDestination, new_filename);
that.pdf.name = new_filename;
callback( new Error(err.message), 'task1');
}else {
that.pdf.path = path.join(newDestination, new_filename);
that.pdf.name = new_filename;
callback(null,'task1');
callback(null,'task1');
}
});
}else {
callback(null,'task1');
}
callback(null,'task1');
},
function(callback){
if(that.isGenerated){
@ -288,7 +189,7 @@ FormSchema.pre('save', function (next) {
'Radio': 'radio'
};
// console.log('autogenerating form');
console.log('autogenerating form');
// console.log(that.pdf.path);
pdfFiller.generateFieldJson(that.pdf.path, function(err, _form_fields){
@ -298,6 +199,7 @@ FormSchema.pre('save', function (next) {
callback( new Error('Generated formfields is empty'), null);
}
// console.log(_form_fields);
//Map PDF field names to FormField field names
for(var i = 0; i < _form_fields.length; i++){
var field = _form_fields[i];
@ -315,10 +217,11 @@ FormSchema.pre('save', function (next) {
// console.log('NEW FORM_FIELDS: ');
// console.log(_form_fields);
that.form_fields = that.form_fields.concat(_form_fields);
// console.log('\n\nOLD FORM_FIELDS: ');
// console.log(that.form_fields);
that.form_fields.concat(_form_fields);
that.isGenerated = false;
callback(null, 'task2');
});
}else{
@ -335,78 +238,151 @@ FormSchema.pre('save', function (next) {
next();
});
}else if(_original){
if(_original.pdf){
fs.remove(_original.pdf.path, function (err) {
if(err) next(err);
console.log('file at '+_original.pdf.path+' successfully deleted');
next();
});
}
}else{
next();
}
});
//Autogenerate Form_fields from PDF if 'isGenerated' flag is set
// FormSchema.pre('save', function (next) {
// var field, _form_fields;
FormSchema.pre('save', function (next) {
// console.log(this.form_fields);
// console.log('_original\n------------\n\n');
// console.log(_original);
// console.log(this.isModified('form_fields') && !!this.form_fields && !!_original);
if(this.isModified('form_fields') && this.form_fields && _original){
var old_form_fields = _original.form_fields,
new_ids = _.map(_.pluck(this.form_fields, '_id'), function(id){ return ''+id;}),
old_ids = _.map(_.pluck(old_form_fields, '_id'), function(id){ return ''+id;}),
deletedIds = getDeletedIndexes(old_ids, new_ids),
that = this;
// console.log('deletedId Indexes\n--------');
// console.log(deletedIds);
// console.log('old_ids\n--------');
// console.log(old_ids);
// console.log('new_ids\n--------');
// console.log(new_ids);
//Preserve fields that have at least one submission
if( deletedIds.length > 0 ){
var modifiedSubmissions = [];
async.forEachOfSeries(deletedIds,
function (deletedIdIndex, key, callback) {
var deleted_id = old_ids[deletedIdIndex];
//Search for submissions with deleted form_field
// if(submissions.length){
// submissionsWithDeletedField = _.select(form.submissions, function(submission){
// var field = _(submission.form_fields).filter(function(field) { return field._id === deleted_id; })
// return !!field;
// });
// //Push old form_field to start of array
// if(submissionsWithDeletedField.length){
// that.form_fields.unshift(old_form_fields[deletedIdIndex]);
// modifiedSubmissions.push.apply(modifiedSubmissions, submissionsWithDeletedField);
// console.log(modifiedSubmissions);
// }
// callback(null, modifiedSubmissions);
// } else{
FormSubmission.
find({ form: that._id, admin: that.admin, form_fields: {$elemMatch: {_id: deleted_id} } }).
exec(function(err, submissions){
if(err){
console.error(err);
return callback(err);
}
// console.log(submissions);
// if(this.pdf){
// if(this.isGenerated){
// var _typeConvMap = {
// 'Multiline': 'textarea',
// 'Text': 'textfield',
// 'Button': 'checkbox',
// 'Choice': 'radio',
// 'Password': 'password',
// 'FileSelect': 'filefield',
// 'Radio': 'radio'
// };
//Delete field if there are no submission(s) found
if(submissions.length) {
//Push old form_field to start of array
// that.form_fields.unshift(old_form_fields[deletedIdIndex]);
modifiedSubmissions.push.apply(modifiedSubmissions, submissions);
}
// var that = this;
// console.log('autogenerating form');
callback(null);
});
// }
},
function (err) {
if(err){
console.error(err.message);
next(err);
}
// try {
// pdfFiller.generateFieldJson(this.pdf.path, function(_form_fields){
// console.log('modifiedSubmissions\n---------\n\n');
// console.log(modifiedSubmissions);
// //Map PDF field names to FormField field names
// for(var i = 0; i < _form_fields.length; i++){
// field = _form_fields[i];
// console.log('preserved deleted fields');
// console.log(submissions);
// //Convert types from FDF to 'FormField' types
// if(_typeConvMap[ field.fieldType+'' ]){
// field.fieldType = _typeConvMap[ field.fieldType+'' ];
// }
async.forEachOfSeries(modifiedSubmissions, function (submission, key, callback) {
// field.fieldValue = '';
// field.created = Date.now();
// field.required = true;
// field.disabled = false;
for(var i = 0; i < deletedIds.length; i++){
// // field = new Field(field);
// // field.save(function(err) {
// // if (err) {
// // console.error(err.message);
// // throw new Error(err.message);
// // });
// // } else {
// // _form_fields[i] = this;
// // }
// // });
// _form_fields[i] = field;
// }
var index = _.findIndex(submission.form_fields, function(field) {
var tmp_id = field._id+'';
// console.log(tmp_id === old_ids[ deletedIds[i] ]);
return tmp_id === old_ids[ deletedIds[i] ];
});
// console.log('NEW FORM_FIELDS: ');
// console.log(_form_fields);
// console.log('index: '+index);
// console.log('\n\nOLD FORM_FIELDS: ');
// console.log(that.form_fields);
var tmpField = submission.form_fields[index];
// that.form_fields = _form_fields;
// next();
// });
// } catch(err){
// next( new Error(err.message) );
// }
// }
// }
if(tmpField){
// console.log('tmpField\n-------\n\n');
// console.log(tmpField);
//Delete old form_field
submission.form_fields.splice(index, 1);
// next();
// });
tmpField.deletePreserved = true;
//Move old form_field to start
submission.form_fields.unshift(tmpField);
that.form_fields.unshift(tmpField);
// console.log('form.form_fields\n--------\n\n');
// console.log(that.form_fields);
}
}
submission.save(function (err) {
if(err) callback(err);
else callback(null);
});
}, function (err) {
if(err){
console.error(err.message);
next(err);
}
// console.log('form.form_fields\n--------\n\n');
// console.log(that.form_fields);
next();
});
}
);
}else {
next();
}
}else {
next();
}
});
FormSchema.methods.generateFDFTemplate = function() {
var _keys = _.pluck(this.form_fields, 'title'),

View file

@ -41,14 +41,14 @@ function validateFormFieldType(value) {
* Question Schema
*/
var FormFieldSchema = new Schema({
created: {
type: Date,
default: Date.now
},
lastModified: {
type: Date,
default: Date.now
},
// created: {
// type: Date,
// default: Date.now
// },
// lastModified: {
// type: Date,
// default: Date.now
// },
title: {
type: String,
default: '',
@ -70,6 +70,11 @@ var FormFieldSchema = new Schema({
type: Boolean,
default: false,
},
deletePreserved: {
type: Boolean,
default: false
},
fieldType: {
type: String,
required: 'Field type cannot be blank',

View file

@ -10,15 +10,15 @@ var mongoose = require('mongoose'),
_ = require('lodash'),
config = require('../../config/config'),
path = require('path'),
fs = require('fs-extra');
fs = require('fs-extra'),
FieldSchema = require('./form_field.server.model.js');
/**
* Form Submission Schema
*/
var FormSubmissionSchema = new Schema({
title: {
type: String,
required: true,
title:{
type: String
},
created: {
type: Date,
@ -28,17 +28,17 @@ var FormSubmissionSchema = new Schema({
admin: {
type: Schema.Types.ObjectId,
ref: 'User',
required: true
},
form_fields: [{type: Schema.Types.Mixed}],
form: {
type: Schema.Types.ObjectId,
ref: 'Form',
form_fields: [Schema.Types.Mixed],//[FieldSchema],
form: {
type:Schema.Types.ObjectId,
ref:'Form',
required: true
},
ipAddr: {
type: String,
required: false
},
geoLocation: {
type: Schema.Types.Mixed,
@ -47,6 +47,9 @@ var FormSubmissionSchema = new Schema({
pdfFilePath: {
type: Schema.Types.Mixed,
},
pdf: {
type: Schema.Types.Mixed,
},
fdfData: {
type: Schema.Types.Mixed,
},
@ -57,62 +60,58 @@ var FormSubmissionSchema = new Schema({
});
//Check for IP Address of submitting person
// FormSubmissionSchema.pre('save', function (next){
// if(this.ipAddr){
// if(this.ipAddr.modified){
// satelize.satelize({ip: this.ipAddr}, function(err, geoData){
// if (err) next( new Error(err.message) );
//Mongoose Relationship initialization
// FormSubmissionSchema.plugin(relationship, { relationshipPathName:'form' });
// this.geoLocation = JSON.parse(geoData);
// next();
// });
// }
// }
// console.log('ipAddr check');
// next();
// });
//Check for IP Address of submitting person
FormSubmissionSchema.pre('save', function (next){
if(this.ipAddr){
if(this.ipAddr.modified){
satelize.satelize({ip: this.ipAddr}, function(err, geoData){
if (err) next( new Error(err.message) );
this.geoLocation = JSON.parse(geoData);
next();
});
}
}
console.log('ipAddr check');
next();
});
//Generate autofilled PDF if flags are set
FormSubmissionSchema.pre('save', function (next) {
// debugger;
var fdfData, dest_filename, dest_path;
var that = this;
var _form = this.form;
var fdfData, dest_filename, dest_path,
that = this,
_form = this.form;
console.log(this.pdf);
// Form.findById(that.form, function(err, _form){
// if(err) next( new Error(err.mesasge) );
that.title = _form.title;
// console.log(_form);
if(this.pdf.path){
if(_form.autofillPDFs){
dest_filename = that.title.replace(/ /g,'')+'_submission_'+Date.now()+'.pdf';
var __path = this.pdf.path.split('/').slice(0,this.pdf.path.split('/').length-1).join('/');
dest_path = path.join(__path, dest_filename);
dest_filename = _form.title.replace(/ /g,'')+'_submission_'+Date.now()+'.pdf';
dest_path = path.join(config.pdfUploadPath, dest_filename);
that.pdfFilePath = dest_path;
this.pdfFilePath = dest_path;
pdfFiller.fillForm(that.pdf.path, dest_path, that.fdfData, function(err){
console.log('fdfData: \n');
console.log(that.fdfData);
// console.log('_form.pdf.path: '+_form.pdf.path);
// console.log('dest_path: '+dest_path);
pdfFiller.fillForm(_form.pdf.path, dest_path, that.fdfData, function(err){
console.log('fdfData: \n');
console.log(that.fdfData);
// console.log('_form.pdf.path: '+_form.pdf.path);
// console.log('dest_path: '+dest_path);
if(err) {
console.log('\n err.message: '+err.message);
next( new Error(err.message) );
}
console.log('Field data from Form: '+_form.title.replace(/ /g,'')+' outputed to new PDF: '+dest_path);
next();
});
} else {
if(err) {
console.log('\n err.message: '+err.message);
next( new Error(err.message) );
}
console.log('Field data from Form: '+that.title.replace(/ /g,'')+' outputed to new PDF: '+dest_path);
next();
}
// });
});
} else {
next();
}
});

View file

@ -47,14 +47,15 @@ var UserSchema = new Schema({
email: {
type: String,
trim: true,
default: '',
unique: 'Account already exists with email',
required: 'Please enter your email',
validate: [validateLocalStrategyProperty, 'Please fill in your email'],
match: [/.+\@.+\..+/, 'Please fill a valid email address']
},
username: {
type: String,
unique: 'Username already exists',
required: 'Please fill in a username',
unique: true,
required: true,
trim: true
},
password: {
@ -84,21 +85,13 @@ var UserSchema = new Schema({
default: 'english',
required: 'User must have a language'
},
updated: {
lastModified: {
type: Date
},
created: {
type: Date,
default: Date.now
},
/* For account activation */
activationToken: {
type: String
},
activationTokenExpires: {
type: Date
},
/* For reset password */
resetPasswordToken: {
@ -112,6 +105,9 @@ var UserSchema = new Schema({
//Create folder for user's pdfs
UserSchema.pre('save', function (next) {
if(!this.username || this.username !== this.email){
this.username = this.email;
}
var newDestination = path.join(config.pdfUploadPath, this.username.replace(/ /g,'')),
stat = null;

View file

@ -22,7 +22,8 @@ module.exports = function(app) {
.delete(users.requiresLogin, forms.hasAuthorization, forms.delete);
app.route('/forms/:formId([a-zA-Z0-9]+)/submissions')
.get(users.requiresLogin, forms.hasAuthorization, forms.listSubmissions);
.get(users.requiresLogin, forms.hasAuthorization, forms.listSubmissions)
.delete(users.requiresLogin, forms.hasAuthorization, forms.deleteSubmissions);
// Finish by binding the form middleware
app.param('formId', forms.formByID);

View file

@ -14,9 +14,9 @@ module.exports = function(app) {
app.route('/users').put(users.requiresLogin, users.update);
app.route('/users/accounts').delete(users.requiresLogin, users.removeOAuthProvider);
// Account activation reset token
app.route('/auth/reset/:token').get(users.validateResetToken);
app.route('/auth/reset/:token').post(users.reset);
// Setting up the users account verification api
app.route('/auth/verify').post(users.resendVerificationEmail);
app.route('/auth/verify/:token').get(users.validateVerificationToken);
// Setting up the users password api
app.route('/users/password').post(users.requiresLogin, users.changePassword);

View file

@ -1,64 +1,64 @@
'use strict';
// 'use strict';
/**
* Module dependencies.
*/
var should = require('should'),
mongoose = require('mongoose'),
User = mongoose.model('User'),
Article = mongoose.model('Article');
// /**
// * Module dependencies.
// */
// var should = require('should'),
// mongoose = require('mongoose'),
// User = mongoose.model('User'),
// Article = mongoose.model('Article');
/**
* Globals
*/
var user, article;
// /**
// * Globals
// */
// var user, article;
/**
* Unit tests
*/
describe('Article Model Unit Tests:', function() {
beforeEach(function(done) {
user = new User({
firstName: 'Full',
lastName: 'Name',
displayName: 'Full Name',
email: 'test@test.com',
username: 'username',
password: 'password'
});
// /**
// * Unit tests
// */
// describe('Article Model Unit Tests:', function() {
// beforeEach(function(done) {
// user = new User({
// firstName: 'Full',
// lastName: 'Name',
// displayName: 'Full Name',
// email: 'test@test.com',
// username: 'username',
// password: 'password'
// });
user.save(function() {
article = new Article({
title: 'Article Title',
content: 'Article Content',
user: user
});
// user.save(function() {
// article = new Article({
// title: 'Article Title',
// content: 'Article Content',
// user: user
// });
done();
});
});
// done();
// });
// });
describe('Method Save', function() {
it('should be able to save without problems', function(done) {
return article.save(function(err) {
should.not.exist(err);
done();
});
});
// describe('Method Save', function() {
// it('should be able to save without problems', function(done) {
// return article.save(function(err) {
// should.not.exist(err);
// done();
// });
// });
it('should be able to show an error when try to save without title', function(done) {
article.title = '';
// it('should be able to show an error when try to save without title', function(done) {
// article.title = '';
return article.save(function(err) {
should.exist(err);
done();
});
});
});
// return article.save(function(err) {
// should.exist(err);
// done();
// });
// });
// });
afterEach(function(done) {
Article.remove().exec(function() {
User.remove().exec(done);
});
});
});
// afterEach(function(done) {
// Article.remove().exec(function() {
// User.remove().exec(done);
// });
// });
// });

View file

@ -1,280 +1,280 @@
'use strict';
// 'use strict';
var should = require('should'),
request = require('supertest'),
app = require('../../server'),
mongoose = require('mongoose'),
User = mongoose.model('User'),
Article = mongoose.model('Article'),
agent = request.agent(app);
// var should = require('should'),
// request = require('supertest'),
// app = require('../../server'),
// mongoose = require('mongoose'),
// User = mongoose.model('User'),
// Article = mongoose.model('Article'),
// agent = request.agent(app);
/**
* Globals
*/
var credentials, user, article;
// /**
// * Globals
// */
// var credentials, user, article;
/**
* Article routes tests
*/
describe('Article CRUD tests', function() {
beforeEach(function(done) {
// Create user credentials
credentials = {
username: 'username',
password: 'password'
};
// /**
// * Article routes tests
// */
// describe('Article CRUD tests', function() {
// beforeEach(function(done) {
// // Create user credentials
// credentials = {
// username: 'username',
// password: 'password'
// };
// Create a new user
user = new User({
firstName: 'Full',
lastName: 'Name',
displayName: 'Full Name',
email: 'test@test.com',
username: credentials.username,
password: credentials.password,
provider: 'local'
});
// // Create a new user
// user = new User({
// firstName: 'Full',
// lastName: 'Name',
// displayName: 'Full Name',
// email: 'test@test.com',
// username: credentials.username,
// password: credentials.password,
// provider: 'local'
// });
// Save a user to the test db and create new article
user.save(function() {
article = {
title: 'Article Title',
content: 'Article Content'
};
// // Save a user to the test db and create new article
// user.save(function() {
// article = {
// title: 'Article Title',
// content: 'Article Content'
// };
done();
});
});
// done();
// });
// });
it('should be able to save an article if logged in', function(done) {
agent.post('/auth/signin')
.send(credentials)
.expect(200)
.end(function(signinErr, signinRes) {
// Handle signin error
if (signinErr) done(signinErr);
// it('should be able to save an article if logged in', function(done) {
// agent.post('/auth/signin')
// .send(credentials)
// .expect(200)
// .end(function(signinErr, signinRes) {
// // Handle signin error
// if (signinErr) done(signinErr);
// Get the userId
var userId = user.id;
// // Get the userId
// var userId = user.id;
// Save a new article
agent.post('/articles')
.send(article)
.expect(200)
.end(function(articleSaveErr, articleSaveRes) {
// Handle article save error
if (articleSaveErr) done(articleSaveErr);
// // Save a new article
// agent.post('/articles')
// .send(article)
// .expect(200)
// .end(function(articleSaveErr, articleSaveRes) {
// // Handle article save error
// if (articleSaveErr) done(articleSaveErr);
// Get a list of articles
agent.get('/articles')
.end(function(articlesGetErr, articlesGetRes) {
// Handle article save error
if (articlesGetErr) done(articlesGetErr);
// // Get a list of articles
// agent.get('/articles')
// .end(function(articlesGetErr, articlesGetRes) {
// // Handle article save error
// if (articlesGetErr) done(articlesGetErr);
// Get articles list
var articles = articlesGetRes.body;
// // Get articles list
// var articles = articlesGetRes.body;
// Set assertions
(articles[0].user._id).should.equal(userId);
(articles[0].title).should.match('Article Title');
// // Set assertions
// (articles[0].user._id).should.equal(userId);
// (articles[0].title).should.match('Article Title');
// Call the assertion callback
done();
});
});
});
});
// // Call the assertion callback
// done();
// });
// });
// });
// });
it('should not be able to save an article if not logged in', function(done) {
agent.post('/articles')
.send(article)
.expect(401)
.end(function(articleSaveErr, articleSaveRes) {
// Call the assertion callback
done(articleSaveErr);
});
});
// it('should not be able to save an article if not logged in', function(done) {
// agent.post('/articles')
// .send(article)
// .expect(401)
// .end(function(articleSaveErr, articleSaveRes) {
// // Call the assertion callback
// done(articleSaveErr);
// });
// });
it('should not be able to save an article if no title is provided', function(done) {
// Invalidate title field
article.title = '';
// it('should not be able to save an article if no title is provided', function(done) {
// // Invalidate title field
// article.title = '';
agent.post('/auth/signin')
.send(credentials)
.expect(200)
.end(function(signinErr, signinRes) {
// Handle signin error
if (signinErr) done(signinErr);
// agent.post('/auth/signin')
// .send(credentials)
// .expect(200)
// .end(function(signinErr, signinRes) {
// // Handle signin error
// if (signinErr) done(signinErr);
// Get the userId
var userId = user.id;
// // Get the userId
// var userId = user.id;
// Save a new article
agent.post('/articles')
.send(article)
.expect(400)
.end(function(articleSaveErr, articleSaveRes) {
// Set message assertion
(articleSaveRes.body.message).should.match('Title cannot be blank');
// // Save a new article
// agent.post('/articles')
// .send(article)
// .expect(400)
// .end(function(articleSaveErr, articleSaveRes) {
// // Set message assertion
// (articleSaveRes.body.message).should.match('Title cannot be blank');
// Handle article save error
done(articleSaveErr);
});
});
});
// // Handle article save error
// done(articleSaveErr);
// });
// });
// });
it('should be able to update an article if signed in', function(done) {
agent.post('/auth/signin')
.send(credentials)
.expect(200)
.end(function(signinErr, signinRes) {
// Handle signin error
if (signinErr) done(signinErr);
// it('should be able to update an article if signed in', function(done) {
// agent.post('/auth/signin')
// .send(credentials)
// .expect(200)
// .end(function(signinErr, signinRes) {
// // Handle signin error
// if (signinErr) done(signinErr);
// Get the userId
var userId = user.id;
// // Get the userId
// var userId = user.id;
// Save a new article
agent.post('/articles')
.send(article)
.expect(200)
.end(function(articleSaveErr, articleSaveRes) {
// Handle article save error
if (articleSaveErr) done(articleSaveErr);
// // Save a new article
// agent.post('/articles')
// .send(article)
// .expect(200)
// .end(function(articleSaveErr, articleSaveRes) {
// // Handle article save error
// if (articleSaveErr) done(articleSaveErr);
// Update article title
article.title = 'WHY YOU GOTTA BE SO MEAN?';
// // Update article title
// article.title = 'WHY YOU GOTTA BE SO MEAN?';
// Update an existing article
agent.put('/articles/' + articleSaveRes.body._id)
.send(article)
.expect(200)
.end(function(articleUpdateErr, articleUpdateRes) {
// Handle article update error
if (articleUpdateErr) done(articleUpdateErr);
// // Update an existing article
// agent.put('/articles/' + articleSaveRes.body._id)
// .send(article)
// .expect(200)
// .end(function(articleUpdateErr, articleUpdateRes) {
// // Handle article update error
// if (articleUpdateErr) done(articleUpdateErr);
// Set assertions
(articleUpdateRes.body._id).should.equal(articleSaveRes.body._id);
(articleUpdateRes.body.title).should.match('WHY YOU GOTTA BE SO MEAN?');
// // Set assertions
// (articleUpdateRes.body._id).should.equal(articleSaveRes.body._id);
// (articleUpdateRes.body.title).should.match('WHY YOU GOTTA BE SO MEAN?');
// Call the assertion callback
done();
});
});
});
});
// // Call the assertion callback
// done();
// });
// });
// });
// });
it('should be able to get a list of articles if not signed in', function(done) {
// Create new article model instance
var articleObj = new Article(article);
// it('should be able to get a list of articles if not signed in', function(done) {
// // Create new article model instance
// var articleObj = new Article(article);
// Save the article
articleObj.save(function() {
// Request articles
request(app).get('/articles')
.end(function(req, res) {
// Set assertion
res.body.should.be.an.Array.with.lengthOf(1);
// // Save the article
// articleObj.save(function() {
// // Request articles
// request(app).get('/articles')
// .end(function(req, res) {
// // Set assertion
// res.body.should.be.an.Array.with.lengthOf(1);
// Call the assertion callback
done();
});
// // Call the assertion callback
// done();
// });
});
});
// });
// });
it('should be able to get a single article if not signed in', function(done) {
// Create new article model instance
var articleObj = new Article(article);
// it('should be able to get a single article if not signed in', function(done) {
// // Create new article model instance
// var articleObj = new Article(article);
// Save the article
articleObj.save(function() {
request(app).get('/articles/' + articleObj._id)
.end(function(req, res) {
// Set assertion
res.body.should.be.an.Object.with.property('title', article.title);
// // Save the article
// articleObj.save(function() {
// request(app).get('/articles/' + articleObj._id)
// .end(function(req, res) {
// // Set assertion
// res.body.should.be.an.Object.with.property('title', article.title);
// Call the assertion callback
done();
});
});
});
// // Call the assertion callback
// done();
// });
// });
// });
it('should return proper error for single article which doesnt exist, if not signed in', function(done) {
request(app).get('/articles/test')
.end(function(req, res) {
// Set assertion
res.body.should.be.an.Object.with.property('message', 'Article is invalid');
// it('should return proper error for single article which doesnt exist, if not signed in', function(done) {
// request(app).get('/articles/test')
// .end(function(req, res) {
// // Set assertion
// res.body.should.be.an.Object.with.property('message', 'Article is invalid');
// Call the assertion callback
done();
});
});
// // Call the assertion callback
// done();
// });
// });
it('should be able to delete an article if signed in', function(done) {
agent.post('/auth/signin')
.send(credentials)
.expect(200)
.end(function(signinErr, signinRes) {
// Handle signin error
if (signinErr) done(signinErr);
// it('should be able to delete an article if signed in', function(done) {
// agent.post('/auth/signin')
// .send(credentials)
// .expect(200)
// .end(function(signinErr, signinRes) {
// // Handle signin error
// if (signinErr) done(signinErr);
// Get the userId
var userId = user.id;
// // Get the userId
// var userId = user.id;
// Save a new article
agent.post('/articles')
.send(article)
.expect(200)
.end(function(articleSaveErr, articleSaveRes) {
// Handle article save error
if (articleSaveErr) done(articleSaveErr);
// // Save a new article
// agent.post('/articles')
// .send(article)
// .expect(200)
// .end(function(articleSaveErr, articleSaveRes) {
// // Handle article save error
// if (articleSaveErr) done(articleSaveErr);
// Delete an existing article
agent.delete('/articles/' + articleSaveRes.body._id)
.send(article)
.expect(200)
.end(function(articleDeleteErr, articleDeleteRes) {
// Handle article error error
if (articleDeleteErr) done(articleDeleteErr);
// // Delete an existing article
// agent.delete('/articles/' + articleSaveRes.body._id)
// .send(article)
// .expect(200)
// .end(function(articleDeleteErr, articleDeleteRes) {
// // Handle article error error
// if (articleDeleteErr) done(articleDeleteErr);
// Set assertions
(articleDeleteRes.body._id).should.equal(articleSaveRes.body._id);
// // Set assertions
// (articleDeleteRes.body._id).should.equal(articleSaveRes.body._id);
// Call the assertion callback
done();
});
});
});
});
// // Call the assertion callback
// done();
// });
// });
// });
// });
it('should not be able to delete an article if not signed in', function(done) {
// Set article user
article.user = user;
// it('should not be able to delete an article if not signed in', function(done) {
// // Set article user
// article.user = user;
// Create new article model instance
var articleObj = new Article(article);
// // Create new article model instance
// var articleObj = new Article(article);
// Save the article
articleObj.save(function() {
// Try deleting article
request(app).delete('/articles/' + articleObj._id)
.expect(401)
.end(function(articleDeleteErr, articleDeleteRes) {
// Set message assertion
(articleDeleteRes.body.message).should.match('User is not logged in');
// // Save the article
// articleObj.save(function() {
// // Try deleting article
// request(app).delete('/articles/' + articleObj._id)
// .expect(401)
// .end(function(articleDeleteErr, articleDeleteRes) {
// // Set message assertion
// (articleDeleteRes.body.message).should.match('User is not logged in');
// Handle article error error
done(articleDeleteErr);
});
// // Handle article error error
// done(articleDeleteErr);
// });
});
});
// });
// });
afterEach(function(done) {
User.remove().exec(function() {
Article.remove().exec(done);
});
});
});
// afterEach(function(done) {
// User.remove().exec(function() {
// Article.remove().exec(done);
// });
// });
// });

View file

@ -6,13 +6,14 @@
var should = require('should'),
mongoose = require('mongoose'),
User = mongoose.model('User'),
Form = mongoose.model('Form');
Form = mongoose.model('Form'),
_ = require('lodash'),
FormSubmission = mongoose.model('FormSubmission');
/**
* Globals
*/
var user, Form,
FormFDF;
var user, myForm, mySubmission, FormFDF;
/**
* Unit tests
@ -29,10 +30,15 @@ describe('Form Model Unit Tests:', function() {
});
user.save(function() {
Form = new Form({
myForm = new Form({
title: 'Form Title',
admin: user,
form_fields: [{'title':'Short Text2','fieldType':'textfield','fieldValue':'','disabled':false},{'disabled':false,'created':1435952663586,'fieldValue':'','fieldFlags':'0','fieldType':'checkbox','title':'nascar'},{'disabled':false,'created':1435952663586,'fieldValue':'','fieldFlags':'0','fieldType':'checkbox','title':'hockey'}]
language: 'english',
form_fields: [
{'fieldType':'textfield', 'title':'First Name', 'fieldValue': ''},
{'fieldType':'checkbox', 'title':'nascar', 'fieldValue': ''},
{'fieldType':'checkbox', 'title':'hockey', 'fieldValue': ''}
]
});
done();
@ -41,38 +47,112 @@ describe('Form Model Unit Tests:', function() {
describe('Method Save', function() {
it('should be able to save without problems', function(done) {
return Form.save(function(err) {
return myForm.save(function(err) {
should.not.exist(err);
done();
});
});
it('should be able to show an error when try to save without title', function(done) {
Form.title = '';
myForm.title = '';
return Form.save(function(err) {
return myForm.save(function(err) {
should.exist(err);
should.equal(err.errors.title.message, 'Title cannot be blank');
done();
});
});
});
describe('Method generateFDFTemplate', function() {
it('should be able to generate one that is correct', function(done) {
return Form.generateFDFTemplate(function(err) {
should.not.exist(err);
describe('Test FormField and Submission Logic', function() {
var new_form_fields_add1, new_form_fields_del, submission_fields, old_fields;
before(function(done){
new_form_fields_add1 = _.clone(myForm.form_fields);
new_form_fields_add1.push(
{'fieldType':'textfield', 'title':'Last Name', 'fieldValue': ''}
);
new_form_fields_del = _.clone(myForm.form_fields);
new_form_fields_del.splice(0, 1);
submission_fields = _.clone(myForm.toObject().form_fields);
submission_fields[0].fieldValue = 'David';
submission_fields[1].fieldValue = true;
submission_fields[2].fieldValue = true;
mySubmission = new FormSubmission({
form_fields: submission_fields,
admin: user,
form: myForm._id,
timeElapsed: 17.55
});
mySubmission.save(function(){
done();
});
});
it('should be able to show an error when try to save without title', function(done) {
Form.title = '';
return Form.save(function(err) {
should.exist(err);
after(function(done){
mySubmission.remove(function(){
done();
});
});
beforeEach(function(done){
old_fields = myForm.toObject().form_fields;
// console.log(old_fields);
done();
});
it('should preserve deleted form_fields that have submissions without any problems', function(done) {
var expected_fields = old_fields.slice(1,3).concat(old_fields.slice(0,1));
// console.log(old_fields);
myForm.form_fields = new_form_fields_del;
return myForm.save(function(err, form) {
should.not.exist(err);
var actual_fields = form.toObject();
should.deepEqual(form.toObject().form_fields, expected_fields, 'old form_fields not equal to newly saved form_fields');
done();
});
});
// it('should delete \'preseved\' form_fields whose submissions have been removed without any problems', function(done) {
// myForm.form_fields = new_form_fields_del;
// myForm.save(function(err, form) {
// should.not.exist(err);
// (form.form_fields).should.be.eql(old_fields, 'old form_fields not equal to newly saved form_fields');
// //Remove submission
// mySubmission.remove(function(err){
// myForm.submissions.should.have.length(0);
// myForm.form_fields.should.not.containDeep(old_fields[0]);
// });
// });
// });
});
describe('Method generateFDFTemplate', function() {
beforeEach(function(done){
FormFDF = {
'First Name': '',
'nascar': '',
'hockey': ''
};
done();
});
it('should be able to generate a FDF template without any problems', function(done) {
var fdfTemplate = myForm.generateFDFTemplate();
(fdfTemplate).should.be.eql(FormFDF);
done();
});
});
afterEach(function(done) {

2
config/env/all.js vendored
View file

@ -9,6 +9,8 @@ module.exports = {
port: process.env.PORT || 3000,
templateEngine: 'swig',
baseUrl: '',
//Sentry DSN Client Key
DSN: 'http://db01e03015ce48e2b68240ea8254b17c:5d878e9bb6c6488fbb70fb81295ee700@sentry.polydaic.com/1',

View file

@ -14,7 +14,7 @@ module.exports = {
// Stream defaults to process.stdout
// Uncomment to enable logging to a log on the file system
options: {
//stream: 'access.log'
// stream: 'access.log'
}
},
app: {
@ -46,12 +46,12 @@ module.exports = {
callbackURL: '/auth/github/callback'
},
mailer: {
from: process.env.MAILER_FROM || 'MAILER_FROM',
from: process.env.MAILER_FROM || 'hi@example.com',
options: {
service: process.env.MAILER_SERVICE_PROVIDER || 'MAILER_SERVICE_PROVIDER',
service: process.env.MAILER_SERVICE_PROVIDER || 'Mandrill',
auth: {
user: process.env.MAILER_EMAIL_ID || 'MAILER_EMAIL_ID',
pass: process.env.MAILER_PASSWORD || 'MAILER_PASSWORD'
user: process.env.MAILER_EMAIL_ID || 'hackouver@gmail.com',
pass: process.env.MAILER_PASSWORD || 'ehOLuSXCBFxLjipRalBxVg'
}
}
}

View file

@ -32,6 +32,7 @@ module.exports = function(db) {
// Initialize express app
var app = express();
// Globbing model files
config.getGlobbedFiles('./app/models/**/*.js').forEach(function(modelPath) {
require(path.resolve(modelPath));
@ -52,7 +53,10 @@ module.exports = function(db) {
// Passing the request url to environment locals
app.use(function(req, res, next) {
res.locals.url = req.protocol + '://' + req.headers.host + req.url;
if(config.baseUrl === ''){
config.baseUrl = req.protocol + '://' + req.headers.host;
}
res.locals.url = req.protocol + '://' + req.headers.host + req.url;
next();
});
@ -103,7 +107,8 @@ module.exports = function(db) {
app.disable('x-powered-by');
// Setting the app router and static folder
app.use(express.static(path.resolve('./public')));
app.use('/', express.static(path.resolve('./public')));
app.use('/uploads', express.static(path.resolve('./uploads')));
var formCtrl = require('../app/controllers/forms.server.controller');
// Setting the pdf upload route and folder

View file

@ -3,7 +3,12 @@
/**
* Module dependencies.
*/
var applicationConfiguration = require('./config/config');
var applicationConfiguration = require('./config/config'),
bowerFiles = require('main-bower-files');
var bowerDep = bowerFiles('**/**.js');
console.log(bowerDep);
// Karma configuration
module.exports = function(config) {
@ -12,7 +17,7 @@ module.exports = function(config) {
frameworks: ['jasmine'],
// List of files / patterns to load in the browser
files: applicationConfiguration.assets.lib.js.concat(applicationConfiguration.assets.js, applicationConfiguration.assets.tests),
files: bowerDep.concat(applicationConfiguration.assets.js, applicationConfiguration.assets.tests),
// Test results reporter to use
// Possible values: 'dots', 'progress', 'junit', 'growl', 'coverage'
@ -39,7 +44,7 @@ module.exports = function(config) {
// - Safari (only Mac)
// - PhantomJS
// - IE (only Windows)
browsers: ['Chrome'],
browsers: ['PhantomJS'],
// If browser does not capture in given timeout [ms], kill it
captureTimeout: 60000,

View file

@ -30,6 +30,7 @@
"connect-mongo": "~0.4.1",
"consolidate": "~0.10.0",
"cookie-parser": "~1.3.2",
"email-verification": "^0.1.9",
"express": "~4.10.1",
"express-session": "~1.9.1",
"forever": "~0.11.0",
@ -64,6 +65,7 @@
"mocha": ">=1.20.0",
"mongoose": "~3.8.8",
"mongoose-datatable": "^1.0.2",
"mongoose-relationship": "^0.1.4",
"morgan": "~1.4.1",
"multer": "~0.1.8",
"nodemailer": "~1.3.0",

File diff suppressed because one or more lines are too long

View file

@ -8,27 +8,30 @@ angular.module('forms').run(['Menus',
}
]).filter('formValidity',
function(){
return function(formObj){
//get keys
var formKeys = Object.keys(formObj);
if(formObj && formObj.form_fields && formObj.visible_form_fields){
//get keys
var formKeys = Object.keys(formObj);
//we only care about things that don't start with $
var fieldKeys = formKeys.filter(function(key){
return key[0] !== '$';
});
//we only care about things that don't start with $
var fieldKeys = formKeys.filter(function(key){
return key[0] !== '$';
});
var fields = formObj.form_fields;
// fieldKeys.map(function(key){
// return formObj[key];
// });
var fields = formObj.form_fields;
// fieldKeys.map(function(key){
// return formObj[key];
// });
var valid_count = fields.filter(function(field){
if(typeof field === 'object'){
return !!(field.fieldValue);
}
}).length;
return valid_count;
var valid_count = fields.filter(function(field){
if(typeof field === 'object'){
return !!(field.fieldValue);
}
}).length;
return valid_count - (formObj.form_fields.length - formObj.visible_form_fields.length);
}
return 0;
};
}).config(['$provide', function ($provide){
$provide.decorator('accordionDirective', function($delegate) {

View file

@ -10,10 +10,6 @@ angular.module('forms').config(['$stateProvider',
url: '/forms',
templateUrl: 'modules/forms/views/list-forms.client.view.html',
}).
state('createForm', {
url: '/forms/create',
templateUrl: 'modules/forms/views/create-form.client.view.html',
}).
state('viewForm', {
url: '/forms/:formId/admin',
templateUrl: 'modules/forms/views/view-form.client.view.html',
@ -27,10 +23,6 @@ angular.module('forms').config(['$stateProvider',
data: {
hideNav: true,
},
}).
state('editForm', {
url: '/forms/:formId/edit',
templateUrl: 'modules/forms/views/create-form.client.view.html',
});
}
]);

View file

@ -1,122 +0,0 @@
// 'use strict';
// angular.module('forms').controller('EditFormController', ['$scope', '$state', '$rootScope', 'Upload', '$stateParams', 'FormFields', 'Forms', 'CurrentForm', '$modal', '$location', '$http',
// function ($scope, $state, $rootScope, Upload, $stateParams, FormFields, Forms, CurrentForm, $modal, $location, $http) {
// $scope.form = {};
// $scope.isNewForm = false;
// $scope.log = '';
// $scope.pdfLoading = false;
// var _current_upload = null;
// // Get current form if it exists, or create new one
// if($stateParams.formId){
// Forms.get({ formId: $stateParams.formId}, function(form){
// $scope.form = angular.fromJson(angular.toJson(form));
// console.log($scope.form);
// });
// } else {
// $scope.form.form_fields = [];
// $scope.isNewForm = true;
// }
// //PDF Functions
// $scope.cancelUpload = function(){
// _current_upload.abort();
// $scope.pdfLoading = false;
// $scope.removePDF();
// };
// $scope.removePDF = function(){
// $scope.form.pdf = null;
// $scope.form.isGenerated = false;
// $scope.form.autofillPDFs = false;
// console.log('form.pdf: '+$scope.form.pdf+' REMOVED');
// };
// $scope.uploadPDF = function(files) {
// if (files && files.length) {
// // for (var i = 0; i < files.length; i++) {
// var file = files[0];
// _current_upload = Upload.upload({
// url: '/upload/pdf',
// fields: {
// 'user': $scope.user,
// 'form': $scope.form
// },
// file: file
// }).progress(function (evt) {
// var progressPercentage = parseInt(100.0 * evt.loaded / evt.total);
// $scope.log = 'progress: ' + progressPercentage + '% ' +
// evt.config.file.name + '\n' + $scope.log;
// $scope.pdfLoading = true;
// }).success(function (data, status, headers, config) {
// $scope.log = 'file ' + data.originalname + ' uploaded as '+ data.name +'. JSON: ' + JSON.stringify(data) + '\n' + $scope.log;
// console.log($scope.form.pdf);
// $scope.form.pdf = angular.fromJson(angular.toJson(data));
// $scope.pdfLoading = false;
// console.log($scope.log);
// console.log('$scope.pdf: '+$scope.form.pdf.name);
// if(!$scope.$$phase){
// $scope.$apply();
// }
// }).error(function(err){
// $scope.pdfLoading = false;
// console.log('Error occured during upload.\n');
// console.log(err);
// });
// // }
// }
// };
// $rootScope.goToWithId = function(route, id) {
// $state.go(route, {'formId': id}, {reload: true});
// };
// // Create new Form
// $rootScope.createOrUpdate = function() {
// if($scope.isNewForm){
// // Create new Form object
// var form = new Forms($scope.form);
// $http.post('/forms', {form: $scope.form})
// .success(function(data, status, headers){
// console.log('form created');
// // Clear form fields
// $scope.form = {};
// // Redirect after save
// $scope.goToWithId('viewForm', $scope.form._id);
// }).error(function(errorResponse){
// console.log(errorResponse);
// $scope.error = errorResponse;
// });
// } else{
// $scope.update(function(err){
// console.log('done updating');
// });
// }
// };
// // Update existing Form
// $rootScope.update = function(cb) {
// var form = new Forms($scope.form);
// console.log('update form');
// console.log($scope.form);
// $http.put('/forms/'+$scope.form._id, {form: $scope.form})
// .success(function(data, status, headers){
// console.log('form updated successfully');
// $scope.goToWithId('viewForm', $scope.form._id);
// cb(null);
// }).error(function(err){
// console.log('Error occured during form UPDATE.\n');
// console.log(err);
// cb(err);
// });
// };
// }
// ]);

View file

@ -3,42 +3,34 @@
// submissions controller
angular.module('forms').controller('ViewSubmissionController', ['$scope', '$stateParams', '$state', 'Submissions','$http',
function($scope, $stateParams, $state, Submissions, $http) {
$scope.submissionId = undefined;
$scope.submissionId = undefined;
// Principal.identity().then(function(user){
// $scope.authentication.user = user;
// }).then(function(){
// Return all form's submissions
$scope.findAll = function() {
$scope.submissions = Submissions.query({
formId: $stateParams.formId
});
};
// Return all form's submissions
$scope.findAll = function() {
$scope.submissions = Submissions.query({
formId: $stateParams.formId
});
};
// Find a specific submission
$scope.findOne = function() {
$scope.submission = Submissions.get({
submissionId: $scope.submissionId,
formId: $stateParams.formId
});
};
// Find a specific submission
$scope.findOne = function() {
$scope.submission = Submissions.get({
submissionId: $scope.submissionId,
formId: $stateParams.formId
});
};
// Remove existing submission
$scope.remove = function(submission) {
if (!submission) {
submission = $scope.submission;
}
$http.delete('/forms/'+$stateParams.formId+'/submissions/'+submission._id).
success(function(data, status, headers){
console.log('submission deleted successfully');
alert('submission deleted..');
});
};
// });
// Remove existing submission
$scope.remove = function(submission) {
if (!submission) {
submission = $scope.submission;
}
$http.delete('/forms/'+$stateParams.formId+'/submissions/'+submission._id).
success(function(data, status, headers){
console.log('submission deleted successfully');
alert('submission deleted..');
});
};
}
]);

View file

@ -4,9 +4,9 @@
angular.module('forms').controller('ViewFormController', ['$rootScope', '$scope', '$stateParams', '$state', 'Forms', 'CurrentForm','$http',
function($rootScope, $scope, $stateParams, $state, Forms, CurrentForm, $http) {
$scope = $rootScope;
$scope.myform = CurrentForm.getForm();
$scope.submissions = undefined;
$scope.saveInProgress = false;
$scope.viewSubmissions = false;
$scope.showCreateModal = false;
$scope.table = {
@ -34,7 +34,7 @@ angular.module('forms').controller('ViewFormController', ['$rootScope', '$scope'
$scope.setForm = function (form) {
$scope.myForm = form;
$scope.myform = form;
};
//Modal functions
@ -52,6 +52,13 @@ angular.module('forms').controller('ViewFormController', ['$rootScope', '$scope'
/*
* Table Functions
*/
$scope.isAtLeastOneChecked = function(){
// console.log('isAtLeastOneChecked');
for(var i=0; i<$scope.table.rows.length; i++){
if($scope.table.rows[i].selected) return true;
}
return false;
};
$scope.toggleAllCheckers = function(){
console.log('toggleAllCheckers');
for(var i=0; i<$scope.table.rows.length; i++){
@ -60,22 +67,56 @@ angular.module('forms').controller('ViewFormController', ['$rootScope', '$scope'
};
$scope.toggleObjSelection = function($event, description) {
$event.stopPropagation();
console.log('checkbox clicked');
};
$scope.rowClicked = function(obj) {
// console.log('row clicked');
obj.selected = !obj.selected;
};
//show submissions of Form
/*
* Form Submission Methods
*/
//Delete selected submissions of Form
$scope.deleteSelectedSubmissions = function(){
// console.log('deleteSelectedSubmissions');
var delete_ids = [];
// for(var i=0; i<$scope.table.rows.length; i++){
// if($scope.table.rows[i].selected){
// delete_ids.push($scope.table.rows[i]._id);
// }
// }
delete_ids = _.chain($scope.table.rows).filter(function(row){
return !!row.selected;
}).pluck('_id').value();
console.log(delete_ids);
$http({ url: '/forms/'+$scope.myform._id+'/submissions',
method: 'DELETE',
data: {deleted_submissions: delete_ids},
headers: {"Content-Type": "application/json;charset=utf-8"}
}).success(function(data, status, headers){
//Remove deleted ids from table
for(var i=0; i<$scope.table.rows.length; i++){
if($scope.table.rows[i].selected){
$scope.table.rows.splice(i, 1);
}
}
})
.error(function(err){
console.log('Could not delete form submissions.\nError: ');
console.log(err);
console.error = err;
});
};
//Fetch and display submissions of Form
$scope.showSubmissions = function(){
$scope.viewSubmissions = true;
$http.get('/forms/'+$scope.myform._id+'/submissions')
.success(function(data, status, headers){
console.log(data[0].form_fields);
// console.log(data[0].form_fields);
var _data = Array();
var _data = [];
for(var i=0; i<data.length; i++){
var _tmpSubFormFields = JSON.parse(JSON.stringify($scope.myform.form_fields));
@ -83,14 +124,14 @@ angular.module('forms').controller('ViewFormController', ['$rootScope', '$scope'
for(var x=0; x<_tmpSubFormFields.length; x++){
var currField__id = _tmpSubFormFields[x]._id,
currField = undefined;
currField;
_.find(data[i].form_fields, function(fieldItem, fieldIdx){
if(fieldItem._id === currField__id){
currField = fieldItem;
console.log(fieldItem.fieldValue);
// console.log(fieldItem.fieldValue);
return true;
};
}
});
if(currField !== undefined){
@ -101,16 +142,17 @@ angular.module('forms').controller('ViewFormController', ['$rootScope', '$scope'
}
}
// _tmpSubFormFields.order = i;
_data[i] = data[i];
_data[i].form_fields = _tmpSubFormFields;
};
}
console.log(JSON.stringify(_data));
// console.log(JSON.stringify(_data));
$scope.submissions = _data;
$scope.table.rows = _data;
if(!$scope.$$phase && !$scope.$digest){
$scope.$apply();
}
// console.log('form submissions successfully fetched');
// console.log( JSON.parse(JSON.stringify($scope.submissions)) ) ;
// console.log( JSON.parse(JSON.stringify($scope.myform.form_fields)) );
@ -126,8 +168,6 @@ angular.module('forms').controller('ViewFormController', ['$rootScope', '$scope'
$scope.viewSubmissions = false;
};
// Remove existing Form
$scope.remove = function(form_id) {
var form = {};
@ -160,33 +200,32 @@ angular.module('forms').controller('ViewFormController', ['$rootScope', '$scope'
// Create new Form
$scope.createNew = function(){
var form = {};
form.title = $scope.myForm.name.$modelValue;
form.language = $scope.myForm.language.$modelValue;
form.title = $scope.myform.name.$modelValue;
form.language = $scope.myform.language.$modelValue;
console.log(form);
$scope.showCreateModal = true;
console.log($scope.myForm);
if($scope.myForm.$valid && $scope.myForm.$dirty){
console.log($scope.myform);
if($scope.myform.$valid && $scope.myform.$dirty){
$http.post('/forms', {form: form})
.success(function(data, status, headers){
console.log('form created');
// Clear form fields
$scope.myForm = {};
$scope.myform = {};
// Redirect after save
$scope.goToWithId('viewForm', $scope.myform._id);
$scope.goToWithId('viewForm', data._id+'');
}).error(function(errorResponse){
console.log(errorResponse);
// $scope.error = errorResponse.data.message;
$scope.error = errorResponse.data.message;
});
}
};
// Update existing Form
$scope.saveInProgress = false;
$scope.update = $rootScope.update = function(cb) {
if(!$scope.saveInProgress){
$scope.saveInProgress = true;
if(!$rootScope.saveInProgress){
$rootScope.saveInProgress = true;
// console.log('begin updating form');
@ -194,15 +233,20 @@ angular.module('forms').controller('ViewFormController', ['$rootScope', '$scope'
$http.put('/forms/'+$scope.myform._id, {form: $scope.myform})
.then(function(response){
// console.log('form updated successfully');
// console.log(response.status);
$rootScope.myform = $scope.myform = response.data;
console.log(response.data);
if(!$scope.$digest){
$scope.$apply();
}
}).catch(function(response){
console.log('Error occured during form UPDATE.\n');
console.log(response.data);
err = response.data;
}).finally(function() {
// console.log('finished updating');
$scope.saveInProgress = false;
$rootScope.saveInProgress = false;
cb(err);
});
}

View file

@ -17,12 +17,31 @@ form .row.field {
font-size:1.2em;
color:#ddd;
}
form.submission-form .row.field > .field-input input {
width:100%;
}
form.submission-form .row.field .field-input > input:focus {
font-size:1em;
}
form.submission-form .select.radio > .field-input input {
width:20%;
}
form.submission-form .select > .field-input input {
width:20%;
}
form.submission-form .select > .field-input .btn {
text-align: left;
margin-bottom:0.7em;
}
form.submission-form .select > .field-input .btn > span {
font-size: 1.10em;
}
form.submission-form .row.field > .field-input input {
width:100%;
}
form.submission-form .row.field .field-input > input:focus {
font-size:1em;
}
form .row.field.textfield > .field-input > input{
padding:0.45em 0.9em;
width:100%;
@ -151,8 +170,9 @@ div.config-form > .row {
}
/* Styles for form list view (/forms) */
section > section.ng-scope {
padding: 0 60px 20px 60px;
section > section.public-form {
padding: 0 6em 7em 6em;
}
.form-item.row {
text-align: center;

View file

@ -40,7 +40,7 @@ angular.module('forms').directive('autoSaveForm', ['$rootScope', '$timeout', fun
});
$scope.$watch('myform.form_fields', function(newValue, oldValue) {
// console.log('watchCount: '+$rootScope.watchCount);
console.log('watchCount: '+$rootScope.watchCount);
if(difference(oldValue,newValue).length === 0 || oldValue === undefined){
return;
}
@ -49,9 +49,9 @@ angular.module('forms').directive('autoSaveForm', ['$rootScope', '$timeout', fun
// console.log('form_fields changed: '+difference(oldValue,newValue).length );
// console.log('$valid: '+$formCtrl.$valid);
// console.log('finishedRender: '+$scope.finishedRender);
// console.log('saveInProgress: '+$scope.saveInProgress);
console.log('saveInProgress: '+$rootScope.saveInProgress);
if($scope.finishedRender && ($formCtrl.$dirty || difference(oldValue,newValue).length !== 0) ) {
if($scope.finishedRender && ($formCtrl.$dirty || difference(oldValue,newValue).length !== 0) && !$rootScope.saveInProgress) {
$rootScope.watchCount++;
if($rootScope.watchCount === 1) {
@ -80,6 +80,8 @@ angular.module('forms').directive('autoSaveForm', ['$rootScope', '$timeout', fun
});
}
}else{
return;
}
}, true);

View file

@ -10,16 +10,16 @@ angular.module('forms').directive('changeFocus', function() {
// console.log('aoeuaoeuaoeuaou');
scope.focusUp = function(){
if(!scope.$first) {
// console.log('aoeuaoeu');
elem[0].previousElementSibling.find('input').focus();
}
scope.apply();
console.log('focusUp');
elem[0].previousElementSibling.find('input').focus();
}
scope.apply();
};
scope.focusDown = function(){
if(!scope.$last) {
elem[0].nextElementSibling.focus();
}
scope.apply();
}
scope.apply();
};
//Bind 'focus-down' click event to given dom element

View file

@ -1,7 +1,7 @@
'use strict';
angular.module('forms').directive('configureFormDirective', ['$rootScope','$http', '$timeout', 'timeCounter', 'Auth', 'FormFields',
function ($rootScope, $http, $timeout, timeCounter, Auth, FormFields) {
angular.module('forms').directive('configureFormDirective', ['$rootScope', '$http', 'Upload', '$timeout', 'timeCounter', 'Auth', 'FormFields',
function ($rootScope, $http, Upload, $timeout, timeCounter, Auth, FormFields) {
return {
controller: function($scope){
$scope.log = '';
@ -39,6 +39,8 @@ angular.module('forms').directive('configureFormDirective', ['$rootScope','$http
if (files && files.length) {
// for (var i = 0; i < files.length; i++) {
var file = files[0];
console.log(file);
_current_upload = Upload.upload({
url: '/upload/pdf',
fields: {
@ -53,13 +55,14 @@ angular.module('forms').directive('configureFormDirective', ['$rootScope','$http
$scope.pdfLoading = true;
}).success(function (data, status, headers, config) {
$scope.log = 'file ' + data.originalname + ' uploaded as '+ data.name +'. JSON: ' + JSON.stringify(data) + '\n' + $scope.log;
console.log($scope.myform.pdf);
$scope.myform.pdf = angular.fromJson(angular.toJson(data));
console.log($scope.myform.pdf);
$scope.pdfLoading = false;
console.log($scope.log);
console.log('$scope.pdf: '+$scope.myform.pdf.name);
if(!$scope.$$phase){
if(!$scope.$$phase && !$scope.$digest){
$scope.$apply();
}
}).error(function(err){
@ -67,7 +70,6 @@ angular.module('forms').directive('configureFormDirective', ['$rootScope','$http
console.log('Error occured during upload.\n');
console.log(err);
});
// }
}
};

View file

@ -20,6 +20,8 @@ angular.module('forms').directive('editFormDirective', ['$rootScope', '$q', '$ht
handle: ' .handle'
}
console.log($scope.myform);
// $scope.draggable = {
// connectWith: ".dropzone",
// start: function (e, ui) {
@ -87,7 +89,7 @@ angular.module('forms').directive('editFormDirective', ['$rootScope', '$q', '$ht
for(var i = 0; i < $scope.addField.types.length; i++){
// console.log($scope.addField.types[i].name === fieldType);
if($scope.addField.types[i].name === fieldType){
if($scope.addField.types[i].name === fieldType){
$scope.addField.types[i].lastAddedID++;
// console.log($scope.addField.types[i].lastAddedID);
fieldTitle = $scope.addField.types[i].value+$scope.addField.types[i].lastAddedID;
@ -99,13 +101,13 @@ angular.module('forms').directive('editFormDirective', ['$rootScope', '$q', '$ht
'fieldType' : fieldType,
'fieldValue' : '',
'required' : true,
'disabled' : false
'disabled' : false,
};
// put newField into fields array
$scope.myform.form_fields.unshift(newField);
console.log('\n\n---------\nAdded field CLIENT');
console.log(Date.now());
// console.log('\n\n---------\nAdded field CLIENT');
// console.log(Date.now());
// console.log($scope.myform.form_fields.length);
};

View file

@ -24,7 +24,8 @@ angular.module('forms').directive('fieldDirective', function($http, $compile) {
'dropdown',
'hidden',
'password',
'radio'
'radio',
'legal'
];
if (__indexOf.call(supported_fields, type) >= 0) {
return templateUrl += type + '.html';
@ -32,7 +33,7 @@ angular.module('forms').directive('fieldDirective', function($http, $compile) {
};
var linker = function(scope, element) {
scope.field.required = scope.required;
// scope.field.required = scope.required;
//Set format only if field is a date
if(scope.field.fieldType === 'date'){

View file

@ -25,16 +25,16 @@ angular.module('forms').directive('formDirective', ['$http', '$timeout', 'timeCo
});
};
$scope.cancel = function(){
alert('Form canceled..');
};
$scope.reloadForm = function(){
$scope.form.submitted = false;
$scope.form.form_fields = _.chain($scope.form.form_fields).map(function(field){
field.fieldValue = '';
return field;
}).value();
}
},
templateUrl: './modules/forms/views/directiveViews/form/form.html',
templateUrl: './modules/forms/views/directiveViews/form/submit-form.html',
restrict: 'E',
scope: {
form:'='

View file

@ -9,6 +9,27 @@ angular.module('forms').factory('Forms', ['$resource',
'query' : {
method: 'GET',
isArray: true,
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;
}); //<-- replace each item with an instance of the resource object
});
return forms;
}
},
'get' : {
method: 'GET',
transformResponse: function(data, header) {
var form = angular.fromJson(data);
form.visible_form_fields = _.filter(form.form_fields, function(field){
return field.deletePreserved === false;
}); //<-- replace each item with an instance of the resource object
console.log(form);
return form;
}
},
'update': {
method: 'PUT'

View file

@ -1,7 +1,7 @@
<div class="field row">
<div class="col-xs-5 field-title field-title">{{field.title}} </div>
<div class="col-xs-7 field-input field-input">
<input ng-model="field.fieldValue" ng-model-options="{ debounce: 250 }" id="{{field.client_id}}" type="checkbox" ng-init="field.fieldValue = false" ng-required="field.required" ng-disabled="field.disabled"/>
<input ng-model="field.fieldValue" ng-model-options="{ debounce: 250 }" type="checkbox" ng-init="field.fieldValue = false" ng-required="field.required" ng-disabled="field.disabled"/>
<span class="required-error" ng-show="field.required && field.fieldValue == 0">(* required)</span>
</div>
<div class="field row">

View file

@ -1,4 +1,4 @@
<div class="field row dropdown">
<div class="field row dropdown" ng-if="field.fieldOptions.length > 0">
<div class="col-xs-5 field-title">{{field.title}} </div>
<div class="col-xs-7 field-input ">
<select ng-model="field.fieldValue" ng-model-options="{ debounce: 250 }" ng-required="field.required" ng-disabled="field.disabled">

View file

@ -0,0 +1,21 @@
<div class="field row radio legal">
<div class="col-xs-12 field-title">
{{field.title}}
<br>
<p>{{field.description}}</p>
</div>
<div class="col-xs-3 field-input container">
<div class="row-fluid">
<label class="btn col-xs-12">
<input type="radio" value="true" ng-model="field.fieldValue" ng-model-options="{ debounce: 250 }" ng-required="field.required" ng-disabled="field.disabled"/>
<span> I accept </span>
</label>
<label class="btn col-xs-12">
<input type="radio" value="false" ng-model="field.fieldValue" ng-model-options="{ debounce: 250 }" ng-required="field.required" ng-disabled="field.disabled"/>
<span>I don't accept </span>
</label>
</div>
<span class="required-error" ng-show="field.required && !field.fieldValue">* required</span>
</div>
</div>
<br>

View file

@ -1,10 +1,10 @@
<div class="field row">
<div class="field row radio" ng-if="field.fieldOptions.length > 0">
<div class="col-xs-5 field-title">{{field.title}} </div>
<div class="col-xs-7 field-input">
<div ng-repeat="option in field.fieldOptions" class="row-fluid">
<label>
<input type="radio" value="{{option.option_value}}" ng-model="field.fieldValue" ng-model-options="{ debounce: 250 }" ng-required="field.required" ng-disabled="field.disabled"/>
&nbsp;<span ng-bind="option.option_title"></span>
<label class="btn col-xs-12">
<input type="radio" value="{{option.option_value}}" ng-model="field.fieldValue" ng-model-options="{ debounce: 250 }" ng-required="field.required" ng-disabled="field.disabled" ng-init="field.fieldValue = field.fieldOptions[0].option_value"/>
<span ng-bind="option.option_title"></span>
</label>
</div>
<span class="required-error" ng-show="field.required && !field.fieldValue">* required</span>

View file

@ -4,7 +4,7 @@
</div>
<div class="col-xs-10 col-xs-offset-2 field-title field-input">
<i class="fa fa-quote-left fa-3"></i>
<p>{{field.fieldValue}} </p>
<p>{{field.description}} </p>
<i class="fa fa-quote-right fa-3"></i>
</div>
</div>

View file

@ -30,9 +30,10 @@
<div class="col-xs-10">
<accordion close-others="accordion.oneAtATime" ui-sortable="dropzone" ng-model="myform.form_fields" class="dropzone">
<accordion-group ng-repeat="field in myform.form_fields" is-open="accordion[$index].isOpen" on-finish-render="setFormValid()">
<accordion-group ng-repeat="field in myform.form_fields" is-open="accordion[$index].isOpen" on-finish-render="setFormValid()" ng-show="!field.deletePreserved">
<accordion-heading>
<div class="handle">
<span class="pull-left" ng-switch="field.fieldType">
<field-icon-directive type-name="{{field.fieldType}}"></field-icon-directive>
@ -46,7 +47,6 @@
</span>
</div>
</accordion-heading>
<div class="accordion-edit container">
<div class="row">
<div class="col-xs-12">
@ -55,7 +55,7 @@
</div>
<div class="row">
<ul class="col-xs-4 container" style="list-style:none;border:2px lightgray solid;">
<field-directive field="field" required="">
<field-directive field="field">
</field-directive>
</ul>
</div>
@ -70,6 +70,10 @@
<div class="col-xs-2">Field Title:</div>
<div class="col-xs-4"><input type="text" ng-model="field.title" value="{{field.title}}" required></div>
</div>
<div class="row">
<div class="col-xs-2">Field Decription:</div>
<div class="col-xs-4"><textarea type="text" ng-model="field.title" value="{{field.description}}"></textarea> </div>
</div>
<br><br>
<hr>
<div class="row" ng-show="showAddOptions(field)">
@ -116,8 +120,7 @@
</label>
</div>
</div>
<hr>
<hr>
</div>
</accordion-group>
@ -133,7 +136,7 @@
</div>
<div class="col-xs-1" style="padding:0 5px;" >
<div class="panel-group tool-panel text-center">
<div class="panel panel-default" ng-repeat="field in myform.form_fields">
<div class="panel panel-default" ng-repeat="field in myform.form_fields" ng-if="!field.deletePreserved">
<div class="panel-heading" style="padding: 10px 10px; height: 37px;" ng-click="deleteField(field.$$hashKey)">
<span class="text-center">
<a href="" class="fa fa-trash-o"></a>
@ -144,7 +147,7 @@
</div>
<div class="col-xs-1" style="padding:0 5px;">
<div class="panel-group tool-panel text-center">
<div class="panel panel-default" ng-repeat="field in myform.form_fields">
<div class="panel panel-default" ng-repeat="field in myform.form_fields" ng-if="!field.deletePreserved">
<div class="panel-heading" style="padding: 10px 10px; height: 37px;" ng-click="duplicateField(field, $index)">
<span class="text-center">
<a href="" class="fa fa-files-o"></a>

View file

@ -1,26 +1,22 @@
<div ng-hide="form.submitted">
<div class="field row">
<div class="col-sm-10 col-sm-offset-1"><h1>{{ form.title }}</h1>
<hr>
<div class="field row" style="padding-bottom:5em;">
<div class="col-sm-10 col-sm-offset-1">
<h1>{{ form.title }}</h1>
<hr>
</div>
</div>
<br>
<br>
<div class="row">
<form name="form" class="submission-form col-sm-offset-1 col-sm-10" name="form" ng-model="form" ng-repeat="field in form.form_fields" >
<field-directive field="field">
<field-directive field="field" ng-if="!field.deletePreserved">
</field-directive>
</form>
</div>
<hr>
<div class="row form-actions">
<button class="btn btn-success col-sm-2 col-sm-offset-5" type="button" ng-disabled="myForm.$valid" ng-click="submit()" style="font-size: 1.6em;">
<button class="btn btn-success col-sm-2 col-sm-offset-5" type="button" ng-disabled="myForm.$valid" ng-click="submit()" style="font-size: 1.6em;">
<i class="icon-edit icon-white"></i> submit
</button>
</button>
</div>
</div>
@ -50,10 +46,4 @@
</button>
</p>
</div>
<!-- <div ng-repeat="field in form.form_fields">
Field Title: {{ field.title }} <br>
Field Value: {{ field.fieldValue }} <br><br>
</div> -->
</div>

View file

@ -33,9 +33,8 @@
Language
</div>
<div class="col-xs-5 field-input">
<select style="color:black;" name="language" required ng-model="formLanguage">
<option ng-repeat="language in languages"
value="{{language}}" ng-selected="language == formLanguage">
<select style="color:black;" name="language" required ng-model="formLanguage" ng-init="formLanguage = user.language">
<option ng-repeat="language in languages" value="{{language}}">
{{language}}
</option>
</select>

View file

@ -46,6 +46,13 @@
View Submissions
</tab-heading>
<div class="submissions-table" ng-show="viewSubmissions">
<div class="row">
<div class="col-xs-1">
<button class="btn btn-danger" ng-click="deleteSelectedSubmissions()" ng-disabled="!isAtLeastOneChecked();"><i class="fa fa-trash-o"></i> Delete Selected</button>
</div>
</div>
<table class="table table-striped table-hover table-condensed">
<thead>
<tr>
@ -83,7 +90,7 @@
{{row.created | date:'yyyy-MM-dd HH:mm:ss'}}
</td>
<td ng-if="row.pdf">
<a href="{{row.pdf.path}}">Generated PDF</a>
<a href="{{row.pdfFilePath}}" download="{{row.pdf.name}}" target="_self">Generated PDF</a>
</td>
</tr>
</tbody>
@ -93,51 +100,4 @@
</tabset>
<!-- </div> -->
</div>
<!-- <div class="row">
<div class="col-xs-8">
<div>
<edit-form-directive form="form" user="user"></edit-form-directive>
<p ng-show="form.form_fields.length == 0">No fields added yet.</p>
</p>
<accordion class="col-xs-10" close-others="accordion.oneAtATime">
<accordion-group heading="{{field.title}} (is a {{field.fieldType}})" ng-repeat="field in form.form_fields">
</accordion-group>
</accordion>
</div>
</div>
<div class="col-xs-3 col-xs-offset-1 container text-right form-controls" data-ng-show="authentication.user._id == form.user._id">
<div class="row">
<a class="col-xs-12 btn btn-default" href="/#!/forms/{{form._id}}/edit">
<i class="glyphicon glyphicon-edit"></i> Edit Form
</a>
</div>
<div class="row">
<a class="col-xs-12 btn btn-danger" data-ng-click="remove();">
<i class="glyphicon glyphicon-trash"></i> Delete Form
</a>
</div>
<div class="row">
<a class="col-xs-12 btn btn-default" data-ng-click="showSubmissions();" ng-hide="viewSubmissions">
View Form Submissions
</a>
<a class="col-xs-12 btn btn-primary" data-ng-click="hideSubmissions();" ng-show="viewSubmissions">
Back to Main View
</a>
</div>
</div>
</div>
-->
<!-- <div class="row">
<small class="col-xs-12">
<em class="text-muted">
Created on
<span data-ng-bind="form.created | date:'mediumDate'"></span>
by
<span data-ng-bind="form.admin.displayName"></span>
</em>
</small>
</div> -->
<!-- <p class="lead" data-ng-bind="form.content"></p> -->
</section>

View file

@ -1,22 +1,23 @@
<link rel="stylesheet" href="./modules/forms/css/form.css">
<section data-ng-controller="SubmitFormController">
<section data-ng-controller="SubmitFormController" class="public-form">
<form-directive form="form"></form-directive>
<section ng-if="!form.hideFooter" class="navbar navbar-fixed-bottom" style="background-color:rgba(242,242,242,0.5); padding-top:15px;">
<div class="container" >
<nav role="navigation">
<ul class="nav navbar-nav navbar-left" >
<li class="">
<!-- <p class="lead">{{form | formValidity}} out of {{form.form_fields.length}} answered</p> -->
<li ng-show="!form.submitted">
<p class="lead">{{form | formValidity}} out of {{form.visible_form_fields.length}} answered</p>
</li>
</ul>
<ul class="nav navbar-nav navbar-right">
<li style="padding-right:20px" >
<a href="/forms/create" class="btn btn-default" ng-hide="authentication.user">create a Medform</a>
<a href="/#!/forms" class="btn btn-default" ng-hide="authentication.isAuthenticated()">create a Medform</a>
</li>
<li style="padding-right:20px" ng-show="authentication.user">
<a href="/forms/{{form._id}}/edit" class="btn btn-default">edit this Medform</a>
<li style="padding-right:20px" ng-show="authentication.isAuthenticated()">
<a href="/#!/forms/{{form._id}}/admin" class="btn btn-default">edit this Medform</a>
</li>
<li style="padding-left:5px">
<div class="btn btn-info" id="focusDownButton">\/</div>

View file

@ -6,7 +6,7 @@ angular.module('users').config(['$httpProvider',
$httpProvider.interceptors.push(function($q, $location) {
return {
responseError: function(response) {
if( $location.path() !== '/users/me' && $location.path() !== '/'){
if( $location.path() !== '/users/me' && $location.path() !== '/' && $location.path() !== '/signup' && response.config){
console.log('intercepted rejection of ', response.config.url, response.status);
if (response.status === 401) {

View file

@ -30,10 +30,6 @@ angular.module('users').config(['$stateProvider',
// Users state routing
$stateProvider.
state('profile', {
// parent: 'restricted',
// data: {
// roles: ['user', 'admin'],
// },
resolve: {
loggedin: checkLoggedin
},
@ -41,13 +37,6 @@ angular.module('users').config(['$stateProvider',
templateUrl: 'modules/users/views/settings/edit-profile.client.view.html'
}).
state('password', {
// resolve: {
// checkLoggedin: Authorization.authorize
// },
// parent: 'restricted',
// data: {
// roles: ['user', 'admin'],
// },
resolve: {
loggedin: checkLoggedin
},
@ -55,10 +44,6 @@ angular.module('users').config(['$stateProvider',
templateUrl: 'modules/users/views/settings/change-password.client.view.html'
}).
state('accounts', {
// parent: 'restricted',
// data: {
// roles: ['user', 'admin'],
// },
resolve: {
loggedin: checkLoggedin
},
@ -83,6 +68,15 @@ angular.module('users').config(['$stateProvider',
templateUrl: 'modules/users/views/authentication/access-denied.client.view.html'
}).
state('resendVerifyEmail', {
url: '/verify',
templateUrl: 'modules/users/views/verify/resend-verify-email.client.view.html'
}).
state('verify', {
url: '/verify/:token',
templateUrl: 'modules/users/views/verify/verify-account.client.view.html'
}).
state('forgot', {
url: '/password/forgot',
templateUrl: 'modules/users/views/password/forgot-password.client.view.html'

View file

@ -3,104 +3,66 @@
angular.module('users').controller('AuthenticationController', ['$scope', '$location', '$state', '$rootScope', 'User', 'Auth',
function($scope, $location, $state, $rootScope, User, Auth) {
$scope = $rootScope;
$scope.credentials = {};
$scope.error = null;
$scope = $rootScope;
$scope.credentials = {};
$scope.error = null;
// If user is signed in then redirect back home
if ($scope.authentication.isAuthenticated()) $state.go('home');
// If user is signed in then redirect back home
if ($scope.authentication.isAuthenticated()) $state.go('home');
$scope.signin = function() {
Auth.currentUser = User.login($scope.credentials).then(
function(response) {
Auth.login(response);
$scope.user = $rootScope.user = Auth.ensureHasCurrentUser(User);
$scope.signin = function() {
Auth.currentUser = User.login($scope.credentials).then(
function(response) {
Auth.login(response);
$scope.user = $rootScope.user = Auth.ensureHasCurrentUser(User);
if($state.previous.name !== 'home' && $state.previous.name !== ''){
$state.go($state.previous.name);
}else{
$state.go('home');
if($state.previous.name !== 'home' && $state.previous.name !== ''){
$state.go($state.previous.name);
}else{
$state.go('home');
}
},
function(error) {
$rootScope.user = Auth.ensureHasCurrentUser(User);
$scope.user = $rootScope.user;
$scope.error = error;
console.log('loginError: '+error);
}
},
function(error) {
$rootScope.user = Auth.ensureHasCurrentUser(User);
$scope.user = $rootScope.user;
);
};
$scope.error = error;
console.log('loginError: '+error);
}
);
};
$scope.signup = function() {
User.signup($scope.credentials).then(
function(response) {
console.log('signup-success');
$state.go('signup-success');
},
function(error) {
if(error) {
$scope.error = error;
}else {
console.log('No response received');
}
}
);
};
$scope.signup = function() {
User.signup($scope.credentials).then(
function(response) {
console.log('signup-success');
$state.go('signup-success');
},
function(error) {
if(error) {
$scope.error = error;
}else {
console.log('No response received');
}
}
);
};
// $scope.signup = function() {
// Principal.signup($scope.credentials).then(
// function(result){
// $state.go('home');
// },
// function(rejection_reason){
// $scope.error = rejection_reason;
// }
// );
// // $http.post('/auth/signup', $scope.credentials).success(function(response) {
// // // If successful we assign the response to the global user model
// // $scope.authentication.user = response;
// // Principal.authenticate(response);
// Submit forgotten password account id
$scope.resendVerifyEmail = function() {
User.resendVerifyEmail($scope.email).then(
function(response){
$scope.success = response.message;
$scope.credentials = null;
},
function(error){
$scope.error = error;
$scope.credentials = null;
}
);
};
// // // And redirect to the index page
// // $location.path('/');
// // }).error(function(response) {
// // $scope.error = response.message;
// // });
// };
// $scope.signin = function() {
// console.log('signin');
// Principal.signin($scope.credentials).then(
// function(result){
// $state.go('home');
// },
// function(rejection_reason){
// $scope.error = rejection_reason;
// }
// );
// // var response_obj = Principal.signin($scope.credentials);
// // if( angular.isDefined(response_obj.error) ){
// // $scope.error = response_obj.error;
// // $location.path('/signin');
// // } else{
// // $location.path('/');
// // }
// // $http.post('/auth/signin', $scope.credentials).success(function(response) {
// // // If successful we assign the response to the global user model
// // $scope.authentication.user = response;
// // Principal.authenticate(response);
// // // And redirect to the index page
// // $location.path('/');
// // }).error(function(response) {
// // Principal.authenticate(null);
// // $scope.error = response.message;
// // });
// };
// }
}
]);

View file

@ -1,47 +0,0 @@
// 'use strict';
// angular.module('users').factory('Authorization', ['$rootScope', '$http', '$q', '$state', 'Principal',
// function($rootScope, $http, $q, $state, Principal) {
// var service = {
// authorize: function(){
// var deferred = $q.defer();
// $http.get('/user/me').success(function(response) {
// //user is logged in
// if(response.data !== null){
// deferred.resolve();
// }else {
// $rootScope.message = 'You need to log in.';
// deferred.reject();
// $state.go('/login');
// }
// });
// return deferred.promise();
// }
// };
// return service;
// // this.authorize = function() {
// // return Principal.identity().then(function(){
// // var isAuthenticated = Principal.isAuthenticated();
// // if( angular.isDefined($rootScope.toState.data) ){
// // // if ($rootScope.toState.data.roles && $rootScope.toState.data.roles.length > 0 && !principal.isInAnyRole($rootScope.toState.data.roles)) {
// // if (!isAuthenticated){ //$location.path('/access_denied'); // user is signed in but not authorized for desired state
// // // console.log('isAuthenticated: '+isAuthenticated);
// // // else {
// // // user is not authenticated. so the state they wanted before you
// // // send them to the signin state, so you can return them when you're done
// // $rootScope.returnToState = $rootScope.toState;
// // $rootScope.returnToStateParams = $rootScope.toStateParams;
// // // now, send them to the signin state so they can log in
// // $location.path('/signin');
// // }
// // // }
// // }
// // });
// // };
// }
// ]);

View file

@ -54,6 +54,18 @@ angular.module('users').factory('User', ['$window', '$q', '$timeout', '$http', '
return deferred.promise;
},
resendVerifyEmail: function(email) {
var deferred = $q.defer();
$http.post('/auth/verify/'+token, email).success(function(response) {
deferred.resolve();
}).error(function(error) {
deferred.reject(error.message || error);
});
return deferred.promise;
},
resetPassword: function(passwordDetails, token) {
var deferred = $q.defer();
$http.get('/auth/password/'+token, passwordDetails).success(function(response) {

View file

@ -38,11 +38,6 @@
<label for="email">Email</label>
<input type="email" id="email" name="email" class="form-control" data-ng-model="credentials.email" placeholder="Email">
</div>
<div class="form-group">
<label for="username">Username</label>
<input type="text" id="username" name="username" class="form-control" data-ng-model="credentials.username" placeholder="Username">
</div>
<hr>
<div class="form-group">
<label for="password">Password</label>
<input type="password" id="password" name="password" class="form-control" data-ng-model="credentials.password" placeholder="Password">

View file

@ -0,0 +1,22 @@
<section class="auth row" data-ng-controller="VerifyController">
<h3 class="col-md-12 text-center">Resend your account verification email</h3>
<p class="small text-center">Enter your account email.</p>
<div class="col-xs-offset-2 col-xs-8 col-md-offset-3 col-md-6">
<form data-ng-submit="resendVerifyEmail()" class="signin form-horizontal" autocomplete="off">
<fieldset>
<div class="form-group">
<input type="text" id="username" name="email" class="form-control" data-ng-model="email" placeholder="bob@example.com">
</div>
<div class="text-center form-group">
<button type="submit" class="btn btn-primary">Submit</button>
</div>
<div data-ng-show="error" class="text-center text-danger">
<strong>{{error}}</strong>
</div>
<div data-ng-show="success" class="text-center text-success">
<strong>{{success}}</strong>
</div>
</fieldset>
</form>
</div>
</section>

View file

@ -0,0 +1,14 @@
<section class="row text-center" data-ng-controller="VerifyController" ng-init="validateVerifyToken()">
<section class="row text-center" ng-if="success">
<h3 class="col-md-12">Password successfully reset</h3>
<a href="/#!/" class="col-md-12">Continue to home page</a>
</section>
<section class="row text-center" ng-if="!success">
<h3 class="col-md-12">Verification link is invalid or has expired</h3>
<a href="/#!/verify" class="col-md-6">Resend your verification email</a>
<a href="/#!/signin" class="col-md-6">Signin to your account</a>
</section>
</section>

20
test.js Normal file
View file

@ -0,0 +1,20 @@
var nodemailer = require('nodemailer'),
config = require('./config/config');
console.log('Start script');
var transporter = nodemailer.createTransport(config.mailer.options);
var verifyMailOptions = {
to: '1nsphq+9hg2ghgtblstc@sharklasers.com',
from: 'Do Not Reply <user@gmail.com>',
subject: 'Confirm your account',
html: '<p>Please verify your account by clicking <a href="${URL}">this link</a>. If you are unable to do so, copy and ' +
'paste the following link into your browser:</p><p>${URL}</p>',
text: 'Please verify your account by clicking the following link, or by copying and pasting it into your browser: ${URL}'
};
transporter.sendMail(verifyMailOptions , function(err, info){
if (err) console.log(err.message);
else console.log(info.response);
});