fixed user permissions problem

This commit is contained in:
David Baldwynn 2015-10-30 11:40:02 -07:00
parent f858fe66a4
commit 92c84dc500
40 changed files with 814 additions and 612 deletions

View file

@ -68,7 +68,6 @@ exports.uploadPDF = function(req, res, next) {
}
};
/**
* Delete a forms submissions
*/
@ -89,6 +88,7 @@ exports.deleteSubmissions = function(req, res) {
res.status(200).send('Form submissions successfully deleted');
});
};
/**
* Submit a form entry
*/
@ -144,13 +144,13 @@ exports.createSubmission = function(req, res) {
exports.listSubmissions = function(req, res) {
var _form = req.form;
var _user = req.user;
// console.log('listSubmissions');
console.log('listSubmissions');
// console.log(_form);
// if(_form.submissions.length){
// res.json(_form.submissions);
// }else{
FormSubmission.find({ form: req.form, admin: _user }).populate('admin', 'form').exec(function(err, _submissions) {
FormSubmission.find({ form: _form._id, admin: _user._id }).populate('admin', 'form').exec(function(err, _submissions) {
if (err) {
console.log(err);
res.status(400).send({
@ -201,7 +201,11 @@ exports.create = function(req, res) {
* Show the current form
*/
exports.read = function(req, res) {
res.json(req.form);
var validUpdateTypes= Form.schema.path('plugins.oscarhost.settings.updateType').enumValues;
var newForm = JSON.parse(JSON.stringify(req.form));
newForm.plugins.oscarhost.settings.validUpdateTypes = validUpdateTypes;
res.json(newForm);
};
/**
@ -211,7 +215,6 @@ exports.update = function(req, res) {
var form = req.form;
delete req.body.form.__v;
delete req.body.form._id;
delete req.body.form.admin;
//Unless we have 'admin' priviledges, updating form admin is disabled
if(req.user.roles.indexOf('admin') === -1) delete req.body.form.admin;
@ -268,7 +271,6 @@ exports.list = function(req, res) {
});
};
/**
* Form middleware
*/
@ -289,13 +291,11 @@ exports.formByID = function(req, res, next, id) {
});
}
else {
// console.log(form.admin);
//Remove sensitive information from User object
form.admin.password = undefined;
form.admin.salt = undefined;
form.provider = undefined;
req.form = form;
next();
}

View file

@ -83,7 +83,7 @@ exports.signup = function(req, res) {
});
} else {
console.log('Error: Temp user already exists!');
res.status(400).send('Error: Temp user already exists!');
res.status(400).send({ message: 'Error: Temp user already exists!' });
}
}
});

View file

@ -10,13 +10,25 @@ var _ = require('lodash'),
/**
* User middleware
*/
exports.userByID = function(req, res, next, id) {
User.findById(id).exec(function(err, user) {
if (err) return next(err);
if (!user) return next(new Error('Failed to load User ' + id));
req.profile = user;
next();
});
exports.userByID = function (req, res, next, id) {
if (!mongoose.Types.ObjectId.isValid(id)) {
return res.status(400).send({
message: 'User is invalid'
});
}
User.findOne({
_id: id
}).exec(function (err, user) {
if (err) {
return next(err);
} else if (!user) {
return next(new Error('Failed to load User ' + id));
}
req.profile = user;
next();
});
};
/**

View file

@ -154,6 +154,26 @@ var FormSchema = new Schema({
},
fieldMap: {
type: Schema.Types.Mixed,
},
validUpdateTypes: {
type: [String]
},
validFields : {
type: [String],
default: [
'address',
'city',
'email',
'firstName',
'hin',
'lastName',
'phone',
'postal',
'province',
'sex',
'spokenLanguage',
'title',
'DOB']
}
},
auth: {
@ -173,7 +193,25 @@ FormSchema.plugin(mUtilities.timestamp, {
modifiedPath: 'lastModified',
useVirtual: false
});
FormSchema.pre('save', function (next) {
var validUpdateTypes= mongoose.model('Form').schema.path('plugins.oscarhost.settings.updateType').enumValues;
this.plugins.oscarhost.settings.validUpdateTypes = validUpdateTypes;
this.plugins.oscarhost.settings.validFields = [
'address',
'city',
'email',
'firstName',
'hin',
'lastName',
'phone',
'postal',
'province',
'sex',
'spokenLanguage',
'title',
'DOB'];
});
//Delete template PDF of current Form
FormSchema.pre('remove', function (next) {
if(this.pdf && process.env.NODE_ENV === 'development'){

View file

@ -64,10 +64,34 @@ var FormFieldSchema = new Schema({
type: Boolean,
default: false
},
validFieldTypes: {
type: [String]
},
fieldType: {
type: String,
required: true,
validate: [validateFormFieldType, 'Invalid field type']
enum: [
'textfield',
'date',
'email',
'link',
'legal',
'url',
'textarea',
'statement',
'welcome',
'thankyou',
'file',
'dropdown',
'scale',
'rating',
'radio',
'checkbox',
'hidden',
'yes_no',
'natural',
'number'
],
},
fieldValue: Schema.Types.Mixed
});
@ -78,61 +102,11 @@ FormFieldSchema.plugin(mUtilities.timestamp, {
modifiedPath: 'lastModified',
useVirtual: false
});
FormFieldSchema.static('validTypes', function(){
return [
'textfield',
'date',
'email',
'legal',
'url',
'textarea',
'statement',
'welcome',
'thankyou',
'file',
'dropdown',
'scale',
'rating',
'radio',
'checkbox',
'hidden',
'yes_no',
'natural',
'number'
];
});
// fieldType Validation
function validateFormFieldType(value) {
if (!value) { return false; }
// FormFieldSchema.pre('init', function (next){
// this.validFieldTypes = Field.schema.path('fieldType').enumValues;
// });
var validTypes = [
'textfield',
'date',
'email',
'legal',
'url',
'textarea',
'statement',
'welcome',
'thankyou',
'file',
'dropdown',
'scale',
'rating',
'radio',
'checkbox',
'hidden',
'yes_no',
'natural',
'number'
];
if (validTypes.indexOf(value) > -1) {
return true;
}
return false;
};
mongoose.model('Field', FormFieldSchema);

View file

@ -103,8 +103,6 @@ FormSubmissionSchema.plugin(mUtilities.timestamp, {
useVirtual: false
});
//Oscarhost API hook
FormSubmissionSchema.pre('save', function (next) {
@ -149,7 +147,7 @@ FormSubmissionSchema.pre('save', function (next) {
if(demographicsTemplate.hasOwnProperty(conversionMap[currField._id])){
_generatedDemo[propertyName] = currField.fieldValue+'';
}else if(propertyName === 'unparsedDOB'){
}else if(propertyName === 'DOB'){
var date = new Date(currField.fieldValue);
_generatedDemo['dateOfBirth'] = date.getDate()+'';
_generatedDemo['yearOfBirth'] = date.getFullYear()+'';

View file

@ -16,7 +16,7 @@ var should = require('should'),
var exampleDemo = {
activeCount: 1,
unparsedDOB: '',
DOB: '',
address: '880-9650 Velit. St.',
chartNo: '',
city: '',
@ -116,7 +116,7 @@ describe('Form Model Unit Tests:', function() {
});
});
it('should be able to findOne my form without problems', function(done) {
return Form.findOne({_id: myForm._id}, function(err,form) {
return Form.findOne({title: myForm.title}).exec(function(err,form) {
should.not.exist(err);
should.exist(form);
should.deepEqual(form.toObject(), myForm.toObject());

View file

@ -17,12 +17,12 @@ var should = require('should'),
/**
* Globals
*/
var credentials, user, _Form, userSession;
var credentials, user, myForm, userSession;
/**
* Form routes tests
*/
describe('Form CRUD tests', function() {
describe('Form Routes Unit tests', function() {
beforeEach(function(done) {
@ -48,7 +48,7 @@ describe('Form CRUD tests', function() {
// Save a user to the test db and create new Form
user.save(function(err) {
if(err) done(err);
_Form = {
myForm = {
title: 'Form Title',
language: 'english',
admin: user._id,
@ -78,7 +78,7 @@ describe('Form CRUD tests', function() {
// Save a new Form
userSession.post('/forms')
.send({form: _Form})
.send({form: myForm})
.expect('Content-Type', /json/)
.expect(200)
.end(function(FormSaveErr, FormSaveRes) {
@ -109,7 +109,7 @@ describe('Form CRUD tests', function() {
it('should not be able to create a Form if not logged in', function(done) {
userSession.post('/forms')
.send({form: _Form})
.send({form: myForm})
.expect(401)
.end(function(FormSaveErr, FormSaveRes) {
(FormSaveRes.body.message).should.equal('User is not logged in');
@ -130,7 +130,7 @@ describe('Form CRUD tests', function() {
it('should not be able to save a Form if no title is provided', function(done) {
// Set Form with a invalid title field
_Form.title = '';
myForm.title = '';
userSession.post('/auth/signin')
.send(credentials)
@ -142,13 +142,12 @@ describe('Form CRUD tests', function() {
// Save a new Form
userSession.post('/forms')
.send({form: _Form})
.send({form: myForm})
.expect(400)
.end(function(FormSaveErr, FormSaveRes) {
// Set message assertion
(FormSaveRes.body.message).should.equal('Form Title cannot be blank');
// Handle Form save error
done();
});
});
@ -165,7 +164,7 @@ describe('Form CRUD tests', function() {
// Save a new Form
userSession.post('/forms')
.send({form: _Form})
.send({form: myForm})
.expect('Content-Type', /json/)
.expect(200)
.end(function(FormSaveErr, FormSaveRes) {
@ -173,11 +172,11 @@ describe('Form CRUD tests', function() {
if (FormSaveErr) done(FormSaveErr);
// Update Form title
_Form.title = 'WHY YOU GOTTA BE SO MEAN?';
myForm.title = 'WHY YOU GOTTA BE SO MEAN?';
// Update an existing Form
userSession.put('/forms/' + FormSaveRes.body._id)
.send({form: _Form})
.send({form: myForm})
.expect('Content-Type', /json/)
.expect(200)
.end(function(FormUpdateErr, FormUpdateRes) {
@ -197,7 +196,7 @@ describe('Form CRUD tests', function() {
it('should be able to read/get a Form if not signed in', function(done) {
// Create new Form model instance
var FormObj = new Form(_Form);
var FormObj = new Form(myForm);
// Save the Form
FormObj.save(function(err, form) {
@ -210,7 +209,7 @@ describe('Form CRUD tests', function() {
if(err) done(err)
// Set assertion
(res.body).should.be.an.Object.with.property('title', _Form.title);
(res.body).should.be.an.Object.with.property('title', myForm.title);
// Call the assertion callback
done();
@ -228,42 +227,41 @@ describe('Form CRUD tests', function() {
// Handle signin error
if (signinErr) done(signinErr);
done();
// Save a new Form
// userSession.post('/forms')
// .send({form: _Form})
// .expect('Content-Type', /json/)
// .expect(200)
// .end(function(FormSaveErr, FormSaveRes) {
// // Handle Form save error
// if (FormSaveErr) done(FormSaveErr);
userSession.post('/forms')
.send({form: myForm})
.expect('Content-Type', /json/)
.expect(200)
.end(function(FormSaveErr, FormSaveRes) {
// Handle Form save error
if (FormSaveErr) done(FormSaveErr);
// // Delete an existing Form
// userSession.delete('/forms/' + FormSaveRes.body._id)
// .send(_Form)
// .expect('Content-Type', /json/)
// .expect(200)
// .end(function(FormDeleteErr, FormDeleteRes) {
// // Handle Form error error
// if (FormDeleteErr) done(FormDeleteErr);
// Delete an existing Form
userSession.delete('/forms/' + FormSaveRes.body._id)
.send(myForm)
.expect('Content-Type', /json/)
.expect(200)
.end(function(FormDeleteErr, FormDeleteRes) {
// Handle Form error error
if (FormDeleteErr) done(FormDeleteErr);
// // Set assertions
// (FormDeleteRes.body._id).should.equal(FormSaveRes.body._id);
// Set assertions
(FormDeleteRes.body._id).should.equal(FormSaveRes.body._id);
// // Call the assertion callback
// done();
// });
// });
// Call the assertion callback
done();
});
});
});
});
it('should not be able to delete an Form if not signed in', function(done) {
// Set Form user
_Form.admin = user;
myForm.admin = user;
// Create new Form model instance
var FormObj = new Form(_Form);
var FormObj = new Form(myForm);
// Save the Form
FormObj.save(function() {
@ -297,7 +295,7 @@ describe('Form CRUD tests', function() {
// Save a new Form
userSession.post('/forms')
.send({form: _Form})
.send({form: myForm})
.expect('Content-Type', /json/)
.expect(200)
.end(function(FormSaveErr, FormSaveRes) {
@ -333,8 +331,8 @@ describe('Form CRUD tests', function() {
var FormObj, _Submission, submissionSession;
beforeEach(function (done) {
_Form.admin = user;
FormObj = new Form(_Form);
myForm.admin = user;
FormObj = new Form(myForm);
FormObj.save(function(err, form) {
if (err) done(err);
@ -489,10 +487,9 @@ describe('Form CRUD tests', function() {
});
});
afterEach(function(done) {
User.remove().exec(function() {
Form.remove().exec(function() {
Form.remove({}).exec(function() {
User.remove({}).exec(function() {
userSession.destroy();
done();
});

View file

@ -85,7 +85,7 @@ describe('FormSubmission Model Unit Tests:', function() {
}
myForm = new Form({
title: 'Form Title1',
admin: user,
admin: user._id,
language: 'english',
form_fields: [
{'fieldType':'textfield', 'title':'What\'s your first name', 'fieldValue': ''},
@ -117,8 +117,8 @@ describe('FormSubmission Model Unit Tests:', function() {
}
mySubmission = new FormSubmission({
admin: user,
form: myForm,
admin: user._id,
form: myForm._id,
timeElapsed: 17.55,
form_fields: submissionFields
});
@ -137,7 +137,7 @@ describe('FormSubmission Model Unit Tests:', function() {
myFieldMap[myForm.form_fields[0]._id+''] = 'firstName';
myFieldMap[myForm.form_fields[1]._id+''] = 'lastName';
myFieldMap[myForm.form_fields[2]._id+''] = 'sex';
myFieldMap[myForm.form_fields[3]._id+''] = 'unparsedDOB';
myFieldMap[myForm.form_fields[3]._id+''] = 'DOB';
myFieldMap[myForm.form_fields[4]._id+''] = 'phone';
myForm.plugins.oscarhost.settings.fieldMap = myFieldMap;
@ -213,7 +213,7 @@ describe('FormSubmission Model Unit Tests:', function() {
});
});
it('should be able to findOne FormSubmission without problems', function(done) {
return FormSubmission.findOne({_id: mySubmission._id}, function(err,submission) {
return FormSubmission.findOne({_id: mySubmission._id}).exec(function(err,submission) {
should.not.exist(err);
should.exist(submission);
should.deepEqual(submission.toObject(), mySubmission.toObject());
@ -308,6 +308,6 @@ describe('FormSubmission Model Unit Tests:', function() {
User.remove().exec(function() {
FormSubmission.remove().exec(done);
});
});
})
});
});

View file

@ -42,123 +42,130 @@ describe('User CRUD tests', function() {
};
// Create a new user
_User = {
// _User = {
// firstName: 'Full',
// lastName: 'Name',
// email: credentials.username,
// username: credentials.username,
// password: credentials.password,
// };
});
// describe('Create, Verify and Activate a User', function() {
// var username = 'testActiveAccount1.be1e58fb@mailosaur.in';
// var link, _tmpUser, activateToken;
// this.timeout(15000);
// it('should be able to create a temporary (non-activated) User', function(done) {
// _User.email = _User.username = username;
// userSession.post('/auth/signup')
// .send(_User)
// .expect(200, 'An email has been sent to you. Please check it to verify your account.')
// .end(function(FormSaveErr, FormSaveRes) {
// tmpUser.findOne({username: _User.username}, function (err, user) {
// should.not.exist(err);
// should.exist(user);
// _tmpUser = user;
// _User.username.should.equal(user.username);
// _User.firstName.should.equal(user.firstName);
// _User.lastName.should.equal(user.lastName);
// activateToken = user.GENERATED_VERIFYING_URL;
// done();
// });
// // // mandrill('/messages/search', {
// // // query: "subject:Confirm",
// // // senders: [
// // // "test@forms.polydaic.com"
// // // ],
// // // limit: 1
// // // }, function(error, emails) {
// // // if (error) console.log( JSON.stringify(error) );
// // // var confirmation_email = emails[0];
// // // mandrill('/messages/content', {
// // // id: confirmation_email._id
// // // }, function(error, email) {
// // // if (error) console.log( JSON.stringify(error) );
// // // // console.log(email);
// // // var link = _(email.text.split('\n')).reverse().value()[1];
// // // console.log(link);
// // // activateToken = _(url.parse(link).hash.split('/')).reverse().value()[0];
// // // console.log('actual activateToken: '+ activateToken);
// // // console.log('expected activateToken: ' + user.GENERATED_VERIFYING_URL);
// // // done();
// // // });
// // // });
// // // mailbox.getEmails(function(err, _emails) {
// // // if(err) done(err);
// // // var emails = _emails;
// // // console.log('mailbox.getEmails:');
// // // console.log(emails[0].text.links);
// // // var link = emails[0].text.links[0].href;
// // // activateToken = _(url.parse(link).hash.split('/')).reverse().value()[0];
// // // console.log('actual activateToken: '+ activateToken);
// // // console.log('expected activateToken: ' + user.GENERATED_VERIFYING_URL);
// // // (activateToken).should.equal(user.GENERATED_VERIFYING_URL);
// // // done();
// // // });
// // });
// });
// });
// it('should be able to verify a User Account', function(done) {
// console.log('activateToken: '+activateToken);
// userSession.get('/auth/verify/'+activateToken)
// .expect(200)
// .end(function(VerifyErr, VerifyRes) {
// should.not.exist(VerifyErr);
// if(VerifyErr) console.log(VerifyRes.text);
// (VerifyRes.text).should.equal('User successfully verified');
// done();
// });
// });
// // it('should receive confirmation email after verifying a User Account', function(done) {
// // mailbox.getEmails(function(err, _emails) {
// // if(err) throw err;
// // var email = _emails[0];
// // // console.log('mailbox.getEmails:');
// // console.log(email);
// // (email.subject).should.equal('Account successfully verified!');
// // done();
// // });
// // });
// });
it('should be able to login and logout a User', function (done) {
var username = 'testActiveAccount.be1e58fb@mailosaur.in';
// _User.email = _User.username = credentials.username = username;
// Create a new user
var newUser = {
firstName: 'Full',
lastName: 'Name',
email: credentials.username,
username: credentials.username,
password: credentials.password,
};
});
describe('Create, Verify and Activate a User', function() {
var username = 'testActiveAccount1.be1e58fb@mailosaur.in';
var link, _tmpUser, activateToken;
this.timeout(15000);
it('should be able to create a temporary (non-activated) User', function(done) {
_User.email = _User.username = username;
userSession.post('/auth/signup')
.send(_User)
.expect(200, 'An email has been sent to you. Please check it to verify your account.')
.end(function(FormSaveErr, FormSaveRes) {
tmpUser.findOne({username: _User.username}, function (err, user) {
should.not.exist(err);
should.exist(user);
_tmpUser = user;
_User.username.should.equal(user.username);
_User.firstName.should.equal(user.firstName);
_User.lastName.should.equal(user.lastName);
activateToken = user.GENERATED_VERIFYING_URL;
done();
});
// // mandrill('/messages/search', {
// // query: "subject:Confirm",
// // senders: [
// // "test@forms.polydaic.com"
// // ],
// // limit: 1
// // }, function(error, emails) {
// // if (error) console.log( JSON.stringify(error) );
// // var confirmation_email = emails[0];
// // mandrill('/messages/content', {
// // id: confirmation_email._id
// // }, function(error, email) {
// // if (error) console.log( JSON.stringify(error) );
// // // console.log(email);
// // var link = _(email.text.split('\n')).reverse().value()[1];
// // console.log(link);
// // activateToken = _(url.parse(link).hash.split('/')).reverse().value()[0];
// // console.log('actual activateToken: '+ activateToken);
// // console.log('expected activateToken: ' + user.GENERATED_VERIFYING_URL);
// // done();
// // });
// // });
// // mailbox.getEmails(function(err, _emails) {
// // if(err) done(err);
// // var emails = _emails;
// // console.log('mailbox.getEmails:');
// // console.log(emails[0].text.links);
// // var link = emails[0].text.links[0].href;
// // activateToken = _(url.parse(link).hash.split('/')).reverse().value()[0];
// // console.log('actual activateToken: '+ activateToken);
// // console.log('expected activateToken: ' + user.GENERATED_VERIFYING_URL);
// // (activateToken).should.equal(user.GENERATED_VERIFYING_URL);
// // done();
// // });
// });
});
});
it('should be able to verify a User Account', function(done) {
console.log('activateToken: '+activateToken);
userSession.get('/auth/verify/'+activateToken)
.expect(200)
.end(function(VerifyErr, VerifyRes) {
should.not.exist(VerifyErr);
if(VerifyErr) console.log(VerifyRes.text);
(VerifyRes.text).should.equal('User successfully verified');
done();
});
});
// it('should receive confirmation email after verifying a User Account', function(done) {
// mailbox.getEmails(function(err, _emails) {
// if(err) throw err;
// var email = _emails[0];
// // console.log('mailbox.getEmails:');
// console.log(email);
// (email.subject).should.equal('Account successfully verified!');
// done();
// });
// });
});
it('should be able to login and logout a User', function (done) {
var username = 'testActiveAccount.be1e58fb@mailosaur.in';
_User.email = _User.username = credentials.username = username;
userSession.post('/auth/signup')
.send(_User)
.send(newUser)
.expect(200)
.end(function(FormSaveErr, FormSaveRes) {
(FormSaveRes.text).should.equal('An email has been sent to you. Please check it to verify your account.');
userSession.post('/auth/signin')
.send(credentials)
.expect('Content-Type', /json/)
@ -183,9 +190,9 @@ describe('User CRUD tests', function() {
});
});
// it('should be able to reset a User\'s password');
it('should be able to reset a User\'s password');
// it('should be able to delete a User account without any problems');
it('should be able to delete a User account without any problems');
afterEach(function(done) {
User.remove().exec(function () {

17
config/env/local.js vendored Normal file
View file

@ -0,0 +1,17 @@
'use strict';
var mandrill_api_key = 'AVCCf1C2dFlrNhx9Iyi_yQ';
//Use mandrill mock API_key if we are testing
// if(process.env.NODE_ENV === 'test') mandrill_api_key = '_YNOKLgT9DGb2sgVGR66yQ';
module.exports = {
// db: {
// uri: 'mongodb://localhost/local-dev',
// options: {
// user: '',
// pass: ''
// }
// },
sessionSecret: process.env.SESSION_SECRET || 'somethingheresecret',
};

View file

@ -182,6 +182,8 @@ module.exports = function(grunt) {
grunt.config.set('applicationJavaScriptFiles', config.assets.js);
grunt.config.set('applicationCSSFiles', config.assets.css);
});
grunt.loadNpmTasks('grunt-html2js');
// Default task(s).
grunt.registerTask('default', ['lint', 'concurrent:default']);

View file

@ -12,7 +12,7 @@
"url": "https://github.com/whitef0x0/NodeForms.git"
},
"engines": {
"node": "~0.10.28",
"node": "~0.12.6",
"npm": "~1.4.28"
},
"scripts": {
@ -22,6 +22,7 @@
},
"dependencies": {
"async": "^1.4.2",
"bcrypt": "^0.8.5",
"body-parser": "~1.9.0",
"bower": "~1.3.8",
"chalk": "~1.0.0",
@ -59,7 +60,7 @@
"karma-jasmine": "^0.2.3",
"karma-phantomjs-launcher": "~0.1.2",
"load-grunt-tasks": "~1.0.0",
"lodash": "~2.4.1",
"lodash": "^3.10.1",
"mailosaur": "^1.0.1",
"main-bower-files": "~2.8.2",
"math": "0.0.3",
@ -92,6 +93,7 @@
"then-fs": "~2.0.0"
},
"devDependencies": {
"grunt-html2js": "^0.3.5",
"karma-chrome-launcher": "^0.1.12",
"karma-jasmine-html-reporter": "^0.1.8",
"karma-mocha-reporter": "^1.1.1",

View file

@ -62,12 +62,15 @@ angular.module(ApplicationConfiguration.applicationModuleName).run(['$rootScope'
Auth.ensureHasCurrentUser(User);
user = Auth.currentUser;
console.log(user.roles);
if(user){
authenticator = new Authorizer(user);
console.log('access denied: '+!authenticator.canAccess(permissions));
if( (permissions !== null) && !authenticator.canAccess(permissions) ){
event.preventDefault();
console.log('access denied')
console.log('access denied');
$state.go('access_denied');
}
}

View file

@ -47,55 +47,55 @@ angular.module(ApplicationConfiguration.applicationModuleName).constant('USER_RO
superuser: 'superuser',
});
// angular.module(ApplicationConfiguration.applicationModuleName).run(['$rootScope', 'Auth', '$state', '$stateParams',
// function($rootScope, Auth, $state, $stateParams) {
angular.module(ApplicationConfiguration.applicationModuleName).run(['$rootScope', 'Auth', '$state', '$stateParams',
function($rootScope, Auth, $state, $stateParams) {
// $rootScope.$state = $state;
// $rootScope.$stateParams = $stateParams;
$rootScope.$state = $state;
$rootScope.$stateParams = $stateParams;
// // add previous state property
// $rootScope.$on('$stateChangeSuccess', function (event, toState, toParams, fromState) {
// $state.previous = fromState;
// add previous state property
$rootScope.$on('$stateChangeSuccess', function (event, toState, toParams, fromState) {
$state.previous = fromState;
// //Redirect to listForms if user is authenticated
// if(toState.name === 'home' || toState.name === 'signin' || toState.name === 'resendVerifyEmail' || toState.name === 'verify' || toState.name === 'signup' || toState.name === 'signup-success'){
// if(Auth.isAuthenticated()){
// event.preventDefault(); // stop current execution
// $state.go('listForms'); // go to listForms page
// }
// }
// //Redirect to 'home' route if user is not authenticated
// else if(toState.name !== 'access_denied' && !Auth.isAuthenticated() ){
// event.preventDefault(); // stop current execution
// $state.go('home'); // go to listForms page
// }
//Redirect to listForms if user is authenticated
if(toState.name === 'home' || toState.name === 'signin' || toState.name === 'resendVerifyEmail' || toState.name === 'verify' || toState.name === 'signup' || toState.name === 'signup-success'){
if(Auth.isAuthenticated()){
event.preventDefault(); // stop current execution
$state.go('listForms'); // go to listForms page
}
}
//Redirect to 'home' route if user is not authenticated
else if(toState.name !== 'access_denied' && !Auth.isAuthenticated() ){
event.preventDefault(); // stop current execution
$state.go('home'); // go to listForms page
}
// });
});
// }
// ]);
}
]);
// //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;
//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;
Auth.ensureHasCurrentUser(User);
user = Auth.currentUser;
// if(user){
// authenticator = new Authorizer(user);
if(user){
authenticator = new Authorizer(user);
// if( (permissions !== null) && !authenticator.canAccess(permissions) ){
// event.preventDefault();
// console.log('access denied')
// $state.go('access_denied');
// }
// }
// });
// }]);
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
angular.element(document).ready(function() {
@ -420,20 +420,21 @@ angular.module('forms').config(['$stateProvider',
permissions: [ 'editForm' ]
}
}).
state('submitForm', {
url: '/forms/:formId',
templateUrl: 'modules/forms/views/submit-form.client.view.html',
data: {
hideNav: true,
},
}).
state('viewForm', {
url: '/forms/:formId/admin',
templateUrl: 'modules/forms/views/admin-form.client.view.html',
data: {
permissions: [ 'editForm' ]
}
}).
state('viewPublicForm', {
url: '/forms/:formId',
templateUrl: 'modules/forms/views/view-public-form.client.view.html',
data: {
hideNav: true,
},
});
});
}
]);
'use strict';
@ -445,15 +446,23 @@ angular.module('forms').controller('AdminFormController', ['$rootScope', '$scope
$scope = $rootScope;
$scope.myform = CurrentForm.getForm();
$scope.myform._id = $stateParams.formId;
$rootScope.saveInProgress = false;
// Find a specific Form
$scope.findOne = function(){
$scope.myform = Forms.get({
Forms.get({
formId: $stateParams.formId
}, function(form){
CurrentForm.setForm(form);
$scope.myform = form;
$scope.myform._id = $stateParams.formId;
}, function(err){
console.error('Could not fetch form');
console.error(err);
});
CurrentForm.setForm($scope.myform);
};
$scope.setForm = function(form){
$scope.myform = form;
};
@ -676,6 +685,8 @@ angular.module('forms').directive('autoSaveForm', ['$rootScope', '$timeout', fun
require: ['^form'],
restrict: 'AE',
link: function($scope, $element, $attrs, $ctrls) {
//DAVID: TODO: Do we really need to check if our directive element is ready everytime
angular.element(document).ready(function() {
var $formCtrl = $ctrls[0],
@ -702,7 +713,7 @@ angular.module('forms').directive('autoSaveForm', ['$rootScope', '$timeout', fun
return false;
};
var debounceSave = function () {
this.debounceSave = function () {
$rootScope.saveInProgress = true;
$rootScope[$attrs.autoSaveCallback](true,
function(err){
@ -719,7 +730,7 @@ angular.module('forms').directive('autoSaveForm', ['$rootScope', '$timeout', fun
//Update/save Form if any Form fields are Dirty and Touched
$scope.$watch(function(newValue, oldValue) {
if($scope.anyDirtyAndTouched($scope.editForm) && !$rootScope.saveInProgress){
debounceSave();
this.debounceSave();
}
});
@ -749,7 +760,7 @@ angular.module('forms').directive('autoSaveForm', ['$rootScope', '$timeout', fun
savePromise = $timeout(function() {
console.log('Saving Form');
debounceSave();
this.debounceSave();
});
}
//If we are finished rendering then form saving should be finished
@ -1092,35 +1103,6 @@ angular.module('forms').directive('editSubmissionsFormDirective', ['$rootScope',
rows: []
};
//Fetch and display submissions of Form
$scope.initFormSubmissions = function(){
$http.get('/forms/'+$scope.myform._id+'/submissions')
.success(function(data, status, headers){
console.log(data[0].form_fields);
var _tmpSubFormFields,
defaultFormFields = _.cloneDeep($scope.myform.form_fields);
//Iterate through form's submissions
for(var i=0; i<data.length; i++){
_tmpSubFormFields = _.merge(defaultFormFields, data[i].form_fields);
data[i].form_fields = _tmpSubFormFields;
}
// console.log(JSON.stringify(_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.error('Could not fetch form submissions.\nError: '+err);
});
};
/*
** Table Functions
*/
@ -1145,6 +1127,35 @@ angular.module('forms').directive('editSubmissionsFormDirective', ['$rootScope',
/*
* Form Submission Methods
*/
//Fetch and display submissions of Form
$scope.initFormSubmissions = function(){
$http.get('/forms/'+$scope.myform._id+'/submissions')
.success(function(data, status, headers){
var _tmpSubFormFields,
defaultFormFields = _.cloneDeep($scope.myform.form_fields);
//Iterate through form's submissions
for(var i=0; i<data.length; i++){
_tmpSubFormFields = _.merge(defaultFormFields, data[i].form_fields);
data[i].form_fields = _tmpSubFormFields;
data[i].selected = false;
}
$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.error('Could not fetch form submissions.\nError: '+err);
});
};
//Delete selected submissions of Form
$scope.deleteSelectedSubmissions = function(){
@ -1191,6 +1202,53 @@ angular.module('forms').directive('editSubmissionsFormDirective', ['$rootScope',
};
}
]);
// 'use strict';
// angular.module('forms').directive('entryPage', ['$templateCache', '$http', '$compile', '$rootScope',
// function($templateCache, $http, $compile, $rootScope) {
// var getTemplateUrl = function(type) {
// var templateUrl = 'modules/forms/views/directiveViews/entryPage/';
// var supported_pages = [
// 'welcome',
// 'thankyou'
// ];
// if (__indexOf.call(supported_pages, type) >= 0) {
// templateUrl += type + '.html';
// }
// var template = $templateCache.get(templateUrl);
// return template;
// };
// return {
// restrict: 'E',
// template: '<div>Start Page</div>',
// scope: {
// 'pageData': '=',
// 'pageType': '&'
// },
// link: function(scope, element) {
// // console.log(attrs);
// console.log('scope.pageData');
// // console.log(scope);
// scope.exitStartPage = function() {
// // console.log(scope.pageData);
// // if(attrs.pageData.showStart) attrs.pageData.showStart = false;
// };
// var template = getTemplateUrl(scope.pageType);
// element.html(template);
// $compile(element.contents())(scope);
// },
// controller: function($scope){
// console.log('entryPage Controller');
// console.log($scope.pageData);
// // $scope.exitStartPage = function() {
// // if($scope.pageData.showStart) scope.pageData.showStart = false;
// // };
// }
// };
// }]);
'use strict';
angular.module('forms').directive('fieldIconDirective', function($http, $compile) {
@ -1294,8 +1352,9 @@ angular.module('forms').directive('fieldDirective', ['$templateCache', '$http',
// GET template content from path
var template = getTemplateUrl(scope.field);
// $http.get(templateUrl).success(function(data) {
element.html(template);
$compile(element.contents())(scope);
element.html(template).show();
// console.log(element.contents());
$compile(element.contents())(scope);
// });
};
@ -1346,46 +1405,49 @@ angular.module('forms').directive('onFinishRender', function ($rootScope, $timeo
'use strict';
angular.module('forms').directive('formDirective', ['$http', '$timeout', 'TimeCounter', 'Auth', '$filter', '$rootScope',
angular.module('forms').directive('submitFormDirective', ['$http', '$timeout', 'TimeCounter', 'Auth', '$filter', '$rootScope',
function ($http, $timeout, TimeCounter, Auth, $filter, $rootScope) {
return {
templateUrl: 'modules/forms/views/directiveViews/form/submit-form.client.view.html',
restrict: 'E',
scope: {
form:'='
myform:'='
},
controller: function($scope){
angular.element(document).ready(function() {
$scope.error = '';
$scope.selected = null;
$scope.submitted = false;
TimeCounter.startClock()
$scope.exitStartPage = function(){
$scope.myform.startPage.showStart = false;
}
$rootScope.setActiveField = function (field_id) {
// console.log('form field clicked: '+field_id);
$scope.selected = field_id;
// console.log($scope.selected);
};
$scope.hideOverlay = function (){
$scope.selected = null;
console.log($scope.myForm);
};
$scope.submit = function(){
var _timeElapsed = TimeCounter.stopClock();
$scope.form.timeElapsed = _timeElapsed;
// console.log('percentageComplete: '+$filter('formValidity')($scope.form)/$scope.form.visible_form_fields.length*100+'%');
$scope.form.percentageComplete = $filter('formValidity')($scope.form)/$scope.form.visible_form_fields.length*100;
console.log($scope.form.percentageComplete);
// delete $scope.form.visible_form_fields;
var form = _.cloneDeep($scope.myform);
form.timeElapsed = _timeElapsed;
// console.log('percentageComplete: '+$filter('formValidity')($scope.myform)/$scope.myform.visible_form_fields.length*100+'%');
form.percentageComplete = $filter('formValidity')($scope.myform)/$scope.myform.visible_form_fields.length*100;
console.log(form.percentageComplete)
delete form.visible_form_fields;
$scope.authentication = Auth;
$scope.submitPromise = $http.post('/forms/'+$scope.form._id,$scope.form)
$scope.submitPromise = $http.post('/forms/'+$scope.myform._id, form)
.success(function(data, status, headers){
console.log('form submitted successfully');
// alert('Form submitted..');
$scope.form.submitted = true;
$scope.myform.submitted = true;
})
.error(function(error){
console.log(error);
@ -1393,19 +1455,17 @@ angular.module('forms').directive('formDirective', ['$http', '$timeout', 'TimeCo
});
};
$scope.exitstartPage = function () {
$scope.form.startPage.showStart = false;
};
$scope.reloadForm = function(){
//Reset Timer
TimeCounter.stopClock();
TimeCounter.startClock();
$scope.form.submitted = false;
$scope.form.form_fields = _.chain($scope.form.form_fields).map(function(field){
field.fieldValue = '';
return field;
}).value();
//Reset Form
$scope.myform.submitted = false;
$scope.myform.form_fields = _.chain($scope.myform.form_fields).map(function(field){
field.fieldValue = '';
return field;
}).value();
};
});
@ -1730,12 +1790,11 @@ angular.module('users').controller('AuthenticationController', ['$scope', '$loca
$scope = $rootScope;
$scope.credentials = {};
$scope.error = null;
$scope.error = '';
$scope.signin = function() {
User.login($scope.credentials).then(
function(response) {
// console.log(response);
Auth.login(response);
$scope.user = $rootScope.user = Auth.ensureHasCurrentUser(User);
@ -1757,18 +1816,21 @@ angular.module('users').controller('AuthenticationController', ['$scope', '$loca
$scope.signup = function() {
User.signup($scope.credentials).then(
function(response) {
console.log('signup-success');
$state.go('signup-success');
},
function(error) {
if(error) {
$scope.error = error;
}else {
console.log('No response received');
}
}
);
function(response) {
console.log('signup-success');
$state.go('signup-success');
},
function(error) {
console.log('Error: ');
console.log(error);
if(error) {
$scope.error = error;
console.log(error);
}else {
console.log('No response received');
}
}
);
};
}
@ -1777,10 +1839,7 @@ angular.module('users').controller('AuthenticationController', ['$scope', '$loca
angular.module('users').controller('PasswordController', ['$scope', '$stateParams', '$state', 'User',
function($scope, $stateParams, $state, User) {
//If user is signed in then redirect back home
// if ($scope.authentication.isAuthenticated()) $state.go('home');
// Submit forgotten password account id
$scope.askForPasswordReset = function() {
User.askForPasswordReset($scope.credentials).then(
@ -1819,73 +1878,68 @@ angular.module('users').controller('PasswordController', ['$scope', '$stateParam
angular.module('users').controller('SettingsController', ['$scope', '$rootScope', '$http', '$state', 'Users',
function($scope, $rootScope, $http, $state, Users) {
$scope.user = $rootScope.user;
console.log($scope.user);
// If user is not signed in then redirect back home
if (!$scope.user) $state.go('home');
$scope.user = $rootScope.user;
// Check if there are additional accounts
$scope.hasConnectedAdditionalSocialAccounts = function(provider) {
for (var i in $scope.user.additionalProvidersData) {
return true;
// Check if there are additional accounts
$scope.hasConnectedAdditionalSocialAccounts = function(provider) {
for (var i in $scope.user.additionalProvidersData) {
return true;
}
return false;
};
// Check if provider is already in use with current user
$scope.isConnectedSocialAccount = function(provider) {
return $scope.user.provider === provider || ($scope.user.additionalProvidersData && $scope.user.additionalProvidersData[provider]);
};
// Remove a user social account
$scope.removeUserSocialAccount = function(provider) {
$scope.success = $scope.error = null;
$http.delete('/users/accounts', {
params: {
provider: provider
}
}).success(function(response) {
// If successful show success message and clear form
$scope.success = true;
$scope.user = response;
}).error(function(response) {
$scope.error = response.message;
});
};
return false;
};
// Check if provider is already in use with current user
$scope.isConnectedSocialAccount = function(provider) {
return $scope.user.provider === provider || ($scope.user.additionalProvidersData && $scope.user.additionalProvidersData[provider]);
};
// Remove a user social account
$scope.removeUserSocialAccount = function(provider) {
// Update a user profile
$scope.updateUserProfile = function(isValid) {
if (isValid) {
$scope.success = $scope.error = null;
var user = new Users($scope.user);
$http.delete('/users/accounts', {
params: {
provider: provider
}
}).success(function(response) {
// If successful show success message and clear form
user.$update(function(response) {
$scope.success = true;
$scope.user = response;
}).error(function(response) {
$scope.error = response.message;
}, function(response) {
$scope.error = response.data.message;
});
};
} else {
$scope.submitted = true;
}
};
// Update a user profile
$scope.updateUserProfile = function(isValid) {
if (isValid) {
$scope.success = $scope.error = null;
var user = new Users($scope.user);
// Change user password
$scope.changeUserPassword = function() {
$scope.success = $scope.error = null;
user.$update(function(response) {
$scope.success = true;
$scope.user = response;
}, function(response) {
$scope.error = response.data.message;
});
} else {
$scope.submitted = true;
}
};
$http.post('/users/password', $scope.passwordDetails).success(function(response) {
// If successful show success message and clear form
$scope.success = true;
$scope.passwordDetails = null;
}).error(function(response) {
$scope.error = response.message;
});
};
// Change user password
$scope.changeUserPassword = function() {
$scope.success = $scope.error = null;
$http.post('/users/password', $scope.passwordDetails).success(function(response) {
// If successful show success message and clear form
$scope.success = true;
$scope.passwordDetails = null;
}).error(function(response) {
$scope.error = response.message;
});
};
// });
}
]);
'use strict';
@ -1938,41 +1992,46 @@ angular.module('users').controller('VerifyController', ['$scope', '$state', '$ro
]);
'use strict';
angular.module('users').factory('Auth', function($window) {
angular.module('users').factory('Auth', ['$window',
function($window) {
var userState = {
isLoggedIn: false
};
var service = {
currentUser: null,
_currentUser: null,
get currentUser(){
return this._currentUser;
},
// Note: we can't make the User a dependency of Auth
// because that would create a circular dependency
// Auth <- $http <- $resource <- LoopBackResource <- User <- Auth
ensureHasCurrentUser: function(User) {
if (service.currentUser && service.currentUser.username) {
if (service._currentUser && service._currentUser.username) {
console.log('Using local current user.');
// console.log(service.currentUser);
return service.currentUser;
// console.log(service._currentUser);
return service._currentUser;
}
else if ($window.user){
console.log('Using cached current user.');
// console.log($window.user);
service.currentUser = $window.user;
return service.currentUser;
service._currentUser = $window.user;
return service._currentUser;
}
else{
console.log('Fetching current user from the server.');
User.getCurrent().then(function(user) {
// success
service.currentUser = user;
service._currentUser = user;
userState.isLoggedIn = true;
$window.user = service.currentUser;
return service.currentUser;
$window.user = service._currentUser;
return service._currentUser;
},
function(response) {
userState.isLoggedIn = false;
service.currentUser = null;
service._currentUser = null;
$window.user = null;
console.log('User.getCurrent() err', response);
return null;
@ -1981,7 +2040,7 @@ angular.module('users').factory('Auth', function($window) {
},
isAuthenticated: function() {
return !!service.currentUser;
return !!service._currentUser;
},
getUserState: function() {
@ -1990,17 +2049,19 @@ angular.module('users').factory('Auth', function($window) {
login: function(new_user) {
userState.isLoggedIn = true;
service.currentUser = new_user;
service._currentUser = new_user;
},
logout: function() {
$window.user = null;
userState.isLoggedIn = false;
service.currentUser = null;
service._currentUser = null;
},
};
return service;
});
}
]);
'use strict';
@ -2041,7 +2102,6 @@ angular.module('users').service('Authorizer', function(APP_PERMISSIONS, USER_ROL
angular.module('users').factory('User', ['$window', '$q', '$timeout', '$http', '$state',
function($window, $q, $timeout, $http, $state) {
var userService = {
getCurrent: function() {
var deferred = $q.defer();
@ -2064,9 +2124,11 @@ angular.module('users').factory('User', ['$window', '$q', '$timeout', '$http', '
}).error(function(error) {
deferred.reject(error.message || error);
});
return deferred.promise;
return deferred.promise;
},
logout: function() {
var deferred = $q.defer();
$http.get('/auth/signout').success(function(response) {
deferred.resolve(null);
@ -2079,12 +2141,10 @@ angular.module('users').factory('User', ['$window', '$q', '$timeout', '$http', '
signup: function(credentials) {
var deferred = $q.defer();
$http.post('/auth/signup', credentials).success(function(response) {
// If successful we assign the response to the global user model
deferred.resolve(response);
}).error(function(error) {
deferred.reject(error.message || error);
});
@ -2092,8 +2152,9 @@ angular.module('users').factory('User', ['$window', '$q', '$timeout', '$http', '
},
resendVerifyEmail: function(_email) {
var deferred = $q.defer();
$http.post('/auth/verify/', {email: _email}).success(function(response) {
$http.post('/auth/verify', {email: _email}).success(function(response) {
deferred.resolve(response);
}).error(function(error) {
deferred.reject(error.message || error);
@ -2103,6 +2164,12 @@ angular.module('users').factory('User', ['$window', '$q', '$timeout', '$http', '
},
validateVerifyToken: function(token) {
//DAVID: TODO: The valid length of a token should somehow be linked to server config values
//DAVID: TODO: SEMI-URGENT: Should we even be doing this?
var validTokenRe = /^([A-Za-z0-9]{48})$/g;
if( !validTokenRe.test(token) ) throw new Error('Error token: '+token+' is not a valid verification token');
var deferred = $q.defer();
$http.get('/auth/verify/'+token).success(function(response) {
deferred.resolve(response);
@ -2113,7 +2180,8 @@ angular.module('users').factory('User', ['$window', '$q', '$timeout', '$http', '
return deferred.promise;
},
resetPassword: function(passwordDetails, token) {
resetPassword: function(passwordDetails, token) {
var deferred = $q.defer();
$http.get('/auth/password/'+token, passwordDetails).success(function(response) {
deferred.resolve();
@ -2126,12 +2194,11 @@ angular.module('users').factory('User', ['$window', '$q', '$timeout', '$http', '
// Submit forgotten password account id
askForPasswordReset: function(credentials) {
var deferred = $q.defer();
$http.post('/auth/forgot', credentials).success(function(response) {
// Show user success message and clear form
deferred.resolve(response);
}).error(function(error) {
// Show user error message
deferred.reject(error.message || error);

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -19,13 +19,27 @@ angular.module('forms').config(['$stateProvider',
data: {
hideNav: true,
},
resolve: {
Forms: 'Forms',
myForm: function (Forms, $stateParams) {
return Forms.get({formId: $stateParams.formId}).$promise;
},
},
controller: 'SubmitFormController'
}).
state('viewForm', {
url: '/forms/:formId/admin',
templateUrl: 'modules/forms/views/admin-form.client.view.html',
data: {
permissions: [ 'editForm' ]
}
},
resolve: {
Forms: 'Forms',
myForm: function (Forms, $stateParams) {
return Forms.get({formId: $stateParams.formId}).$promise;
},
},
controller: 'AdminFormController'
});
}

View file

@ -1,14 +1,16 @@
'use strict';
// Forms controller
angular.module('forms').controller('AdminFormController', ['$rootScope', '$scope', '$stateParams', '$state', 'Forms', 'CurrentForm', '$http', '$modal',
function($rootScope, $scope, $stateParams, $state, Forms, CurrentForm, $http, $modal) {
angular.module('forms').controller('AdminFormController', ['$rootScope', '$scope', '$stateParams', '$state', 'Forms', 'CurrentForm', '$http', '$modal', 'myForm',
function($rootScope, $scope, $stateParams, $state, Forms, CurrentForm, $http, $modal, myForm) {
$scope = $rootScope;
$scope.myform = CurrentForm.getForm();
$scope.myform._id = $stateParams.formId;
$scope.myform = myForm;
$rootScope.saveInProgress = false;
CurrentForm.setForm($scope.myform);
// console.log($scope.myform);
// Find a specific Form
$scope.findOne = function(){
@ -105,5 +107,6 @@ angular.module('forms').controller('AdminFormController', ['$rootScope', '$scope
}
};
}
]);

View file

@ -1,40 +1,24 @@
'use strict';
// Forms controller
angular.module('forms').controller('SubmitFormController', ['$scope', '$rootScope', '$stateParams', '$state', 'Forms', 'CurrentForm', 'Auth',
function($scope, $rootScope, $stateParams, $state, Forms, CurrentForm, Auth) {
angular.module('forms').controller('SubmitFormController', ['$scope', '$rootScope', '$stateParams', '$state', 'Forms', 'CurrentForm', 'Auth', 'myForm',
function($scope, $rootScope, $stateParams, $state, Forms, CurrentForm, Auth, myForm) {
$scope.authentication = Auth;
$scope.initForm = function(){
Forms.get({
formId: $stateParams.formId
}).$promise.then(
//success
function(form){
$scope.myform = form;
$scope.myform = myForm;
if(!$scope.myform.isLive){
// Show navbar if form is not public AND user IS loggedin
if($scope.authentication.isAuthenticated()){
$scope.hideNav = $rootScope.hideNav = false;
}
// Redirect if form is not public user IS NOT loggedin
else {
$scope.hideNav = $rootScope.hideNav = true;
$state.go('access_denied');
}
}else{
$scope.hideNav = $rootScope.hideNav = true;
}
},
//error
function( error ){
$scope.error = error.message;
console.error('ERROR: '+error.message);
$state.go('access_denied');
}
);
};
if(!$scope.myform.isLive){
// Show navbar if form is not public AND user IS loggedin
if($scope.authentication.isAuthenticated()){
$scope.hideNav = $rootScope.hideNav = false;
}
// Redirect if form is not public user IS NOT loggedin
else {
$scope.hideNav = $rootScope.hideNav = true;
$state.go('access_denied');
}
}else{
$scope.hideNav = $rootScope.hideNav = true;
}
}
]);

View file

@ -290,6 +290,10 @@ div.config-form .row.field {
border-radius: 4px;
}
.admin-form .oscar-field-select {
margin: 10px 0 10px;
}
.view-form-btn.span {
padding-right:0.6em;
}

View file

@ -1,5 +1,18 @@
'use strict';
_.mixin({ removeDateFields : function(o){
var clone = _.clone(o);
for(var i=0; i<clone.length; i++){
_.each(clone[i], function(v,k){
// console.log('key: '+k);
if(k === 'lastModified' || k === 'created'){
delete clone[i][k];
}
});
}
return clone;
}});
angular.module('forms').directive('autoSaveForm', ['$rootScope', '$timeout', function($rootScope, $timeout) {
return {
@ -14,10 +27,10 @@ angular.module('forms').directive('autoSaveForm', ['$rootScope', '$timeout', fun
savePromise = null;
$rootScope.finishedRender = false;
$scope.$on('editFormFieldsStarted', function(ngRepeatFinishedEvent) {
$scope.$on('editFormFields Started', function(ngRepeatFinishedEvent) {
$rootScope.finishedRender = false;
});
$scope.$on('editFormFieldsFinished', function(ngRepeatFinishedEvent) {
$scope.$on('editFormFields Finished', function(ngRepeatFinishedEvent) {
$rootScope.finishedRender = true;
});
@ -34,7 +47,7 @@ angular.module('forms').directive('autoSaveForm', ['$rootScope', '$timeout', fun
return false;
};
this.debounceSave = function () {
var debounceSave = function () {
$rootScope.saveInProgress = true;
$rootScope[$attrs.autoSaveCallback](true,
function(err){
@ -48,32 +61,48 @@ angular.module('forms').directive('autoSaveForm', ['$rootScope', '$timeout', fun
});
};
//Update/save Form if any Form fields are Dirty and Touched
//Update/Save Form if any Form fields are Dirty and Touched
$scope.$watch(function(newValue, oldValue) {
if($scope.anyDirtyAndTouched($scope.editForm) && !$rootScope.saveInProgress){
this.debounceSave();
// console.log($scope);
// console.log($scope.$parent.editForm);
if($rootScope.finishedRender && $scope.anyDirtyAndTouched($scope.$parent.editForm) && !$rootScope.saveInProgress){
console.log('Form saving started');
debounceSave();
}
});
//Autosave Form when model (specificed in $attrs.autoSaveWatch) changes
$scope.$watch($attrs.autoSaveWatch, function(newValue, oldValue) {
var changedFields = !_.isEqual(oldValue,newValue);
newValue = angular.copy(newValue);
oldValue = angular.copy(oldValue);
newValue.form_fields = _.removeDateFields(newValue.form_fields);
oldValue.form_fields = _.removeDateFields(oldValue.form_fields);
var changedFields = !_.isEqual(oldValue.form_fields,newValue.form_fields) || !_.isEqual(oldValue.startPage, newValue.startPage);
var changedFieldMap = !!oldValue.plugins.oscarhost.settings.fieldMap && !_.isEqual(oldValue.plugins.oscarhost.settings.fieldMap,newValue.plugins.oscarhost.settings.fieldMap);
if( (!newValue && !oldValue) || !oldValue ){
return;
}
// console.log('Autosaving');
// console.log('\n\n----------');
// console.log('$dirty: '+ $formCtrl.$dirty );
// console.log('!$dirty: '+ !$formCtrl.$dirty );
// console.log('changedFields: '+changedFields);
// console.log('changedFieldMap: '+changedFieldMap);
// console.log('finishedRender: '+$rootScope.finishedRender);
// console.log('saveInProgress: '+$rootScope.saveInProgress);
// console.log('!saveInProgress: '+!$rootScope.saveInProgress);
// console.log('newValue: '+newValue);
// console.log('oldValue: '+oldValue);
// console.log(oldValue.form_fields);
// console.log(newValue.form_fields);
//Save form ONLY IF rendering is finished, form_fields have been change AND currently not save in progress
if($rootScope.finishedRender && (changedFields && !$formCtrl.$dirty) && !$rootScope.saveInProgress) {
//Save form ONLY IF rendering is finished, form_fields have been changed AND currently not save in progress
if($rootScope.finishedRender && ((changedFields && !$formCtrl.$dirty) || changedFieldMap) && !$rootScope.saveInProgress) {
console.log('saving form now');
if(savePromise) {
$timeout.cancel(savePromise);
savePromise = null;
@ -81,7 +110,7 @@ angular.module('forms').directive('autoSaveForm', ['$rootScope', '$timeout', fun
savePromise = $timeout(function() {
console.log('Saving Form');
this.debounceSave();
debounceSave();
});
}
//If we are finished rendering then form saving should be finished

View file

@ -1,7 +1,7 @@
'use strict';
angular.module('forms').directive('configureFormDirective', ['$rootScope', '$http', 'Upload', '$timeout', 'TimeCounter', 'Auth', 'FormFields',
function ($rootScope, $http, Upload, $timeout, TimeCounter, Auth, FormFields) {
angular.module('forms').directive('configureFormDirective', ['$rootScope', '$http', 'Upload', '$timeout', 'TimeCounter', 'Auth', 'FormFields', 'CurrentForm',
function ($rootScope, $http, Upload, $timeout, TimeCounter, Auth, FormFields, CurrentForm) {
return {
templateUrl: 'modules/forms/views/directiveViews/form/configure-form.client.view.html',
restrict: 'E',
@ -12,6 +12,12 @@ angular.module('forms').directive('configureFormDirective', ['$rootScope', '$htt
formFields:'@'
},
controller: function($scope){
console.log($scope.myform);
if( CurrentForm.getForm().plugins){
if(CurrentForm.getForm().plugins.oscarhost.baseUrl) $scope.oscarhostAPI = true;
}else{
$scope.oscarhostAPI = false;
}
$scope.log = '';
$scope.pdfLoading = false;
$scope.languages = $rootScope.languages;

View file

@ -9,7 +9,10 @@ angular.module('forms').directive('editFormDirective', ['$rootScope', '$q', '$ht
myform:'=',
},
controller: function($scope){
var field_ids = _($scope.myform.form_fields).pluck('_id');
for(var i=0; i<field_ids.length; i++){
$scope.myform.plugins.oscarhost.settings.fieldMap[field_ids[i]] = null;
}
/*
** Initialize scope with variables
*/
@ -31,6 +34,26 @@ angular.module('forms').directive('editFormDirective', ['$rootScope', '$q', '$ht
//Populate local scope with rootScope methods/variables
$scope.update = $rootScope.update;
//Many-to-many Select for Mapping OscarhostFields -> FormFields
$scope.oscarFieldsLeft = function(field_id){
if($scope.myform && $scope.myform.plugins.oscarhost.settings.validFields.length > 0){
if(!$scope.myform.plugins.oscarhost.settings.fieldMap) $scope.myform.plugins.oscarhost.settings.fieldMap = {};
var oscarhostFields = $scope.myform.plugins.oscarhost.settings.validFields;
var currentFields = _($scope.myform.plugins.oscarhost.settings.fieldMap).invert().keys().value();
if( $scope.myform.plugins.oscarhost.settings.fieldMap.hasOwnProperty(field_id) ){
currentFields = _(currentFields).difference($scope.myform.plugins.oscarhost.settings.fieldMap[field_id]);
}
// console.log($scope.myform.plugins.oscarhost.settings.fieldMap);
//Get all oscarhostFields that haven't been mapped to a formfield
return _(oscarhostFields).difference(currentFields).value();
}
return [];
};
/*
** FormFields (ui-sortable) drag-and-drop configuration
*/
@ -38,7 +61,6 @@ angular.module('forms').directive('editFormDirective', ['$rootScope', '$q', '$ht
handle: ' .handle'
};
// $scope.draggable = {
// connectWith: ".dropzone",
// start: function (e, ui) {
@ -111,7 +133,7 @@ angular.module('forms').directive('editFormDirective', ['$rootScope', '$q', '$ht
};
// console.log('\n\n---------\nAdded field CLIENT');
// console.log(newField);
newField._id = _.uniqueId();
// newField._id = _.uniqueId();
// put newField into fields array
if(modifyForm){
@ -122,6 +144,12 @@ angular.module('forms').directive('editFormDirective', ['$rootScope', '$q', '$ht
// Delete particular field on button click
$scope.deleteField = function (field_index){
$scope.myform.plugins.oscarhost.settings.fieldMap = {};
//Delete field from field map
var currFieldId = $scope.myform.form_fields[field_index]._id
delete $scope.myform.plugins.oscarhost.settings.fieldMap[currFieldId];
//Delete field
$scope.myform.form_fields.splice(field_index, 1);
};
$scope.duplicateField = function (field_index){
@ -184,8 +212,7 @@ angular.module('forms').directive('editFormDirective', ['$rootScope', '$q', '$ht
var newOption = {
'option_id' : option_id,
'option_title' : 'Option ' + option_id,
'option_value' : option_id
'option_value' : 'Option ' + option_id,
};
// put new option into fieldOptions array

View file

@ -1,47 +0,0 @@
// 'use strict';
// angular.module('forms').directive('entryPage', ['$templateCache', '$http', '$compile', '$rootScope',
// function($templateCache, $http, $compile, $rootScope) {
// var getTemplateUrl = function(type) {
// var templateUrl = 'modules/forms/views/directiveViews/entryPage/';
// var supported_pages = [
// 'welcome',
// 'thankyou'
// ];
// if (__indexOf.call(supported_pages, type) >= 0) {
// templateUrl += type + '.html';
// }
// var template = $templateCache.get(templateUrl);
// return template;
// };
// return {
// restrict: 'E',
// template: '<div>Start Page</div>',
// scope: {
// 'pageData': '=',
// 'pageType': '&'
// },
// link: function(scope, element) {
// // console.log(attrs);
// console.log('scope.pageData');
// // console.log(scope);
// scope.exitStartPage = function() {
// // console.log(scope.pageData);
// // if(attrs.pageData.showStart) attrs.pageData.showStart = false;
// };
// var template = getTemplateUrl(scope.pageType);
// element.html(template);
// $compile(element.contents())(scope);
// },
// controller: function($scope){
// console.log('entryPage Controller');
// console.log($scope.pageData);
// // $scope.exitStartPage = function() {
// // if($scope.pageData.showStart) scope.pageData.showStart = false;
// // };
// }
// };
// }]);

View file

@ -13,7 +13,7 @@ angular.module('forms').directive('fieldDirective', ['$templateCache', '$http',
var getTemplateUrl = function(field) {
console.log(field.validFieldTypes);
var type = field.fieldType;
var templateUrl = 'modules/forms/views/directiveViews/field/';
var supported_fields = [
@ -22,6 +22,7 @@ angular.module('forms').directive('fieldDirective', ['$templateCache', '$http',
'textarea',
'checkbox',
'date',
'link',
'dropdown',
'hidden',
'password',
@ -34,10 +35,9 @@ angular.module('forms').directive('fieldDirective', ['$templateCache', '$http',
'natural'
];
if (__indexOf.call(supported_fields, type) >= 0) {
templateUrl += type + '.html';
templateUrl = templateUrl+type+'.html';
}
var template = $templateCache.get(templateUrl);
return template;
return templateUrl;
};
var linker = function(scope, element) {
@ -53,24 +53,13 @@ angular.module('forms').directive('fieldDirective', ['$templateCache', '$http',
defaultDate: 0,
};
}
//DAVID: TODO: Make natural language processing work
//Set only if we have a natural lang processing field
// else if(scope.field.fieldType === 'natural'){
// scope.field.fieldMatchValue = '';
// //Fires when field is changed
// scope.$watch('scope.field', function(newField, oldField) {
// });
// }
// GET template content from path
var template = getTemplateUrl(scope.field);
// $http.get(templateUrl).success(function(data) {
element.html(template).show();
// console.log(element.contents());
$compile(element.contents())(scope);
// });
var templateUrl = getTemplateUrl(scope.field);
$http.get(templateUrl).success(function(data) {
element.html(data).show();
$compile(element.contents())(scope);
});
};
return {

View file

@ -13,10 +13,9 @@ angular.module('forms').directive('onFinishRender', function ($rootScope, $timeo
}
var broadcastMessage = attrs.onFinishRender || 'ngRepeat';
if(scope.$first) {
if(scope.$first && !scope.$last) {
scope.$evalAsync(function () {
// console.log(broadcastMessage+' Started');
// console.log(Date.now());
$rootScope.$broadcast(broadcastMessage+' Started');
});

View file

@ -24,6 +24,7 @@ angular.module('forms').factory('Forms', ['$resource',
method: 'GET',
transformResponse: function(data, header) {
var form = angular.fromJson(data);
console.log(form);
form.visible_form_fields = _.filter(form.form_fields, function(field){
return (field.deletePreserved === false);

View file

@ -72,6 +72,12 @@
};
};
//Mock Users Service
beforeEach(module(function($provide) {
$provide.service('myForm', function($q) {
return sampleForm;
});
}));
// The $resource service augments the response object with methods for updating and deleting the resource.

View file

@ -82,6 +82,14 @@
beforeEach(module('stateMock'));
//Mock Users Service
beforeEach(module(function($provide) {
$provide.service('myForm', function($q) {
return sampleForm;
});
}));
// The injector ignores leading and trailing underscores here (i.e. _$httpBackend_).
// This allows us to inject a service but then attach it to a variable
// with the same name as the service.

View file

@ -41,6 +41,13 @@
],
};
//Mock Users Service
beforeEach(module(function($provide) {
$provide.service('myForm', function($q) {
return sampleForm;
});
}));
//Mock Users Service
beforeEach(module(function($provide) {
$provide.service('User', function($q) {
@ -206,7 +213,7 @@
}));
it('$scope.initForm() should populate $scope.myform with current Form', inject(function(Forms) {
it('on controller instantiation it should populate $scope.myform with current Form', inject(function(Forms) {
var controller = createSubmitFormController();
@ -215,13 +222,8 @@
// Set GET response
$httpBackend.expectGET(/^(\/forms\/)([0-9a-fA-F]{24})$/).respond(200, sampleForm);
// Run controller functionality
scope.initForm();
$httpBackend.flush();
$state.ensureAllTransitionsHappened();
// Test scope value
expect( scope.myform.toJSON() ).toEqualData(sampleForm);
expect( scope.myform ).toEqualData(sampleForm);
expect( scope.hideNav ).toEqual(false);
}));
});

View file

@ -1,4 +1,3 @@
'use strict';
(function() {
// Forms Controller Spec

View file

@ -1,4 +1,4 @@
<section data-ng-controller="AdminFormController" data-ng-init="findOne()" class="container admin-form">
<section class="container admin-form" cg-busy="{promise:updatePromise,templateUrl:'modules/forms/views/directiveViews/cgBusy/update-form-message-TypeB.html',message:'Updating form...',backdrop:false,minDuration:700}">
<!-- Modal Delete Dialog Template -->
<script type="text/ng-template" id="myModalContent.html">
@ -61,7 +61,7 @@
</div>
</div>
<div class="row" cg-busy="{promise:updatePromise,templateUrl:'modules/forms/views/directiveViews/cgBusy/update-form-message-TypeB.html',message:'Updating form...',backdrop:false}">
<div class="row">
<tabset class="col-xs-12">
<tab>
<tab-heading>

View file

@ -1,3 +1,4 @@
<!-- cgBusy Template -->
<div>
<div style="text-align: center; font-size: 20px;position: fixed; bottom: 0; right: 45px; background-color: gray; color: white; padding: 5px 15px 5px 10px;">{{$message}}</div>
<div style="text-align: center; font-size: 20px;position: fixed; bottom: 0; right: 45px; background-color: gray; color: white; padding: 5px 15px 5px 10px; z-index: 10;">{{$message}}</div>
</div>

View file

@ -12,9 +12,9 @@
ng-required="field.required"
ng-disabled="field.disabled">
<option ng-repeat="option in field.fieldOptions"
ng-selected="option.option_id == field.fieldValue"
ng-value="option.option_id">
{{option.option_title}}
ng-selected="option.option_value == field.fieldValue"
ng-value="option.option_value">
{{option.option_value}}
</option>
</select>
</div>

View file

@ -65,7 +65,7 @@
</div>
</div>
<!-- generate form from PDF yes/no field -->
<!-- Generate form from PDF yes/no field -->
<div class="row field">
<div class="col-sm-6 field-title">
<h5>Autogenerate Form?</h5>
@ -84,29 +84,77 @@
</div>
</div>
<!-- activate oscarhost API yes/no field -->
<div class="row field">
<div class="field-title col-sm-6">
<h5>Use Oscarhost API?</h5>
</div>
<div class="field-input col-sm-6">
<label>
<input type="radio" data-ng-value="true" ng-model="oscarhostAPI" ng-required="true" />
&nbsp;<span>Yes</span>
</label>
<label>
<input type="radio" data-ng-value="false" ng-model="oscarhostAPI" 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 field" ng-if="oscarhostAPI">
<div class="field-title col-sm-4">
<h5>EMR API Key</h5>
<h5>Oscarhost API Username</h5>
</div>
<div class="col-sm-8">
<input type="text"
ng-model="myform.EMR.api_key"
value="{{myform.EMR.api_key}}"
style="width: 100%;">
ng-model="myform.plugins.oscarhost.auth.user"
value="{{myform.plugins.oscarhost.auth.user}}"
style="width: 100%;"
required>
</div>
</div>
<div class="row field">
<div class="row field" ng-if="oscarhostAPI">
<div class="field-title col-sm-4">
<h5>EMR URL</h5>
<h5>Oscarhost API Password</h5>
</div>
<div class="col-sm-8">
<input type="password"
ng-model="myform.plugins.oscarhost.auth.pass"
value="{{myform.plugins.oscarhost.auth.pass}}"
style="width: 100%;"
required>
</div>
</div>
<div class="row field" ng-if="oscarhostAPI">
<div class="field-title col-sm-4">
<h5>Oscarhost API URL</h5>
</div>
<div class="col-sm-8">
<input type="link"
ng-model="myform.EMR.url"
value="{{myform.EMR.url}}"
style="width: 100%;">
ng-model="myform.plugins.oscarhost.baseUrl"
value="{{myform.plugins.oscarhost.baseUrl}}"
style="width: 100%;"
required>
</div>
</div>
<div class="row field" ng-if="oscarhostAPI">
<div class="field-title col-sm-4">
<h5>Oscarhost API update type</h5>
</div>
<div class="col-sm-8">
<select ng-model="myform.plugins.oscarhost.settings.updateType">
<option ng-repeat="updateType in myform.plugins.oscarhost.settings.validUpdateTypes" ng-value="updateType">
{{updateType}}
</option>
</select>
</div>
</div>
@ -114,10 +162,9 @@
<!-- generate typeform from NodeForm yes/no field -->
<div class="row field">
<div class="col-sm-6 field-title">
<h5>Autogenerate Typeform?</h5>
<h5>Autogenerate into Typeform?</h5>
</div>
<div class="col-sm-6 field-input">
<label>
<input type="radio" data-ng-value="true" ng-model="myform.Typeform.isGenerated" ng-required="true" />
&nbsp;<span>Yes</span>

View file

@ -22,7 +22,6 @@
</div>
</div>
</div>
</div>
</div>
@ -156,7 +155,7 @@
<div class="col-sm-12 col-md-10"><hr></div>
</div>
<div class="row">
<div class="col-sm-12 col-md-10">
<div class="col-sm-12 col-md-8">
<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="editFormFields" ng-if="!field.deletePreserved">
@ -218,19 +217,15 @@
<div class="col-md-4 col-xs-12">Options:</div>
<div class="col-md-8 col-xs-12">
<div ng-repeat="option in field.fieldOptions" class="row">
<input type="text" name="{{option.option_title}}{{field._id}}" ng-model="option.option_title" value="{{option.option_title}}" class="col-xs-5">
<input type="text" name="{{option.option_value}}{{field._id}}" ng-model="option.option_value" class="col-xs-5">
<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>
<span class="label label-inverse col-md-4 hidden-xs hidden-sm">
Value: {{ option.option_value }}
</span>
</div>
<div class="row">
<button class="btn btn-primary btn-small ol-md-12 col-sm-4 col-sm-offset-4 col-xs-6 col-xs-offset-6" type="button" ng-click="addOption(field)">
<button class="btn btn-primary btn-small col-md-offset-0 col-md-6 col-sm-4 col-sm-offset-4 col-xs-6 col-xs-offset-6" type="button" ng-click="addOption(field)">
<i class="icon-plus icon-white"></i> Add Option
</button>
</div>
</div>
@ -412,6 +407,22 @@
</div>
</div>
</div>
<div class="col-md-2 hidden-xs hidden-sm" style="padding:0 5px;" ng-if="myform.plugins.oscarhost.baseUrl">
<div class="panel-group text-center">
<div class="panel panel-default" ng-repeat="field in myform.form_fields" ng-if="!field.deletePreserved" style="border: none;">
<select ng-model="myform.plugins.oscarhost.settings.fieldMap[field._id]" style="height:39.2px">
<option value="">N/A</option>
<option ng-repeat="oscarhost_field in oscarFieldsLeft(field._id)"
ng-selected="oscarhost_field == myform.plugins.oscarhost.settings.fieldMap[field._id]"
ng-value="oscarhost_field">
{{oscarhost_field}}
</option>
</select>
</div>
</div>
</div>
</div>
</div>

View file

@ -52,11 +52,10 @@
<div data-ng-repeat="form in myforms" class="col-xs-6 col-xs-offset-3 col-sm-4 col-sm-offset-1 col-md-3 col-md-offset-1 form-item container">
<div class="row">
<span class="pull-right">
<i style="cursor:pointer;" class="fa fa-trash-o" ng-click="removeForm(form._id)"></i>
<i style="cursor:pointer;" class="fa fa-files-o" ng-click="duplicate($index)"></i>
</span>
<span class="pull-right">
<i style="cursor:pointer;" class="fa fa-trash-o" ng-click="removeForm($index)"></i>
<i style="cursor:pointer;" class="fa fa-files-o" ng-click="duplicate($index)"></i>
</span>
</div>
<div class="row">

View file

@ -1,4 +1,4 @@
<section data-ng-controller="SubmitFormController" class="public-form" ng-init="initForm()">
<section class="public-form">
<submit-form-directive myform="myform"></submit-form-directive>

View file

@ -7,6 +7,9 @@ var init = require('./config/init')(),
mongoose = require('mongoose'),
chalk = require('chalk');
require('events').EventEmitter.prototype._maxListeners = 100;
/**
* Main application entry file.
* Please note that the order of loading is important.