diff --git a/app/controllers/forms.server.controller.js b/app/controllers/forms.server.controller.js index 6348c1c8..ae20ad36 100644 --- a/app/controllers/forms.server.controller.js +++ b/app/controllers/forms.server.controller.js @@ -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; diff --git a/app/controllers/users/users.authentication.server.controller.js b/app/controllers/users/users.authentication.server.controller.js index b936ccda..a71e71b1 100755 --- a/app/controllers/users/users.authentication.server.controller.js +++ b/app/controllers/users/users.authentication.server.controller.js @@ -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: '

Please verify your account by clicking this link. If you are unable to do so, copy and ' + + 'paste the following link into your browser:

${URL}

', + 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: '

Your account has been successfully verified.

', + 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'} ); + } }); }; diff --git a/app/controllers/users/users.verify.server.controller.js b/app/controllers/users/users.verify.server.controller.js new file mode 100644 index 00000000..5e1455ad --- /dev/null +++ b/app/controllers/users/users.verify.server.controller.js @@ -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; + } + ); + }; + + } +]); \ No newline at end of file diff --git a/app/models/form.server.model.js b/app/models/form.server.model.js index c31b74a4..aa9d11b2 100644 --- a/app/models/form.server.model.js +++ b/app/models/form.server.model.js @@ -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 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'), diff --git a/app/models/form_field.server.model.js b/app/models/form_field.server.model.js index 796b3293..8a034b40 100644 --- a/app/models/form_field.server.model.js +++ b/app/models/form_field.server.model.js @@ -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', diff --git a/app/models/form_submission.server.model.js b/app/models/form_submission.server.model.js index b9336db2..531abdee 100644 --- a/app/models/form_submission.server.model.js +++ b/app/models/form_submission.server.model.js @@ -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(); + } }); diff --git a/app/models/user.server.model.js b/app/models/user.server.model.js index 2ae755af..e97e385a 100755 --- a/app/models/user.server.model.js +++ b/app/models/user.server.model.js @@ -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; diff --git a/app/routes/forms.server.routes.js b/app/routes/forms.server.routes.js index 36a2da37..e4b60589 100644 --- a/app/routes/forms.server.routes.js +++ b/app/routes/forms.server.routes.js @@ -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); diff --git a/app/routes/users.server.routes.js b/app/routes/users.server.routes.js index 48fb4d6a..a4460461 100755 --- a/app/routes/users.server.routes.js +++ b/app/routes/users.server.routes.js @@ -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); diff --git a/app/tests/article.server.model.test.js b/app/tests/article.server.model.test.js index b4b76b8a..3b6ad3f2 100755 --- a/app/tests/article.server.model.test.js +++ b/app/tests/article.server.model.test.js @@ -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); +// }); +// }); +// }); diff --git a/app/tests/article.server.routes.test.js b/app/tests/article.server.routes.test.js index c583c3f3..5dcf929f 100755 --- a/app/tests/article.server.routes.test.js +++ b/app/tests/article.server.routes.test.js @@ -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); +// }); +// }); +// }); diff --git a/app/tests/form.server.model.test.js b/app/tests/form.server.model.test.js index afc1263d..c8d86e74 100644 --- a/app/tests/form.server.model.test.js +++ b/app/tests/form.server.model.test.js @@ -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) { diff --git a/config/env/all.js b/config/env/all.js index 986863a2..67df6bd9 100755 --- a/config/env/all.js +++ b/config/env/all.js @@ -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', diff --git a/config/env/development.js b/config/env/development.js index af9f27d9..caea8d69 100755 --- a/config/env/development.js +++ b/config/env/development.js @@ -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' } } } diff --git a/config/express.js b/config/express.js index 445d75b7..d7d12769 100755 --- a/config/express.js +++ b/config/express.js @@ -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 diff --git a/karma.conf.js b/karma.conf.js index f20106f0..effde2de 100755 --- a/karma.conf.js +++ b/karma.conf.js @@ -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, diff --git a/package.json b/package.json index 32e885eb..e3f3fe4c 100644 --- a/package.json +++ b/package.json @@ -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", diff --git a/public/dist/application.min.css b/public/dist/application.min.css index aaa3ce7c..5baa926a 100644 --- a/public/dist/application.min.css +++ b/public/dist/application.min.css @@ -1 +1 @@ -.navbar-inverse{background-color:#fafafa;border:0}.navbar .navbar-brand{font-size:1.6em;font-weight:900;color:#ff8383}.navbar .navbar-brand:hover,.navbar .navbar-brand:visited{color:#FA787E}.navbar li.dropdown a.dropdown-toggle:hover>*{color:#000}.navbar li.dropdown a.dropdown-toggle>*{color:#d9d9d9}.navbar li.dropdown.open a.dropdown-toggle:hover>*{color:#fff}.navbar .navbar-brand span{text-decoration:underline}.nav.navbar-nav.navbar-right li{padding-right:20px}.content{margin-top:70px}.undecorated-link:hover{text-decoration:none}.ng-cloak,.x-ng-cloak,[data-ng-cloak],[ng-cloak],[ng\:cloak],[x-ng-cloak]{display:none!important}.ng-invalid.ng-dirty{border-color:#FA787E}.ng-valid.ng-dirty{border-color:#78FA89}.browsehappy.jumbotron.hide,body.ng-cloak{display:block}section.hero-section{width:100%}section.hero-section .jumbotron{background-color:transparent;color:#fff}.image-background{position:absolute;top:0;left:0;height:230%;width:100%;z-index:-98;background-image:url(http://yourplaceandmine.ie/wp-content/uploads/2014/09/Daingean-meeting-048_13-1080x675.jpg);background-repeat:no-repeat;background-position:0 50%;background-size:cover}.opacity-background{position:absolute;top:0;left:0;height:230%;width:100%;background-color:rgba(0,0,0,.5);z-index:-97}section.hero-section .jumbotron .signup-btn{background-color:#FA787E;border:none;font-size:2em;padding:.3em .9em;color:#fff;background-color:rgba(250,120,126,.65) #FA787E}.row-height{display:table;table-layout:fixed;height:100%;width:100%}.col-height{display:table-cell;float:none;height:100%}.col-top{vertical-align:top}.col-middle{vertical-align:middle}.col-bottom{vertical-align:bottom}@media (min-width:480px){.row-xs-height{display:table;table-layout:fixed;height:100%;width:100%}.col-xs-height{display:table-cell;float:none;height:100%}.col-xs-top{vertical-align:top}.col-xs-middle{vertical-align:middle}.col-xs-bottom{vertical-align:bottom}}@media (min-width:768px){.row-sm-height{display:table;table-layout:fixed;height:100%;width:100%}.col-sm-height{display:table-cell;float:none;height:100%}.col-sm-top{vertical-align:top}.col-sm-middle{vertical-align:middle}.col-sm-bottom{vertical-align:bottom}}@media (min-width:992px){.row-md-height{display:table;table-layout:fixed;height:100%;width:100%}.col-md-height{display:table-cell;float:none;height:100%}.col-md-top{vertical-align:top}.col-md-middle{vertical-align:middle}.col-md-bottom{vertical-align:bottom}}@media (min-width:1200px){.row-lg-height{display:table;table-layout:fixed;height:100%;width:100%}.col-lg-height{display:table-cell;float:none;height:100%}.col-lg-top{vertical-align:top}.col-lg-middle{vertical-align:middle}.col-lg-bottom{vertical-align:bottom}}form .row.field{padding:1em 0 3em}form .row.field>.field-title{margin-top:.5em;font-size:1.5em}form.submission-form .row.field.statement>.field-title{font-size:1.7em}form.submission-form .row.field.statement>.field-input{font-size:1.2em;color:#ddd}form.submission-form .row.field>.field-input input{width:500px}form.submission-form .row.field .field-input>input:focus{font-size:1em}form .row.field.textfield>.field-input>input{padding:.45em .9em;width:600px}div.config-form>.row{padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #e3e3e3;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.05);box-shadow:inset 0 1px 1px rgba(0,0,0,.05);width:90%}div.config-form>.row>.container:nth-of-type(odd){border-right:1px #ddd solid}div.config-form .row>.field-input{padding-top:1.2em;padding-left:.1em}div.config-form .row>.field-input label{padding-left:1.3em;display:block}.admin-form>.page-header{padding-bottom:0;margin-bottom:40px}.admin-form>.page-header h1{margin-bottom:0}.admin-form>.page-header>.col-xs-3{padding-top:1.4em}.admin-form .form-controls .row{padding:5px}.admin-form .page-header{border:none}.admin-form .tab-content{padding-top:3em}.admin-form .panel-heading{background-color:#f1f1f1}.admin-form .panel-heading:hover{background-color:#fff;cursor:pointer}.admin-form .panel-heading a:hover{text-decoration:none}.current-fields .tool-panel>.panel-default:hover{border-color:#9d9d9d;cursor:pointer}.current-fields .tool-panel>.panel-default .panel-heading{background-color:#fff;color:#9d9d9d!important}.current-fields .tool-panel>.panel-default .panel-heading:hover{background-color:#eee;color:#000!important;cursor:pointer}.current-fields .tool-panel>.panel-default .panel-heading a{color:inherit}.current-fields .tool-panel>.panel-default .panel-heading a:hover{text-decoration:none}.admin-form .add-field{background-color:#ddd}.admin-form .add-field .col-xs-6{padding:.25em .4em}.admin-form .add-field .col-xs-6 .panel-heading{border-width:1px;border-style:solid;border-color:#bbb;border-radius:4px}.status-light{padding-left:.6em}.status-light.status-light-off{color:#BE0000}.status-light.status-light-on{color:#3C0}section>section.ng-scope{padding:0 60px 20px}.form-item.row{text-align:center;border-bottom:6px inset #ccc;background-color:#eee;width:180px;height:215px;margin-bottom:45px}.form-item.row.create-new{background-color:#838383;color:#fff}.form-item.row.create-new.new-form{background-color:#ff8383;z-index:11}.form-item.row.create-new.new-form:hover{background-color:#ff6464}.form-item.new-form a.btn{font-size:.95em}.overlay{position:absolute;top:0;left:0;height:193%;width:inherit;background-color:rgba(0,0,0,.5);z-index:10}.form-item.row.create-new:hover,.form-item.row:hover{border-bottom:8px inset #ccc;background-color:#d9d9d9}.form-item.row.create-new:hover{background-color:#515151}.form-item.row>.title-row{position:relative;top:15px;padding-top:3em;padding-bottom:3.65em}.form-item.row>.title-row h4{font-size:1.3em}.form-item.row.create-new>.title-row{padding:0}.form-item.row.create-new>.title-row h4{font-size:7em}.form-item.row>.details-row{margin-top:3.2em}.form-item.row>.details-row small{font-size:.6em}.form-item.row.create-new>.details-row small{font-size:.95em}@media (min-width:992px){.nav-users{position:fixed}}.remove-account-container{display:inline-block;position:relative}.btn-remove-account{top:10px;right:10px;position:absolute}section.auth{margin-top:5em}section.auth>h3{font-size:3em;font-weight:500;color:#777}section.auth.signup-view>h3{font-size:4.4em;padding-bottom:.5em} \ No newline at end of file +.navbar-inverse{background-color:#fafafa;border:0}.navbar .navbar-brand{font-size:1.6em;font-weight:900;color:#ff8383}.navbar .navbar-brand:hover,.navbar .navbar-brand:visited{color:#FA787E}.navbar li.dropdown a.dropdown-toggle:hover>*{color:#000}.navbar li.dropdown a.dropdown-toggle>*{color:#d9d9d9}.navbar li.dropdown.open a.dropdown-toggle:hover>*{color:#fff}.navbar .navbar-brand span{text-decoration:underline}.nav.navbar-nav.navbar-right li{padding-right:20px}.content{margin-top:70px}.undecorated-link:hover{text-decoration:none}.ng-cloak,.x-ng-cloak,[data-ng-cloak],[ng-cloak],[ng\:cloak],[x-ng-cloak]{display:none!important}.ng-invalid.ng-dirty{border-color:#FA787E}.ng-valid.ng-dirty{border-color:#78FA89}.browsehappy.jumbotron.hide,body.ng-cloak{display:block}section.hero-section{width:100%}section.hero-section .jumbotron{background-color:transparent;color:#fff}.image-background{position:absolute;top:0;left:0;height:230%;width:100%;z-index:-98;background-image:url(http://yourplaceandmine.ie/wp-content/uploads/2014/09/Daingean-meeting-048_13-1080x675.jpg);background-repeat:no-repeat;background-position:0 50%;background-size:cover}.opacity-background{position:absolute;top:0;left:0;height:230%;width:100%;background-color:rgba(0,0,0,.5);z-index:-97}section.hero-section .jumbotron .signup-btn{background-color:#FA787E;border:none;font-size:2em;padding:.3em .9em;color:#fff;background-color:rgba(250,120,126,.65) #FA787E}.row-height{display:table;table-layout:fixed;height:100%;width:100%}.col-height{display:table-cell;float:none;height:100%}.col-top{vertical-align:top}.col-middle{vertical-align:middle}.col-bottom{vertical-align:bottom}@media (min-width:480px){.row-xs-height{display:table;table-layout:fixed;height:100%;width:100%}.col-xs-height{display:table-cell;float:none;height:100%}.col-xs-top{vertical-align:top}.col-xs-middle{vertical-align:middle}.col-xs-bottom{vertical-align:bottom}}@media (min-width:768px){.row-sm-height{display:table;table-layout:fixed;height:100%;width:100%}.col-sm-height{display:table-cell;float:none;height:100%}.col-sm-top{vertical-align:top}.col-sm-middle{vertical-align:middle}.col-sm-bottom{vertical-align:bottom}}@media (min-width:992px){.row-md-height{display:table;table-layout:fixed;height:100%;width:100%}.col-md-height{display:table-cell;float:none;height:100%}.col-md-top{vertical-align:top}.col-md-middle{vertical-align:middle}.col-md-bottom{vertical-align:bottom}}@media (min-width:1200px){.row-lg-height{display:table;table-layout:fixed;height:100%;width:100%}.col-lg-height{display:table-cell;float:none;height:100%}.col-lg-top{vertical-align:top}.col-lg-middle{vertical-align:middle}.col-lg-bottom{vertical-align:bottom}}.btn{border:1px solid #c6c6c6!important}form .row.field{padding:1em 0 3em}form .row.field>.field-title{margin-top:.5em;font-size:1.5em}form.submission-form .row.field.statement>.field-title{font-size:1.7em}form.submission-form .row.field.statement>.field-input{font-size:1.2em;color:#ddd}form.submission-form .select.radio>.field-input input,form.submission-form .select>.field-input input{width:20%}form.submission-form .select>.field-input .btn{text-align:left;margin-bottom:.7em}form.submission-form .select>.field-input .btn>span{font-size:1.1em}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:.45em .9em;width:100%;line-height:160%}form .row.field.dropdown>.field-input{height:34px;overflow:hidden}form .row.field.dropdown>.field-input>select{padding:.45em .9em;width:100%;background:0 0;font-size:16px;border:1px solid #ccc;height:34px}div.config-form>.row{padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #e3e3e3;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.05);box-shadow:inset 0 1px 1px rgba(0,0,0,.05);width:90%}div.config-form>.row>.container:nth-of-type(odd){border-right:1px #ddd solid}div.config-form .row>.field-input{padding-top:1.2em;padding-left:.1em}div.config-form .row>.field-input label{padding-left:1.3em;display:block}.admin-form>.page-header{padding-bottom:0;margin-bottom:40px}.admin-form>.page-header h1{margin-bottom:0}.admin-form>.page-header>.col-xs-3{padding-top:1.4em}.admin-form .form-controls .row{padding:5px}.admin-form .page-header{border:none}.admin-form .tab-content{padding-top:3em}.admin-form .panel-heading{background-color:#f1f1f1}.admin-form .panel-heading:hover{background-color:#fff;cursor:pointer}.admin-form .panel-heading a:hover{text-decoration:none}.current-fields .tool-panel>.panel-default:hover{border-color:#9d9d9d;cursor:pointer}.current-fields .tool-panel>.panel-default .panel-heading{background-color:#fff;color:#9d9d9d!important}.current-fields .tool-panel>.panel-default .panel-heading:hover{background-color:#eee;color:#000!important;cursor:pointer}.current-fields .tool-panel>.panel-default .panel-heading a{color:inherit}.current-fields .tool-panel>.panel-default .panel-heading a:hover{text-decoration:none}.admin-form .add-field{background-color:#ddd}.admin-form .add-field .col-xs-6{padding:.25em .4em}.admin-form .add-field .col-xs-6 .panel-heading{border-width:1px;border-style:solid;border-color:#bbb;border-radius:4px}.status-light{padding-left:.6em}.status-light.status-light-off{color:#BE0000}.status-light.status-light-on{color:#3C0}section>section.ng-scope{padding:0 60px 20px}.form-item.row{text-align:center;border-bottom:6px inset #ccc;background-color:#eee;width:180px;height:215px;margin-bottom:45px}.form-item.row.create-new{background-color:#838383;color:#fff}.form-item.row.create-new.new-form{background-color:#ff8383;z-index:11}.form-item.row.create-new.new-form:hover{background-color:#ff6464}.form-item.new-form a.btn{font-size:.95em}.overlay{position:absolute;top:0;left:0;height:193%;width:inherit;background-color:rgba(0,0,0,.5);z-index:10}.form-item.row.create-new:hover,.form-item.row:hover{border-bottom:8px inset #ccc;background-color:#d9d9d9}.form-item.row.create-new:hover{background-color:#515151}.form-item.row>.title-row{position:relative;top:15px;padding-top:3em;padding-bottom:3.65em}.form-item.row>.title-row h4{font-size:1.3em}.form-item.row.create-new>.title-row{padding:0}.form-item.row.create-new>.title-row h4{font-size:7em}.form-item.row>.details-row{margin-top:3.2em}.form-item.row>.details-row small{font-size:.6em}.form-item.row.create-new>.details-row small{font-size:.95em}@media (min-width:992px){.nav-users{position:fixed}}.remove-account-container{display:inline-block;position:relative}.btn-remove-account{top:10px;right:10px;position:absolute}section.auth{margin-top:5em}section.auth>h3{font-size:3em;font-weight:500;color:#777}section.auth.signup-view>h3{font-size:4.4em;padding-bottom:.5em} \ No newline at end of file diff --git a/public/modules/forms/config/forms.client.config.js b/public/modules/forms/config/forms.client.config.js index 4086df08..6478eb1d 100644 --- a/public/modules/forms/config/forms.client.config.js +++ b/public/modules/forms/config/forms.client.config.js @@ -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) { diff --git a/public/modules/forms/config/forms.client.routes.js b/public/modules/forms/config/forms.client.routes.js index a2ebdc1c..5ec819c4 100644 --- a/public/modules/forms/config/forms.client.routes.js +++ b/public/modules/forms/config/forms.client.routes.js @@ -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', }); } ]); \ No newline at end of file diff --git a/public/modules/forms/controllers/create-form.client.controller.js b/public/modules/forms/controllers/create-form.client.controller.js deleted file mode 100644 index d636315c..00000000 --- a/public/modules/forms/controllers/create-form.client.controller.js +++ /dev/null @@ -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); -// }); -// }; -// } -// ]); diff --git a/public/modules/forms/controllers/view-form-submission.client.controller.js b/public/modules/forms/controllers/view-form-submission.client.controller.js index fc45e136..24e74182 100644 --- a/public/modules/forms/controllers/view-form-submission.client.controller.js +++ b/public/modules/forms/controllers/view-form-submission.client.controller.js @@ -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..'); + }); + }; } ]); \ No newline at end of file diff --git a/public/modules/forms/controllers/view-form.client.controller.js b/public/modules/forms/controllers/view-form.client.controller.js index a9344488..b64c7f8a 100644 --- a/public/modules/forms/controllers/view-form.client.controller.js +++ b/public/modules/forms/controllers/view-form.client.controller.js @@ -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 .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; diff --git a/public/modules/forms/directives/auto-save.client.directive.js b/public/modules/forms/directives/auto-save.client.directive.js index 6fbc9711..52b7c8af 100644 --- a/public/modules/forms/directives/auto-save.client.directive.js +++ b/public/modules/forms/directives/auto-save.client.directive.js @@ -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); diff --git a/public/modules/forms/directives/change-focus.client.directive.js b/public/modules/forms/directives/change-focus.client.directive.js index c8116c13..ce86fabc 100644 --- a/public/modules/forms/directives/change-focus.client.directive.js +++ b/public/modules/forms/directives/change-focus.client.directive.js @@ -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 diff --git a/public/modules/forms/directives/configure-form.client.directive.js b/public/modules/forms/directives/configure-form.client.directive.js index ef3c1c73..ac34201c 100644 --- a/public/modules/forms/directives/configure-form.client.directive.js +++ b/public/modules/forms/directives/configure-form.client.directive.js @@ -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); }); - // } } }; diff --git a/public/modules/forms/directives/edit-form.client.directive.js b/public/modules/forms/directives/edit-form.client.directive.js index 689f457a..e89f30b9 100644 --- a/public/modules/forms/directives/edit-form.client.directive.js +++ b/public/modules/forms/directives/edit-form.client.directive.js @@ -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); }; diff --git a/public/modules/forms/directives/field.client.directive.js b/public/modules/forms/directives/field.client.directive.js index caa77296..c94d7947 100644 --- a/public/modules/forms/directives/field.client.directive.js +++ b/public/modules/forms/directives/field.client.directive.js @@ -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'){ diff --git a/public/modules/forms/directives/form.client.directive.js b/public/modules/forms/directives/submit-form.client.directive.js similarity index 85% rename from public/modules/forms/directives/form.client.directive.js rename to public/modules/forms/directives/submit-form.client.directive.js index aed747bd..3cf2cfac 100644 --- a/public/modules/forms/directives/form.client.directive.js +++ b/public/modules/forms/directives/submit-form.client.directive.js @@ -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:'=' diff --git a/public/modules/forms/services/forms.client.service.js b/public/modules/forms/services/forms.client.service.js index 2666a105..5294f3ad 100644 --- a/public/modules/forms/services/forms.client.service.js +++ b/public/modules/forms/services/forms.client.service.js @@ -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' diff --git a/public/modules/forms/views/directiveViews/field/checkbox.html b/public/modules/forms/views/directiveViews/field/checkbox.html index 012127b2..b5fa2ae0 100755 --- a/public/modules/forms/views/directiveViews/field/checkbox.html +++ b/public/modules/forms/views/directiveViews/field/checkbox.html @@ -1,7 +1,7 @@
{{field.title}}
- + (* required)
diff --git a/public/modules/forms/views/directiveViews/field/dropdown.html b/public/modules/forms/views/directiveViews/field/dropdown.html index b97dd331..2d9fd88d 100755 --- a/public/modules/forms/views/directiveViews/field/dropdown.html +++ b/public/modules/forms/views/directiveViews/field/dropdown.html @@ -1,4 +1,4 @@ - +
diff --git a/public/modules/forms/views/directiveViews/field/radio.html b/public/modules/forms/views/directiveViews/field/radio.html index d62ca3ba..d2128e3b 100755 --- a/public/modules/forms/views/directiveViews/field/radio.html +++ b/public/modules/forms/views/directiveViews/field/radio.html @@ -1,10 +1,10 @@ -
+
{{field.title}}
-
* required diff --git a/public/modules/forms/views/directiveViews/field/statement.html b/public/modules/forms/views/directiveViews/field/statement.html index e10e297f..8a8d3143 100644 --- a/public/modules/forms/views/directiveViews/field/statement.html +++ b/public/modules/forms/views/directiveViews/field/statement.html @@ -4,7 +4,7 @@
-

