got table submissions to display correctly

This commit is contained in:
David Baldwynn 2015-07-21 16:25:45 -07:00
parent ca9af627a5
commit 79dfbbc8a7
52 changed files with 1417 additions and 943 deletions

View file

@ -79,7 +79,6 @@ exports.createSubmission = function(req, res) {
submission.form_fields = req.body.form_fields; submission.form_fields = req.body.form_fields;
submission.title = req.body.title; submission.title = req.body.title;
submission.timeElapsed = req.body.timeElapsed; submission.timeElapsed = req.body.timeElapsed;
// console.log(req.body);s
// submission.ipAddr = req.headers['x-forwarded-for'] || req.connection.remoteAddress; // submission.ipAddr = req.headers['x-forwarded-for'] || req.connection.remoteAddress;
if(form.autofillPDFs){ if(form.autofillPDFs){
@ -126,8 +125,8 @@ exports.createSubmission = function(req, res) {
message: errorHandler.getErrorMessage(err) message: errorHandler.getErrorMessage(err)
}); });
} }
console.log(results); // console.log(results);
console.log(that.form_fields); // console.log(that.form_fields);
res.status(200).send('Form submission successfully saved'); res.status(200).send('Form submission successfully saved');
}); });
}; };
@ -137,21 +136,31 @@ exports.createSubmission = function(req, res) {
*/ */
exports.listSubmissions = function(req, res) { exports.listSubmissions = function(req, res) {
var _form = req.form; var _form = req.form;
var _user = req.user;
// console.log(_form);
// if(_form.submissions.length){ // if(_form.submissions.length){
// res.json(_form.submissions); // res.json(_form.submissions);
// }else{ // }else{
FormSubmission.find({ form: req.form }).populate('admin', 'form').exec(function(err, _submissions) { FormSubmission.find({ form: req.form, admin: _user }).populate('admin', 'form').exec(function(err, _submissions) {
if (err) { if (err) {
console.log(err); console.log(err);
res.status(400).send({ res.status(400).send({
message: errorHandler.getErrorMessage(err) message: errorHandler.getErrorMessage(err)
}); });
} else {
// _form.submissions = _submissions;
_form.update({ $set : { submissions: _submissions }});
res.status(200);
} }
_form.update({ $set : { submissions: _submissions }}).exec(function(err, form){
if (err) {
console.log(err);
res.status(400).send({
message: errorHandler.getErrorMessage(err)
});
}
res.json(_submissions);
});
// res.status(200).send('Updated forms');
}); });
// } // }
}; };
@ -192,10 +201,21 @@ exports.read = function(req, res) {
exports.update = function(req, res) { exports.update = function(req, res) {
console.log('in form.update()'); console.log('in form.update()');
var form = req.form; console.log(req.body.form.form_fields);
form = _.extend(form, req.body.form);
form.admin = req.user;
var form = req.form;
delete req.body.form.__v;
delete req.body.form._id;
delete req.body.form.created;
delete req.body.form.lastModified;
//Unless we have 'admin' priviledges, updating form admin is disabled
if(req.user.roles.indexOf('admin') === -1) delete req.body.form.admin;
form = _.extend(form, req.body.form);
// console.log(req.body.form);
// form.form_fields = req.body.form.form_fields;
form.save(function(err) { form.save(function(err) {
if (err) { if (err) {
console.log(err); console.log(err);
@ -267,28 +287,6 @@ exports.formByID = function(req, res, next, id) {
}); });
} }
else { else {
if(!form.admin){
form.admin = req.user;
form.save(function(err) {
if (err) {
console.log(err);
res.status(400).send({
message: errorHandler.getErrorMessage(err)
});
} else {
//Remove sensitive information from User object
form.admin.password = null;
form.admin.created = null;
form.admin.salt = null;
req.form = form;
next();
}
});
}
console.log(form.submissions);
//Remove sensitive information from User object //Remove sensitive information from User object
form.admin.password = null; form.admin.password = null;
form.admin.created = null; form.admin.created = null;

View file

@ -7,8 +7,94 @@ var _ = require('lodash'),
errorHandler = require('../errors.server.controller'), errorHandler = require('../errors.server.controller'),
mongoose = require('mongoose'), mongoose = require('mongoose'),
passport = require('passport'), passport = require('passport'),
async = require('async'),
config = require('../../../config/config'),
nodemailer = require('nodemailer'),
crypto = require('crypto'),
User = mongoose.model('User'); User = mongoose.model('User');
var smtpTransport = nodemailer.createTransport(config.mailer.options);
/**
* 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');
}
res.redirect('/#!/password/reset/' + req.params.token);
});
};
/**
* 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');
});
};
/** /**
* Signup * Signup
*/ */
@ -34,14 +120,15 @@ exports.signup = function(req, res) {
// Remove sensitive data before login // Remove sensitive data before login
user.password = undefined; user.password = undefined;
user.salt = undefined; user.salt = undefined;
res.status(200).send('new user successfully registered');
req.login(user, function(err) { // req.login(user, function(err) {
if (err) { // if (err) {
res.status(400).send(err); // res.status(400).send(err);
} else { // } else {
res.status(200).send('user successfully loggedin'); // res.status(200).send('new user successfully registered');
} // }
}); // });
} }
}); });
}; };
@ -60,7 +147,9 @@ exports.signin = function(req, res, next) {
req.login(user, function(err) { req.login(user, function(err) {
if (err) { if (err) {
res.status(400).send(err); return res.status(400).send({
message: errorHandler.getErrorMessage(err)
});
} else { } else {
res.json(user); res.json(user);
} }
@ -74,8 +163,8 @@ exports.signin = function(req, res, next) {
*/ */
exports.signout = function(req, res) { exports.signout = function(req, res) {
req.logout(); req.logout();
// res.status(200).send('user successfully logged out'); res.status(200).send('user successfully logged out');
res.redirect('/'); // res.redirect('/');
}; };
/** /**

View file

@ -52,5 +52,13 @@ exports.update = function(req, res) {
* Send User * Send User
*/ */
exports.me = function(req, res) { exports.me = function(req, res) {
var _user = req.user;
delete _user.password;
delete _user.salt;
delete _user.provider;
delete _user.__v;
delete _user.created;
res.json(req.user || null); res.json(req.user || null);
}; };

View file

@ -5,14 +5,16 @@
*/ */
var mongoose = require('mongoose'), var mongoose = require('mongoose'),
FieldSchema = require('./form_field.server.model.js'), FieldSchema = require('./form_field.server.model.js'),
FormSubmissionSchema = require('./form_submission.server.model.js'),
Schema = mongoose.Schema, Schema = mongoose.Schema,
pdfFiller = require('pdffiller'), pdfFiller = require('pdffiller'),
_ = require('lodash'), _ = require('lodash'),
config = require('../../config/config'), config = require('../../config/config'),
path = require('path'), path = require('path'),
fs = require('fs-extra'), fs = require('fs-extra'),
async = require('async'), async = require('async');
Field = mongoose.model('Field', FieldSchema); var Field = mongoose.model('Field', FieldSchema);
var FormSubmission = mongoose.model('FormSubmission', FormSubmissionSchema);
/** /**
@ -44,7 +46,7 @@ var FormSchema = new Schema({
default: '', default: '',
}, },
form_fields: { form_fields: {
type: [Schema.Types.Mixed], type: [FieldSchema],
set: function(form_fields) { set: function(form_fields) {
this._previousFormFields = this.form_fields; this._previousFormFields = this.form_fields;
return form_fields; return form_fields;
@ -58,7 +60,8 @@ var FormSchema = new Schema({
admin: { admin: {
type: Schema.Types.ObjectId, type: Schema.Types.ObjectId,
ref: 'User' ref: 'User',
required: 'Form must have an Admin'
}, },
pdf: { pdf: {
@ -67,6 +70,7 @@ var FormSchema = new Schema({
pdfFieldMap: { pdfFieldMap: {
type: Schema.Types.Mixed type: Schema.Types.Mixed
}, },
hideFooter: { hideFooter: {
type: Boolean, type: Boolean,
default: false, default: false,
@ -85,6 +89,10 @@ var FormSchema = new Schema({
}, },
}); });
FormSchema.post('init', function() {
this._original = this.toObject();
});
//Delete template PDF of current Form //Delete template PDF of current Form
FormSchema.pre('remove', function (next) { FormSchema.pre('remove', function (next) {
if(this.pdf){ if(this.pdf){
@ -109,6 +117,7 @@ FormSchema.pre('save', function (next) {
//Concatenate submission and form's form_fields //Concatenate submission and form's form_fields
// FormSchema.pre('save', function (next) { // FormSchema.pre('save', function (next) {
// if(this.isModified('form_fields')){ // if(this.isModified('form_fields')){
// if(this.submissions.length){ // if(this.submissions.length){
// for(var i=0; i<this.submissions.length; i++){ // for(var i=0; i<this.submissions.length; i++){
// var submission = this.submissions[i]; // var submission = this.submissions[i];
@ -116,11 +125,119 @@ FormSchema.pre('save', function (next) {
// this.submissions[i].form_fields = submission.form_fields.concat(_.difference(this.form_fields, this._previousFormFields)); // this.submissions[i].form_fields = submission.form_fields.concat(_.difference(this.form_fields, this._previousFormFields));
// } // }
// } // }
// this.form_fields = this._previousFormFields.concat(_.difference(this.form_fields, this._previousFormFields)); // this.form_fields = this._previousFormFields.concat(_.difference(this.form_fields, this._previousFormFields));
// } // }
// next(); // next();
// }); // });
function getDeletedIndexes(needle, haystack){
var deletedIndexes = [];
if(haystack.length > 0){
for(var i = 0; i < needle.length; i++){
if(haystack.indexOf(needle[i]) <= -1){
deletedIndexes.push(i);
}
}
}
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 //Move PDF to permanent location after new template is uploaded
FormSchema.pre('save', function (next) { FormSchema.pre('save', function (next) {
@ -129,7 +246,6 @@ FormSchema.pre('save', function (next) {
async.series([ async.series([
function(callback){ function(callback){
if(that.isModified('pdf')){ if(that.isModified('pdf')){
// console.log('about to move PDF');
var new_filename = that.title.replace(/ /g,'')+'_template.pdf'; var new_filename = that.title.replace(/ /g,'')+'_template.pdf';
@ -142,26 +258,21 @@ FormSchema.pre('save', function (next) {
fs.mkdirSync(newDestination); fs.mkdirSync(newDestination);
} }
if (stat && !stat.isDirectory()) { if (stat && !stat.isDirectory()) {
// console.log('Directory '+newDestination+' cannot be created'); callback( new Error('Directory cannot be created because an inode of a different type exists at "' + config.pdfUploadPath + '"'), null);
callback( new Error('Directory cannot be created because an inode of a different type exists at "' + config.pdfUploadPath + '"') );
} }
// console.log('about to move PDF');
fs.move(that.pdf.path, path.join(newDestination, new_filename), function (err) { fs.move(that.pdf.path, path.join(newDestination, new_filename), function (err) {
if (err) { if (err) {
console.error(err); console.error(err);
callback( new Error(err.message) ); callback( new Error(err.message), null);
} }
that.pdf.path = path.join(newDestination, new_filename); that.pdf.path = path.join(newDestination, new_filename);
that.pdf.name = new_filename; that.pdf.name = new_filename;
// console.log('\n\n PDF file:'+that.pdf.name+' successfully moved to: '+that.pdf.path);
callback(null,'task1'); callback(null,'task1');
}); });
} }
callback(null,null); callback(null,'task1');
}, },
function(callback){ function(callback){
if(that.isGenerated){ if(that.isGenerated){
@ -182,9 +293,9 @@ FormSchema.pre('save', function (next) {
pdfFiller.generateFieldJson(that.pdf.path, function(err, _form_fields){ pdfFiller.generateFieldJson(that.pdf.path, function(err, _form_fields){
if(err){ if(err){
next( new Error(err.message), null); callback( new Error(err.message), null);
}else if(!_form_fields.length){ }else if(!_form_fields.length || _form_fields === undefined || _form_fields === null){
next( new Error('Generated formfields is empty'), null); callback( new Error('Generated formfields is empty'), null);
} }
//Map PDF field names to FormField field names //Map PDF field names to FormField field names
@ -196,21 +307,8 @@ FormSchema.pre('save', function (next) {
field.fieldType = _typeConvMap[ field.fieldType+'' ]; field.fieldType = _typeConvMap[ field.fieldType+'' ];
} }
field.fieldValue = ''; field = new Field(field);
field.created = Date.now(); field.required = false;
field.required = true;
field.disabled = false;
// field = new Field(field);
// field.save(function(err) {
// if (err) {
// console.error(err.message);
// throw new Error(err.message);
// });
// } else {
// _form_fields[i] = that;
// }
// });
_form_fields[i] = field; _form_fields[i] = field;
} }
@ -310,28 +408,7 @@ FormSchema.pre('save', function (next) {
// next(); // next();
// }); // });
// FormSchema.methods.generateSubmissionsCSV = function (cb) { FormSchema.methods.generateFDFTemplate = function() {
// if(this.submissions.length){
// submissions = this.submissions
// }else{
// submissions =
// }
// _values.forEach(function(val){
// if(val === true){
// val = 'Yes';
// }else if(val === false) {
// val = 'Off';
// }
// });
// var jsonObj = _.zipObject(_keys, _values);
// return jsonObj;
// };
FormSchema.methods.generateFDFTemplate = function (cb) {
var _keys = _.pluck(this.form_fields, 'title'), var _keys = _.pluck(this.form_fields, 'title'),
_values = _.pluck(this.form_fields, 'fieldValue'); _values = _.pluck(this.form_fields, 'fieldValue');

View file

@ -8,7 +8,7 @@ var mongoose = require('mongoose'),
// questionType Validation // questionType Validation
function validateFormFieldType(value) { function validateFormFieldType(value) {
if (!value || typeof myVar !== 'string' ) { return false; } if (!value) { return false; }
var validTypes = [ var validTypes = [
'textfield', 'textfield',
@ -17,20 +17,16 @@ function validateFormFieldType(value) {
'legal', 'legal',
'url', 'url',
'number', 'number',
'textarea', 'textarea',
'statement', 'statement',
'welcome', 'welcome',
'thankyou', 'thankyou',
'file', 'file',
'dropdown', 'dropdown',
'scale', 'scale',
'rating', 'rating',
'radio', 'radio',
'checkbox', 'checkbox',
'hidden', 'hidden',
]; ];
@ -49,7 +45,11 @@ var FormFieldSchema = new Schema({
type: Date, type: Date,
default: Date.now default: Date.now
}, },
name: { lastModified: {
type: Date,
default: Date.now
},
title: {
type: String, type: String,
default: '', default: '',
trim: true, trim: true,
@ -60,7 +60,7 @@ var FormFieldSchema = new Schema({
default: '', default: '',
}, },
fieldOptions: [{ fieldOptions: [{
type: String type: Schema.Types.Mixed
}], }],
required: { required: {
type: Boolean, type: Boolean,
@ -75,7 +75,7 @@ var FormFieldSchema = new Schema({
required: 'Field type cannot be blank', required: 'Field type cannot be blank',
validate: [validateFormFieldType, 'Invalid field type'] validate: [validateFormFieldType, 'Invalid field type']
}, },
value: Schema.Types.Mixed fieldValue: Schema.Types.Mixed
}); });

View file

@ -10,9 +10,6 @@ var mongoose = require('mongoose'),
_ = require('lodash'), _ = require('lodash'),
config = require('../../config/config'), config = require('../../config/config'),
path = require('path'), path = require('path'),
Form = mongoose.model('Form'),
FieldSchema = require('./form_field.server.model.js'),
Field = mongoose.model('Field', FieldSchema),
fs = require('fs-extra'); fs = require('fs-extra');
/** /**
@ -119,4 +116,6 @@ FormSubmissionSchema.pre('save', function (next) {
}); });
mongoose.model('FormSubmission', FormSubmissionSchema); module.exports = FormSubmissionSchema;
// mongoose.model('FormSubmission', FormSubmissionSchema);

View file

@ -74,7 +74,7 @@ var UserSchema = new Schema({
roles: { roles: {
type: [{ type: [{
type: String, type: String,
enum: ['user', 'admin'] enum: ['user', 'admin', 'superuser']
}], }],
default: ['user'] default: ['user']
}, },
@ -91,6 +91,15 @@ var UserSchema = new Schema({
type: Date, type: Date,
default: Date.now default: Date.now
}, },
/* For account activation */
activationToken: {
type: String
},
activationTokenExpires: {
type: Date
},
/* For reset password */ /* For reset password */
resetPasswordToken: { resetPasswordToken: {
type: String type: String

View file

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

View file

@ -14,6 +14,10 @@ module.exports = function(app) {
app.route('/users').put(users.requiresLogin, users.update); app.route('/users').put(users.requiresLogin, users.update);
app.route('/users/accounts').delete(users.requiresLogin, users.removeOAuthProvider); 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 password api // Setting up the users password api
app.route('/users/password').post(users.requiresLogin, users.changePassword); app.route('/users/password').post(users.requiresLogin, users.changePassword);
app.route('/auth/forgot').post(users.forgot); app.route('/auth/forgot').post(users.forgot);

View file

@ -0,0 +1,83 @@
'use strict';
/**
* Module dependencies.
*/
var should = require('should'),
mongoose = require('mongoose'),
User = mongoose.model('User'),
Form = mongoose.model('Form');
/**
* Globals
*/
var user, Form,
FormFDF;
/**
* Unit tests
*/
describe('Form 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() {
Form = 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'}]
});
done();
});
});
describe('Method Save', function() {
it('should be able to save without problems', function(done) {
return Form.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 = '';
return Form.save(function(err) {
should.exist(err);
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);
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);
done();
});
});
});
afterEach(function(done) {
Form.remove().exec(function() {
User.remove().exec(done);
});
});
});

BIN
app/tests/test.pdf Normal file

Binary file not shown.

View file

@ -0,0 +1,18 @@
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
</head>
<body>
<p>Dear {{name}},</p>
<br>
<p>
You have just created a new account at {{appName}}. To use your account you must activate it.s
</p>
<p>Please visit this url to activate your account:</p>
<p>{{url}}</p>
<strong>If you didn't make this request, you can ignore this email.</strong>
<br>
<br>
<p>The {{appName}} Support Team</p>
</body>
</html>

View file

@ -23,7 +23,10 @@
"restangular": "~1.5.1", "restangular": "~1.5.1",
"fontawesome": "~4.3.0", "fontawesome": "~4.3.0",
"ng-file-upload": "~5.0.9", "ng-file-upload": "~5.0.9",
"angular-raven": "~0.5.11" "angular-raven": "~0.5.11",
"angular-ui-date": "~0.0.8",
"lodash": "~3.10.0",
"angular-ui-sortable": "~0.13.4"
}, },
"resolutions": { "resolutions": {
"angular": "^1.2.21", "angular": "^1.2.21",

View file

@ -150,6 +150,25 @@ module.exports = function(db) {
require(path.resolve(routePath))(app); require(path.resolve(routePath))(app);
}); });
// Add headers for Sentry
app.use(function (req, res, next) {
// Website you wish to allow to connect
res.setHeader('Access-Control-Allow-Origin', 'http://sentry.polydaic.com');
// Request methods you wish to allow
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE');
// Request headers you wish to allow
res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,content-type');
// Set to true if you need the website to include cookies in the requests sent
// to the API (e.g. in case you use sessions)
res.setHeader('Access-Control-Allow-Credentials', true);
// Pass to next layer of middleware
next();
});
// Sentry (Raven) middleware // Sentry (Raven) middleware
app.use(raven.middleware.express.requestHandler(config.DSN)); app.use(raven.middleware.express.requestHandler(config.DSN));

View file

@ -0,0 +1,96 @@
[
[{
"fieldType": "textfield",
"fieldValue": "snthsnth",
"_id": "55aec5d284bae1a1996210bd",
"disabled": false,
"fieldOptions": [],
"description": "",
"title": "Short Text2",
"lastModified": "2015-07-21T22:21:06.653Z",
"created": "2015-07-21T22:21:06.653Z",
"$$hashKey": "02J"
}, {
"fieldType": "textfield",
"fieldValue": "duieedi",
"_id": "55aec5b084bae1a1996210b4",
"disabled": false,
"fieldOptions": [],
"description": "",
"title": "Last Name",
"lastModified": "2015-07-21T22:20:32.053Z",
"created": "2015-07-21T22:20:32.053Z",
"$$hashKey": "02K"
}],
[{
"fieldType": "textfield",
"fieldValue": "snthsnth",
"_id": "55aec5d284bae1a1996210bd",
"disabled": false,
"fieldOptions": [],
"description": "",
"title": "Short Text2",
"lastModified": "2015-07-21T22:21:06.653Z",
"created": "2015-07-21T22:21:06.653Z",
"$$hashKey": "02J"
}, {
"fieldType": "textfield",
"fieldValue": "duieedi",
"_id": "55aec5b084bae1a1996210b4",
"disabled": false,
"fieldOptions": [],
"description": "",
"title": "Last Name",
"lastModified": "2015-07-21T22:20:32.053Z",
"created": "2015-07-21T22:20:32.053Z",
"$$hashKey": "02K"
}],
[{
"fieldType": "textfield",
"fieldValue": "snthsnth",
"_id": "55aec5d284bae1a1996210bd",
"disabled": false,
"fieldOptions": [],
"description": "",
"title": "Short Text2",
"lastModified": "2015-07-21T22:21:06.653Z",
"created": "2015-07-21T22:21:06.653Z",
"$$hashKey": "02J"
}, {
"fieldType": "textfield",
"fieldValue": "duieedi",
"_id": "55aec5b084bae1a1996210b4",
"disabled": false,
"fieldOptions": [],
"description": "",
"title": "Last Name",
"lastModified": "2015-07-21T22:20:32.053Z",
"created": "2015-07-21T22:20:32.053Z",
"$$hashKey": "02K"
}],
[{
"fieldType": "textfield",
"fieldValue": "snthsnth",
"_id": "55aec5d284bae1a1996210bd",
"disabled": false,
"fieldOptions": [],
"description": "",
"title": "Short Text2",
"lastModified": "2015-07-21T22:21:06.653Z",
"created": "2015-07-21T22:21:06.653Z",
"$$hashKey": "02J"
}, {
"fieldType": "textfield",
"fieldValue": "duieedi",
"_id": "55aec5b084bae1a1996210b4",
"disabled": false,
"fieldOptions": [],
"description": "",
"title": "Last Name",
"lastModified": "2015-07-21T22:20:32.053Z",
"created": "2015-07-21T22:20:32.053Z",
"$$hashKey": "02K"
}]
]

View file

@ -0,0 +1,22 @@
##First Form Auto-Update
1. Added field CLIENT
time: 2553
2. Finding form SERVER
time: 2841
3. Update form CLIENT
time: 2870
4.Updated form SERVER
time: 2863
##Second Form Auto-Update
1. Added field CLIENT
time: 2755
2. Finding form SERVER
time: 2898

View file

@ -114,13 +114,13 @@ module.exports = function(grunt) {
} }
} }
}, },
ngAnnotate: { // ngAnnotate: {
production: { // production: {
files: { // files: {
'public/dist/application.js': '<%= applicationJavaScriptFiles %>' // 'public/dist/application.js': '<%= applicationJavaScriptFiles %>'
} // }
} // }
}, // },
concurrent: { concurrent: {
default: ['nodemon', 'watch'], default: ['nodemon', 'watch'],
debug: ['nodemon', 'watch', 'node-inspector'], debug: ['nodemon', 'watch', 'node-inspector'],
@ -179,7 +179,7 @@ module.exports = function(grunt) {
grunt.registerTask('lint', ['newer:jshint', 'newer:csslint']); grunt.registerTask('lint', ['newer:jshint', 'newer:csslint']);
// Build task(s). // Build task(s).
grunt.registerTask('build', ['lint', 'loadConfig', 'ngAnnotate', 'uglify', 'cssmin']); grunt.registerTask('build', ['lint', 'loadConfig', 'uglify', 'cssmin']); //'ngAnnotate', ]);
// Test task. // Test task.
grunt.registerTask('test', ['test:server', 'test:client']); grunt.registerTask('test', ['test:server', 'test:client']);

View file

@ -39,7 +39,7 @@ module.exports = function(config) {
// - Safari (only Mac) // - Safari (only Mac)
// - PhantomJS // - PhantomJS
// - IE (only Windows) // - IE (only Windows)
browsers: ['PhantomJS'], browsers: ['Chrome'],
// If browser does not capture in given timeout [ms], kill it // If browser does not capture in given timeout [ms], kill it
captureTimeout: 60000, captureTimeout: 60000,

View file

@ -21,7 +21,7 @@
"postinstall": "bower install --config.interactive=false; grunt build" "postinstall": "bower install --config.interactive=false; grunt build"
}, },
"dependencies": { "dependencies": {
"async": "~0.9.0", "async": "^1.4.0",
"body-parser": "~1.9.0", "body-parser": "~1.9.0",
"bower": "~1.3.8", "bower": "~1.3.8",
"chalk": "~1.0.0", "chalk": "~1.0.0",
@ -63,6 +63,7 @@
"method-override": "~2.3.0", "method-override": "~2.3.0",
"mocha": ">=1.20.0", "mocha": ">=1.20.0",
"mongoose": "~3.8.8", "mongoose": "~3.8.8",
"mongoose-datatable": "^1.0.2",
"morgan": "~1.4.1", "morgan": "~1.4.1",
"multer": "~0.1.8", "multer": "~0.1.8",
"nodemailer": "~1.3.0", "nodemailer": "~1.3.0",
@ -80,5 +81,9 @@
"supertest": "~0.14.0", "supertest": "~0.14.0",
"swig": "~1.4.1", "swig": "~1.4.1",
"then-fs": "~2.0.0" "then-fs": "~2.0.0"
},
"devDependencies": {
"karma-chrome-launcher": "^0.1.12",
"karma-jasmine": "^0.2.3"
} }
} }

View file