{{field.fieldValue}}

+

{{field.description}}

diff --git a/public/modules/forms/views/directiveViews/form/edit-form.html b/public/modules/forms/views/directiveViews/form/edit-form.html index 001e17b0..51103589 100644 --- a/public/modules/forms/views/directiveViews/form/edit-form.html +++ b/public/modules/forms/views/directiveViews/form/edit-form.html @@ -30,9 +30,10 @@
- + +
@@ -46,7 +47,6 @@
-
@@ -55,7 +55,7 @@
    - +
@@ -70,6 +70,10 @@
Field Title:
+
+
Field Decription:
+
+



@@ -116,8 +120,7 @@
-
- +
@@ -133,7 +136,7 @@
-
+
@@ -144,7 +147,7 @@
-
+
diff --git a/public/modules/forms/views/directiveViews/form/form.html b/public/modules/forms/views/directiveViews/form/submit-form.html similarity index 71% rename from public/modules/forms/views/directiveViews/form/form.html rename to public/modules/forms/views/directiveViews/form/submit-form.html index 698cc3de..d98cf786 100755 --- a/public/modules/forms/views/directiveViews/form/form.html +++ b/public/modules/forms/views/directiveViews/form/submit-form.html @@ -1,26 +1,22 @@
-
-

{{ form.title }}