@ -9,20 +9,34 @@ angular.module(ApplicationConfiguration.applicationModuleName).config(['$locatio
$locationProvider.hashPrefix('!'); $locationProvider.hashPrefix('!');
} }
]); ]);
angular.module(ApplicationConfiguration.applicationModuleName).run(['$rootScope', '$state', '$stateParams',
function($rootScope, $state, $stateParams) { //Permission Constants
angular.module(ApplicationConfiguration.applicationModuleName).constant('APP_PERMISSIONS', {
viewAdminSettings: 'viewAdminSettings',
editAdminSettings: 'editAdminSettings',
editForm: 'editForm',
viewPrivateForm: 'viewPrivateForm',
});
//User Role constants
angular.module(ApplicationConfiguration.applicationModuleName).constant('USER_ROLES', {
admin: 'admin',
normal: 'user',
superuser: 'superuser',
});
angular.module(ApplicationConfiguration.applicationModuleName).run(['$rootScope', 'Auth', '$state', '$stateParams',
function($rootScope, Auth, $state, $stateParams) {
$rootScope.$state = $state; $rootScope.$state = $state;
$rootScope.$stateParams = $stateParams; $rootScope.$stateParams = $stateParams;
// add previous state property // add previous state property
$rootScope.$on('$stateChangeSuccess', function (event, toState, toParams, fromState) { $rootScope.$on('$stateChangeSuccess', function (event, toState, toParams, fromState) {
console.log(fromState);
$state.previous = fromState; $state.previous = fromState;
//Redirect home to listForms if user is authenticated //Redirect home to listForms if user is authenticated
if(toState.name === 'home'){ if(toState.name === 'home'){
if($rootScope.authentication.isAuthenticated()){ if(Auth.isAuthenticated()){
event.preventDefault(); // stop current execution event.preventDefault(); // stop current execution
$state.go('listForms'); // go to login $state.go('listForms'); // go to login
} }
@ -32,6 +46,31 @@ angular.module(ApplicationConfiguration.applicationModuleName).run(['$rootScope'
} }
]); ]);
//Page access/authorization logic
angular.module(ApplicationConfiguration.applicationModuleName).run(['$rootScope', 'Auth', 'User', 'Authorizer', '$state', '$stateParams',
function($rootScope, Auth, User, Authorizer, $state, $stateParams) {
$rootScope.$on('$stateChangeStart', function(event, next) {
var authenticator, permissions, user;
permissions = next && next.data && next.data.permissions ? next.data.permissions : null;
Auth.ensureHasCurrentUser(User);
user = Auth.currentUser;
if(user){
authenticator = new Authorizer(user);
// console.log('Permissions');
// console.log(permissions);
if( (permissions !== null) && !authenticator.canAccess(permissions) ){
event.preventDefault();
console.log('access denied')
$state.go('access_denied');
}
}
});
}]);
//Then define the init function for starting up the application //Then define the init function for starting up the application
angular.element(document).ready(function() { angular.element(document).ready(function() {
//Fixing facebook bug with redirect //Fixing facebook bug with redirect

View file

@ -32,28 +32,66 @@ angular.module(ApplicationConfiguration.applicationModuleName).config(['$locatio
$locationProvider.hashPrefix('!'); $locationProvider.hashPrefix('!');
} }
]); ]);
angular.module(ApplicationConfiguration.applicationModuleName).run(['$rootScope', '$state', '$stateParams',
function($rootScope, $state, $stateParams) {
$rootScope.$state = $state; //Permission Constants
$rootScope.$stateParams = $stateParams; angular.module(ApplicationConfiguration.applicationModuleName).constant('APP_PERMISSIONS', {
viewAdminSettings: 'viewAdminSettings',
editAdminSettings: 'editAdminSettings',
editForm: 'editForm',
viewPrivateForm: 'viewPrivateForm',
});
//User Role constants
angular.module(ApplicationConfiguration.applicationModuleName).constant('USER_ROLES', {
admin: 'admin',
normal: 'user',
superuser: 'superuser',
});
// add previous state property // angular.module(ApplicationConfiguration.applicationModuleName).run(['$rootScope', 'Auth', '$state', '$stateParams',
$rootScope.$on('$stateChangeSuccess', function (event, toState, toParams, fromState) { // function($rootScope, Auth, $state, $stateParams) {
console.log(fromState);
$state.previous = fromState;
//Redirect home to listForms if user is authenticated // $rootScope.$state = $state;
if(toState.name === 'home'){ // $rootScope.$stateParams = $stateParams;
if($rootScope.authentication.isAuthenticated()){
event.preventDefault(); // stop current execution
$state.go('listForms'); // go to login
}
}
});
} // // add previous state property
]); // $rootScope.$on('$stateChangeSuccess', function (event, toState, toParams, fromState) {
// // console.log(fromState);
// $state.previous = fromState;
// //Redirect home to listForms if user is authenticated
// if(toState.name === 'home'){
// if(Auth.isAuthenticated()){
// event.preventDefault(); // stop current execution
// $state.go('listForms'); // go to login
// }
// }
// });
// }
// ]);
angular.module(ApplicationConfiguration.applicationModuleName).run(['$rootScope', 'Auth', 'User', 'Authorizer', '$state', '$stateParams',
function($rootScope, Auth, User, Authorizer, $state, $stateParams) {
$rootScope.$on('$stateChangeStart', function(event, next) {
var authenticator, permissions, user;
permissions = next && next.data ? next.data.permissions : null;
Auth.ensureCurrentUser(User);
user = Auth.currentUser;
// if(user){}
authenticator = new Authorizer(user);
if( (permissions !== null) && !authenticator.canAccess(permissions) ){
event.preventDefault();
if (!user) {
$state.go('sigin');
} else {
$state.go('access_denied');
}
}
});
}]);
//Then define the init function for starting up the application //Then define the init function for starting up the application
angular.element(document).ready(function() { angular.element(document).ready(function() {
@ -71,7 +109,7 @@ ApplicationConfiguration.registerModule('core', ['users']);
'use strict'; 'use strict';
// Use Application configuration module to register a new module // Use Application configuration module to register a new module
ApplicationConfiguration.registerModule('forms', ['ngFileUpload', 'users']); ApplicationConfiguration.registerModule('forms', ['ngFileUpload', 'ui.date', 'users']);
'use strict'; 'use strict';
// Use Application configuration module to register a new module // Use Application configuration module to register a new module
@ -454,131 +492,128 @@ angular.module('forms').config(['$stateProvider',
}); });
} }
]); ]);
'use strict'; // 'use strict';
angular.module('forms').controller('EditFormController', ['$scope', '$state', '$rootScope', 'Upload', '$stateParams', 'FormFields', 'Forms', 'CurrentForm', '$modal', '$location', '$http', // 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) { // function ($scope, $state, $rootScope, Upload, $stateParams, FormFields, Forms, CurrentForm, $modal, $location, $http) {
$scope.form = {}; // $scope.form = {};
$scope.isNewForm = false; // $scope.isNewForm = false;
$scope.log = ''; // $scope.log = '';
$scope.pdfLoading = false; // $scope.pdfLoading = false;
var _current_upload = null; // var _current_upload = null;
// Get current form if it exists, or create new one // // Get current form if it exists, or create new one
if($stateParams.formId){ // if($stateParams.formId){
Forms.get({ formId: $stateParams.formId}, function(form){ // Forms.get({ formId: $stateParams.formId}, function(form){
$scope.form = angular.fromJson(angular.toJson(form)); // $scope.form = angular.fromJson(angular.toJson(form));
console.log($scope.form); // console.log($scope.form);
}); // });
} else { // } else {
$scope.form.form_fields = []; // $scope.form.form_fields = [];
$scope.isNewForm = true; // $scope.isNewForm = true;
} // }
//PDF Functions // //PDF Functions
$scope.cancelUpload = function(){ // $scope.cancelUpload = function(){
_current_upload.abort(); // _current_upload.abort();
$scope.pdfLoading = false; // $scope.pdfLoading = false;
$scope.removePDF(); // $scope.removePDF();
}; // };
$scope.removePDF = function(){ // $scope.removePDF = function(){
$scope.form.pdf = null; // $scope.form.pdf = null;
$scope.form.isGenerated = false; // $scope.form.isGenerated = false;
$scope.form.autofillPDFs = false; // $scope.form.autofillPDFs = false;
console.log('form.pdf: '+$scope.form.pdf+' REMOVED'); // console.log('form.pdf: '+$scope.form.pdf+' REMOVED');
}; // };
$scope.uploadPDF = function(files) { // $scope.uploadPDF = function(files) {
if (files && files.length) { // if (files && files.length) {
// for (var i = 0; i < files.length; i++) { // // for (var i = 0; i < files.length; i++) {
var file = files[0]; // var file = files[0];
_current_upload = Upload.upload({ // _current_upload = Upload.upload({
url: '/upload/pdf', // url: '/upload/pdf',
fields: { // fields: {
'user': $scope.user, // 'user': $scope.user,
'form': $scope.form // 'form': $scope.form
}, // },
file: file // file: file
}).progress(function (evt) { // }).progress(function (evt) {
var progressPercentage = parseInt(100.0 * evt.loaded / evt.total); // var progressPercentage = parseInt(100.0 * evt.loaded / evt.total);
$scope.log = 'progress: ' + progressPercentage + '% ' + // $scope.log = 'progress: ' + progressPercentage + '% ' +
evt.config.file.name + '\n' + $scope.log; // evt.config.file.name + '\n' + $scope.log;
$scope.pdfLoading = true; // $scope.pdfLoading = true;
}).success(function (data, status, headers, config) { // }).success(function (data, status, headers, config) {
$scope.log = 'file ' + data.originalname + ' uploaded as '+ data.name +'. JSON: ' + JSON.stringify(data) + '\n' + $scope.log; // $scope.log = 'file ' + data.originalname + ' uploaded as '+ data.name +'. JSON: ' + JSON.stringify(data) + '\n' + $scope.log;
console.log($scope.form.pdf); // console.log($scope.form.pdf);
$scope.form.pdf = angular.fromJson(angular.toJson(data)); // $scope.form.pdf = angular.fromJson(angular.toJson(data));
$scope.pdfLoading = false; // $scope.pdfLoading = false;
console.log($scope.log); // console.log($scope.log);
console.log('$scope.pdf: '+$scope.form.pdf.name); // console.log('$scope.pdf: '+$scope.form.pdf.name);
if(!$scope.$$phase){ // if(!$scope.$$phase){
$scope.$apply(); // $scope.$apply();
} // }
}).error(function(err){ // }).error(function(err){
$scope.pdfLoading = false; // $scope.pdfLoading = false;
console.log('Error occured during upload.\n'); // console.log('Error occured during upload.\n');
console.log(err); // console.log(err);
}); // });
// } // // }
} // }
}; // };
$rootScope.goToWithId = function(route, id) { // $rootScope.goToWithId = function(route, id) {
$state.go(route, {'formId': id}, {reload: true}); // $state.go(route, {'formId': id}, {reload: true});
}; // };
// Create new Form // // Create new Form
$rootScope.createOrUpdate = function() { // $rootScope.createOrUpdate = function() {
if($scope.isNewForm){ // if($scope.isNewForm){
// Create new Form object // // Create new Form object
var form = new Forms($scope.form); // var form = new Forms($scope.form);
$http.post('/forms', {form: $scope.form}) // $http.post('/forms', {form: $scope.form})
.success(function(data, status, headers){ // .success(function(data, status, headers){
console.log('form created'); // console.log('form created');
// Clear form fields // // Clear form fields
$scope.form = {}; // $scope.form = {};
// Redirect after save // // Redirect after save
$scope.goToWithId('viewForm', $scope.form._id); // $scope.goToWithId('viewForm', $scope.form._id);
}).error(function(errorResponse){ // }).error(function(errorResponse){
console.log(errorResponse); // console.log(errorResponse);
$scope.error = errorResponse; // $scope.error = errorResponse;
}); // });
} else{ // } else{
$scope.update(); // $scope.update(function(err){
} // console.log('done updating');
}; // });
// }
// };
// Update existing Form // // Update existing Form
$rootScope.update = function() { // $rootScope.update = function(cb) {
var form = new Forms($scope.form); // var form = new Forms($scope.form);
console.log('update form'); // console.log('update form');
console.log($scope.form); // console.log($scope.form);
$http.put('/forms/'+$scope.form._id, {form: $scope.form}) // $http.put('/forms/'+$scope.form._id, {form: $scope.form})
.success(function(data, status, headers){ // .success(function(data, status, headers){
console.log('form updated successfully'); // console.log('form updated successfully');
$scope.goToWithId('viewForm', $scope.form._id); // $scope.goToWithId('viewForm', $scope.form._id);
}).error(function(err){ // cb(null);
console.log('Error occured during form UPDATE.\n'); // }).error(function(err){
console.log(err); // console.log('Error occured during form UPDATE.\n');
}); // console.log(err);
// form.$update({formId: $scope.form._id}, function(response) { // cb(err);
// console.log('form successfully updated'); // });
// $scope.goToWithId('viewForm', response._id); // };
// }, function(errorResponse) { // }
// console.log(errorResponse.data.message); // ]);
// $scope.error = errorResponse.data.message;
// });
};
}
]);
'use strict'; 'use strict';
@ -652,10 +687,30 @@ angular.module('forms').controller('ViewFormController', ['$rootScope', '$scope'
rows: [] rows: []
}; };
// Return all user's Forms
$scope.findAll = function() {
$scope.myforms = Forms.query();
};
// Find a specific Form
$scope.findOne = function() {
$scope.myform = Forms.get({
formId: $stateParams.formId
});
CurrentForm.setForm($scope.myform);
};
$scope.goToWithId = function(route, id) {
$state.go(route, {'formId': id}, {reload: true});
};
$scope.setForm = function (form) { $scope.setForm = function (form) {
$scope.myForm = form; $scope.myForm = form;
}; };
//Modal functions
$scope.openCreateModal = function(){ $scope.openCreateModal = function(){
if(!$scope.showCreateModal){ if(!$scope.showCreateModal){
$scope.showCreateModal = true; $scope.showCreateModal = true;
@ -667,53 +722,9 @@ angular.module('forms').controller('ViewFormController', ['$rootScope', '$scope'
} }
}; };
//Create new form /*
$scope.createNew = function(){ * Table Functions
var form = {}; */
form.title = $scope.myForm.name.$modelValue;
form.language = $scope.myForm.language.$modelValue;
console.log(form);
$scope.showCreateModal = true;
console.log($scope.myForm);
if($scope.myForm.$valid && $scope.myForm.$dirty){
$http.post('/forms', {form: form})
.success(function(data, status, headers){
console.log('form created');
// Clear form fields
$scope.myForm = {};
// Redirect after save
$scope.goToWithId('viewForm', $scope.myform._id);
}).error(function(errorResponse){
console.log(errorResponse);
// $scope.error = errorResponse.data.message;
});
}
};
$scope.saveInProgress = false;
$scope.update = function() {
if(!$scope.saveInProgress){
$scope.saveInProgress = true;
console.log('start update()');
$http.put('/forms/'+$scope.myform._id, {form: $scope.myform})
.then(function(response){
console.log('form updated successfully');
console.log('$scope.saveInProgress: '+$scope.saveInProgress);
// $rootScope.goToWithId('viewForm', $scope.myform._id);
}).catch(function(response){
console.log('Error occured during form UPDATE.\n');
console.log(response.data);
}).finally(function() {
$scope.saveInProgress = false;
});
}
};
//Table Functions
$scope.toggleAllCheckers = function(){ $scope.toggleAllCheckers = function(){
console.log('toggleAllCheckers'); console.log('toggleAllCheckers');
for(var i=0; i<$scope.table.rows.length; i++){ for(var i=0; i<$scope.table.rows.length; i++){
@ -723,12 +734,11 @@ angular.module('forms').controller('ViewFormController', ['$rootScope', '$scope'
$scope.toggleObjSelection = function($event, description) { $scope.toggleObjSelection = function($event, description) {
$event.stopPropagation(); $event.stopPropagation();
console.log('checkbox clicked'); console.log('checkbox clicked');
}; };
$scope.rowClicked = function(obj) {
$scope.rowClicked = function(obj) {
console.log('row clicked'); console.log('row clicked');
obj.selected = !obj.selected; obj.selected = !obj.selected;
}; };
//show submissions of Form //show submissions of Form
$scope.showSubmissions = function(){ $scope.showSubmissions = function(){
@ -758,24 +768,12 @@ angular.module('forms').controller('ViewFormController', ['$rootScope', '$scope'
} }
console.log($scope.submissions); console.log($scope.submissions);
}; };
//hide submissions of Form //hide submissions of Form
$scope.hideSubmissions = function(){ $scope.hideSubmissions = function(){
$scope.viewSubmissions = false; $scope.viewSubmissions = false;
}; };
// Return all user's Forms
$scope.findAll = function() {
$scope.myforms = Forms.query();
};
// Find a specific Form
$scope.findOne = function() {
$scope.myform = Forms.get({
formId: $stateParams.formId
});
CurrentForm.setForm($scope.myform);
};
// Remove existing Form // Remove existing Form
$scope.remove = function(form_id) { $scope.remove = function(form_id) {
@ -806,56 +804,55 @@ angular.module('forms').controller('ViewFormController', ['$rootScope', '$scope'
}); });
}; };
$scope.goToWithId = function(route, id) {
$state.go(route, {'formId': id}, {reload: true});
};
// Create new Form // Create new Form
$rootScope.createOrUpdate = function() { $scope.createNew = function(){
if($scope.isNewForm){ var form = {};
// Create new Form object form.title = $scope.myForm.name.$modelValue;
var form = new Forms($scope.myform); form.language = $scope.myForm.language.$modelValue;
console.log(form);
$scope.showCreateModal = true;
$http.post('/forms', {form: $scope.myform}) console.log($scope.myForm);
if($scope.myForm.$valid && $scope.myForm.$dirty){
$http.post('/forms', {form: form})
.success(function(data, status, headers){ .success(function(data, status, headers){
console.log('form created'); console.log('form created');
// Clear form fields // Clear form fields
$scope.myform = {}; $scope.myForm = {};
// Redirect after save // Redirect after save
$scope.goToWithId('viewForm', $scope.myform._id); $scope.goToWithId('viewForm', $scope.myform._id);
}).error(function(errorResponse){ }).error(function(errorResponse){
console.log(errorResponse.data.message); console.log(errorResponse);
$scope.error = errorResponse.data.message; // $scope.error = errorResponse.data.message;
}); });
} else{
$rootScope.update();
} }
}; };
// $rootScope.saveInProgress = false;
var saveFinished = function() {
$rootScope.saveInProgress = false;
console.log('update form');
};
// Update existing Form // Update existing Form
$rootScope.update = function() { $scope.saveInProgress = false;
$scope.update = $rootScope.update = function(cb) {
if(!$scope.saveInProgress){
$scope.saveInProgress = true;
$rootScope.saveInProgress = true; $rootScope.saveInProgress = true;
console.log('update form'); console.log('begin updating form');
var err = null;
$http.put('/forms/'+$scope.myform._id, {form: $scope.myform}) $http.put('/forms/'+$scope.myform._id, {form: $scope.myform})
.then(function(response){ .then(function(response){
console.log('form updated successfully'); console.log('form updated successfully');
}).catch(function(response){ console.log(response.status);
console.log('Error occured during form UPDATE.\n'); }).catch(function(response){
console.log(response.data); console.log('Error occured during form UPDATE.\n');
}).finally(function() { console.log(response.data);
$rootScope.saveInProgress = false; err = response.data;
console.log('update form'); }).finally(function() {
}); console.log('finished updating');
$scope.saveInProgress = false;
cb(err);
});
}
}; };
$rootScope.resetForm = function(){ $rootScope.resetForm = function(){
@ -872,11 +869,15 @@ angular.module('forms').directive('autoSaveForm', ['$rootScope', '$timeout', fun
return { return {
require: ['^form'], require: ['^form'],
// scope: {
// callback: '&autoSaveCallback'
// },
link: function($scope, $element, $attrs, $ctrls) { link: function($scope, $element, $attrs, $ctrls) {
if(!$rootScope.watchCount === undefined){ if($rootScope.watchCount === undefined){
$rootScope.watchCount = 0; $rootScope.watchCount = 0;
} }
var difference = function(array){ var difference = function(array){
var rest = Array.prototype.concat.apply(Array.prototype, Array.prototype.slice.call(arguments, 1)); var rest = Array.prototype.concat.apply(Array.prototype, Array.prototype.slice.call(arguments, 1));
@ -896,7 +897,7 @@ angular.module('forms').directive('autoSaveForm', ['$rootScope', '$timeout', fun
var expression = $attrs.autoSaveForm || 'true'; var expression = $attrs.autoSaveForm || 'true';
$scope.$on('ngRepeatStarted', function(ngRepeatFinishedEvent) { $scope.$on('ngRepeatStarted', function(ngRepeatFinishedEvent) {
$scope.finishedRender = false; // $scope.finishedRender = false;
$rootScope.watchCount = 0; $rootScope.watchCount = 0;
}); });
$scope.$on('ngRepeatFinished', function(ngRepeatFinishedEvent) { $scope.$on('ngRepeatFinished', function(ngRepeatFinishedEvent) {
@ -904,20 +905,20 @@ angular.module('forms').directive('autoSaveForm', ['$rootScope', '$timeout', fun
}); });
$scope.$watch('myform.form_fields', function(newValue, oldValue) { $scope.$watch('myform.form_fields', function(newValue, oldValue) {
console.log('watchCount: '+$rootScope.watchCount);
if(difference(oldValue,newValue).length === 0 || oldValue === undefined){ if(difference(oldValue,newValue).length === 0 || oldValue === undefined){
return; return;
} }
// console.log('\n\n-------\n$pristine: '+( $formCtrl.$pristine ) ); console.log('\n\n----------\n$dirty: '+( $formCtrl.$dirty ) );
// console.log('$dirty: '+( $formCtrl.$dirty ) ); console.log('form_fields changed: '+difference(oldValue,newValue).length );
// console.log('form_fields changed: '+difference(oldValue.form_fields,newValue.form_fields).length );
// console.log('$valid: '+$formCtrl.$valid); // console.log('$valid: '+$formCtrl.$valid);
// console.log('finishedRender: '+$scope.finishedRender); console.log('finishedRender: '+$scope.finishedRender);
// console.log('saveInProgress: '+$scope.saveInProgress); // console.log('saveInProgress: '+$scope.saveInProgress);
if($scope.finishedRender && ($formCtrl.$dirty || difference(oldValue,newValue).length !== 0) ) { if($scope.finishedRender && ($formCtrl.$dirty || difference(oldValue,newValue).length !== 0) ) {
$rootScope.watchCount++; $rootScope.watchCount++;
if($rootScope.watchCount === 1) { if($rootScope.watchCount === 1) {
if(savePromise) { if(savePromise) {
@ -927,15 +928,22 @@ angular.module('forms').directive('autoSaveForm', ['$rootScope', '$timeout', fun
savePromise = $timeout(function() { savePromise = $timeout(function() {
savePromise = null; savePromise = null;
// Still valid? $rootScope[$attrs.autoSaveCallback](
// if($formCtrl.$valid) { function(err){
if($scope.$eval(expression) !== false) { if(!err){
console.log('Form data persisted -- setting pristine flag'); // console.log('Form data persisted -- setting pristine flag');
$formCtrl.$setPristine(); console.log('\n\n---------\nUpdate form CLIENT');
} console.log(Date.now());
// } $rootScope.watchCount = 0;
$formCtrl.$setPristine();
}else{
console.log('Error form data NOT persisted');
console.log(err);
}
});
}); });
} }
} }
@ -1103,7 +1111,7 @@ angular.module('forms').directive('editFormDirective', ['$rootScope', '$q', '$ht
// console.log($scope.addField.types[i].name === fieldType); // 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++; $scope.addField.types[i].lastAddedID++;
console.log($scope.addField.types[i].lastAddedID); // console.log($scope.addField.types[i].lastAddedID);
fieldTitle = $scope.addField.types[i].value+$scope.addField.types[i].lastAddedID; fieldTitle = $scope.addField.types[i].value+$scope.addField.types[i].lastAddedID;
break; break;
} }
@ -1118,14 +1126,16 @@ angular.module('forms').directive('editFormDirective', ['$rootScope', '$q', '$ht
// put newField into fields array // put newField into fields array
$scope.myform.form_fields.unshift(newField); $scope.myform.form_fields.unshift(newField);
console.log($scope.myform.form_fields.length); console.log('\n\n---------\nAdded field CLIENT');
console.log(Date.now());
// console.log($scope.myform.form_fields.length);
}; };
// deletes particular field on button click // deletes particular field on button click
$scope.deleteField = function (hashKey){ $scope.deleteField = function (hashKey){
console.log($scope.myform.form_fields); // console.log($scope.myform.form_fields);
for(var i = 0; i < $scope.myform.form_fields.length; i++){ for(var i = 0; i < $scope.myform.form_fields.length; i++){
console.log($scope.myform.form_fields[i].$$hashKey === hashKey); // console.log($scope.myform.form_fields[i].$$hashKey === hashKey);
if($scope.myform.form_fields[i].$$hashKey === hashKey){ if($scope.myform.form_fields[i].$$hashKey === hashKey){
$scope.myform.form_fields.splice(i, 1); $scope.myform.form_fields.splice(i, 1);
break; break;
@ -1230,7 +1240,7 @@ var __indexOf = [].indexOf || function(item) {
}; };
angular.module('forms').directive('fieldDirective', function($http, $compile) { angular.module('forms').directive('fieldDirective', function($http, $compile) {
var getTemplateUrl = function(field) { var getTemplateUrl = function(field) {
@ -1254,6 +1264,17 @@ angular.module('forms').directive('fieldDirective', function($http, $compile) {
var linker = function(scope, element) { 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'){
$scope.dateOptions = {
changeYear: true,
changeMonth: true,
altFormat: "mm/dd/yyyy",
yearRange: '1900:-0',
defaultDate: 0,
};
}
// GET template content from path // GET template content from path
var templateUrl = getTemplateUrl(scope.field); var templateUrl = getTemplateUrl(scope.field);
@ -1546,7 +1567,7 @@ angular.module('users').config(['$httpProvider',
}; };
}); });
}]); }]);
'use strict';
// Setting up route // Setting up route
angular.module('users').config(['$stateProvider', angular.module('users').config(['$stateProvider',
@ -1620,7 +1641,7 @@ angular.module('users').config(['$stateProvider',
}). }).
state('signup-success', { state('signup-success', {
url: '/signup-success', url: '/signup-success',
templateUrl: 'modules/users/views/authentication/signup.client.view.html' templateUrl: 'modules/users/views/authentication/signup-success.client.view.html'
}). }).
state('signin', { state('signin', {
url: '/signin', url: '/signin',
@ -1662,14 +1683,12 @@ angular.module('users').controller('AuthenticationController', ['$scope', '$loca
if ($scope.authentication.isAuthenticated()) $state.go('home'); if ($scope.authentication.isAuthenticated()) $state.go('home');
$scope.signin = function() { $scope.signin = function() {
// console.log("signin");
// console.log($scope.credentials);
Auth.currentUser = User.login($scope.credentials).then( Auth.currentUser = User.login($scope.credentials).then(
function(response) { function(response) {
Auth.login(response); Auth.login(response);
$scope.user = $rootScope.user = Auth.ensureHasCurrentUser(User); $scope.user = $rootScope.user = Auth.ensureHasCurrentUser(User);
if($state.previous.name !== 'home'){ if($state.previous.name !== 'home' && $state.previous.name !== ''){
$state.go($state.previous.name); $state.go($state.previous.name);
}else{ }else{
$state.go('home'); $state.go('home');
@ -1687,8 +1706,9 @@ angular.module('users').controller('AuthenticationController', ['$scope', '$loca
}; };
$scope.signup = function() { $scope.signup = function() {
User.save($scope.registration, User.signup($scope.credentials).then(
function() { function(response) {
console.log('signup-success');
$state.go('signup-success'); $state.go('signup-success');
}, },
function(error) { function(error) {
@ -1986,6 +2006,39 @@ angular.module('users')
// // }; // // };
// } // }
// ]); // ]);
'use strict';
app.service('Authorizer', function(APP_PERMISSIONS, USER_ROLES) {
return function(user) {
return {
canAccess: function(permissions) {
var i, len, permission;
if (!angular.isArray(permissions)) {
permissions = [permissions];
}
for (i = 0, len = permissions.length; i < len; i++) {
permission = permissions[i];
if (APP_PERMISSIONS[permission] === null) {
throw 'Bad permission value';
}
if (user && user.role) {
switch (permission) {
case APP_PERMISSIONS.viewAdminSettings:
case APP_PERMISSIONS.editAdminSettings:
return user.role === USER_ROLES.admin;
case APP_PERMISSIONS.viewPrivateForm:
case APP_PERMISSIONS.editForm:
return user.role === USER_ROLES.admin || user.role === USER_ROLES.normal;
}
} else {
return false;
}
}
return false;
}
};
};
});
// 'use strict'; // 'use strict';
// angular.module('users').factory('AuthenticationService', function($http, $timeout, $q) { // angular.module('users').factory('AuthenticationService', function($http, $timeout, $q) {

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -1,6 +1,6 @@
'use strict'; 'use strict';
// Configuring the Articles module // Configuring the Forms drop-down menus
angular.module('forms').run(['Menus', angular.module('forms').run(['Menus',
function(Menus) { function(Menus) {
// Set top bar menu items // Set top bar menu items
@ -30,4 +30,10 @@ angular.module('forms').run(['Menus',
}).length; }).length;
return valid_count; return valid_count;
}; };
}); }).config(['$provide', function ($provide){
$provide.decorator('accordionDirective', function($delegate) {
var directive = $delegate[0];
directive.replace = true;
return $delegate;
});
}]);

View file

@ -17,13 +17,15 @@ angular.module('forms').config(['$stateProvider',
state('viewForm', { state('viewForm', {
url: '/forms/:formId/admin', url: '/forms/:formId/admin',
templateUrl: 'modules/forms/views/view-form.client.view.html', templateUrl: 'modules/forms/views/view-form.client.view.html',
data: {
permissions: [ 'editForm' ]
}
}). }).
state('viewPublicForm', { state('viewPublicForm', {
url: '/forms/:formId', url: '/forms/:formId',
templateUrl: 'modules/forms/views/view-public-form.client.view.html', templateUrl: 'modules/forms/views/view-public-form.client.view.html',
data: { data: {
hideNav: true, hideNav: true,
hideFooter: false
}, },
}). }).
state('editForm', { state('editForm', {

View file

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

View file

@ -14,10 +14,30 @@ angular.module('forms').controller('ViewFormController', ['$rootScope', '$scope'
rows: [] rows: []
}; };
// Return all user's Forms
$scope.findAll = function() {
$scope.myforms = Forms.query();
};
// Find a specific Form
$scope.findOne = function() {
$scope.myform = Forms.get({
formId: $stateParams.formId
});
CurrentForm.setForm($scope.myform);
};
$scope.goToWithId = function(route, id) {
$state.go(route, {'formId': id}, {reload: true});
};
$scope.setForm = function (form) { $scope.setForm = function (form) {
$scope.myForm = form; $scope.myForm = form;
}; };
//Modal functions
$scope.openCreateModal = function(){ $scope.openCreateModal = function(){
if(!$scope.showCreateModal){ if(!$scope.showCreateModal){
$scope.showCreateModal = true; $scope.showCreateModal = true;
@ -29,53 +49,9 @@ angular.module('forms').controller('ViewFormController', ['$rootScope', '$scope'
} }
}; };
//Create new form /*
$scope.createNew = function(){ * Table Functions
var form = {}; */
form.title = $scope.myForm.name.$modelValue;
form.language = $scope.myForm.language.$modelValue;
console.log(form);
$scope.showCreateModal = true;
console.log($scope.myForm);
if($scope.myForm.$valid && $scope.myForm.$dirty){
$http.post('/forms', {form: form})
.success(function(data, status, headers){
console.log('form created');
// Clear form fields
$scope.myForm = {};
// Redirect after save
$scope.goToWithId('viewForm', $scope.myform._id);
}).error(function(errorResponse){
console.log(errorResponse);
// $scope.error = errorResponse.data.message;
});
}
};
$scope.saveInProgress = false;
$scope.update = function() {
if(!$scope.saveInProgress){
$scope.saveInProgress = true;
console.log('start update()');
$http.put('/forms/'+$scope.myform._id, {form: $scope.myform})
.then(function(response){
console.log('form updated successfully');
console.log('$scope.saveInProgress: '+$scope.saveInProgress);
// $rootScope.goToWithId('viewForm', $scope.myform._id);
}).catch(function(response){
console.log('Error occured during form UPDATE.\n');
console.log(response.data);
}).finally(function() {
$scope.saveInProgress = false;
});
}
};
//Table Functions
$scope.toggleAllCheckers = function(){ $scope.toggleAllCheckers = function(){
console.log('toggleAllCheckers'); console.log('toggleAllCheckers');
for(var i=0; i<$scope.table.rows.length; i++){ for(var i=0; i<$scope.table.rows.length; i++){
@ -85,59 +61,72 @@ angular.module('forms').controller('ViewFormController', ['$rootScope', '$scope'
$scope.toggleObjSelection = function($event, description) { $scope.toggleObjSelection = function($event, description) {
$event.stopPropagation(); $event.stopPropagation();
console.log('checkbox clicked'); console.log('checkbox clicked');
}; };
$scope.rowClicked = function(obj) {
$scope.rowClicked = function(obj) { // console.log('row clicked');
console.log('row clicked');
obj.selected = !obj.selected; obj.selected = !obj.selected;
}; };
//show submissions of Form //show submissions of Form
$scope.showSubmissions = function(){ $scope.showSubmissions = function(){
$scope.viewSubmissions = true; $scope.viewSubmissions = true;
if(!$scope.table.rows.length){
$http.get('/forms/'+$scope.myform._id+'/submissions')
.success(function(data, status, headers){
console.log(data);
$scope.submissions = data;
$scope.table.rows = data;
console.log('form submissions successfully fetched');
})
.error(function(err){
console.log('Could not fetch form submissions.\nError: '+err);
});
} else if(!$scope.submissions.length){
$http.get('/forms/'+$scope.myform._id+'/submissions')
.success(function(data, status, headers){
$scope.submissions = data;
$scope.table.rows = data;
console.log($scope.table.rows);
console.log('form submissions successfully fetched');
})
.error(function(err){
console.log('Could not fetch form submissions.\nError: '+err);
});
}
console.log($scope.submissions);
};
$http.get('/forms/'+$scope.myform._id+'/submissions')
.success(function(data, status, headers){
console.log(data[0].form_fields);
var _data = Array();
for(var i=0; i<data.length; i++){
var _tmpSubFormFields = JSON.parse(JSON.stringify($scope.myform.form_fields));
for(var x=0; x<_tmpSubFormFields.length; x++){
var currField__id = _tmpSubFormFields[x]._id,
currField = undefined;
_.find(data[i].form_fields, function(fieldItem, fieldIdx){
if(fieldItem._id === currField__id){
currField = fieldItem;
console.log(fieldItem.fieldValue);
return true;
};
});
if(currField !== undefined){
_tmpSubFormFields[x].fieldValue = currField.fieldValue;
_tmpSubFormFields[x].$$hashKey = currField.$$hashKey;
}else {
_tmpSubFormFields[x].fieldValue = '';
}
}
// _tmpSubFormFields.order = i;
_data[i] = data[i];
_data[i].form_fields = _tmpSubFormFields;
};
console.log(JSON.stringify(_data));
$scope.submissions = _data;
$scope.table.rows = _data;
// console.log('form submissions successfully fetched');
// console.log( JSON.parse(JSON.stringify($scope.submissions)) ) ;
// console.log( JSON.parse(JSON.stringify($scope.myform.form_fields)) );
})
.error(function(err){
console.log('Could not fetch form submissions.\nError: '+err);
});
};
//hide submissions of Form //hide submissions of Form
$scope.hideSubmissions = function(){ $scope.hideSubmissions = function(){
$scope.viewSubmissions = false; $scope.viewSubmissions = false;
}; };
// Return all user's Forms
$scope.findAll = function() {
$scope.myforms = Forms.query();
};
// Find a specific Form
$scope.findOne = function() {
$scope.myform = Forms.get({
formId: $stateParams.formId
});
CurrentForm.setForm($scope.myform);
};
// Remove existing Form // Remove existing Form
$scope.remove = function(form_id) { $scope.remove = function(form_id) {
@ -168,56 +157,55 @@ angular.module('forms').controller('ViewFormController', ['$rootScope', '$scope'
}); });
}; };
$scope.goToWithId = function(route, id) {
$state.go(route, {'formId': id}, {reload: true});
};
// Create new Form // Create new Form
$rootScope.createOrUpdate = function() { $scope.createNew = function(){
if($scope.isNewForm){ var form = {};
// Create new Form object form.title = $scope.myForm.name.$modelValue;
var form = new Forms($scope.myform); form.language = $scope.myForm.language.$modelValue;
console.log(form);
$scope.showCreateModal = true;
$http.post('/forms', {form: $scope.myform}) console.log($scope.myForm);
if($scope.myForm.$valid && $scope.myForm.$dirty){
$http.post('/forms', {form: form})
.success(function(data, status, headers){ .success(function(data, status, headers){
console.log('form created'); console.log('form created');
// Clear form fields // Clear form fields
$scope.myform = {}; $scope.myForm = {};
// Redirect after save // Redirect after save
$scope.goToWithId('viewForm', $scope.myform._id); $scope.goToWithId('viewForm', $scope.myform._id);
}).error(function(errorResponse){ }).error(function(errorResponse){
console.log(errorResponse.data.message); console.log(errorResponse);
$scope.error = errorResponse.data.message; // $scope.error = errorResponse.data.message;
}); });
} else{
$rootScope.update();
} }
}; };
// $rootScope.saveInProgress = false;
var saveFinished = function() {
$rootScope.saveInProgress = false;
console.log('update form');
};
// Update existing Form // Update existing Form
$rootScope.update = function() { $scope.saveInProgress = false;
$scope.update = $rootScope.update = function(cb) {
if(!$scope.saveInProgress){
$scope.saveInProgress = true;
$rootScope.saveInProgress = true; $rootScope.saveInProgress = true;
console.log('update form'); // console.log('begin updating form');
var err = null;
$http.put('/forms/'+$scope.myform._id, {form: $scope.myform}) $http.put('/forms/'+$scope.myform._id, {form: $scope.myform})
.then(function(response){ .then(function(response){
console.log('form updated successfully'); // console.log('form updated successfully');
}).catch(function(response){ // console.log(response.status);
console.log('Error occured during form UPDATE.\n'); }).catch(function(response){
console.log(response.data); console.log('Error occured during form UPDATE.\n');
}).finally(function() { console.log(response.data);
$rootScope.saveInProgress = false; err = response.data;
console.log('update form'); }).finally(function() {
}); // console.log('finished updating');
$scope.saveInProgress = false;
cb(err);
});
}
}; };
$rootScope.resetForm = function(){ $rootScope.resetForm = function(){

View file

@ -1,3 +1,7 @@
.btn {
border: 1px solid #c6c6c6!important;
}
/* Styles for form submission view (/forms/:formID) */ /* Styles for form submission view (/forms/:formID) */
form .row.field { form .row.field {
padding: 1em 0 3em 0; padding: 1em 0 3em 0;
@ -14,14 +18,28 @@ form .row.field {
color:#ddd; color:#ddd;
} }
form.submission-form .row.field > .field-input input { form.submission-form .row.field > .field-input input {
width:500px; width:100%;
} }
form.submission-form .row.field .field-input > input:focus { form.submission-form .row.field .field-input > input:focus {
font-size:1em; font-size:1em;
} }
form .row.field.textfield > .field-input > input{ form .row.field.textfield > .field-input > input{
padding:0.45em 0.9em; padding:0.45em 0.9em;
width:600px; width:100%;
line-height:160%;
}
form .row.field.dropdown > .field-input {
height: 34px;
overflow: hidden;
}
form .row.field.dropdown > .field-input > select{
padding:0.45em 0.9em;
width:100%;
background: transparent;
font-size: 16px;
border: 1px solid #ccc;
height: 34px;
} }
div.config-form > .row { div.config-form > .row {

View file

@ -4,16 +4,20 @@ angular.module('forms').directive('autoSaveForm', ['$rootScope', '$timeout', fun
return { return {
require: ['^form'], require: ['^form'],
// scope: {
// callback: '&autoSaveCallback'
// },
link: function($scope, $element, $attrs, $ctrls) { link: function($scope, $element, $attrs, $ctrls) {
if(!$rootScope.watchCount === undefined){ if($rootScope.watchCount === undefined){
$rootScope.watchCount = 0; $rootScope.watchCount = 0;
} }
var difference = function(array){ var difference = function(array){
var rest = Array.prototype.concat.apply(Array.prototype, Array.prototype.slice.call(arguments, 1)); var rest = Array.prototype.concat.apply(Array.prototype, Array.prototype.slice.call(arguments, 1));
var containsEquals = function(obj, target) { var containsEquals = function(obj, target) {
if (obj == null) return false; if (obj === null) return false;
return _.any(obj, function(value) { return _.any(obj, function(value) {
return _.isEqual(value, target); return _.isEqual(value, target);
}); });
@ -28,7 +32,7 @@ angular.module('forms').directive('autoSaveForm', ['$rootScope', '$timeout', fun
var expression = $attrs.autoSaveForm || 'true'; var expression = $attrs.autoSaveForm || 'true';
$scope.$on('ngRepeatStarted', function(ngRepeatFinishedEvent) { $scope.$on('ngRepeatStarted', function(ngRepeatFinishedEvent) {
$scope.finishedRender = false; // $scope.finishedRender = false;
$rootScope.watchCount = 0; $rootScope.watchCount = 0;
}); });
$scope.$on('ngRepeatFinished', function(ngRepeatFinishedEvent) { $scope.$on('ngRepeatFinished', function(ngRepeatFinishedEvent) {
@ -36,20 +40,20 @@ angular.module('forms').directive('autoSaveForm', ['$rootScope', '$timeout', fun
}); });
$scope.$watch('myform.form_fields', function(newValue, oldValue) { $scope.$watch('myform.form_fields', function(newValue, oldValue) {
// console.log('watchCount: '+$rootScope.watchCount);
if(difference(oldValue,newValue).length === 0 || oldValue === undefined){ if(difference(oldValue,newValue).length === 0 || oldValue === undefined){
return; return;
} }
// console.log('\n\n-------\n$pristine: '+( $formCtrl.$pristine ) ); // console.log('\n\n----------\n$dirty: '+( $formCtrl.$dirty ) );
// console.log('$dirty: '+( $formCtrl.$dirty ) ); // console.log('form_fields changed: '+difference(oldValue,newValue).length );
// console.log('form_fields changed: '+difference(oldValue.form_fields,newValue.form_fields).length );
// console.log('$valid: '+$formCtrl.$valid); // console.log('$valid: '+$formCtrl.$valid);
// console.log('finishedRender: '+$scope.finishedRender); // console.log('finishedRender: '+$scope.finishedRender);
// console.log('saveInProgress: '+$scope.saveInProgress); // console.log('saveInProgress: '+$scope.saveInProgress);
if($scope.finishedRender && ($formCtrl.$dirty || difference(oldValue,newValue).length !== 0) ) { if($scope.finishedRender && ($formCtrl.$dirty || difference(oldValue,newValue).length !== 0) ) {
$rootScope.watchCount++; $rootScope.watchCount++;
if($rootScope.watchCount === 1) { if($rootScope.watchCount === 1) {
if(savePromise) { if(savePromise) {
@ -59,15 +63,22 @@ angular.module('forms').directive('autoSaveForm', ['$rootScope', '$timeout', fun
savePromise = $timeout(function() { savePromise = $timeout(function() {
savePromise = null; savePromise = null;
// Still valid? $rootScope[$attrs.autoSaveCallback](
// if($formCtrl.$valid) { function(err){
if($scope.$eval(expression) !== false) { if(!err){
console.log('Form data persisted -- setting pristine flag'); console.log('Form data persisted -- setting pristine flag');
$formCtrl.$setPristine(); console.log('\n\n---------\nUpdate form CLIENT');
} console.log(Date.now());
// } $rootScope.watchCount = 0;
$formCtrl.$setPristine();
}else{
console.log('Error form data NOT persisted');
console.log(err);
}
});
}); });
} }
} }

View file

@ -7,9 +7,10 @@ angular.module('forms').directive('configureFormDirective', ['$rootScope','$http
$scope.log = ''; $scope.log = '';
$scope.pdfLoading = false; $scope.pdfLoading = false;
$scope.languages = $rootScope.languages; $scope.languages = $rootScope.languages;
var _current_upload = null; var _current_upload = null;
$scope.createOrUpdate = $rootScope.createOrUpdate;
$scope.resetForm = $rootScope.resetForm; $scope.resetForm = $rootScope.resetForm;
$scope.update = $rootScope.update;
var _unbindedPdfFields = $scope.pdfFields; var _unbindedPdfFields = $scope.pdfFields;

View file

@ -13,6 +13,58 @@ angular.module('forms').directive('editFormDirective', ['$rootScope', '$q', '$ht
//Populate local scope with rootScope methods/variables //Populate local scope with rootScope methods/variables
$scope.update = $rootScope.update; $scope.update = $rootScope.update;
/*
** FormFields (ui-sortable) drag-and-drop configuration
*/
$scope.dropzone = {
handle: ' .handle'
}
// $scope.draggable = {
// connectWith: ".dropzone",
// start: function (e, ui) {
// // $scope.$apply(function() {
// // $scope.dragging = true
// // });
// $('.dropzone').sortable('refresh');
// },
// update: function (e, ui) {
// var isInDropzone = $(e.target).parentsUntil('.panel-group').hasClass('dropzone');
// console.log('isInDropzone: '+isInDropzone);
// //Disable drag and drop if we aren't in dropzone
// if(!isInDropzone){
// ui.item.sortable.cancel();
// }
// },
// stop: function (e, ui) {
// var isInDropzone = $(e.target).parentsUntil('.panel-group').hasClass('dropzone');
// //Disable drag and drop if we aren't in dropzone
// if(isInDropzone){
// console.log($(e.target));
// }
// // if (ui.item.sortable.droptarget === undefined) {
// // $scope.$apply($scope.dragging = false);
// // return;
// // }else if (ui.item.sortable.droptarget[0].classList[0] === "dropzone") {
// // // run code when item is dropped in the dropzone
// // $scope.$apply($scope.dragging = false);
// // }else{
// // // $scope.$apply($scope.dragging = false);
// // }
// // console.log('has class .dropzone :'+);
// // if ($(e.target).hasClass('dropzone') && ui.item.sortable.droptarget && e.target != ui.item.sortable.droptarget[0] ) {
// // // restore original types
// // $scope.addField.types = FormFields.fields;
// // }
// }
// };
//Populate AddField with all available form field types //Populate AddField with all available form field types
$scope.addField = {}; $scope.addField = {};
$scope.addField.types = FormFields.fields; $scope.addField.types = FormFields.fields;
@ -37,7 +89,7 @@ angular.module('forms').directive('editFormDirective', ['$rootScope', '$q', '$ht
// console.log($scope.addField.types[i].name === fieldType); // 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++; $scope.addField.types[i].lastAddedID++;
console.log($scope.addField.types[i].lastAddedID); // console.log($scope.addField.types[i].lastAddedID);
fieldTitle = $scope.addField.types[i].value+$scope.addField.types[i].lastAddedID; fieldTitle = $scope.addField.types[i].value+$scope.addField.types[i].lastAddedID;
break; break;
} }
@ -52,14 +104,16 @@ angular.module('forms').directive('editFormDirective', ['$rootScope', '$q', '$ht
// put newField into fields array // put newField into fields array
$scope.myform.form_fields.unshift(newField); $scope.myform.form_fields.unshift(newField);
console.log($scope.myform.form_fields.length); console.log('\n\n---------\nAdded field CLIENT');
console.log(Date.now());
// console.log($scope.myform.form_fields.length);
}; };
// deletes particular field on button click // deletes particular field on button click
$scope.deleteField = function (hashKey){ $scope.deleteField = function (hashKey){
console.log($scope.myform.form_fields); // console.log($scope.myform.form_fields);
for(var i = 0; i < $scope.myform.form_fields.length; i++){ for(var i = 0; i < $scope.myform.form_fields.length; i++){
console.log($scope.myform.form_fields[i].$$hashKey === hashKey); // console.log($scope.myform.form_fields[i].$$hashKey === hashKey);
if($scope.myform.form_fields[i].$$hashKey === hashKey){ if($scope.myform.form_fields[i].$$hashKey === hashKey){
$scope.myform.form_fields.splice(i, 1); $scope.myform.form_fields.splice(i, 1);
break; break;
@ -77,13 +131,12 @@ angular.module('forms').directive('editFormDirective', ['$rootScope', '$q', '$ht
// add new option to the field // add new option to the field
$scope.addOption = function (field){ $scope.addOption = function (field){
if(!field.field_options) if(!field.fieldOptions) field.fieldOptions = [];
field.field_options = [];
var lastOptionID = 0; var lastOptionID = 0;
if(field.field_options[field.field_options.length-1]) if(field.fieldOptions[field.fieldOptions.length-1])
lastOptionID = field.field_options[field.field_options.length-1].option_id; lastOptionID = field.fieldOptions[field.fieldOptions.length-1].option_id;
// new option's id // new option's id
var option_id = lastOptionID + 1; var option_id = lastOptionID + 1;
@ -94,15 +147,15 @@ angular.module('forms').directive('editFormDirective', ['$rootScope', '$q', '$ht
'option_value' : option_id 'option_value' : option_id
}; };
// put new option into field_options array // put new option into fieldOptions array
field.field_options.push(newOption); field.fieldOptions.push(newOption);
}; };
// delete particular option // delete particular option
$scope.deleteOption = function (field, option){ $scope.deleteOption = function (field, option){
for(var i = 0; i < field.field_options.length; i++){ for(var i = 0; i < field.fieldOptions.length; i++){
if(field.field_options[i].option_id === option.option_id){ if(field.fieldOptions[i].option_id === option.option_id){
field.field_options.splice(i, 1); field.fieldOptions.splice(i, 1);
break; break;
} }
} }
@ -110,10 +163,11 @@ angular.module('forms').directive('editFormDirective', ['$rootScope', '$q', '$ht
// decides whether field options block will be shown (true for dropdown and radio fields) // decides whether field options block will be shown (true for dropdown and radio fields)
$scope.showAddOptions = function (field){ $scope.showAddOptions = function (field){
if(field.fieldType == 'dropdown' || field.fieldType == 'checkbox' || field.fieldType == 'scale' || field.fieldType == 'rating' || field.fieldType == 'radio') if(field.fieldType === 'dropdown' || field.fieldType === 'checkbox' || field.fieldType === 'scale' || field.fieldType === 'rating' || field.fieldType === 'radio'){
return true; return true;
else } else {
return false; return false;
}
}; };
}, },

View file

@ -10,20 +10,20 @@ angular.module('forms').directive('fieldIconDirective', function($http, $compile
}, },
controller: function($scope){ controller: function($scope){
var iconTypeMap = { var iconTypeMap = {
"textfield": "fa fa-pencil-square-o", 'textfield': 'fa fa-pencil-square-o',
"dropdown": "fa fa-th-list", 'dropdown': 'fa fa-th-list',
"date": "fa fa-calendar", 'date': 'fa fa-calendar',
"checkbox": "fa fa-check-square-o", 'checkbox': 'fa fa-check-square-o',
"radio": "fa fa-dot-circle-o", 'radio': 'fa fa-dot-circle-o',
"email": "fa fa-envelope-o", 'email': 'fa fa-envelope-o',
"textarea": "fa fa-pencil-square", 'textarea': 'fa fa-pencil-square',
"legal": "fa fa-legal", 'legal': 'fa fa-legal',
"file": "fa fa-cloud-upload", 'file': 'fa fa-cloud-upload',
"rating": "fa fa-star-half-o", 'rating': 'fa fa-star-half-o',
"link": "fa fa-link", 'link': 'fa fa-link',
"scale": "fa fa-sliders", 'scale': 'fa fa-sliders',
"stripe": "fa fa-credit-card", 'stripe': 'fa fa-credit-card',
"statement": "fa fa-quote-left", 'statement': 'fa fa-quote-left',
} }
$scope.typeIcon = iconTypeMap[$scope.typeName]; $scope.typeIcon = iconTypeMap[$scope.typeName];
}, },

View file

@ -9,7 +9,7 @@ var __indexOf = [].indexOf || function(item) {
}; };
angular.module('forms').directive('fieldDirective', function($http, $compile) { angular.module('forms').directive('fieldDirective', function($http, $compile) {
var getTemplateUrl = function(field) { var getTemplateUrl = function(field) {
@ -33,6 +33,17 @@ angular.module('forms').directive('fieldDirective', function($http, $compile) {
var linker = function(scope, element) { 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'){
scope.dateOptions = {
changeYear: true,
changeMonth: true,
altFormat: "mm/dd/yyyy",
yearRange: '1900:-0',
defaultDate: 0,
};
}
// GET template content from path // GET template content from path
var templateUrl = getTemplateUrl(scope.field); var templateUrl = getTemplateUrl(scope.field);

View file

@ -4,5 +4,5 @@ angular.module('forms').directive('formLocator', function() {
link: function(scope) { link: function(scope) {
scope.$emit('formLocator'); scope.$emit('formLocator');
} }
} };
}); });

View file

@ -29,6 +29,10 @@ angular.module('forms').directive('formDirective', ['$http', '$timeout', 'timeCo
alert('Form canceled..'); alert('Form canceled..');
}; };
$scope.reloadForm = function(){
$scope.form.submitted = false;
}
}, },
templateUrl: './modules/forms/views/directiveViews/form/form.html', templateUrl: './modules/forms/views/directiveViews/form/form.html',
restrict: 'E', restrict: 'E',

View file

@ -16,5 +16,5 @@ angular.module('forms').directive('onFinishRender', function ($rootScope, $timeo
}, 500); }, 500);
} }
} }
} };
}); });

View file

@ -1,4 +1,4 @@
'use strict'; 'use strict';
// Use Application configuration module to register a new module // Use Application configuration module to register a new module
ApplicationConfiguration.registerModule('forms', ['ngFileUpload', 'users']); ApplicationConfiguration.registerModule('forms', ['ngFileUpload', 'ui.date', 'ui.sortable', 'users']);

View file

@ -1,231 +0,0 @@
<link rel="stylesheet" href="./modules/forms/css/form.css">
<section data-ng-controller="EditFormController">
<div ng-if="isNewForm">
<h1>Create your form</h1> <br>
<blockquote>
<p>Select field type you want to add to the form below and click on 'Add Field' button. Don't forget to set field properties. After you finish creating the form, you can preview the form by clicking Preview Form button.</p>
</blockquote>
</div>
<div ng-if="!isNewForm">
<h2>Edit your form</h2> <br>
</div>
<div class="well">
<div class="form-fields" ng-hide="previewMode">
<div class="form-properties row">
<div class="col-sm-12"><h3>Form Title</h3></div>
</div>
<div class="row">
<div class="col-sm-4"><p style="margin-top:20px;"><input type="text" name="form-name" ng-disabled="previewMode" ng-model="form.title" style="width:200px; height:30px;"></p></div>
</div>
<div class="row">
<div class="col-sm-12">
<h3>Fields</h3>
</div>
</div>
<div class="row">
<div class="add-field col-md-3 col-sm-12">
<select ng-model="addField.new" ng-options="type.name as type.value for type in addField.types"></select>
<button type="submit" class="btn" ng-click="addNewField()">
<i class="icon-plus"></i> Add Field
</button>
</div>
<div class="col-sm-3 col-md-8 col-md-offset-1">
<p ng-show="form.form_fields.length == 0">No fields added yet.</p>
<accordion close-others="accordion.oneAtATime">
<accordion-group heading="{{field.title}}" ng-repeat="field in form.form_fields">
<div class="accordion-edit">
<button class="btn btn-danger pull-right" type="button" ng-click="deleteField(field.client_id)"><i class="icon-trash icon-white"></i> Delete</button>
<div class="row">
<div class="col-xs-2">Field ID: </div>
<div class="col-xs-4">{{field.client_id}}</div>
</div>
<div class="row">
<div class="col-xs-2">Field Type:</div>
<div class="col-xs-4">{{field.fieldType}}</div>
</div>
<div class="clear"></div> <hr>
<div class="row">
<div class="col-xs-2">Field Title:</div>
<div class="col-xs-4"><input type="text" ng-model="field.title" value="{{field.title}}"></div>
</div>
<div class="row">
<div class="col-xs-2">Field Default Value:</div>
<div class="col-xs-4"><input type="text" ng-model="field.fieldValue" value="{{field.fieldValue}}"></div>
</div>
<div class="row" ng-show="showAddOptions(field)">
<div class="col-xs-2">Field Options:</div>
<div class="col-xs-6">
<div ng-repeat="option in field.field_options">
<input type="text" ng-model="option.option_title" value="{{option.option_title}}">
<a class="btn btn-danger btn-mini right" type="button" ng-click="deleteOption(field, option)"><i class="icon-minus icon-white"></i></a>
<span class="label label-inverse">Value: {{ option.option_value }}</span>
</div>
<button class="btn btn-primary btn-small" type="button" ng-click="addOption(field)"><i class="icon-plus icon-white"></i> Add Option</button>
</div>
</div>
<div class="clear"></div> <hr>
<div class="row">
<div class="col-xs-2">Required:</div>
<div class="col-xs-4">
<label>
<input type="radio" ng-value="true" ng-selected ng-model="field.required"/>
&nbsp; Yes
</label>
<label>
<input type="radio" ng-value="false" ng-model="field.required"/>
&nbsp; No
</label>
</div>
</div>
<div class="clear"></div> <hr>
<div class="row">
<div class="col-xs-2">Disabled:</div>
<div class="col-xs-4">
<label>
<input type="radio" ng-value="true" ng-selected ng-model="field.disabled"/>
&nbsp; Yes
</label>
<label>
<input type="radio" ng-value="false" ng-model="field.disabled"/>
&nbsp; No
</label>
</div>
</div>
</div>
</accordion-group>
</accordion>
</div>
</div>
<div class="row">
<div class="col-sm-12">
<h3>Form PDF</h3>
</div>
</div>
<div class="row">
<div class="col-sm-12">
<h5>Upload your PDF</h5>
</div>
<div class="col-sm-12">
<div class="input-group ">
<div tabindex="-1" class="form-control file-caption">
<span class="file-caption-ellipsis" ng-if="!form.pdf"></span>
<div class="file-caption-name" ng-if="form.pdf">
{{form.pdf.originalname}}
</div>
</div>
<div class="input-group-btn">
<button type="button" ng-if="form.pdf" ng-click="removePDF();" title="Clear selected files" class="btn btn-danger fileinput-remove fileinput-remove-button">
<i class="glyphicon glyphicon-trash" ></i>
Delete
</button>
<button type="button" ng-if="pdfLoading" title="Abort ongoing upload" class="btn btn-default" ng-click="cancelUpload()">
<i class="glyphicon glyphicon-ban-circle"></i>
Cancel
</button>
<div class="btn btn-success btn-file" ngf-select ngf-change="uploadPDF($files)" ng-if="!form.pdf">
<i class="glyphicon glyphicon-upload"></i>
Upload your PDF
</div>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-sm-12">
<h5>Autogenerate Form?</h5>
</div>
<br><br>
<div class="col-sm-4">
<label>
<input type="radio" data-ng-value="true" ng-model="form.isGenerated" ng-required="true" />
&nbsp;<span>Yes</span>
</label>
<label>
<input type="radio" data-ng-value="false" ng-model="form.isGenerated" ng-required="true" />
&nbsp;<span>No</span>
</label>
<!-- <span class="required-error" ng-show="field.required && !field.fieldValue">* required</span> -->
</div>
</div>
<div class="row" ng-if="form.isGenerated">
<div class="col-sm-12">
<h5>Save Submissions as PDFs?</h5>
</div>
<br><br>
<div class="col-sm-4">
<label>
<input type="radio" data-ng-value="true" ng-model="form.autofillPDFs" ng-required="true" />
&nbsp;<span>Yes</span>
</label>
<label>
<input type="radio" data-ng-value="false" ng-model="form.autofillPDFs" ng-required="true" />
&nbsp;<span>No</span>
</label>
<!-- <span class="required-error" ng-show="field.required && !field.fieldValue">* required</span> -->
</div>
</div>
<br><br>
<div class="row">
<div class="col-sm-offset-3 col-sm-2">
<button class="btn btn-primary btn-large" type="button" ng-click="createOrUpdate()"><i class="icon-arrow-left icon-white"></i> Save Changes</button>
</div>
<div class="col-sm-1">
<button class="btn btn-primary" type="button" ng-data-href="#!/forms/{{form._id}}/admin"><i class="icon-eye-open icon-white"></i> Cancel</button>
</div>
<div class="col-sm-1 col-sm-offset-1">
<button class="btn btn-secondary" type="button" ng-click="previewOn()"><i class="icon-eye-open icon-white"></i> Preview Form</button>
</div>
</div>
<br><hr>
<!-- <div class="text-center">
<a class="btn btn-small btn-primary" ng-show="!showJson" ng-click="showJson = true">Show form json object</a>
<a class="btn btn-small btn-inverse" ng-show="showJson" ng-click="showJson = false">Hide form json object</a><br><br>
</div>
<div ng-show="showJson">
<h4>Form object content:</h4>
<pre>{{ form | json }}</pre>
</div> -->
</div>
<div class="form-fields-preview" ng-show="previewMode">
<form-directive form="previewForm"></form-directive>
<p class="text-center">
<button class="btn btn-primary btn-large right" type="button" ng-click="previewOff()"><i class="icon-arrow-left icon-white"></i> Back to Create Mode</button>
</p>
</div>
</div>
</section>

View file

@ -3,7 +3,7 @@
<span class="required-error" ng-show="field.required && !field.fieldValue">* required </span> <span class="required-error" ng-show="field.required && !field.fieldValue">* required </span>
<div class="col-xs-7 field-input"> <div class="col-xs-7 field-input">
<div class="control-group input-append"> <div class="control-group input-append">
<input type="text" ng-model="field.fieldValue" ng-model-options="{ debounce: 250 }" data-date-format="mm/dd/yyyy" bs-datepicker ng-required="field.required" ng-disabled="field.disabled"> <input ui-date="dateOptions" ng-model="field.fieldValue" ng-model-options="{ debounce: 250 }" ng-required="field.required" ng-disabled="field.disabled">
<button type="button" class="btn" data-toggle="datepicker"><i class="icon-calendar"></i></button> <button type="button" class="btn" data-toggle="datepicker"><i class="icon-calendar"></i></button>
</div> </div>
</div> </div>

View file

@ -1,8 +1,8 @@
<div class="field row"> <div class="field row dropdown">
<div class="col-xs-7 field-title">{{field.title}} </div> <div class="col-xs-5 field-title">{{field.title}} </div>
<div class="col-xs-5 field-input"> <div class="col-xs-7 field-input ">
<select ng-model="field.fieldValue" ng-model-options="{ debounce: 250 }" ng-required="field.required" ng-disabled="field.disabled"> <select ng-model="field.fieldValue" ng-model-options="{ debounce: 250 }" ng-required="field.required" ng-disabled="field.disabled">
<option ng-repeat="option in field.field_options" <option ng-repeat="option in field.fieldOptions"
ng-selected="option.option_value == field.fieldValue" ng-selected="option.option_value == field.fieldValue"
value="{{option.option_id}}"> value="{{option.option_id}}">
{{option.option_title}} {{option.option_title}}

View file

@ -1,7 +1,7 @@
<div class="field row"> <div class="field row">
<div class="col-xs-5 field-title">{{field.title}} </div> <div class="col-xs-5 field-title">{{field.title}} </div>
<div class="col-xs-7 field-input"> <div class="col-xs-7 field-input">
<div ng-repeat="option in field.field_options" class="row-fluid"> <div ng-repeat="option in field.fieldOptions" class="row-fluid">
<label> <label>
<input type="radio" value="{{option.option_value}}" ng-model="field.fieldValue" ng-model-options="{ debounce: 250 }" ng-required="field.required" ng-disabled="field.disabled"/> <input type="radio" value="{{option.option_value}}" ng-model="field.fieldValue" ng-model-options="{ debounce: 250 }" ng-required="field.required" ng-disabled="field.disabled"/>
&nbsp;<span ng-bind="option.option_title"></span> &nbsp;<span ng-bind="option.option_title"></span>

View file

@ -180,7 +180,7 @@
</div> </div>
<div class="row"> <div class="row">
<div class="col-sm-offset-4 col-sm-2"> <div class="col-sm-offset-4 col-sm-2">
<button class="btn btn-primary btn-large" type="button" ng-click="createOrUpdate()"><i class="icon-arrow-left icon-white"></i> Save Changes</button> <button class="btn btn-primary btn-large" type="button" ng-click="update()"><i class="icon-arrow-left icon-white"></i> Save Changes</button>
</div> </div>
<div class="col-sm-1"> <div class="col-sm-1">
<button class="btn btn-primary" type="button" ng-click="resetForm()"><i class="icon-eye-open icon-white"></i> Cancel</button> <button class="btn btn-primary" type="button" ng-click="resetForm()"><i class="icon-eye-open icon-white"></i> Cancel</button>

View file

@ -1,4 +1,5 @@
<form class="row" name="fieldForm" form-locator auto-save-form="update()" form="myform" novalidation> <form class="row" name="fieldForm" form-locator auto-save-form auto-save-callback="update" form="myform" novalidation>
<div class="col-xs-5 add-field"> <div class="col-xs-5 add-field">
<!-- <select ng-model="addField.new" ng-options="type.name as type.value for type in addField.types"></select> <!-- <select ng-model="addField.new" ng-options="type.name as type.value for type in addField.types"></select>
<button type="submit" class="btn" ng-click="addNewField()"> <button type="submit" class="btn" ng-click="addNewField()">
@ -8,7 +9,7 @@
<h3 class="col-xs-12">Add New Field</h3> <h3 class="col-xs-12">Add New Field</h3>
<span ng-if="form.$dirty && form.$valid" class="help-block">Updating ...</span> <span ng-if="form.$dirty && form.$valid" class="help-block">Updating ...</span>
</div> </div>
<div class="panel-group row"> <div class="panel-group row" class="draggable" ng-model="addField.types">
<div class="col-xs-6" ng-repeat="type in addField.types" on-finish-render> <div class="col-xs-6" ng-repeat="type in addField.types" on-finish-render>
<div class="panel panel-default" style="background-color:#f5f5f5;"> <div class="panel panel-default" style="background-color:#f5f5f5;">
<div class="panel-heading" ng-click="addNewField(type.name)" style="cursor: pointer; font-size:14px;"> <div class="panel-heading" ng-click="addNewField(type.name)" style="cursor: pointer; font-size:14px;">
@ -27,23 +28,26 @@
<!-- <p ng-show="form.form_fields.length == 0">No fields added yet.</p> --> <!-- <p ng-show="form.form_fields.length == 0">No fields added yet.</p> -->
<div class="row"> <div class="row">
<div class="col-xs-10"> <div class="col-xs-10">
<accordion close-others="accordion.oneAtATime"> <accordion close-others="accordion.oneAtATime" ui-sortable="dropzone" ng-model="myform.form_fields" class="dropzone">
<accordion-group ng-repeat="field in myform.form_fields" is-open="accordion[$index].isOpen" on-finish-render="setFormValid()"> <accordion-group ng-repeat="field in myform.form_fields" is-open="accordion[$index].isOpen" on-finish-render="setFormValid()">
<accordion-heading> <accordion-heading>
<span class="pull-left" ng-switch="field.fieldType"> <div class="handle">
<field-icon-directive type-name="{{field.fieldType}}"></field-icon-directive> <span class="pull-left" ng-switch="field.fieldType">
</span> <field-icon-directive type-name="{{field.fieldType}}"></field-icon-directive>
<span style="padding-left:1.2em;">{{field.title}}</span> </span>
<span class="pull-right"> <span style="padding-left:1.2em;">{{field.title}}</span>
<i class="fa fa-chevron-right" ng-hide="accordion[$index].isOpen"> <span class="pull-right">
</i> <i class="fa fa-chevron-right" ng-hide="accordion[$index].isOpen">
<i class="fa fa-chevron-down" ng-show="accordion[$index].isOpen"> </i>
</i> <i class="fa fa-chevron-down" ng-show="accordion[$index].isOpen">
</span> </i>
</span>
</div>
</accordion-heading> </accordion-heading>
<div class="accordion-edit container"> <div class="accordion-edit container">
<!-- <button class="btn btn-danger pull-right" type="button" ng-click="deleteField(field.client_id)"><i class="icon-trash icon-white"></i> Delete</button> -->
<div class="row"> <div class="row">
<div class="col-xs-12"> <div class="col-xs-12">
<h4>Preview</h4> <h4>Preview</h4>
@ -55,7 +59,9 @@
</field-directive> </field-directive>
</ul> </ul>
</div> </div>
<div class="clear"></div> <hr> <div class="clear"></div> <hr>
<div class="row"> <div class="row">
<div class="col-xs-2">Field Type:</div> <div class="col-xs-2">Field Type:</div>
<div class="col-xs-4">{{field.fieldType}}</div> <div class="col-xs-4">{{field.fieldType}}</div>
@ -69,7 +75,7 @@
<div class="row" ng-show="showAddOptions(field)"> <div class="row" ng-show="showAddOptions(field)">
<div class="col-xs-2">Field Options:</div> <div class="col-xs-2">Field Options:</div>
<div class="col-xs-6 container"> <div class="col-xs-6 container">
<div ng-repeat="option in field.field_options" class="row"> <div ng-repeat="option in field.fieldOptions" class="row">
<input type="text" name="{{option.option_title}}" ng-model="option.option_title" value="{{option.option_title}}" class="col-xs-4"> <input type="text" name="{{option.option_title}}" ng-model="option.option_title" value="{{option.option_title}}" class="col-xs-4">
<a class="btn btn-danger btn-mini right" type="button" ng-click="deleteOption(field, option)" class="col-xs-3"><i class="fa fa-trash-o"></i></a> <a class="btn btn-danger btn-mini right" type="button" ng-click="deleteOption(field, option)" class="col-xs-3"><i class="fa fa-trash-o"></i></a>
@ -114,6 +120,7 @@
</div> </div>
</accordion-group> </accordion-group>
<div class="panel panel-default" style="border-style: dashed; border-color: #a9a9a9;"> <div class="panel panel-default" style="border-style: dashed; border-color: #a9a9a9;">
<div class="panel-heading"> <div class="panel-heading">
<h4 class="panel-title text-center" style="color: #a9a9a9;"> <h4 class="panel-title text-center" style="color: #a9a9a9;">
@ -121,6 +128,7 @@
</h4> </h4>
</div> </div>
</div> </div>
</accordion> </accordion>
</div> </div>
<div class="col-xs-1" style="padding:0 5px;" > <div class="col-xs-1" style="padding:0 5px;" >

View file

@ -41,7 +41,7 @@
<div class="row form-actions"> <div class="row form-actions">
<p class="text-center col-xs-3 col-xs-offset-4"> <p class="text-center col-xs-3 col-xs-offset-4">
<button class="btn btn-success left" type="button"> <button class="btn btn-success left" type="button">
<a href="/#!/forms/{{form._id}}" style="color:white;"> Submit again?</a> <a href="#" ng-click="reloadForm()" style="color:white;"> Submit again?</a>
</button> </button>
</p> </p>
<p class="text-center col-xs-2" ng-if="authentication.isAuthenticated()"> <p class="text-center col-xs-2" ng-if="authentication.isAuthenticated()">

View file

@ -10,7 +10,7 @@
</div> </div>
<div class="col-xs-2"> <div class="col-xs-2">
<small class=" pull-right"> <small class=" pull-right">
<a class="btn btn-default" href="/#!/forms/{{form._id}}"> <a class="btn btn-default" href="/#!/forms/{{myform._id}}">
<span ng-show="myform.isLive">View Live</span> <span ng-hide="myform.isLive">Preview</span> Form <span ng-show="myform.isLive">View Live</span> <span ng-hide="myform.isLive">Preview</span> Form
<i class="status-light status-light-on fa fa-dot-circle-o" ng-show="myform.isLive"></i> <i class="status-light status-light-on fa fa-dot-circle-o" ng-show="myform.isLive"></i>
<i class="status-light status-light-off fa fa-dot-circle-o" ng-hide="myform.isLive"></i> <i class="status-light status-light-off fa fa-dot-circle-o" ng-hide="myform.isLive"></i>
@ -53,7 +53,7 @@
<input ng-model="table.masterChecker" ng-change="toggleAllCheckers()" type="checkbox"/> <input ng-model="table.masterChecker" ng-change="toggleAllCheckers()" type="checkbox"/>
</th> </th>
<th>#</th> <th>#</th>
<th data-ng-repeat="(key, value) in submissions[0].form_fields"> <th data-ng-repeat="(key, value) in myform.form_fields">
{{value.title}} {{value.title}}
</th> </th>
<th> <th>
@ -70,7 +70,7 @@
<tbody> <tbody>
<tr data-ng-repeat="row in table.rows" ng-click="rowClicked(row)"> <tr data-ng-repeat="row in table.rows" ng-click="rowClicked(row)">
<td> <td>
<!-- <input ng-model="row.selected" type="checkbox"/> --> <input ng-model="row.selected" type="checkbox"/>
</td> </td>
<th class="scope">{{$index+1}}</th> <th class="scope">{{$index+1}}</th>
<td data-ng-repeat="(key, value) in row.form_fields"> <td data-ng-repeat="(key, value) in row.form_fields">

View file

@ -72,7 +72,7 @@ angular.module('users').config(['$stateProvider',
}). }).
state('signup-success', { state('signup-success', {
url: '/signup-success', url: '/signup-success',
templateUrl: 'modules/users/views/authentication/signup.client.view.html' templateUrl: 'modules/users/views/authentication/signup-success.client.view.html'
}). }).
state('signin', { state('signin', {
url: '/signin', url: '/signin',

View file

@ -11,14 +11,12 @@ angular.module('users').controller('AuthenticationController', ['$scope', '$loca
if ($scope.authentication.isAuthenticated()) $state.go('home'); if ($scope.authentication.isAuthenticated()) $state.go('home');
$scope.signin = function() { $scope.signin = function() {
// console.log("signin");
// console.log($scope.credentials);
Auth.currentUser = User.login($scope.credentials).then( Auth.currentUser = User.login($scope.credentials).then(
function(response) { function(response) {
Auth.login(response); Auth.login(response);
$scope.user = $rootScope.user = Auth.ensureHasCurrentUser(User); $scope.user = $rootScope.user = Auth.ensureHasCurrentUser(User);
if($state.previous.name !== 'home'){ if($state.previous.name !== 'home' && $state.previous.name !== ''){
$state.go($state.previous.name); $state.go($state.previous.name);
}else{ }else{
$state.go('home'); $state.go('home');
@ -36,8 +34,9 @@ angular.module('users').controller('AuthenticationController', ['$scope', '$loca
}; };
$scope.signup = function() { $scope.signup = function() {
User.save($scope.registration, User.signup($scope.credentials).then(
function() { function(response) {
console.log('signup-success');
$state.go('signup-success'); $state.go('signup-success');
}, },
function(error) { function(error) {

View file

@ -27,6 +27,6 @@ section.auth {
padding-bottom: 0.5em; padding-bottom: 0.5em;
} }
section.auth.signup-view.success > h3 { /* section.auth.signup-view.success > h3 {
padding-bottom: 1.2em; padding-bottom: 1.2em;
} }*/

View file

@ -0,0 +1,34 @@
'use strict';
angular.module('users').service('Authorizer', function(APP_PERMISSIONS, USER_ROLES) {
return function(user) {
return {
canAccess: function(permissions) {
var i, len, permission;
if (!angular.isArray(permissions)) {
permissions = [permissions];
}
for (i = 0, len = permissions.length; i < len; i++) {
permission = permissions[i];
if (APP_PERMISSIONS[permission] === null) {
throw 'Bad permission value';
}
if (user && user.roles) {
switch (permission) {
case APP_PERMISSIONS.viewAdminSettings:
case APP_PERMISSIONS.editAdminSettings:
return user.roles.indexOf(USER_ROLES.admin) > -1;
case APP_PERMISSIONS.viewPrivateForm:
case APP_PERMISSIONS.editForm:
return user.roles.indexOf(USER_ROLES.admin) > -1 || user.roles.indexOf(USER_ROLES.normal) > -1;
}
} else {
return false;
}
}
return false;
}
};
};
});

View file

@ -1,8 +1,62 @@
'use strict'; 'use strict';
(function() { (function() {
// Principal controller Spec for E2E Tests
describe('AuthenticationController E2E Tests', function() {
describe('/signup should work for a unique username', function() {
beforeEach(function() {
var ptor = protractor.getInstance();
ptor.get('http://localhost:3000/#!/signup');
});
it('should show the signup panel on page load', function() {
expect($('section > section.row.auth > .col-md-12.text-center')).toEqual('Signup with your email');
});
//Jasmine it statement : What "it" will do.
it('Verify that the user is logged in', function() {
//Delete all cookies
browser.driver.manage().deleteAllCookies();
//Enter UserName
element.all(by.model('username')).get(0).sendKeys('abc@wingify.com');
//Enter Password
element(by.model('password')).sendKeys('test');
//Click Submit button
element(by.css('.login-form button[type="submit"]')).click();
//Wait for the current URL to change to welcome
browser.driver.wait(function() {
return browser.driver.getCurrentUrl().then(function(url) {
return (/welcome/).test(url);
});
});
var firstname = element(by.model('credentials.firstname')),
lastname = element(by.model('credentials.lastname')),
email = element(by.model('credentials.email')),
password = element(by.model('credentials.password')),
username = element(by.model('credentials.username'));
email.sendKeys('admin@app.com');
username.sendKeys('admin');
firstname.sendKeys('admin_first');
firstname.sendKeys('admin_last');
password.sendKeys('1234');
//Click signup button
element(by.css('.btn.btn-large.btn-primary')).click().then(function () {
expect(browser.getCurrentUrl()).toEqual('http://localhost:3000/#!/signup-success');
});
});
});
});
// Principal controller Spec // Principal controller Spec
describe('AuthenticationController', function() { describe('AuthenticationController Unit Tests', function() {
// Initialize global variables // Initialize global variables
var AuthenticationController, var AuthenticationController,
scope, scope,

View file

@ -17,17 +17,15 @@
<img src="/modules/users/img/buttons/github.png"> <img src="/modules/users/img/buttons/github.png">
</a> </a>
</div> --> </div> -->
<h3 class="col-xs-offset-2 col-xs-8 col-md-offset-3 col-md-6 text-center">Signup with your email</h3> <h3 class="col-xs-offset-2 col-xs-8 col-md-offset-3 col-md-6 text-center">Signup Successful</h3>
<div class="col-xs-offset-2 col-xs-8 col-md-offset-3 col-md-6"> <div class="col-xs-offset-2 col-xs-8 col-md-offset-3 col-md-6">
<h2>Congrats! You've successfully registered an account at MedForms. </h2> <h2>
<p>Before you continue, make sure to check your email for our verification email. If you don't receive it within 24h drop us a line</p> Congrats! You've successfully registered an account at MedForms. <br>But your account is <b>not verified yet</b>
<ul> </h2>
<li> <p>Before you continue, make sure to check your email for our verification email. If you don't receive it within 24h drop us a line at <a href="mail:hi@medforms.com">hi@medforms.com</a></p>
Click <div class="text-center form-group">
<em href="#!/">Here</em> <button type="submit" class="btn btn-large btn-primary"><a href="/">Continue</a></button>
to continue </div>
</li>
</ul>
</div> </div>
</div> </div>
</section> </section>

View file

@ -48,8 +48,7 @@
<input type="password" id="password" name="password" class="form-control" data-ng-model="credentials.password" placeholder="Password"> <input type="password" id="password" name="password" class="form-control" data-ng-model="credentials.password" placeholder="Password">
</div> </div>
<div class="text-center form-group"> <div class="text-center form-group">
<button type="submit" class="btn btn-large btn-primary">Sign up</button>&nbsp; or&nbsp; <button type="submit" class="btn btn-large btn-primary">Sign up</button>
<a href="/#!/signin" class="show-signup">Sign in</a>
</div> </div>
</fieldset> </fieldset>