-
+
+
+

{{ form.title }}

+
- -
-
-
- +
- - +
- +
@@ -50,10 +46,4 @@

- - -
\ No newline at end of file diff --git a/public/modules/forms/views/list-forms.client.view.html b/public/modules/forms/views/list-forms.client.view.html index ee6e3cdb..bfaeea7b 100644 --- a/public/modules/forms/views/list-forms.client.view.html +++ b/public/modules/forms/views/list-forms.client.view.html @@ -33,9 +33,8 @@ Language
- + diff --git a/public/modules/forms/views/view-form.client.view.html b/public/modules/forms/views/view-form.client.view.html index fd5ceb90..2083f786 100644 --- a/public/modules/forms/views/view-form.client.view.html +++ b/public/modules/forms/views/view-form.client.view.html @@ -46,6 +46,13 @@ View Submissions
+ +
+
+ +
+ +
@@ -83,7 +90,7 @@ {{row.created | date:'yyyy-MM-dd HH:mm:ss'}} @@ -93,51 +100,4 @@ - - - \ No newline at end of file diff --git a/public/modules/forms/views/view-public-form.client.view.html b/public/modules/forms/views/view-public-form.client.view.html index e73399f5..155ba747 100644 --- a/public/modules/forms/views/view-public-form.client.view.html +++ b/public/modules/forms/views/view-public-form.client.view.html @@ -1,22 +1,23 @@ -
+
+
- Generated PDF + Generated PDF