added testing

This commit is contained in:
David Baldwynn 2015-08-18 14:44:36 -07:00
parent d5a399f8fc
commit 52a305cf9b
58 changed files with 3236 additions and 2480 deletions

View File

@ -197,7 +197,6 @@ exports.create = function(req, res) {
});
};
/**
* Show the current form
*/
@ -209,23 +208,15 @@ exports.read = function(req, res) {
* Update a form
*/
exports.update = function(req, res) {
// console.log('in form.update()');
// console.log(req.body.form.form_fields);
var form = req.form;
delete req.body.form.__v;
delete req.body.form._id;
delete req.body.form.admin;
// console.log(form.admin);
//Unless we have 'admin' priviledges, updating form admin is disabled
if(req.user.roles.indexOf('admin') === -1) delete req.body.form.admin;
form = _.extend(form, req.body.form);
// console.log(req.body.form);
// form.form_fields = req.body.form.form_fields;
form.save(function(err, form) {
if (err) {
@ -234,7 +225,6 @@ exports.update = function(req, res) {
message: errorHandler.getErrorMessage(err)
});
} else {
// console.log('updated form');
res.json(form);
}
});

View File

@ -105,7 +105,7 @@ exports.signin = function(req, res, next) {
*/
exports.signout = function(req, res) {
req.logout();
res.status(200).send('user successfully logged out');
res.status(200).send('Successfully logged out');
// res.redirect('/');
};

View File

@ -20,6 +20,25 @@ var FieldSchema = require('./form_field.server.model.js'),
FormSubmission = mongoose.model('FormSubmission', FormSubmissionSchema);
var ButtonSchema = new Schema({
url: {
type: String,
match: [/((([A-Za-z]{3,9}:(?:\/\/)?)(?:[-;:&=\+\$,\w]+@)?[A-Za-z0-9.-]+|(?:www.|[-;:&=\+\$,\w]+@)[A-Za-z0-9.-]+)((?:\/[\+~%\/.\w-_]*)?\??(?:[-\+=&;%@.\w_]*)#?(?:[\w]*))?)/],
},
action: String,
text: String,
bgColor: {
type: String,
match: [/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/],
default: '#5bc0de'
},
color: {
type: String,
match: [/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/],
default: '#ffffff'
}
});
/**
* Form Schema
*/
@ -73,30 +92,16 @@ var FormSchema = new Schema({
type: Boolean,
default: false,
},
introText:{
introTitle:{
type: String,
default: 'Welcome to Form'
},
introParagraph:{
type: String,
},
buttons:[{
url: {
type: String,
match: [/((([A-Za-z]{3,9}:(?:\/\/)?)(?:[-;:&=\+\$,\w]+@)?[A-Za-z0-9.-]+|(?:www.|[-;:&=\+\$,\w]+@)[A-Za-z0-9.-]+)((?:\/[\+~%\/.\w-_]*)?\??(?:[-\+=&;%@.\w_]*)#?(?:[\w]*))?)/],
},
action: String,
buttonText: String,
backgroundColor: {
type: String,
match: [/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/],
default: '#5bc0de'
},
color: {
type: String,
match: [/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/],
default: '#ffffff'
}
}]
buttons:[ButtonSchema]
},
hideFooter: {
type: Boolean,
default: false,

View File

@ -6,51 +6,18 @@
var mongoose = require('mongoose'),
Schema = mongoose.Schema;
// questionType Validation
function validateFormFieldType(value) {
if (!value) { return false; }
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;
}
/**
* Question Schema
*/
var FormFieldSchema = new Schema({
// created: {
// type: Date,
// default: Date.now
// },
// lastModified: {
// type: Date,
// default: Date.now
// },
created: {
type: Date,
default: Date.now
},
lastModified: {
type: Date,
default: Date.now
},
title: {
type: String,
default: '',
@ -86,6 +53,63 @@ var FormFieldSchema = new Schema({
});
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; }
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;
}
module.exports = FormFieldSchema;
// mongoose.model('Field', FormFieldSchema);

View File

@ -91,7 +91,6 @@ FormSubmissionSchema.pre('save', function (next) {
if(this.pdf && this.pdf.path){
// console.log(this.pdf);
dest_filename = that.title.replace(/ /g,'')+'_submission_'+Date.now()+'.pdf';
var __path = this.pdf.path.split('/').slice(0,this.pdf.path.split('/').length-1).join('/');
dest_path = path.join(__path, dest_filename);
@ -99,12 +98,6 @@ FormSubmissionSchema.pre('save', function (next) {
that.pdfFilePath = dest_path;
pdfFiller.fillForm(that.pdf.path, dest_path, that.fdfData, function(err){
// console.log('fdfData: \n');
// console.log(that.fdfData);
// console.log('_form.pdf.path: '+_form.pdf.path);
// console.log('dest_path: '+dest_path);
if(err) {
console.log('\n err.message: '+err.message);
next( new Error(err.message) );

View File

@ -1,189 +1,189 @@
// 'use strict';
'use strict';
// /**
// * Module dependencies.
// */
// var should = require('should'),
// mongoose = require('mongoose'),
// User = mongoose.model('User'),
// Form = mongoose.model('Form'),
// _ = require('lodash'),
// FormSubmission = mongoose.model('FormSubmission');
/**
* Module dependencies.
*/
var should = require('should'),
mongoose = require('mongoose'),
User = mongoose.model('User'),
Form = mongoose.model('Form'),
_ = require('lodash'),
FormSubmission = mongoose.model('FormSubmission');
// /**
// * Globals
// */
// var user, myForm, mySubmission;
/**
* Globals
*/
var user, myForm, mySubmission;
// /**
// * 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'
// });
/**
* 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() {
// myForm = new Form({
// title: 'Form Title',
// admin: user,
// language: 'english',
// form_fields: [
// {'fieldType':'textfield', 'title':'First Name', 'fieldValue': ''},
// {'fieldType':'checkbox', 'title':'nascar', 'fieldValue': ''},
// {'fieldType':'checkbox', 'title':'hockey', 'fieldValue': ''}
// ]
// });
user.save(function() {
myForm = new Form({
title: 'Form Title',
admin: user,
language: 'english',
form_fields: [
{'fieldType':'textfield', 'title':'First Name', 'fieldValue': ''},
{'fieldType':'checkbox', 'title':'nascar', 'fieldValue': ''},
{'fieldType':'checkbox', 'title':'hockey', 'fieldValue': ''}
]
});
// done();
// });
// });
done();
});
});
// describe('Method Save', function() {
// it('should be able to save without problems', function(done) {
// return myForm.save(function(err) {
// should.not.exist(err);
// done();
// });
// });
describe('Method Save', function() {
it('should be able to save without problems', function(done) {
return myForm.save(function(err) {
should.not.exist(err);
done();
});
});
// it('should be able to show an error when try to save without title', function(done) {
// var _form = myForm;
// _form.title = '';
it('should be able to show an error when try to save without title', function(done) {
var _form = myForm;
_form.title = '';
// return _form.save(function(err) {
// should.exist(err);
// should.equal(err.errors.title.message, 'Form Title cannot be blank');
// done();
// });
// });
// });
return _form.save(function(err) {
should.exist(err);
should.equal(err.errors.title.message, 'Form Title cannot be blank');
done();
});
});
});
// describe('Method Find', function(){
// beforeEach(function(done){
// myForm.save(function(err) {
// done();
// });
// });
// it('should be able to findOne my form without problems', function(done) {
// return Form.findOne({_id: myForm._id}, function(err,form) {
// should.not.exist(err);
// should.exist(form);
// should.deepEqual(form.toObject(), myForm.toObject());
// done();
// });
// });
// });
describe('Method Find', function(){
beforeEach(function(done){
myForm.save(function(err) {
done();
});
});
it('should be able to findOne my form without problems', function(done) {
return Form.findOne({_id: myForm._id}, function(err,form) {
should.not.exist(err);
should.exist(form);
should.deepEqual(form.toObject(), myForm.toObject());
done();
});
});
});
// describe('Test FormField and Submission Logic', function() {
// var new_form_fields_add1, new_form_fields_del, submission_fields, old_fields, form;
describe('Test FormField and Submission Logic', function() {
var new_form_fields_add1, new_form_fields_del, submission_fields, old_fields, form;
// before(function(){
// new_form_fields_add1 = _.clone(myForm.toObject().form_fields);
// new_form_fields_add1.push(
// {'fieldType':'textfield', 'title':'Last Name', 'fieldValue': ''}
// );
before(function(){
new_form_fields_add1 = _.clone(myForm.toObject().form_fields);
new_form_fields_add1.push(
{'fieldType':'textfield', 'title':'Last Name', 'fieldValue': ''}
);
// new_form_fields_del = _.clone(myForm.toObject().form_fields);
// new_form_fields_del.splice(0, 1);
new_form_fields_del = _.clone(myForm.toObject().form_fields);
new_form_fields_del.splice(0, 1);
// submission_fields = _.clone(myForm.toObject().form_fields);
// submission_fields[0].fieldValue = 'David';
// submission_fields[1].fieldValue = true;
// submission_fields[2].fieldValue = true;
submission_fields = _.clone(myForm.toObject().form_fields);
submission_fields[0].fieldValue = 'David';
submission_fields[1].fieldValue = true;
submission_fields[2].fieldValue = true;
// mySubmission = new FormSubmission({
// form_fields: submission_fields,
// admin: user,
// form: myForm,
// timeElapsed: 17.55
// });
mySubmission = new FormSubmission({
form_fields: submission_fields,
admin: user,
form: myForm,
timeElapsed: 17.55
});
// });
});
// beforeEach(function(done){
// myForm.save(function(){
// mySubmission.save(function(){
// done();
// });
// });
// });
beforeEach(function(done){
myForm.save(function(){
mySubmission.save(function(){
done();
});
});
});
// afterEach(function(done){
// mySubmission.remove(function(){
// done();
// });
// });
afterEach(function(done){
mySubmission.remove(function(){
done();
});
});
// // it('should preserve deleted form_fields that have submissions without any problems', function(done) {
// it('should preserve deleted form_fields that have submissions without any problems', function(done) {
// // old_fields = myForm.toObject().form_fields;
// // // console.log(old_fields);
// old_fields = myForm.toObject().form_fields;
// // console.log(old_fields);
// // // var expected_fields = old_fields.slice(1,3).concat(old_fields.slice(0,1));
// // var expected_fields = old_fields.slice(1,3).concat(old_fields.slice(0,1));
// // myForm.form_fields = new_form_fields_del;
// myForm.form_fields = new_form_fields_del;
// // myForm.save(function(err, _form) {
// myForm.save(function(err, _form) {
// // should.not.exist(err);
// // should.exist(_form);
// should.not.exist(err);
// should.exist(_form);
// // // var actual_fields = _.map(_form.toObject().form_fields, function(o){ _.omit(o, '_id')});
// // // old_fields = _.map(old_fields, function(o){ _.omit(o, '_id')});
// // var actual_fields = _.map(_form.toObject().form_fields, function(o){ _.omit(o, '_id')});
// // old_fields = _.map(old_fields, function(o){ _.omit(o, '_id')});
// // // console.log(old_fields);
// // should.deepEqual(JSON.stringify(_form.toObject().form_fields), JSON.stringify(old_fields), 'old form_fields not equal to newly saved form_fields');
// // done();
// // });
// // });
// // console.log(old_fields);
// should.deepEqual(JSON.stringify(_form.toObject().form_fields), JSON.stringify(old_fields), 'old form_fields not equal to newly saved form_fields');
// done();
// });
// });
// // it('should delete \'preserved\' form_fields whose submissions have been removed without any problems', function(done) {
// it('should delete \'preserved\' form_fields whose submissions have been removed without any problems', function(done) {
// // myForm.form_fields = new_form_fields_del;
// // myForm.save(function(err, form
// // should.not.exist(err);
// // (form.form_fields).should.be.eql(old_fields, 'old form_fields not equal to newly saved form_fields');
// myForm.form_fields = new_form_fields_del;
// myForm.save(function(err, form
// should.not.exist(err);
// (form.form_fields).should.be.eql(old_fields, 'old form_fields not equal to newly saved form_fields');
// // //Remove submission
// // mySubmission.remove(function(err){
// // myForm.submissions.should.have.length(0);
// // myForm.form_fields.should.not.containDeep(old_fields[0]);
// // });
// // });
// // });
// });
// //Remove submission
// mySubmission.remove(function(err){
// myForm.submissions.should.have.length(0);
// myForm.form_fields.should.not.containDeep(old_fields[0]);
// });
// });
// });
});
// // describe('Method generateFDFTemplate', function() {
// // var FormFDF;
// // before(function(done){
// // return myForm.save(function(err, form){
// describe('Method generateFDFTemplate', function() {
// var FormFDF;
// before(function(done){
// return myForm.save(function(err, form){
// // FormFDF = {
// // 'First Name': '',
// // 'nascar': '',
// // 'hockey': ''
// // };
// // done();
// // });
// // });
// FormFDF = {
// 'First Name': '',
// 'nascar': '',
// 'hockey': ''
// };
// done();
// });
// });
// // it('should be able to generate a FDF template without any problems', function() {
// // var fdfTemplate = myForm.generateFDFTemplate();
// // (fdfTemplate).should.be.eql(FormFDF);
// // });
// // });
// it('should be able to generate a FDF template without any problems', function() {
// var fdfTemplate = myForm.generateFDFTemplate();
// (fdfTemplate).should.be.eql(FormFDF);
// });
// });
// afterEach(function(done) {
// Form.remove().exec(function() {
// User.remove().exec(done);
// });
// });
// });
afterEach(function(done) {
Form.remove().exec(function() {
User.remove().exec(done);
});
});
});

View File

@ -1,496 +1,502 @@
// 'use strict';
// var should = require('should'),
// _ = require('lodash'),
// app = require('../../server'),
// request = require('supertest'),
// Session = require('supertest-session')({
// app: app
// }),
// mongoose = require('mongoose'),
// User = mongoose.model('User'),
// Form = mongoose.model('Form'),
// FormSubmission = mongoose.model('FormSubmission'),
// agent = request.agent(app);
// /**
// * Globals
// */
// var credentials, user, _Form;
// /**
// * Form routes tests
// */
// describe('Form CRUD tests', function() {
// beforeEach(function(done) {
// // Create user credentials
// credentials = {
// username: 'test@test.com',
// password: 'password'
// };
// // Create a new user
// user = new User({
// firstName: 'Full',
// lastName: 'Name',
// email: 'test@test.com',
// username: credentials.username,
// password: credentials.password,
// provider: 'local'
// });
// // Save a user to the test db and create new Form
// user.save(function(err) {
// if(err) done(err);
// _Form = {
// title: 'Form Title',
// language: 'english',
// admin: user._id,
// form_fields: [
// {'fieldType':'textfield', 'title':'First Name', 'fieldValue': ''},
// {'fieldType':'checkbox', 'title':'nascar', 'fieldValue': ''},
// {'fieldType':'checkbox', 'title':'hockey', 'fieldValue': ''}
// ]
// };
// done();
// });
// });
// it('should be able to save a Form if logged in', function(done) {
// agent.post('/auth/signin')
// .send(credentials)
// .expect('Content-Type', /json/)
// .expect(200)
// .end(function(signinErr, signinRes) {
// // Handle signin error
// if (signinErr) done(signinErr);
// var user = signinRes.body;
// var userId = user._id;
// // Save a new Form
// agent.post('/forms')
// .send({form: _Form})
// .expect('Content-Type', /json/)
// .expect(200)
// .end(function(FormSaveErr, FormSaveRes) {
// // Handle Form save error
// if (FormSaveErr) done(FormSaveErr);
// // Get a list of Forms
// agent.get('/forms')
// .expect('Content-Type', /json/)
// .expect(200)
// .end(function(FormsGetErr, FormsGetRes) {
// // Handle Form save error
// if (FormsGetErr) done(FormsGetErr);
// // Get Forms list
// var Forms = FormsGetRes.body;
// // Set assertions
// (Forms[0].admin).should.equal(userId);
// (Forms[0].title).should.match('Form Title');
// // Call the assertion callback
// done();
// });
// });
// });
// });
// it('should not be able to create a Form if not logged in', function(done) {
// agent.post('/forms')
// .send({form: _Form})
// .expect(401)
// .end(function(FormSaveErr, FormSaveRes) {
// (FormSaveRes.body.message).should.equal('User is not logged in');
// // Call the assertion callback
// done(FormSaveErr);
// });
// });
// it('should not be able to get list of users\' Forms if not logged in', function(done) {
// agent.get('/forms')
// .expect(401)
// .end(function(FormSaveErr, FormSaveRes) {
// (FormSaveRes.body.message).should.equal('User is not logged in');
// // Call the assertion callback
// done(FormSaveErr);
// });
// });
// 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 = '';
// agent.post('/auth/signin')
// .send(credentials)
// .expect('Content-Type', /json/)
// .expect(200)
// .end(function(signinErr, signinRes) {
// // Handle signin error
// if (signinErr) done(signinErr);
// // Save a new Form
// agent.post('/forms')
// .send({form: _Form})
// .expect(400)
// .end(function(FormSaveErr, FormSaveRes) {
// // Set message assertion
// (FormSaveRes.body.message).should.equal('Form Title cannot be blank');
// // Handle Form save error
// done();
// });
// });
// });
// it('should be able to update a Form if signed in', function(done) {
// agent.post('/auth/signin')
// .send(credentials)
// .expect('Content-Type', /json/)
// .expect(200)
// .end(function(signinErr, signinRes) {
// // Handle signin error
// if (signinErr) done(signinErr);
// // Save a new Form
// agent.post('/forms')
// .send({form: _Form})
// .expect('Content-Type', /json/)
// .expect(200)
// .end(function(FormSaveErr, FormSaveRes) {
// // Handle Form save error
// if (FormSaveErr) done(FormSaveErr);
// // Update Form title
// _Form.title = 'WHY YOU GOTTA BE SO MEAN?';
// // Update an existing Form
// agent.put('/forms/' + FormSaveRes.body._id)
// .send({form: _Form})
// .expect('Content-Type', /json/)
// .expect(200)
// .end(function(FormUpdateErr, FormUpdateRes) {
// // Handle Form update error
// if (FormUpdateErr) done(FormUpdateErr);
// // Set assertions
// (FormUpdateRes.body._id).should.equal(FormSaveRes.body._id);
// (FormUpdateRes.body.title).should.match('WHY YOU GOTTA BE SO MEAN?');
// // Call the assertion callback
// done();
// });
// });
// });
// });
// 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);
// // Save the Form
// FormObj.save(function(err, form) {
// if(err) done(err);
// request(app).get('/forms/' + form._id)
// .expect('Content-Type', /json/)
// .expect(200)
// .end(function(err, res) {
// if(err) done(err)
// // Set assertion
// (res.body).should.be.an.Object.with.property('title', _Form.title);
// // Call the assertion callback
// done();
// });
// });
// });
// it('should be able to delete a Form if signed in', function(done) {
// agent.post('/auth/signin')
// .send(credentials)
// .expect('Content-Type', /json/)
// .expect(200)
// .end(function(signinErr, signinRes) {
// // Handle signin error
// if (signinErr) done(signinErr);
// done();
// // Save a new Form
// // agent.post('/forms')
// // .send({form: _Form})
// // .expect('Content-Type', /json/)
// // .expect(200)
// // .end(function(FormSaveErr, FormSaveRes) {
// // // Handle Form save error
// // if (FormSaveErr) done(FormSaveErr);
// // // Delete an existing Form
// // agent.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);
// // // Set assertions
// // (FormDeleteRes.body._id).should.equal(FormSaveRes.body._id);
// // // 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;
// // Create new Form model instance
// var FormObj = new Form(_Form);
// // Save the Form
// FormObj.save(function() {
// // Try deleting Form
// request(app).delete('/forms/' + FormObj._id)
// .expect(401)
// .end(function(FormDeleteErr, FormDeleteRes) {
// // Set message assertion
// (FormDeleteRes.body.message).should.match('User is not logged in');
// // Handle Form error error
// done(FormDeleteErr);
// });
// });
// });
// it('should be able to upload a PDF an Form if logged in', function(done) {
// agent.post('/auth/signin')
// .send(credentials)
// .expect('Content-Type', /json/)
// .expect(200)
// .end(function(signinErr, signinRes) {
// // Handle signin error
// if (signinErr) done(signinErr);
// var user = signinRes.body;
// var userId = user._id;
// // Save a new Form
// agent.post('/forms')
// .send({form: _Form})
// .expect('Content-Type', /json/)
// .expect(200)
// .end(function(FormSaveErr, FormSaveRes) {
// // Handle Form save error
// if (FormSaveErr) done(FormSaveErr);
// // Get a list of Forms
// agent.get('/forms')
// .expect('Content-Type', /json/)
// .expect(200)
// .end(function(FormsGetErr, FormsGetRes) {
// // Handle Form save error
// if (FormsGetErr) done(FormsGetErr);
// // Get Forms list
// var Forms = FormsGetRes.body;
// // Set assertions
// (Forms[0].admin).should.equal(userId);
// (Forms[0].title).should.match('Form Title');
// // Call the assertion callback
// done();
// });
// });
// });
// });
// describe('Form Submission tests', function() {
// var FormObj, _Submission, submissionSession;
// beforeEach(function (done) {
// _Form.admin = user;
// FormObj = new Form(_Form);
// FormObj.save(function(err, form) {
// if (err) done(err);
// _Submission = {
// form_fields: [
// {'fieldType':'textfield', 'title':'First Name', 'fieldValue': 'David'},
// {'fieldType':'checkbox', 'title':'nascar', 'fieldValue': true},
// {'fieldType':'checkbox', 'title':'hockey', 'fieldValue': false}
// ],
// form: form._id,
// admin: user._id,
// percentageComplete: 100,
// timeElapsed: 11.55
// };
// FormObj = form;
// //Setup test session
// submissionSession = new Session();
// done();
// });
// });
// it('should be able to create a Form Submission without signing in', function(done) {
// //Create Submission
// submissionSession.post('/forms/' + FormObj._id)
// .send(_Submission)
// .expect(200)
// .end(function(err, res) {
// should.not.exist(err);
// done();
// });
// });
// it('should be able to get Form Submissions if signed in', function(done) {
// submissionSession.post('/auth/signin')
// .send(credentials)
// .expect('Content-Type', /json/)
// .expect(200)
// .end(function(signinErr, signinRes) {
// should.not.exist(signinErr);
// //Create Submission
// submissionSession.post('/forms/' + FormObj._id)
// .send(_Submission)
// .expect(200)
// .end(function(err, res) {
// should.not.exist(err);
// submissionSession.get('/forms/' + FormObj._id + '/submissions')
// .expect('Content-Type', /json/)
// .expect(200)
// .end(function(err, res) {
// // Set assertion
// should.not.exist(err);
// // Call the assertion callback
// done();
// });
// });
// });
// });
// it('should not be able to get Form Submissions if not signed in', function(done) {
// // Attempt to fetch form submissions
// submissionSession.get('/forms/' + FormObj._id + '/submissions')
// .expect(401)
// .end(function(err, res) {
'use strict';
var should = require('should'),
_ = require('lodash'),
app = require('../../server'),
request = require('supertest'),
Session = require('supertest-session')({
app: app
}),
mongoose = require('mongoose'),
User = mongoose.model('User'),
Form = mongoose.model('Form'),
FormSubmission = mongoose.model('FormSubmission'),
agent = request.agent(app);
/**
* Globals
*/
var credentials, user, _Form;
/**
* Form routes tests
*/
describe('Form CRUD tests', function() {
beforeEach(function(done) {
//Initialize Session
userSession = new Session();
// Create user credentials
credentials = {
username: 'test@test.com',
password: 'password'
};
// Create a new user
user = new User({
firstName: 'Full',
lastName: 'Name',
email: 'test@test.com',
username: credentials.username,
password: credentials.password,
provider: 'local'
});
// Save a user to the test db and create new Form
user.save(function(err) {
if(err) done(err);
_Form = {
title: 'Form Title',
language: 'english',
admin: user._id,
form_fields: [
{'fieldType':'textfield', 'title':'First Name', 'fieldValue': ''},
{'fieldType':'checkbox', 'title':'nascar', 'fieldValue': ''},
{'fieldType':'checkbox', 'title':'hockey', 'fieldValue': ''}
]
};
done();
});
});
it('should be able to save a Form if logged in', function(done) {
userSession.post('/auth/signin')
.send(credentials)
.expect('Content-Type', /json/)
.expect(200)
.end(function(signinErr, signinRes) {
// Handle signin error
if (signinErr) done(signinErr);
var user = signinRes.body;
var userId = user._id;
// 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);
// Get a list of Forms
userSession.get('/forms')
.expect('Content-Type', /json/)
.expect(200)
.end(function(FormsGetErr, FormsGetRes) {
// Handle Form save error
if (FormsGetErr) done(FormsGetErr);
// Get Forms list
var Forms = FormsGetRes.body;
// Set assertions
(Forms[0].admin).should.equal(userId);
(Forms[0].title).should.match('Form Title');
// Call the assertion callback
done();
});
});
});
});
it('should not be able to create a Form if not logged in', function(done) {
userSession.post('/forms')
.send({form: _Form})
.expect(401)
.end(function(FormSaveErr, FormSaveRes) {
(FormSaveRes.body.message).should.equal('User is not logged in');
// Call the assertion callback
done(FormSaveErr);
});
});
it('should not be able to get list of users\' Forms if not logged in', function(done) {
userSession.get('/forms')
.expect(401)
.end(function(FormSaveErr, FormSaveRes) {
(FormSaveRes.body.message).should.equal('User is not logged in');
// Call the assertion callback
done(FormSaveErr);
});
});
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 = '';
userSession.post('/auth/signin')
.send(credentials)
.expect('Content-Type', /json/)
.expect(200)
.end(function(signinErr, signinRes) {
// Handle signin error
if (signinErr) done(signinErr);
// Save a new Form
userSession.post('/forms')
.send({form: _Form})
.expect(400)
.end(function(FormSaveErr, FormSaveRes) {
// Set message assertion
(FormSaveRes.body.message).should.equal('Form Title cannot be blank');
// Handle Form save error
done();
});
});
});
it('should be able to update a Form if signed in', function(done) {
userSession.post('/auth/signin')
.send(credentials)
.expect('Content-Type', /json/)
.expect(200)
.end(function(signinErr, signinRes) {
// Handle signin error
if (signinErr) done(signinErr);
// 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);
// Update Form title
_Form.title = 'WHY YOU GOTTA BE SO MEAN?';
// Update an existing Form
userSession.put('/forms/' + FormSaveRes.body._id)
.send({form: _Form})
.expect('Content-Type', /json/)
.expect(200)
.end(function(FormUpdateErr, FormUpdateRes) {
// Handle Form update error
if (FormUpdateErr) done(FormUpdateErr);
// Set assertions
(FormUpdateRes.body._id).should.equal(FormSaveRes.body._id);
(FormUpdateRes.body.title).should.match('WHY YOU GOTTA BE SO MEAN?');
// Call the assertion callback
done();
});
});
});
});
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);
// Save the Form
FormObj.save(function(err, form) {
if(err) done(err);
request(app).get('/forms/' + form._id)
.expect('Content-Type', /json/)
.expect(200)
.end(function(err, res) {
if(err) done(err)
// Set assertion
(res.body).should.be.an.Object.with.property('title', _Form.title);
// Call the assertion callback
done();
});
});
});
it('should be able to delete a Form if signed in', function(done) {
userSession.post('/auth/signin')
.send(credentials)
.expect('Content-Type', /json/)
.expect(200)
.end(function(signinErr, signinRes) {
// 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);
// // 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);
// // Set assertions
// (FormDeleteRes.body._id).should.equal(FormSaveRes.body._id);
// // 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;
// Create new Form model instance
var FormObj = new Form(_Form);
// Save the Form
FormObj.save(function() {
// Try deleting Form
request(app).delete('/forms/' + FormObj._id)
.expect(401)
.end(function(FormDeleteErr, FormDeleteRes) {
// Set message assertion
(FormDeleteRes.body.message).should.match('User is not logged in');
// Handle Form error error
done(FormDeleteErr);
});
});
});
it('should be able to upload a PDF an Form if logged in', function(done) {
userSession.post('/auth/signin')
.send(credentials)
.expect('Content-Type', /json/)
.expect(200)
.end(function(signinErr, signinRes) {
// Handle signin error
if (signinErr) done(signinErr);
var user = signinRes.body;
var userId = user._id;
// 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);
// Get a list of Forms
userSession.get('/forms')
.expect('Content-Type', /json/)
.expect(200)
.end(function(FormsGetErr, FormsGetRes) {
// Handle Form save error
if (FormsGetErr) done(FormsGetErr);
// Get Forms list
var Forms = FormsGetRes.body;
// Set assertions
(Forms[0].admin).should.equal(userId);
(Forms[0].title).should.match('Form Title');
// Call the assertion callback
done();
});
});
});
});
describe('Form Submission tests', function() {
var FormObj, _Submission, submissionSession;
beforeEach(function (done) {
_Form.admin = user;
FormObj = new Form(_Form);
FormObj.save(function(err, form) {
if (err) done(err);
_Submission = {
form_fields: [
{'fieldType':'textfield', 'title':'First Name', 'fieldValue': 'David'},
{'fieldType':'checkbox', 'title':'nascar', 'fieldValue': true},
{'fieldType':'checkbox', 'title':'hockey', 'fieldValue': false}
],
form: form._id,
admin: user._id,
percentageComplete: 100,
timeElapsed: 11.55
};
FormObj = form;
//Setup test session
submissionSession = new Session();
done();
});
});
it('should be able to create a Form Submission without signing in', function(done) {
//Create Submission
submissionSession.post('/forms/' + FormObj._id)
.send(_Submission)
.expect(200)
.end(function(err, res) {
should.not.exist(err);
done();
});
});
it('should be able to get Form Submissions if signed in', function(done) {
submissionSession.post('/auth/signin')
.send(credentials)
.expect('Content-Type', /json/)
.expect(200)
.end(function(signinErr, signinRes) {
should.not.exist(signinErr);
//Create Submission
submissionSession.post('/forms/' + FormObj._id)
.send(_Submission)
.expect(200)
.end(function(err, res) {
should.not.exist(err);
submissionSession.get('/forms/' + FormObj._id + '/submissions')
.expect('Content-Type', /json/)
.expect(200)
.end(function(err, res) {
// Set assertion
should.not.exist(err);
// Call the assertion callback
done();
});
});
});
});
it('should not be able to get Form Submissions if not signed in', function(done) {
// Attempt to fetch form submissions
submissionSession.get('/forms/' + FormObj._id + '/submissions')
.expect(401)
.end(function(err, res) {
// // Set assertions
// (res.body.message).should.equal('User is not logged in');
// Set assertions
(res.body.message).should.equal('User is not logged in');
// // Call the assertion callback
// done();
// });
// });
// Call the assertion callback
done();
});
});
// it('should not be able to delete Form Submission if not signed in', function(done) {
// var SubmissionObj = new FormSubmission(_Submission);
it('should not be able to delete Form Submission if not signed in', function(done) {
var SubmissionObj = new FormSubmission(_Submission);
// SubmissionObj.save(function (err, submission) {
// should.not.exist(err);
// var submission_ids = _.pluck([submission], '_id');
// // Attempt to delete form submissions
// submissionSession.delete('/forms/' + FormObj._id + '/submissions')
// .send({deleted_submissions: submission_ids})
// .expect(401)
// .end(function(err, res) {
SubmissionObj.save(function (err, submission) {
should.not.exist(err);
var submission_ids = _.pluck([submission], '_id');
// Attempt to delete form submissions
submissionSession.delete('/forms/' + FormObj._id + '/submissions')
.send({deleted_submissions: submission_ids})
.expect(401)
.end(function(err, res) {
// // Set assertions
// should.not.exist(err);
// (res.body.message).should.equal('User is not logged in');
// Set assertions
should.not.exist(err);
(res.body.message).should.equal('User is not logged in');
// // Call the assertion callback
// done();
// });
// });
// });
// Call the assertion callback
done();
});
});
});
// it('should be able to delete Form Submission if signed in', function(done) {
// // Create new FormSubmission model instance
// var SubmissionObj = new FormSubmission(_Submission);
it('should be able to delete Form Submission if signed in', function(done) {
// Create new FormSubmission model instance
var SubmissionObj = new FormSubmission(_Submission);
// SubmissionObj.save(function (err, submission) {
// should.not.exist(err);
SubmissionObj.save(function (err, submission) {
should.not.exist(err);
// // Signin as user
// submissionSession.post('/auth/signin')
// .send(credentials)
// .expect('Content-Type', /json/)
// .expect(200)
// .end(function(signinErr, signinRes) {
// // Handle signin error
// if (signinErr) done(signinErr);
// Signin as user
submissionSession.post('/auth/signin')
.send(credentials)
.expect('Content-Type', /json/)
.expect(200)
.end(function(signinErr, signinRes) {
// Handle signin error
if (signinErr) done(signinErr);
// var submission_ids = _.pluck([submission], '_id');
var submission_ids = _.pluck([submission], '_id');
// //Delete form submissions
// submissionSession.delete('/forms/' + FormObj._id + '/submissions')
// .send({deleted_submissions: submission_ids})
// .expect(200)
// .end(function(err, res) {
//Delete form submissions
submissionSession.delete('/forms/' + FormObj._id + '/submissions')
.send({deleted_submissions: submission_ids})
.expect(200)
.end(function(err, res) {
// // Set assertions
// should.not.exist(err);
// (res.text).should.equal('Form submissions successfully deleted');
// Set assertions
should.not.exist(err);
(res.text).should.equal('Form submissions successfully deleted');
// // Call the assertion callback
// done();
// });
// });
// });
// });
// Call the assertion callback
done();
});
});
});
});
// afterEach(function(done) {//logout current user if there is one
// FormSubmission.remove().exec(function() {
// Form.remove().exec(function (err) {
// submissionSession.destroy();
// done();
// });
// });
// });
// });
afterEach(function(done) {//logout current user if there is one
FormSubmission.remove().exec(function() {
Form.remove().exec(function (err) {
submissionSession.destroy();
done();
});
});
});
});
// afterEach(function(done) {
// User.remove().exec(function() {
// Form.remove().exec(done);
// });
// });
// });
afterEach(function(done) {
User.remove().exec(function() {
Form.remove().exec(function() {
userSession.destroy();
});
});
});
});

View File

@ -1,90 +1,90 @@
// 'use strict';
'use strict';
// /**
// * Module dependencies.
// */
// var should = require('should'),
// mongoose = require('mongoose'),
// User = mongoose.model('User');
/**
* Module dependencies.
*/
var should = require('should'),
mongoose = require('mongoose'),
User = mongoose.model('User');
// /**
// * Globals
// */
// var user, user2;
/**
* Globals
*/
var user, user2;
// /**
// * Unit tests
// */
// describe('User Model Unit Tests:', function() {
// beforeEach(function(done) {
// user = new User({
// firstName: 'Full',
// lastName: 'Name',
// email: 'test@test.com',
// username: 'test@test.com',
// password: 'password',
// provider: 'local'
// });
// user2 = new User({
// firstName: 'Full',
// lastName: 'Name',
// email: 'test@test.com',
// username: 'test@test.com',
// password: 'password',
// provider: 'local'
// });
/**
* Unit tests
*/
describe('User Model Unit Tests:', function() {
beforeEach(function(done) {
user = new User({
firstName: 'Full',
lastName: 'Name',
email: 'test@test.com',
username: 'test@test.com',
password: 'password',
provider: 'local'
});
user2 = new User({
firstName: 'Full',
lastName: 'Name',
email: 'test@test.com',
username: 'test@test.com',
password: 'password',
provider: 'local'
});
// done();
// });
done();
});
// describe('Method Save', function() {
// it('should begin with no users', function(done) {
// User.find({}, function(err, users) {
// users.should.have.length(0);
// done();
// });
// });
describe('Method Save', function() {
it('should begin with no users', function(done) {
User.find({}, function(err, users) {
users.should.have.length(0);
done();
});
});
// it('should be able to save without problems', function(done) {
// user.save(done);
// });
it('should be able to save without problems', function(done) {
user.save(done);
});
// it('should fail to save an existing user again', function(done) {
// user.save(function() {
// user2.save(function(err) {
// should.exist(err);
// done();
// });
// });
// });
it('should fail to save an existing user again', function(done) {
user.save(function() {
user2.save(function(err) {
should.exist(err);
done();
});
});
});
// it('should be able to show an error when try to save without first name', function(done) {
// user.firstName = '';
// return user.save(function(err) {
// should.exist(err);
// done();
// });
// });
// });
it('should be able to show an error when try to save without first name', function(done) {
user.firstName = '';
return user.save(function(err) {
should.exist(err);
done();
});
});
});
// describe('Method findUniqueUsername', function() {
// beforeEach(function(done) {
// User.find({}, function(err, users) {
// users.should.have.length(0);
// user.save(done);
// });
// });
describe('Method findUniqueUsername', function() {
beforeEach(function(done) {
User.find({}, function(err, users) {
users.should.have.length(0);
user.save(done);
});
});
// it('should be able to find unique version of existing username without problems', function(done) {
// User.findUniqueUsername(user.username, null, function (availableUsername) {
// availableUsername.should.not.equal(user.username);
// done();
// });
// });
it('should be able to find unique version of existing username without problems', function(done) {
User.findUniqueUsername(user.username, null, function (availableUsername) {
availableUsername.should.not.equal(user.username);
done();
});
});
// });
});
// afterEach(function(done) {
// User.remove().exec(done);
// });
// });
afterEach(function(done) {
User.remove().exec(done);
});
});

View File

@ -17,6 +17,9 @@ var should = require('should'),
var mailosaur = require('mailosaur')(config.mailosaur.key),
mailbox = new mailosaur.Mailbox(config.mailosaur.mailbox_id);
var mandrill = require('node-mandrill')(config.mailer.options.auth.pass);
/**
* Globals
*/
@ -26,7 +29,7 @@ var credentials, _User, _Session;
* Form routes tests
*/
describe('User CRUD tests', function() {
this.timeout(10000);
this.timeout(15000);
var userSession;
beforeEach(function(done) {
@ -52,11 +55,9 @@ describe('User CRUD tests', function() {
});
describe('create, activate and confirm a User Account', function () {
var username = 'testActiveAccount.be1e58fb@mailosaur.in';
var link, activateToken;
var link, _tmpUser, activateToken = '';
it('should be able to create a temporary (non-activated) User', function(done) {
_User.email = _User.username = username;
@ -66,89 +67,142 @@ describe('User CRUD tests', function() {
.end(function(FormSaveErr, FormSaveRes) {
(FormSaveRes.text).should.equal('An email has been sent to you. Please check it to verify your account.');
// setTimeout(function() {
setTimeout(function() {
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);
mailbox.getEmails(function(err, _emails) {
if(err) done(err);
var emails = _emails;
mandrill('/messages/search', {
query: "subject:Confirm",
senders: [
"test@forms.polydaic.com"
],
limit: 1
}, function(error, emails) {
if (error) console.log( JSON.stringify(error) );
console.log('mailbox.getEmails:');
for(var i=0; i<emails.length; i++){
console.log(emails[i].text.links);
}
var confirmation_email = emails[0];
var link = emails[0].text.links[0].href;
var activateToken = url.parse(link).hash.split('/').slice(-1)[0];
mandrill('/messages/content', {
id: confirmation_email._id
}, function(error, email) {
if (error) console.log( JSON.stringify(error) );
activateToken.should.equal(user.GENERATED_VERIFYING_URL);
// 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();
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();
// userSession.get('/auth/verify/'+activateToken)
// .expect(200)
// .end(function(VerifyErr, VerifyRes) {
// should.not.exist(VerifyErr);
// (VerifyRes.text).should.equal('User successfully verified');
// done();
// });
// });
});
// }, 1000);
}, 3000);
});
});
// it('should be able to activate/verify a User Account', function(done) {
// _User.email = _User.username = username;
// mailbox.getEmails(function(err, _emails) {
// if(err) done(err);
// var emails = _emails;
// console.log('mailbox.getEmails:');
// console.log(emails[0].text.links);
// link = emails[0].text.links[0].href;
// activateToken = url.parse(link).hash.split('/').slice(-1)[0];
// userSession.get('/auth/verify/'+activateToken)
// .expect(200, 'User successfully verified')
// .end(function(VerifyErr, VerifyRes) {
// should.not.exist(VerifyErr);
// done();
// });
// });
// it('should be able to verify a User Account', function(done) {
// userSession.get('/auth/verify/'+activateToken)
// .expect(200)
// .end(function(VerifyErr, VerifyRes) {
// should.not.exist(VerifyErr);
// (VerifyRes.text).should.equal('User successfully verified');
// done();
// });
// });
// it('should receive confirmation email after activating a User Account', function(done) {
// _User.email = _User.username = username;
// 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;
// var activateToken = url.parse(link).hash.split('/').slice(-1)[0];
// userSession.get('/auth/verify/'+activateToken)
// .expect(200, 'User successfully verified')
// .end(function(VerifyErr, VerifyRes) {
// should.not.exist(VerifyErr);
// 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)
.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/)
.expect(200)
.end(function(signinErr, signinRes) {
// Handle signin error
if (signinErr) throw signinErr;
userSession.get('/auth/signout')
.expect(200)
.end(function(signoutErr, signoutRes) {
// Handle signout error
if (signoutErr) throw signoutErr;
(signoutRes.text).should.equal('Successfully logged out');
done();
});
});
});
});
it('should be able to reset a User\'s password');
it('should be able to delete a User account without any problems');
afterEach(function(done) {
User.remove().exec(function () {
tmpUser.remove().exec(function(){
// mailbox.deleteAllEmail(function (err, body) {
// if(err) done(err);
mailbox.deleteAllEmail(function (err, body) {
if(err) done(err);
userSession.destroy();
done();
// });
});
});
});
});

View File

@ -1,7 +1,7 @@
{
"name": "MedForm",
"description": "PDF generated form builder",
"version": "0.0.3",
"version": "1.0.3",
"homepage": "https://github.com/whitef0x0/medform",
"authors": [
"David Baldwynn <polydaic@gmail.com> (http://baldwynn.me)"
@ -11,10 +11,10 @@
"appPath": "public/modules",
"dependencies": {
"bootstrap": "~3",
"angular": "~1.3.17",
"angular-resource": "~1.2",
"angular": "^1.3.17",
"angular-resource": "~1.4.4",
"angular-animate": "~1.3",
"angular-mocks": "~1.2",
"angular-mocks": "1.3.0",
"angular-bootstrap": "~0.12.0",
"angular-ui-utils": "~0.1.1",
"angular-ui-router": "~0.2.11",
@ -28,9 +28,7 @@
"angular-ui-sortable": "~0.13.4",
"angular-busy": "~4.1.3",
"angular-permission": "~0.3.1",
"angular-input-stars": "*"
},
"resolutions": {
"angular": "~1.3.17"
"angular-input-stars": "~1.5.5",
"file-saver.js": "~1.20150507.2"
}
}

8
config/env/test.js vendored
View File

@ -20,7 +20,7 @@ module.exports = {
}
},
app: {
title: 'MedForms'
title: 'MedForms Test'
},
facebook: {
clientID: process.env.FACEBOOK_ID || 'APP_ID',
@ -50,10 +50,10 @@ module.exports = {
mailer: {
from: process.env.MAILER_FROM || 'MAILER_FROM',
options: {
service: process.env.MAILER_SERVICE_PROVIDER || 'MAILER_SERVICE_PROVIDER',
service: process.env.MAILER_SERVICE_PROVIDER || '',
auth: {
user: process.env.MAILER_EMAIL_ID || 'MAILER_EMAIL_ID',
pass: process.env.MAILER_PASSWORD || 'MAILER_PASSWORD'
user: process.env.MAILER_EMAIL_ID || '',
pass: process.env.MAILER_PASSWORD || ''
}
}
}

View File

@ -51,7 +51,7 @@ var config_nev = function () {
confirmMailOptions: {
from: config.mailer.from,
subject: 'Successfully verified!',
subject: 'Account successfully verified!',
html: '<p>Your account has been successfully verified.</p>',
text: 'Your account has been successfully verified.'
},

View File

@ -0,0 +1,182 @@
body, html {
margin:0; padding: 0;
}
body {
font-family: Helvetica Neue, Helvetica,Arial;
font-size: 10pt;
}
div.header, div.footer {
background: #eee;
padding: 1em;
}
div.header {
z-index: 100;
position: fixed;
top: 0;
border-bottom: 1px solid #666;
width: 100%;
}
div.footer {
border-top: 1px solid #666;
}
div.body {
margin-top: 10em;
}
div.meta {
font-size: 90%;
text-align: center;
}
h1, h2, h3 {
font-weight: normal;
}
h1 {
font-size: 12pt;
}
h2 {
font-size: 10pt;
}
pre {
font-family: Consolas, Menlo, Monaco, monospace;
margin: 0;
padding: 0;
line-height: 14px;
font-size: 14px;
-moz-tab-size: 2;
-o-tab-size: 2;
tab-size: 2;
}
div.path { font-size: 110%; }
div.path a:link, div.path a:visited { color: #000; }
table.coverage { border-collapse: collapse; margin:0; padding: 0 }
table.coverage td {
margin: 0;
padding: 0;
color: #111;
vertical-align: top;
}
table.coverage td.line-count {
width: 50px;
text-align: right;
padding-right: 5px;
}
table.coverage td.line-coverage {
color: #777 !important;
text-align: right;
border-left: 1px solid #666;
border-right: 1px solid #666;
}
table.coverage td.text {
}
table.coverage td span.cline-any {
display: inline-block;
padding: 0 5px;
width: 40px;
}
table.coverage td span.cline-neutral {
background: #eee;
}
table.coverage td span.cline-yes {
background: #b5d592;
color: #999;
}
table.coverage td span.cline-no {
background: #fc8c84;
}
.cstat-yes { color: #111; }
.cstat-no { background: #fc8c84; color: #111; }
.fstat-no { background: #ffc520; color: #111 !important; }
.cbranch-no { background: yellow !important; color: #111; }
.cstat-skip { background: #ddd; color: #111; }
.fstat-skip { background: #ddd; color: #111 !important; }
.cbranch-skip { background: #ddd !important; color: #111; }
.missing-if-branch {
display: inline-block;
margin-right: 10px;
position: relative;
padding: 0 4px;
background: black;
color: yellow;
}
.skip-if-branch {
display: none;
margin-right: 10px;
position: relative;
padding: 0 4px;
background: #ccc;
color: white;
}
.missing-if-branch .typ, .skip-if-branch .typ {
color: inherit !important;
}
.entity, .metric { font-weight: bold; }
.metric { display: inline-block; border: 1px solid #333; padding: 0.3em; background: white; }
.metric small { font-size: 80%; font-weight: normal; color: #666; }
div.coverage-summary table { border-collapse: collapse; margin: 3em; font-size: 110%; }
div.coverage-summary td, div.coverage-summary table th { margin: 0; padding: 0.25em 1em; border-top: 1px solid #666; border-bottom: 1px solid #666; }
div.coverage-summary th { text-align: left; border: 1px solid #666; background: #eee; font-weight: normal; }
div.coverage-summary th.file { border-right: none !important; }
div.coverage-summary th.pic { border-left: none !important; text-align: right; }
div.coverage-summary th.pct { border-right: none !important; }
div.coverage-summary th.abs { border-left: none !important; text-align: right; }
div.coverage-summary td.pct { text-align: right; border-left: 1px solid #666; }
div.coverage-summary td.abs { text-align: right; font-size: 90%; color: #444; border-right: 1px solid #666; }
div.coverage-summary td.file { border-left: 1px solid #666; white-space: nowrap; }
div.coverage-summary td.pic { min-width: 120px !important; }
div.coverage-summary a:link { text-decoration: none; color: #000; }
div.coverage-summary a:visited { text-decoration: none; color: #777; }
div.coverage-summary a:hover { text-decoration: underline; }
div.coverage-summary tfoot td { border-top: 1px solid #666; }
div.coverage-summary .sorter {
height: 10px;
width: 7px;
display: inline-block;
margin-left: 0.5em;
background: url(sort-arrow-sprite.png) no-repeat scroll 0 0 transparent;
}
div.coverage-summary .sorted .sorter {
background-position: 0 -20px;
}
div.coverage-summary .sorted-desc .sorter {
background-position: 0 -10px;
}
.high { background: #b5d592 !important; }
.medium { background: #ffe87c !important; }
.low { background: #fc8c84 !important; }
span.cover-fill, span.cover-empty {
display:inline-block;
border:1px solid #444;
background: white;
height: 12px;
}
span.cover-fill {
background: #ccc;
border-right: 1px solid #444;
}
span.cover-empty {
background: white;
border-left: none;
}
span.cover-full {
border-right: none !important;
}
pre.prettyprint {
border: none !important;
padding: 0 !important;
margin: 0 !important;
}
.com { color: #999 !important; }
.ignore-none { color: #999; font-weight: normal; }

View File

@ -0,0 +1,60 @@
<!doctype html>
<html lang="en">
<head>
<title>Code coverage report for All files</title>
<meta charset="utf-8">
<link rel="stylesheet" href="prettify.css">
<link rel="stylesheet" href="base.css">
<style type='text/css'>
div.coverage-summary .sorter {
background-image: url(sort-arrow-sprite.png);
}
</style>
</head>
<body>
<div class="header high">
<h1>Code coverage report for <span class="entity">All files</span></h1>
<h2>
Statements: <span class="metric">100% <small>(0 / 0)</small></span> &nbsp;&nbsp;&nbsp;&nbsp;
Branches: <span class="metric">100% <small>(0 / 0)</small></span> &nbsp;&nbsp;&nbsp;&nbsp;
Functions: <span class="metric">100% <small>(0 / 0)</small></span> &nbsp;&nbsp;&nbsp;&nbsp;
Lines: <span class="metric">100% <small>(0 / 0)</small></span> &nbsp;&nbsp;&nbsp;&nbsp;
Ignored: <span class="metric"><span class="ignore-none">none</span></span> &nbsp;&nbsp;&nbsp;&nbsp;
</h2>
<div class="path"></div>
</div>
<div class="body">
<div class="coverage-summary">
<table>
<thead>
<tr>
<th data-col="file" data-fmt="html" data-html="true" class="file">File</th>
<th data-col="pic" data-type="number" data-fmt="html" data-html="true" class="pic"></th>
<th data-col="statements" data-type="number" data-fmt="pct" class="pct">Statements</th>
<th data-col="statements_raw" data-type="number" data-fmt="html" class="abs"></th>
<th data-col="branches" data-type="number" data-fmt="pct" class="pct">Branches</th>
<th data-col="branches_raw" data-type="number" data-fmt="html" class="abs"></th>
<th data-col="functions" data-type="number" data-fmt="pct" class="pct">Functions</th>
<th data-col="functions_raw" data-type="number" data-fmt="html" class="abs"></th>
<th data-col="lines" data-type="number" data-fmt="pct" class="pct">Lines</th>
<th data-col="lines_raw" data-type="number" data-fmt="html" class="abs"></th>
</tr>
</thead>
<tbody></tbody>
</table>
</div>
</div>
<div class="footer">
<div class="meta">Generated by <a href="http://istanbul-js.org/" target="_blank">istanbul</a> at Mon Aug 17 2015 15:29:08 GMT-0700 (PDT)</div>
</div>
<script src="prettify.js"></script>
<script>
window.onload = function () {
if (typeof prettyPrint === 'function') {
prettyPrint();
}
};
</script>
<script src="sorter.js"></script>
</body>
</html>

View File

@ -0,0 +1 @@
.pln{color:#000}@media screen{.str{color:#080}.kwd{color:#008}.com{color:#800}.typ{color:#606}.lit{color:#066}.pun,.opn,.clo{color:#660}.tag{color:#008}.atn{color:#606}.atv{color:#080}.dec,.var{color:#606}.fun{color:red}}@media print,projection{.str{color:#060}.kwd{color:#006;font-weight:bold}.com{color:#600;font-style:italic}.typ{color:#404;font-weight:bold}.lit{color:#044}.pun,.opn,.clo{color:#440}.tag{color:#006;font-weight:bold}.atn{color:#404}.atv{color:#060}}pre.prettyprint{padding:2px;border:1px solid #888}ol.linenums{margin-top:0;margin-bottom:0}li.L0,li.L1,li.L2,li.L3,li.L5,li.L6,li.L7,li.L8{list-style-type:none}li.L1,li.L3,li.L5,li.L7,li.L9{background:#eee}

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 209 B

View File

@ -0,0 +1,156 @@
var addSorting = (function () {
"use strict";
var cols,
currentSort = {
index: 0,
desc: false
};
// returns the summary table element
function getTable() { return document.querySelector('.coverage-summary table'); }
// returns the thead element of the summary table
function getTableHeader() { return getTable().querySelector('thead tr'); }
// returns the tbody element of the summary table
function getTableBody() { return getTable().querySelector('tbody'); }
// returns the th element for nth column
function getNthColumn(n) { return getTableHeader().querySelectorAll('th')[n]; }
// loads all columns
function loadColumns() {
var colNodes = getTableHeader().querySelectorAll('th'),
colNode,
cols = [],
col,
i;
for (i = 0; i < colNodes.length; i += 1) {
colNode = colNodes[i];
col = {
key: colNode.getAttribute('data-col'),
sortable: !colNode.getAttribute('data-nosort'),
type: colNode.getAttribute('data-type') || 'string'
};
cols.push(col);
if (col.sortable) {
col.defaultDescSort = col.type === 'number';
colNode.innerHTML = colNode.innerHTML + '<span class="sorter"></span>';
}
}
return cols;
}
// attaches a data attribute to every tr element with an object
// of data values keyed by column name
function loadRowData(tableRow) {
var tableCols = tableRow.querySelectorAll('td'),
colNode,
col,
data = {},
i,
val;
for (i = 0; i < tableCols.length; i += 1) {
colNode = tableCols[i];
col = cols[i];
val = colNode.getAttribute('data-value');
if (col.type === 'number') {
val = Number(val);
}
data[col.key] = val;
}
return data;
}
// loads all row data
function loadData() {
var rows = getTableBody().querySelectorAll('tr'),
i;
for (i = 0; i < rows.length; i += 1) {
rows[i].data = loadRowData(rows[i]);
}
}
// sorts the table using the data for the ith column
function sortByIndex(index, desc) {
var key = cols[index].key,
sorter = function (a, b) {
a = a.data[key];
b = b.data[key];
return a < b ? -1 : a > b ? 1 : 0;
},
finalSorter = sorter,
tableBody = document.querySelector('.coverage-summary tbody'),
rowNodes = tableBody.querySelectorAll('tr'),
rows = [],
i;
if (desc) {
finalSorter = function (a, b) {
return -1 * sorter(a, b);
};
}
for (i = 0; i < rowNodes.length; i += 1) {
rows.push(rowNodes[i]);
tableBody.removeChild(rowNodes[i]);
}
rows.sort(finalSorter);
for (i = 0; i < rows.length; i += 1) {
tableBody.appendChild(rows[i]);
}
}
// removes sort indicators for current column being sorted
function removeSortIndicators() {
var col = getNthColumn(currentSort.index),
cls = col.className;
cls = cls.replace(/ sorted$/, '').replace(/ sorted-desc$/, '');
col.className = cls;
}
// adds sort indicators for current column being sorted
function addSortIndicators() {
getNthColumn(currentSort.index).className += currentSort.desc ? ' sorted-desc' : ' sorted';
}
// adds event listeners for all sorter widgets
function enableUI() {
var i,
el,
ithSorter = function ithSorter(i) {
var col = cols[i];
return function () {
var desc = col.defaultDescSort;
if (currentSort.index === i) {
desc = !currentSort.desc;
}
sortByIndex(i, desc);
removeSortIndicators();
currentSort.index = i;
currentSort.desc = desc;
addSortIndicators();
};
};
for (i =0 ; i < cols.length; i += 1) {
if (cols[i].sortable) {
el = getNthColumn(i).querySelector('.sorter');
if (el.addEventListener) {
el.addEventListener('click', ithSorter(i));
} else {
el.attachEvent('onclick', ithSorter(i));
}
}
}
}
// adds sorting functionality to the UI
return function () {
if (!getTable()) {
return;
}
cols = loadColumns();
loadData(cols);
addSortIndicators();
enableUI();
};
})();
window.addEventListener('load', addSorting);

View File

@ -0,0 +1,182 @@
body, html {
margin:0; padding: 0;
}
body {
font-family: Helvetica Neue, Helvetica,Arial;
font-size: 10pt;
}
div.header, div.footer {
background: #eee;
padding: 1em;
}
div.header {
z-index: 100;
position: fixed;
top: 0;
border-bottom: 1px solid #666;
width: 100%;
}
div.footer {
border-top: 1px solid #666;
}
div.body {
margin-top: 10em;
}
div.meta {
font-size: 90%;
text-align: center;
}
h1, h2, h3 {
font-weight: normal;
}
h1 {
font-size: 12pt;
}
h2 {
font-size: 10pt;
}
pre {
font-family: Consolas, Menlo, Monaco, monospace;
margin: 0;
padding: 0;
line-height: 14px;
font-size: 14px;
-moz-tab-size: 2;
-o-tab-size: 2;
tab-size: 2;
}
div.path { font-size: 110%; }
div.path a:link, div.path a:visited { color: #000; }
table.coverage { border-collapse: collapse; margin:0; padding: 0 }
table.coverage td {
margin: 0;
padding: 0;
color: #111;
vertical-align: top;
}
table.coverage td.line-count {
width: 50px;
text-align: right;
padding-right: 5px;
}
table.coverage td.line-coverage {
color: #777 !important;
text-align: right;
border-left: 1px solid #666;
border-right: 1px solid #666;
}
table.coverage td.text {
}
table.coverage td span.cline-any {
display: inline-block;
padding: 0 5px;
width: 40px;
}
table.coverage td span.cline-neutral {
background: #eee;
}
table.coverage td span.cline-yes {
background: #b5d592;
color: #999;
}
table.coverage td span.cline-no {
background: #fc8c84;
}
.cstat-yes { color: #111; }
.cstat-no { background: #fc8c84; color: #111; }
.fstat-no { background: #ffc520; color: #111 !important; }
.cbranch-no { background: yellow !important; color: #111; }
.cstat-skip { background: #ddd; color: #111; }
.fstat-skip { background: #ddd; color: #111 !important; }
.cbranch-skip { background: #ddd !important; color: #111; }
.missing-if-branch {
display: inline-block;
margin-right: 10px;
position: relative;
padding: 0 4px;
background: black;
color: yellow;
}
.skip-if-branch {
display: none;
margin-right: 10px;
position: relative;
padding: 0 4px;
background: #ccc;
color: white;
}
.missing-if-branch .typ, .skip-if-branch .typ {
color: inherit !important;
}
.entity, .metric { font-weight: bold; }
.metric { display: inline-block; border: 1px solid #333; padding: 0.3em; background: white; }
.metric small { font-size: 80%; font-weight: normal; color: #666; }
div.coverage-summary table { border-collapse: collapse; margin: 3em; font-size: 110%; }
div.coverage-summary td, div.coverage-summary table th { margin: 0; padding: 0.25em 1em; border-top: 1px solid #666; border-bottom: 1px solid #666; }
div.coverage-summary th { text-align: left; border: 1px solid #666; background: #eee; font-weight: normal; }
div.coverage-summary th.file { border-right: none !important; }
div.coverage-summary th.pic { border-left: none !important; text-align: right; }
div.coverage-summary th.pct { border-right: none !important; }
div.coverage-summary th.abs { border-left: none !important; text-align: right; }
div.coverage-summary td.pct { text-align: right; border-left: 1px solid #666; }
div.coverage-summary td.abs { text-align: right; font-size: 90%; color: #444; border-right: 1px solid #666; }
div.coverage-summary td.file { border-left: 1px solid #666; white-space: nowrap; }
div.coverage-summary td.pic { min-width: 120px !important; }
div.coverage-summary a:link { text-decoration: none; color: #000; }
div.coverage-summary a:visited { text-decoration: none; color: #777; }
div.coverage-summary a:hover { text-decoration: underline; }
div.coverage-summary tfoot td { border-top: 1px solid #666; }
div.coverage-summary .sorter {
height: 10px;
width: 7px;
display: inline-block;
margin-left: 0.5em;
background: url(sort-arrow-sprite.png) no-repeat scroll 0 0 transparent;
}
div.coverage-summary .sorted .sorter {
background-position: 0 -20px;
}
div.coverage-summary .sorted-desc .sorter {
background-position: 0 -10px;
}
.high { background: #b5d592 !important; }
.medium { background: #ffe87c !important; }
.low { background: #fc8c84 !important; }
span.cover-fill, span.cover-empty {
display:inline-block;
border:1px solid #444;
background: white;
height: 12px;
}
span.cover-fill {
background: #ccc;
border-right: 1px solid #444;
}
span.cover-empty {
background: white;
border-left: none;
}
span.cover-full {
border-right: none !important;
}
pre.prettyprint {
border: none !important;
padding: 0 !important;
margin: 0 !important;
}
.com { color: #999 !important; }
.ignore-none { color: #999; font-weight: normal; }

View File

@ -0,0 +1,60 @@
<!doctype html>
<html lang="en">
<head>
<title>Code coverage report for All files</title>
<meta charset="utf-8">
<link rel="stylesheet" href="prettify.css">
<link rel="stylesheet" href="base.css">
<style type='text/css'>
div.coverage-summary .sorter {
background-image: url(sort-arrow-sprite.png);
}
</style>
</head>
<body>
<div class="header high">
<h1>Code coverage report for <span class="entity">All files</span></h1>
<h2>
Statements: <span class="metric">100% <small>(0 / 0)</small></span> &nbsp;&nbsp;&nbsp;&nbsp;
Branches: <span class="metric">100% <small>(0 / 0)</small></span> &nbsp;&nbsp;&nbsp;&nbsp;
Functions: <span class="metric">100% <small>(0 / 0)</small></span> &nbsp;&nbsp;&nbsp;&nbsp;
Lines: <span class="metric">100% <small>(0 / 0)</small></span> &nbsp;&nbsp;&nbsp;&nbsp;
Ignored: <span class="metric"><span class="ignore-none">none</span></span> &nbsp;&nbsp;&nbsp;&nbsp;
</h2>
<div class="path"></div>
</div>
<div class="body">
<div class="coverage-summary">
<table>
<thead>
<tr>
<th data-col="file" data-fmt="html" data-html="true" class="file">File</th>
<th data-col="pic" data-type="number" data-fmt="html" data-html="true" class="pic"></th>
<th data-col="statements" data-type="number" data-fmt="pct" class="pct">Statements</th>
<th data-col="statements_raw" data-type="number" data-fmt="html" class="abs"></th>
<th data-col="branches" data-type="number" data-fmt="pct" class="pct">Branches</th>
<th data-col="branches_raw" data-type="number" data-fmt="html" class="abs"></th>
<th data-col="functions" data-type="number" data-fmt="pct" class="pct">Functions</th>
<th data-col="functions_raw" data-type="number" data-fmt="html" class="abs"></th>
<th data-col="lines" data-type="number" data-fmt="pct" class="pct">Lines</th>
<th data-col="lines_raw" data-type="number" data-fmt="html" class="abs"></th>
</tr>
</thead>
<tbody></tbody>
</table>
</div>
</div>
<div class="footer">
<div class="meta">Generated by <a href="http://istanbul-js.org/" target="_blank">istanbul</a> at Mon Aug 17 2015 15:29:08 GMT-0700 (PDT)</div>
</div>
<script src="prettify.js"></script>
<script>
window.onload = function () {
if (typeof prettyPrint === 'function') {
prettyPrint();
}
};
</script>
<script src="sorter.js"></script>
</body>
</html>

View File

@ -0,0 +1 @@
.pln{color:#000}@media screen{.str{color:#080}.kwd{color:#008}.com{color:#800}.typ{color:#606}.lit{color:#066}.pun,.opn,.clo{color:#660}.tag{color:#008}.atn{color:#606}.atv{color:#080}.dec,.var{color:#606}.fun{color:red}}@media print,projection{.str{color:#060}.kwd{color:#006;font-weight:bold}.com{color:#600;font-style:italic}.typ{color:#404;font-weight:bold}.lit{color:#044}.pun,.opn,.clo{color:#440}.tag{color:#006;font-weight:bold}.atn{color:#404}.atv{color:#060}}pre.prettyprint{padding:2px;border:1px solid #888}ol.linenums{margin-top:0;margin-bottom:0}li.L0,li.L1,li.L2,li.L3,li.L5,li.L6,li.L7,li.L8{list-style-type:none}li.L1,li.L3,li.L5,li.L7,li.L9{background:#eee}

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 209 B

View File

@ -0,0 +1,156 @@
var addSorting = (function () {
"use strict";
var cols,
currentSort = {
index: 0,
desc: false
};
// returns the summary table element
function getTable() { return document.querySelector('.coverage-summary table'); }
// returns the thead element of the summary table
function getTableHeader() { return getTable().querySelector('thead tr'); }
// returns the tbody element of the summary table
function getTableBody() { return getTable().querySelector('tbody'); }
// returns the th element for nth column
function getNthColumn(n) { return getTableHeader().querySelectorAll('th')[n]; }
// loads all columns
function loadColumns() {
var colNodes = getTableHeader().querySelectorAll('th'),
colNode,
cols = [],
col,
i;
for (i = 0; i < colNodes.length; i += 1) {
colNode = colNodes[i];
col = {
key: colNode.getAttribute('data-col'),
sortable: !colNode.getAttribute('data-nosort'),
type: colNode.getAttribute('data-type') || 'string'
};
cols.push(col);
if (col.sortable) {
col.defaultDescSort = col.type === 'number';
colNode.innerHTML = colNode.innerHTML + '<span class="sorter"></span>';
}
}
return cols;
}
// attaches a data attribute to every tr element with an object
// of data values keyed by column name
function loadRowData(tableRow) {
var tableCols = tableRow.querySelectorAll('td'),
colNode,
col,
data = {},
i,
val;
for (i = 0; i < tableCols.length; i += 1) {
colNode = tableCols[i];
col = cols[i];
val = colNode.getAttribute('data-value');
if (col.type === 'number') {
val = Number(val);
}
data[col.key] = val;
}
return data;
}
// loads all row data
function loadData() {
var rows = getTableBody().querySelectorAll('tr'),
i;
for (i = 0; i < rows.length; i += 1) {
rows[i].data = loadRowData(rows[i]);
}
}
// sorts the table using the data for the ith column
function sortByIndex(index, desc) {
var key = cols[index].key,
sorter = function (a, b) {
a = a.data[key];
b = b.data[key];
return a < b ? -1 : a > b ? 1 : 0;
},
finalSorter = sorter,
tableBody = document.querySelector('.coverage-summary tbody'),
rowNodes = tableBody.querySelectorAll('tr'),
rows = [],
i;
if (desc) {
finalSorter = function (a, b) {
return -1 * sorter(a, b);
};
}
for (i = 0; i < rowNodes.length; i += 1) {
rows.push(rowNodes[i]);
tableBody.removeChild(rowNodes[i]);
}
rows.sort(finalSorter);
for (i = 0; i < rows.length; i += 1) {
tableBody.appendChild(rows[i]);
}
}
// removes sort indicators for current column being sorted
function removeSortIndicators() {
var col = getNthColumn(currentSort.index),
cls = col.className;
cls = cls.replace(/ sorted$/, '').replace(/ sorted-desc$/, '');
col.className = cls;
}
// adds sort indicators for current column being sorted
function addSortIndicators() {
getNthColumn(currentSort.index).className += currentSort.desc ? ' sorted-desc' : ' sorted';
}
// adds event listeners for all sorter widgets
function enableUI() {
var i,
el,
ithSorter = function ithSorter(i) {
var col = cols[i];
return function () {
var desc = col.defaultDescSort;
if (currentSort.index === i) {
desc = !currentSort.desc;
}
sortByIndex(i, desc);
removeSortIndicators();
currentSort.index = i;
currentSort.desc = desc;
addSortIndicators();
};
};
for (i =0 ; i < cols.length; i += 1) {
if (cols[i].sortable) {
el = getNthColumn(i).querySelector('.sorter');
if (el.addEventListener) {
el.addEventListener('click', ithSorter(i));
} else {
el.attachEvent('onclick', ithSorter(i));
}
}
}
}
// adds sorting functionality to the UI
return function () {
if (!getTable()) {
return;
}
cols = loadColumns();
loadData(cols);
addSortIndicators();
enableUI();
};
})();
window.addEventListener('load', addSorting);

View File

@ -151,7 +151,19 @@ module.exports = function(grunt) {
unit: {
configFile: 'karma.conf.js'
}
}
},
// protractor: {
// options: {
// configFile: 'protractor.conf.js',
// keepAlive: true,
// noColor: false
// },
// e2e: {
// options: {
// args: {} // Target-specific arguments
// }
// }
// },
});
// Load NPM tasks

View File

@ -8,8 +8,6 @@ var applicationConfiguration = require('./config/config'),
var bowerDep = bowerFiles('**/**.js');
console.log(bowerDep);
// Karma configuration
module.exports = function(config) {
config.set({
@ -21,7 +19,12 @@ module.exports = function(config) {
// Test results reporter to use
// Possible values: 'dots', 'progress', 'junit', 'growl', 'coverage'
reporters: ['progress'],
reporters: ['mocha', 'html', 'progress'],
// plugins: [
// 'karma-jasmine',
// 'karma-mocha-reporter',
// ],
// Web server port
port: 9876,
@ -51,6 +54,6 @@ module.exports = function(config) {
// Continuous Integration mode
// If true, it capture browsers, run tests and exit
singleRun: true
singleRun: false
});
};

View File

@ -90,6 +90,9 @@
},
"devDependencies": {
"karma-chrome-launcher": "^0.1.12",
"karma-jasmine": "^0.2.3"
"karma-jasmine": "^0.2.3",
"karma-jasmine-html-reporter": "^0.1.8",
"karma-mocha-reporter": "^1.1.1",
"node-mandrill": "^1.0.1"
}
}

6
protractor.conf.js Normal file
View File

@ -0,0 +1,6 @@
'use strict';
// Protractor configuration
exports.config = {
specs: ['modules/*/tests/e2e/*.js']
};

View File

@ -142,14 +142,10 @@ angular.module('core').config(['$stateProvider', '$urlRouterProvider',
]);
'use strict';
angular.module('core').controller('HeaderController', ['$rootScope','$scope','Menus', '$state', 'Auth', 'User',
angular.module('core').controller('HeaderController', ['$rootScope', '$scope', 'Menus', '$state', 'Auth', 'User',
function ($rootScope, $scope, Menus, $state, Auth, User) {
$scope.user = $rootScope.user = Auth.ensureHasCurrentUser(User);
$scope.authentication = $rootScope.authentication = Auth;
// if(!$scope.user || !$scope.user.username){
// $scope.user = $rootScope.user = User.getCurrent();
// $scope.authentication.currentUser = $rootScope.authentication.currentUser = $scope.user;
// }
$rootScope.languages = $scope.languages = ['english', 'french', 'spanish'];
@ -426,7 +422,7 @@ angular.module('forms').config(['$stateProvider',
}).
state('viewForm', {
url: '/forms/:formId/admin',
templateUrl: 'modules/forms/views/view-form.client.view.html',
templateUrl: 'modules/forms/views/admin-form.client.view.html',
data: {
permissions: [ 'editForm' ]
}
@ -442,6 +438,121 @@ angular.module('forms').config(['$stateProvider',
]);
'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) {
var deleteModal;
$scope = $rootScope;
$scope.myform = CurrentForm.getForm();
$rootScope.saveInProgress = false;
// Find a specific Form
$scope.findOne = function() {
$scope.myform = Forms.get({
formId: $stateParams.formId
});
CurrentForm.setForm($scope.myform);
};
$scope.setForm = function (form) {
$scope.myform = form;
};
$rootScope.resetForm = function(){
$scope.myform = Forms.get({
formId: $stateParams.formId
});
};
/*
** DeleteModal Functions
*/
$scope.openDeleteModal = function() {
deleteModal = $modal.open({
animation: $scope.animationsEnabled,
templateUrl: 'myModalContent.html',
controller: 'AdminFormController',
});
};
$scope.cancelDeleteModal = function(){
if(deleteModal){
deleteModal.dismiss('cancel');
}
};
// Remove existing Form
$scope.remove = function(form_id) {
if(deleteModal && deleteModal.opened){
deleteModal.close();
var form = {};
if(!form_id){
form = CurrentForm.getForm();
if(!form) form = $scope.myform;
}else {
form._id = form_id;
}
$http.delete('/forms/'+form._id)
.success(function(data, status, headers){
console.log('form deleted successfully');
if(!form_id){
$state.go('listForms', {}, {reload: true});
}
if($scope.myforms.length > 0){
$scope.myforms = _.filter($scope.myforms, function(myform){
return myform._id !== form._id;
});
}
}).error(function(error){
console.log('ERROR: Form could not be deleted.');
console.error(error);
}).finally(function(){
});
}
};
// Update existing Form
$scope.update = $rootScope.update = function(immediate, cb) {
// console.log('immediate: '+immediate);
var continueUpdate = true;
if(immediate){
continueUpdate = !$rootScope.saveInProgress;
}
if(continueUpdate){
console.log('begin updating form');
var err = null;
if(immediate){ $rootScope.saveInProgress = true; }
$scope.updatePromise = $http.put('/forms/'+$scope.myform._id, {form: $scope.myform})
.then(function(response){
$rootScope.myform = $scope.myform = response.data;
console.log(response.data);
}).catch(function(response){
console.log('Error occured during form UPDATE.\n');
console.log(response.data);
err = response.data;
}).finally(function() {
console.log('finished updating');
if(immediate){$rootScope.saveInProgress = false; }
cb(err);
});
}
};
}
]);
'use strict';
// Forms controller
angular.module('forms').controller('ListFormsController', ['$rootScope', '$scope', '$stateParams', '$state', 'Forms', 'CurrentForm','$http',
function($rootScope, $scope, $stateParams, $state, Forms, CurrentForm, $http) {
@ -566,253 +677,6 @@ angular.module('forms').controller('SubmitFormController', ['$scope', '$rootScop
]);
'use strict';
// Forms controller
angular.module('forms').controller('ViewFormController', ['$rootScope', '$scope', '$stateParams', '$state', 'Forms', 'CurrentForm', '$http', '$modal',
function($rootScope, $scope, $stateParams, $state, Forms, CurrentForm, $http, $modal) {
var deleteModal;
$scope = $rootScope;
$scope.myform = CurrentForm.getForm();
$rootScope.saveInProgress = false;
$scope.viewSubmissions = false;
$scope.table = {
masterChecker: false,
rows: []
};
// Find a specific Form
$scope.findOne = function() {
$scope.myform = Forms.get({
formId: $stateParams.formId
});
CurrentForm.setForm($scope.myform);
};
$scope.setForm = function (form) {
$scope.myform = form;
};
$rootScope.resetForm = function(){
$scope.myform = Forms.get({
formId: $stateParams.formId
});
};
/*
* Table Functions
*/
$scope.isAtLeastOneChecked = function(){
// console.log('isAtLeastOneChecked');
for(var i=0; i<$scope.table.rows.length; i++){
if($scope.table.rows[i].selected) return true;
}
return false;
};
$scope.toggleAllCheckers = function(){
// console.log('toggleAllCheckers');
for(var i=0; i<$scope.table.rows.length; i++){
$scope.table.rows[i].selected = $scope.table.masterChecker;
}
};
$scope.toggleObjSelection = function($event, description) {
$event.stopPropagation();
};
$scope.rowClicked = function(row_index) {
$scope.table.rows[row_index].selected = !$scope.table.rows[row_index].selected;
};
/*
* Form Submission Methods
*/
//Delete selected submissions of Form
$scope.deleteSelectedSubmissions = function(){
// console.log('deleteSelectedSubmissions');
var delete_ids = _.chain($scope.table.rows).filter(function(row){
return !!row.selected;
}).pluck('_id').value();
$http({ url: '/forms/'+$scope.myform._id+'/submissions',
method: 'DELETE',
data: {deleted_submissions: delete_ids},
headers: {"Content-Type": "application/json;charset=utf-8"}
}).success(function(data, status, headers){
//Remove deleted ids from table
var tmpArray = [];
for(var i=0; i<$scope.table.rows.length; i++){
if(!$scope.table.rows[i].selected){
tmpArray.push($scope.table.rows[i]);
}
}
console.log(tmpArray);
$scope.table.rows = tmpArray;
})
.error(function(err){
console.log('Could not delete form submissions.\nError: ');
console.log(err);
console.error = err;
});
};
//Export selected submissions of Form
$scope.exportSubmissions = function(){
// console.log('exportSelectedSubmissions');
// var export_ids = _.chain($scope.table.rows).filter(function(row){
// return !!row.selected;
// }).pluck('_id').value();
var blob = new Blob([document.getElementById('table-submission-data').innerHTM], {
type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8"
});
saveAs(blob, $scope.myform.title+'_export_'+Date.now()+".xls");
};
//Fetch and display submissions of Form
$scope.showSubmissions = function(){
$scope.viewSubmissions = true;
$http.get('/forms/'+$scope.myform._id+'/submissions')
.success(function(data, status, headers){
// console.log(data[0].form_fields);
var _data = [];
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;
_.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 = '';
}
}
_data[i] = data[i];
_data[i].form_fields = _tmpSubFormFields;
}
// console.log(JSON.stringify(_data));
$scope.submissions = _data;
$scope.table.rows = _data;
if(!$scope.$$phase && !$scope.$digest){
$scope.$apply();
}
// console.log('form submissions successfully fetched');
// console.log( JSON.parse(JSON.stringify($scope.submissions)) ) ;
// console.log( JSON.parse(JSON.stringify($scope.myform.form_fields)) );
})
.error(function(err){
console.log('Could not fetch form submissions.\nError: '+err);
});
};
//hide submissions of Form
$scope.hideSubmissions = function(){
$scope.viewSubmissions = false;
};
/*
** DeleteModal Functions
*/
$scope.openDeleteModal = function() {
deleteModal = $modal.open({
animation: $scope.animationsEnabled,
templateUrl: 'myModalContent.html',
controller: 'ViewFormController',
});
};
$scope.cancelDeleteModal = function(){
if(deleteModal){
deleteModal.dismiss('cancel');
}
};
// Remove existing Form
$scope.remove = function(form_id) {
if(deleteModal && deleteModal.opened){
deleteModal.close();
var form = {};
if(!form_id){
form = CurrentForm.getForm();
if(!form) form = $scope.myform;
}else {
form._id = form_id;
}
$http.delete('/forms/'+form._id)
.success(function(data, status, headers){
console.log('form deleted successfully');
if(!form_id){
$state.go('listForms', {}, {reload: true});
}
if($scope.myforms.length > 0){
$scope.myforms = _.filter($scope.myforms, function(myform){
return myform._id !== form._id;
});
}
}).error(function(error){
console.log('ERROR: Form could not be deleted.');
console.error(error);
}).finally(function(){
});
}
};
// Update existing Form
$scope.update = $rootScope.update = function(immediate, cb) {
console.log('immediate: '+immediate);
var continueUpdate = true;
if(immediate){
continueUpdate = !$rootScope.saveInProgress;
}
if(continueUpdate){
console.log('begin updating form');
var err = null;
if(immediate){ $rootScope.saveInProgress = true; }
$scope.updatePromise = $http.put('/forms/'+$scope.myform._id, {form: $scope.myform})
.then(function(response){
$rootScope.myform = $scope.myform = response.data;
console.log(response.data);
}).catch(function(response){
console.log('Error occured during form UPDATE.\n');
console.log(response.data);
err = response.data;
}).finally(function() {
console.log('finished updating');
if(immediate){$rootScope.saveInProgress = false; }
cb(err);
});
}
};
}
]);
'use strict';
angular.module('forms').directive('autoSaveForm', ['$rootScope', '$timeout', function($rootScope, $timeout) {
return {
@ -952,325 +816,6 @@ angular.module('forms').directive('changeFocus', function() {
});
'use strict';
angular.module('forms').directive('configureFormDirective', ['$rootScope', '$http', 'Upload', '$timeout', 'timeCounter', 'Auth', 'FormFields',
function ($rootScope, $http, Upload, $timeout, timeCounter, Auth, FormFields) {
return {
templateUrl: './modules/forms/views/directiveViews/form/configure-form.html',
restrict: 'E',
scope: {
myform:'=',
user:'=',
pdfFields:'@',
formFields:'@'
},
controller: function($scope){
$scope.log = '';
$scope.pdfLoading = false;
$scope.languages = $rootScope.languages;
var _current_upload = null;
$scope.resetForm = $rootScope.resetForm;
$scope.update = $rootScope.update;
var _unbindedPdfFields = $scope.pdfFields;
//DAVID: TODO: finish this so we can create a Form.pdfFieldMap
// $scope.getUnbindedPdfFields = function(fieldType){
// _unbindedPdfFields = $scope.pdfFields
// }
//PDF Functions
$scope.cancelUpload = function(){
_current_upload.abort();
$scope.pdfLoading = false;
$scope.removePDF();
};
$scope.removePDF = function(){
$scope.myform.pdf = null;
$scope.myform.isGenerated = false;
$scope.myform.autofillPDFs = false;
console.log('form.pdf: '+$scope.myform.pdf+' REMOVED');
};
$scope.uploadPDF = function(files) {
if (files && files.length) {
// for (var i = 0; i < files.length; i++) {
var file = files[0];
console.log(file);
_current_upload = Upload.upload({
url: '/upload/pdf',
fields: {
'user': $scope.user,
'form': $scope.myform
},
file: file
}).progress(function (evt) {
var progressPercentage = parseInt(100.0 * evt.loaded / evt.total);
$scope.log = 'progress: ' + progressPercentage + '% ' +
evt.config.file.name + '\n' + $scope.log;
$scope.pdfLoading = true;
}).success(function (data, status, headers, config) {
$scope.log = 'file ' + data.originalname + ' uploaded as '+ data.name +'. JSON: ' + JSON.stringify(data) + '\n' + $scope.log;
$scope.myform.pdf = angular.fromJson(angular.toJson(data));
console.log($scope.myform.pdf);
$scope.pdfLoading = false;
console.log($scope.log);
if(!$scope.$$phase && !$scope.$digest){
$scope.$apply();
}
}).error(function(err){
$scope.pdfLoading = false;
console.log('Error occured during upload.\n');
console.log(err);
});
}
};
}
};
}
]);
'use strict';
angular.module('forms')
.directive('editFormDirective', ['$rootScope', '$q', '$http', '$timeout', 'timeCounter', 'Auth', 'FormFields',
function ($rootScope, $q, $http, $timeout, timeCounter, Auth, FormFields) {
return {
templateUrl: './modules/forms/views/directiveViews/form/edit-form.html',
restrict: 'E',
scope: {
myform:'=',
},
// transclude: true,
controller: function($scope){
/*
** Initialize scope with variables
*/
//Populate AddField with all available form field types
$scope.addField = {};
$scope.addField.types = FormFields.fields;
$scope.addField.types.forEach(function(type){
type.lastAddedID = 1;
return type;
});
// Accordion settings
$scope.accordion = {};
$scope.accordion.oneAtATime = true;
//Populate local scope with rootScope methods/variables
$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;
// // }
// }
// };
/*
** Field CRUD Methods
*/
// Add a new field
$scope.addNewField = function(addOrReturn, fieldType){
// incr field_id counter
$scope.addField.lastAddedID++;
var fieldTitle;
for(var i = 0; i < $scope.addField.types.length; i++){
// console.log($scope.addField.types[i].name === fieldType);
if($scope.addField.types[i].name === fieldType){
$scope.addField.types[i].lastAddedID++;
// console.log($scope.addField.types[i].lastAddedID);
fieldTitle = $scope.addField.types[i].value+$scope.addField.types[i].lastAddedID;
break;
}
}
var newField = {
'title' : fieldTitle,
'fieldType' : fieldType,
'fieldValue' : '',
'required' : true,
'disabled' : false,
};
console.log('\n\n---------\nAdded field CLIENT');
console.log(newField);
// put newField into fields array
if(addOrReturn){
$scope.myform.form_fields.push(newField);
}else {
return newField;
}
// console.log(Date.now());
// console.log($scope.myform.form_fields.length);
};
// deletes particular field on button click
$scope.deleteField = function (hashKey){
// console.log($scope.myform.form_fields);
for(var i = 0; i < $scope.myform.form_fields.length; i++){
// console.log($scope.myform.form_fields[i].$$hashKey === hashKey);
if($scope.myform.form_fields[i].$$hashKey === hashKey){
$scope.myform.form_fields.splice(i, 1);
break;
}
}
};
$scope.duplicateField = function (field_index){
console.log('field_index: '+field_index);
var field = $scope.addNewField(false, $scope.myform.form_fields[field_index].fieldType);
field.title = $scope.myform.form_fields[field_index].title;
console.log($scope.myform.form_fields[field_index]);
//Insert field at selected index
$scope.myform.form_fields.splice(field_index+1, 0, field);
// for(var i = 0; i < $scope.myform.form_fields.length; i++){
// if($scope.myform.form_fields[i].field_id === field.field_id){
// break;
// }
// }
};
/*
** StartPage Button Methods
*/
// add new Button to the field
$scope.addButton = function (Button){
var lastButtonID = 0;
if($scope.myform.StartPage.buttons[$scope.myform.StartPage.buttons.length-1])
lastButtonID = $scope.myform.StartPage.buttons[$scope.myform.StartPage.buttons.length-1].button_id;
// put new option into fieldOptions array
Button.backgroundColor = '#5bc0de';
Button.button_id = lastButtonID;
Button.color = '#ffffff';
$scope.myform.StartPage.buttons.push(Button);
};
// delete particular option
$scope.deleteButton = function (button_index){
$scope.myform.StartPage.buttons.splice(button_index, 1);
};
/*
** Field Option Methods
*/
// add new option to the field
$scope.addOption = function (field){
if(!field.fieldOptions) field.fieldOptions = [];
var lastOptionID = 0;
if(field.fieldOptions[field.fieldOptions.length-1])
lastOptionID = field.fieldOptions[field.fieldOptions.length-1].option_id;
// new option's id
var option_id = lastOptionID + 1;
var newOption = {
'option_id' : option_id,
'option_title' : 'Option ' + option_id,
'option_value' : option_id
};
// put new option into fieldOptions array
field.fieldOptions.push(newOption);
};
// delete particular option
$scope.deleteOption = function (field, option){
for(var i = 0; i < field.fieldOptions.length; i++){
if(field.fieldOptions[i].option_id === option.option_id){
field.fieldOptions.splice(i, 1);
break;
}
}
};
// decides whether field options block will be shown (true for dropdown and radio fields)
$scope.showAddOptions = function (field){
if(field.fieldType === 'dropdown' || field.fieldType === 'checkbox' || field.fieldType === 'radio'){
return true;
} else {
return false;
}
};
},
};
}
]);
'use strict';
angular.module('forms').directive('fieldIconDirective', function($http, $compile) {
return {
@ -1385,14 +930,6 @@ angular.module('forms').directive('fieldDirective', ['$http', '$compile', '$root
};
}]);
'use strict';
angular.module('forms').directive('formLocator', function() {
return {
link: function(scope) {
scope.$emit('formLocator');
}
};
});
'use strict';
angular.module('forms').directive('onFinishRender', function ($rootScope, $timeout) {
return {
@ -1428,7 +965,7 @@ angular.module('forms').directive('onFinishRender', function ($rootScope, $timeo
angular.module('forms').directive('formDirective', ['$http', '$timeout', 'timeCounter', 'Auth', '$filter', '$rootScope',
function ($http, $timeout, timeCounter, Auth, $filter, $rootScope) {
return {
templateUrl: './modules/forms/views/directiveViews/form/submit-form.html',
templateUrl: './modules/forms/views/directiveViews/form/submit-form.client.view.html',
restrict: 'E',
scope: {
form:'='
@ -1497,6 +1034,12 @@ angular.module('forms').directive('formDirective', ['$http', '$timeout', 'timeCo
angular.module('forms').directive('tableDirective', ['$http', '$timeout', 'Auth',
function ($http, $timeout, Auth) {
return {
templateUrl: './modules/forms/views/directiveViews/table/table.html',
restrict: 'E',
scope: {
rows:'=',
extras:'=',
},
controller: function($scope){
$scope.toggleChecker = function(checked) {
@ -1513,13 +1056,10 @@ angular.module('forms').directive('tableDirective', ['$http', '$timeout', 'Auth'
$scope.gridOptions.$gridScope.checker = allChecked;
};
},
templateUrl: './modules/forms/views/directiveViews/table/table.html',
restrict: 'E',
scope: {
rows:'=',
extras:'=',
}
};
}
]);
@ -2047,8 +1587,7 @@ angular.module('users').controller('VerifyController', ['$scope', '$state', '$ro
'use strict';
angular.module('users').factory('Auth', function($window) {
var userState =
{
var userState = {
isLoggedIn: false
};

File diff suppressed because one or more lines are too long

View File

@ -1,13 +1,9 @@
'use strict';
angular.module('core').controller('HeaderController', ['$rootScope','$scope','Menus', '$state', 'Auth', 'User',
angular.module('core').controller('HeaderController', ['$rootScope', '$scope', 'Menus', '$state', 'Auth', 'User',
function ($rootScope, $scope, Menus, $state, Auth, User) {
$scope.user = $rootScope.user = Auth.ensureHasCurrentUser(User);
$scope.authentication = $rootScope.authentication = Auth;
// if(!$scope.user || !$scope.user.username){
// $scope.user = $rootScope.user = User.getCurrent();
// $scope.authentication.currentUser = $rootScope.authentication.currentUser = $scope.user;
// }
$rootScope.languages = $scope.languages = ['english', 'french', 'spanish'];

View File

@ -1,24 +1,24 @@
'use strict';
// 'use strict';
(function() {
describe('HeaderController', function() {
//Initialize global variables
var scope,
HeaderController;
// (function() {
// describe('HeaderController', function() {
// //Initialize global variables
// var scope,
// HeaderController;
// Load the main application module
beforeEach(module(ApplicationConfiguration.applicationModuleName));
// // Load the main application module
// beforeEach(module(ApplicationConfiguration.applicationModuleName));
beforeEach(inject(function($controller, $rootScope) {
scope = $rootScope.$new();
// beforeEach(inject(function($controller, $rootScope) {
// scope = $rootScope.$new();
HeaderController = $controller('HeaderController', {
$scope: scope
});
}));
// HeaderController = $controller('HeaderController', {
// $scope: scope
// });
// }));
it('should expose the authentication service', function() {
expect(scope.authentication).toBeTruthy();
});
});
})();
// it('should expose the authentication service', function() {
// expect(scope.authentication).toBeTruthy();
// });
// });
// })();

View File

@ -1,24 +1,24 @@
'use strict';
// 'use strict';
(function() {
describe('HomeController', function() {
//Initialize global variables
var scope,
HomeController;
// (function() {
// describe('HomeController', function() {
// //Initialize global variables
// var scope,
// HomeController;
// Load the main application module
beforeEach(module(ApplicationConfiguration.applicationModuleName));
// // Load the main application module
// beforeEach(module(ApplicationConfiguration.applicationModuleName));
beforeEach(inject(function($controller, $rootScope) {
scope = $rootScope.$new();
// beforeEach(inject(function($controller, $rootScope) {
// scope = $rootScope.$new();
HomeController = $controller('HomeController', {
$scope: scope
});
}));
// HomeController = $controller('HomeController', {
// $scope: scope
// });
// }));
it('should expose the authentication service', function() {
expect(scope.authentication).toBeTruthy();
});
});
})();
// it('should expose the authentication service', function() {
// expect(scope.authentication).toBeTruthy();
// });
// });
// })();

View File

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

View File

@ -0,0 +1,115 @@
'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) {
var deleteModal;
$scope = $rootScope;
$scope.myform = CurrentForm.getForm();
$rootScope.saveInProgress = false;
// Find a specific Form
$scope.findOne = function(){
$scope.myform = Forms.get({
formId: $stateParams.formId
});
CurrentForm.setForm($scope.myform);
};
$scope.setForm = function(form){
$scope.myform = form;
};
$rootScope.resetForm = function(){
$scope.myform = Forms.get({
formId: $stateParams.formId
});
};
/*
** DeleteModal Functions
*/
$scope.openDeleteModal = function(){
deleteModal = $modal.open({
animation: $scope.animationsEnabled,
templateUrl: 'myModalContent.html',
controller: 'AdminFormController',
});
};
$scope.cancelDeleteModal = function(){
if(deleteModal){
deleteModal.dismiss('cancel');
}
};
// Remove existing Form
$scope.remove = function(form_id) {
if(deleteModal && deleteModal.opened){
deleteModal.close();
var form = {};
if(!form_id){
form = CurrentForm.getForm();
if(!form) form = $scope.myform;
}else {
form._id = form_id;
}
$http.delete('/forms/'+form._id)
.success(function(data, status, headers){
console.log('form deleted successfully');
if(!form_id){
$state.go('listForms', {}, {reload: true});
}
if($scope.myforms.length > 0){
$scope.myforms = _.filter($scope.myforms, function(myform){
return myform._id !== form._id;
});
}
}).error(function(error){
console.log('ERROR: Form could not be deleted.');
console.error(error);
}).finally(function(){
});
}
};
// Update existing Form
$scope.update = $rootScope.update = function(shouldUpdateNow, cb){
// console.log('shouldUpdateNow: '+shouldUpdateNow);
var continueUpdate = true;
if(shouldUpdateNow){
continueUpdate = !$rootScope.saveInProgress;
}
if(continueUpdate){
console.log('begin updating form');
var err = null;
if(shouldUpdateNow){ $rootScope.saveInProgress = true; }
$scope.updatePromise = $http.put('/forms/'+$scope.myform._id, {form: $scope.myform})
.then(function(response){
$rootScope.myform = $scope.myform = response.data;
console.log(response.data);
}).catch(function(response){
console.log('Error occured during form UPDATE.\n');
console.log(response.data);
err = response.data;
}).finally(function() {
console.log('finished updating');
if(shouldUpdateNow){$rootScope.saveInProgress = false; }
cb(err);
});
}
};
}
]);

View File

@ -1,247 +0,0 @@
'use strict';
// Forms controller
angular.module('forms').controller('ViewFormController', ['$rootScope', '$scope', '$stateParams', '$state', 'Forms', 'CurrentForm', '$http', '$modal',
function($rootScope, $scope, $stateParams, $state, Forms, CurrentForm, $http, $modal) {
var deleteModal;
$scope = $rootScope;
$scope.myform = CurrentForm.getForm();
$rootScope.saveInProgress = false;
$scope.viewSubmissions = false;
$scope.table = {
masterChecker: false,
rows: []
};
// Find a specific Form
$scope.findOne = function() {
$scope.myform = Forms.get({
formId: $stateParams.formId
});
CurrentForm.setForm($scope.myform);
};
$scope.setForm = function (form) {
$scope.myform = form;
};
$rootScope.resetForm = function(){
$scope.myform = Forms.get({
formId: $stateParams.formId
});
};
/*
* Table Functions
*/
$scope.isAtLeastOneChecked = function(){
// console.log('isAtLeastOneChecked');
for(var i=0; i<$scope.table.rows.length; i++){
if($scope.table.rows[i].selected) return true;
}
return false;
};
$scope.toggleAllCheckers = function(){
// console.log('toggleAllCheckers');
for(var i=0; i<$scope.table.rows.length; i++){
$scope.table.rows[i].selected = $scope.table.masterChecker;
}
};
$scope.toggleObjSelection = function($event, description) {
$event.stopPropagation();
};
$scope.rowClicked = function(row_index) {
$scope.table.rows[row_index].selected = !$scope.table.rows[row_index].selected;
};
/*
* Form Submission Methods
*/
//Delete selected submissions of Form
$scope.deleteSelectedSubmissions = function(){
// console.log('deleteSelectedSubmissions');
var delete_ids = _.chain($scope.table.rows).filter(function(row){
return !!row.selected;
}).pluck('_id').value();
$http({ url: '/forms/'+$scope.myform._id+'/submissions',
method: 'DELETE',
data: {deleted_submissions: delete_ids},
headers: {"Content-Type": "application/json;charset=utf-8"}
}).success(function(data, status, headers){
//Remove deleted ids from table
var tmpArray = [];
for(var i=0; i<$scope.table.rows.length; i++){
if(!$scope.table.rows[i].selected){
tmpArray.push($scope.table.rows[i]);
}
}
console.log(tmpArray);
$scope.table.rows = tmpArray;
})
.error(function(err){
console.log('Could not delete form submissions.\nError: ');
console.log(err);
console.error = err;
});
};
//Export selected submissions of Form
$scope.exportSubmissions = function(){
// console.log('exportSelectedSubmissions');
// var export_ids = _.chain($scope.table.rows).filter(function(row){
// return !!row.selected;
// }).pluck('_id').value();
var blob = new Blob([document.getElementById('table-submission-data').innerHTM], {
type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8"
});
saveAs(blob, $scope.myform.title+'_export_'+Date.now()+".xls");
};
//Fetch and display submissions of Form
$scope.showSubmissions = function(){
$scope.viewSubmissions = true;
$http.get('/forms/'+$scope.myform._id+'/submissions')
.success(function(data, status, headers){
// console.log(data[0].form_fields);
var _data = [];
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;
_.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 = '';
}
}
_data[i] = data[i];
_data[i].form_fields = _tmpSubFormFields;
}
// console.log(JSON.stringify(_data));
$scope.submissions = _data;
$scope.table.rows = _data;
if(!$scope.$$phase && !$scope.$digest){
$scope.$apply();
}
// console.log('form submissions successfully fetched');
// console.log( JSON.parse(JSON.stringify($scope.submissions)) ) ;
// console.log( JSON.parse(JSON.stringify($scope.myform.form_fields)) );
})
.error(function(err){
console.log('Could not fetch form submissions.\nError: '+err);
});
};
//hide submissions of Form
$scope.hideSubmissions = function(){
$scope.viewSubmissions = false;
};
/*
** DeleteModal Functions
*/
$scope.openDeleteModal = function() {
deleteModal = $modal.open({
animation: $scope.animationsEnabled,
templateUrl: 'myModalContent.html',
controller: 'ViewFormController',
});
};
$scope.cancelDeleteModal = function(){
if(deleteModal){
deleteModal.dismiss('cancel');
}
};
// Remove existing Form
$scope.remove = function(form_id) {
if(deleteModal && deleteModal.opened){
deleteModal.close();
var form = {};
if(!form_id){
form = CurrentForm.getForm();
if(!form) form = $scope.myform;
}else {
form._id = form_id;
}
$http.delete('/forms/'+form._id)
.success(function(data, status, headers){
console.log('form deleted successfully');
if(!form_id){
$state.go('listForms', {}, {reload: true});
}
if($scope.myforms.length > 0){
$scope.myforms = _.filter($scope.myforms, function(myform){
return myform._id !== form._id;
});
}
}).error(function(error){
console.log('ERROR: Form could not be deleted.');
console.error(error);
}).finally(function(){
});
}
};
// Update existing Form
$scope.update = $rootScope.update = function(immediate, cb) {
console.log('immediate: '+immediate);
var continueUpdate = true;
if(immediate){
continueUpdate = !$rootScope.saveInProgress;
}
if(continueUpdate){
console.log('begin updating form');
var err = null;
if(immediate){ $rootScope.saveInProgress = true; }
$scope.updatePromise = $http.put('/forms/'+$scope.myform._id, {form: $scope.myform})
.then(function(response){
$rootScope.myform = $scope.myform = response.data;
console.log(response.data);
}).catch(function(response){
console.log('Error occured during form UPDATE.\n');
console.log(response.data);
err = response.data;
}).finally(function() {
console.log('finished updating');
if(immediate){$rootScope.saveInProgress = false; }
cb(err);
});
}
};
}
]);

View File

@ -1,3 +1,15 @@
.panel-default.startPage {
/*background-color: #eee;*/
border-style: dashed;
border-color: #a9a9a9;
border-width:3px;
}
section.content p {
word-break: break-all;
}
.btn {
border: 1px solid #c6c6c6!important;
}

View File

@ -3,7 +3,7 @@
angular.module('forms').directive('configureFormDirective', ['$rootScope', '$http', 'Upload', '$timeout', 'timeCounter', 'Auth', 'FormFields',
function ($rootScope, $http, Upload, $timeout, timeCounter, Auth, FormFields) {
return {
templateUrl: './modules/forms/views/directiveViews/form/configure-form.html',
templateUrl: './modules/forms/views/directiveViews/form/configure-form.client.view.html',
restrict: 'E',
scope: {
myform:'=',

View File

@ -4,7 +4,7 @@ angular.module('forms')
.directive('editFormDirective', ['$rootScope', '$q', '$http', '$timeout', 'timeCounter', 'Auth', 'FormFields',
function ($rootScope, $q, $http, $timeout, timeCounter, Auth, FormFields) {
return {
templateUrl: './modules/forms/views/directiveViews/form/edit-form.html',
templateUrl: './modules/forms/views/directiveViews/form/edit-form.client.view.html',
restrict: 'E',
scope: {
myform:'=',
@ -142,44 +142,43 @@ angular.module('forms')
field.title = $scope.myform.form_fields[field_index].title;
console.log($scope.myform.form_fields[field_index]);
//Insert field at selected index
$scope.myform.form_fields.splice(field_index+1, 0, field);
// for(var i = 0; i < $scope.myform.form_fields.length; i++){
// if($scope.myform.form_fields[i].field_id === field.field_id){
// break;
// }
// }
};
/*
** StartPage Button Methods
** startPage Button Methods
*/
// add new Button to the field
$scope.addButton = function (Button){
// add new Button to the startPage/EndPage
$scope.addButton = function (newButtons){
var lastButtonID = 0;
var newButton = {};
newButton.bgColor = '#ddd';
newButton.color = '#ffffff';
newButton.text = 'Button';
if($scope.myform.StartPage.buttons[$scope.myform.StartPage.buttons.length-1])
lastButtonID = $scope.myform.StartPage.buttons[$scope.myform.StartPage.buttons.length-1].button_id;
// put new option into fieldOptions array
Button.backgroundColor = '#5bc0de';
Button.button_id = lastButtonID;
Button.color = '#ffffff';
$scope.myform.StartPage.buttons.push(Button);
$scope.myform.startPage.buttons.push(newButton);
};
// delete particular option
$scope.deleteButton = function (button_index){
$scope.myform.StartPage.buttons.splice(button_index, 1);
// delete particular Button
$scope.deleteButton = function(button){
var hashKey = _.chain(button.$$hashKey).words().last().parseInt().value();
for(var i = 0; i < $scope.myform.startPage.buttons.length; i++){
var currHashKey = _.chain($scope.myform.startPage.buttons[i].$$hashKey).words().last().parseInt().value();;
if(currHashKey === hashKey){
$scope.myform.startPage.buttons.splice(i, 1);
break;
}
}
};
/*
** Field Option Methods
*/

View File

@ -1,8 +0,0 @@
'use strict';
angular.module('forms').directive('formLocator', function() {
return {
link: function(scope) {
scope.$emit('formLocator');
}
};
});

View File

@ -0,0 +1,153 @@
'use strict';
angular.module('forms').directive('submissionsFormDirective', ['$rootScope', '$http', 'Upload', '$timeout', 'timeCounter', 'Auth', 'FormFields',
function ($rootScope, $http, Upload, $timeout, timeCounter, Auth, FormFields) {
return {
templateUrl: './modules/forms/views/directiveViews/form/submissions-form.client.view.html',
restrict: 'E',
scope: {
myform:'=',
user:'='
},
controller: function($scope){
$scope.table = {
masterChecker: false,
rows: []
};
/*
** Table Functions
*/
$scope.isAtLeastOneChecked = function(){
// console.log('isAtLeastOneChecked');
for(var i=0; i<$scope.table.rows.length; i++){
if($scope.table.rows[i].selected) return true;
}
return false;
};
$scope.toggleAllCheckers = function(){
// console.log('toggleAllCheckers');
for(var i=0; i<$scope.table.rows.length; i++){
$scope.table.rows[i].selected = $scope.table.masterChecker;
}
};
$scope.toggleObjSelection = function($event, description) {
$event.stopPropagation();
};
$scope.rowClicked = function(row_index) {
$scope.table.rows[row_index].selected = !$scope.table.rows[row_index].selected;
};
/*
* Form Submission Methods
*/
//Delete selected submissions of Form
$scope.deleteSelectedSubmissions = function(){
// console.log('deleteSelectedSubmissions');
var delete_ids = _.chain($scope.table.rows).filter(function(row){
return !!row.selected;
}).pluck('_id').value();
$http({ url: '/forms/'+$scope.myform._id+'/submissions',
method: 'DELETE',
data: {deleted_submissions: delete_ids},
headers: {'Content-Type': 'application/json;charset=utf-8'}
}).success(function(data, status, headers){
//Remove deleted ids from table
var tmpArray = [];
for(var i=0; i<$scope.table.rows.length; i++){
if(!$scope.table.rows[i].selected){
tmpArray.push($scope.table.rows[i]);
}
}
console.log(tmpArray);
$scope.table.rows = tmpArray;
})
.error(function(err){
console.log('Could not delete form submissions.\nError: ');
console.log(err);
console.error = err;
});
};
//Export selected submissions of Form
$scope.exportSubmissions = function(type){
var fileMIMETypeMap = {
'xls': 'vnd.openxmlformats-officedocument.spreadsheetml.sheet',
'json': 'json',
'csv': 'csv',
};
var blob = new Blob([document.getElementById('table-submission-data').innerHTM], {
type: 'application/'+fileMIMETypeMap[type]+';charset=utf-8'
});
saveAs(blob, $scope.myform.title+'_sumbissions_export_'+Date.now()+'.'+type);
};
//Fetch and display submissions of Form
$scope.showSubmissions = function(){
$http.get('/forms/'+$scope.myform._id+'/submissions')
.success(function(data, status, headers){
var _data = [],
_currentSubmission,
_tmpSubFormFields,
defaultFormFields = JSON.parse(JSON.stringify($scope.myform.form_fields));
//Iterate through form's submissions
for(var i=0; i<data.length; i++){
// _tmpSubFormFields = defaultFormFields;
_tmpSubFormFields = _.merge(defaultFormFields, data[i].form_fields);
_data[i].form_fields = _tmpSubFormFields;
// currentSubmission = data[i];
// for(var x=0; x<defaultFormFields.length; x++){
// var currField__id = defaultFormFields[x]._id,
// currField;
// _.find(currentSubmission.form_fields, function(fieldItem, fieldIdx){
// if(fieldItem._id === currField__id){
// currField = fieldItem;
// return true;
// }
// });
// if( (typeof currField) !== 'undefined'){
// _tmpSubFormFields[x].fieldValue = currField.fieldValue;
// _tmpSubFormFields[x].$$hashKey = currField.$$hashKey;
// }else {
// _tmpSubFormFields[x].fieldValue = '';
// }
// }
// _data[i] = currentSubmission;
// _data[i].form_fields = _tmpSubFormFields;
}
// console.log(JSON.stringify(_data));
$scope.submissions = _data;
$scope.table.rows = _data;
if(!$scope.$$phase && !$scope.$digest){
$scope.$apply();
}
// console.log('form submissions successfully fetched');
// console.log( JSON.parse(JSON.stringify($scope.submissions)) ) ;
// console.log( JSON.parse(JSON.stringify($scope.myform.form_fields)) );
})
.error(function(err){
console.error('Could not fetch form submissions.\nError: '+err);
});
};
}
};
}
]);

View File

@ -3,7 +3,7 @@
angular.module('forms').directive('formDirective', ['$http', '$timeout', 'timeCounter', 'Auth', '$filter', '$rootScope',
function ($http, $timeout, timeCounter, Auth, $filter, $rootScope) {
return {
templateUrl: './modules/forms/views/directiveViews/form/submit-form.html',
templateUrl: './modules/forms/views/directiveViews/form/submit-form.client.view.html',
restrict: 'E',
scope: {
form:'='
@ -48,7 +48,7 @@ angular.module('forms').directive('formDirective', ['$http', '$timeout', 'timeCo
};
$scope.exitStartPage = function () {
$scope.exitstartPage = function () {
$scope.form.startPage.showStart = false;
};

View File

@ -3,6 +3,12 @@
angular.module('forms').directive('tableDirective', ['$http', '$timeout', 'Auth',
function ($http, $timeout, Auth) {
return {
templateUrl: './modules/forms/views/directiveViews/table/table.html',
restrict: 'E',
scope: {
rows:'=',
extras:'=',
},
controller: function($scope){
$scope.toggleChecker = function(checked) {
@ -19,13 +25,10 @@ angular.module('forms').directive('tableDirective', ['$http', '$timeout', 'Auth'
$scope.gridOptions.$gridScope.checker = allChecked;
};
},
templateUrl: './modules/forms/views/directiveViews/table/table.html',
restrict: 'E',
scope: {
rows:'=',
extras:'=',
}
};
}
]);

View File

@ -0,0 +1,184 @@
'use strict';
(function() {
// Forms Controller Spec
describe('AdminFormController Tests', function() {
// Initialize global variables
var AdminFormController,
scope,
$httpBackend,
$stateParams,
$location;
// The $resource service augments the response object with methods for updating and deleting the resource.
// If we were to use the standard toEqual matcher, our tests would fail because the test values would not match
// the responses exactly. To solve the problem, we define a new toEqualData Jasmine matcher.
// When the toEqualData matcher compares two objects, it takes only object properties into
// account and ignores methods.
beforeEach(function() {
jasmine.addMatchers({
toEqualData: function(util, customEqualityTesters) {
return {
compare: function(actual, expected) {
return {
pass: angular.equals(actual, expected)
};
}
};
}
});
});
// Then we can start by loading the main application module
beforeEach(module(ApplicationConfiguration.applicationModuleName));
// 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.
beforeEach(inject(function($controller, $rootScope, _$location_, _$state_, _$stateParams_, _$httpBackend_) {
// Set a new global scope
scope = $rootScope.$new();
// Point global variables to injected services
$stateParams = _$stateParams_;
$httpBackend = _$httpBackend_;
$location = _$location_;
// Initialize the Forms controller.
AdminFormController = $controller('AdminFormController', {
$scope: scope,
});
}));
//Mock Authentication Service
$provide.value("MyLoginServce", {
ensureHasCurrentUser: function(){
return true;
},
redirectForLogin: function {}
});
it('$scope.findOne() should fetch current Form', inject(function(Forms) {
// Define a sample article object
var sampleForm = new Forms({
title: 'Form Title',
admin: 'ed873933b1f1dea0ce12fab9',
language: 'english',
form_fields: [
{'fieldType':'textfield', 'title':'First Name', 'fieldValue': ''},
{'fieldType':'checkbox', 'title':'nascar', 'fieldValue': ''},
{'fieldType':'checkbox', 'title':'hockey', 'fieldValue': ''}
]
});
// Set the URL parameter
$stateParams.formId = '525a8422f6d0f87f0e407a33';
// Set GET response
$httpBackend.expectGET(/forms\/([0-9a-fA-F]{24})$/).respond(sampleForm);
// Run controller functionality
scope.findOne();
$httpBackend.flush();
// Test scope value
expect(scope.article).toEqualData(sampleArticle);
}));
// it('$scope.find() should create an array with at least one article object fetched from XHR', inject(function(Forms) {
// // Create sample article using the Forms service
// var sampleArticle = new Forms({
// title: 'An Article about MEAN',
// content: 'MEAN rocks!'
// });
// // Create a sample Forms array that includes the new article
// var sampleForms = [sampleForm];
// // Set GET response
// $httpBackend.expectGET('Forms').respond(sampleForms);
// // Run controller functionality
// scope.find();
// $httpBackend.flush();
// // Test scope value
// expect(scope.Forms).toEqualData(sampleForms);
// }));
// it('$scope.create() with valid form data should send a POST request with the form input values and then locate to new object URL', inject(function(Forms) {
// // Create a sample article object
// var sampleArticlePostData = new Forms({
// title: 'An Article about MEAN',
// content: 'MEAN rocks!'
// });
// // Create a sample article response
// var sampleArticleResponse = new Forms({
// _id: '525cf20451979dea2c000001',
// title: 'An Article about MEAN',
// content: 'MEAN rocks!'
// });
// // Fixture mock form input values
// scope.title = 'An Article about MEAN';
// scope.content = 'MEAN rocks!';
// // Set POST response
// $httpBackend.expectPOST('Forms', sampleArticlePostData).respond(sampleArticleResponse);
// // Run controller functionality
// scope.create();
// $httpBackend.flush();
// // Test form inputs are reset
// expect(scope.title).toEqual('');
// expect(scope.content).toEqual('');
// // Test URL redirection after the article was created
// expect($location.path()).toBe('/Forms/' + sampleArticleResponse._id);
// }));
// it('$scope.update() should update a valid article', inject(function(Forms) {
// // Define a sample article put data
// var sampleArticlePutData = new Forms({
// _id: '525cf20451979dea2c000001',
// title: 'An Article about MEAN',
// content: 'MEAN Rocks!'
// });
// // Mock article in scope
// scope.article = sampleArticlePutData;
// // Set PUT response
// $httpBackend.expectPUT(/Forms\/([0-9a-fA-F]{24})$/).respond();
// // Run controller functionality
// scope.update();
// $httpBackend.flush();
// // Test URL location to new object
// expect($location.path()).toBe('/Forms/' + sampleArticlePutData._id);
// }));
// it('$scope.remove() should send a DELETE request with a valid articleId and remove the article from the scope', inject(function(Forms) {
// // Create new article object
// var sampleArticle = new Forms({
// _id: '525a8422f6d0f87f0e407a33'
// });
// // Create new Forms array and include the article
// scope.Forms = [sampleArticle];
// // Set expected DELETE response
// $httpBackend.expectDELETE(/Forms\/([0-9a-fA-F]{24})$/).respond(204);
// // Run controller functionality
// scope.remove(sampleArticle);
// $httpBackend.flush();
// // Test array after successful delete
// expect(scope.Forms.length).toBe(0);
// }));
});
}());

View File

@ -0,0 +1,91 @@
// 'use strict';
// (function() {
// // Forms Controller Spec
// describe('SubmissionsFormDirective Tests', function() {
// // Initialize global variables
// var SubmissionsFormDirective,
// scope,
// $httpBackend,
// $stateParams,
// $location;
// // The $resource service augments the response object with methods for updating and deleting the resource.
// // If we were to use the standard toEqual matcher, our tests would fail because the test values would not match
// // the responses exactly. To solve the problem, we define a new toEqualData Jasmine matcher.
// // When the toEqualData matcher compares two objects, it takes only object properties into
// // account and ignores methods.
// beforeEach(function() {
// jasmine.addMatchers({
// toEqualData: function(util, customEqualityTesters) {
// return {
// compare: function(actual, expected) {
// return {
// pass: angular.equals(actual, expected)
// };
// }
// };
// }
// });
// });
// // Then we can start by loading the main application module
// beforeEach(module(ApplicationConfiguration.applicationModuleName));
// // 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.
// beforeEach(inject(function($controller, $rootScope, _$location_, _$stateParams_, _$httpBackend_) {
// // Set a new global scope
// scope = $rootScope.$new();
// // Point global variables to injected services
// $stateParams = _$stateParams_;
// $httpBackend = _$httpBackend_;
// $location = _$location_;
// // Initialize the Forms controller.
// FormsController = $controller('AdminFormsController', {
// $scope: scope
// });
// }));
// function compileDirective(tpl) {
// // function to compile a fresh directive with the given template, or a default one
// // compile the tpl with the $rootScope created above
// // wrap our directive inside a form to be able to test
// // that our form integration works well (via ngModelController)
// // our directive instance is then put in the global 'elm' variable for further tests
// if (!tpl) tpl = '<div rn-stepper ng-model="testModel"></div></form>';
// tpl = '<form name="form">' + tpl + '</tpl>';
// // inject allows you to use AngularJS dependency injection
// // to retrieve and use other services
// inject(function($compile) {
// var form = $compile(tpl)(scope);
// elm = form.find('div');
// });
// // $digest is necessary to finalize the directive generation
// scope.$digest();
// }
// describe('initialisation', function() {
// // before each test in this block, generates a fresh directive
// beforeEach(function() {
// compileDirective();
// });
// // a single test example, check the produced DOM
// it('should produce 2 buttons and a div', function() {
// expect(elm.find('button').length).toEqual(2);
// expect(elm.find('div').length).toEqual(1);
// });
// it('should check validity on init', function() {
// expect(scope.form.$valid).toBeTruthy();
// });
// });
// it('$scope.find() should create an array with at least one article object fetched from XHR', inject(function(Forms) {
// }));
// });
// }());

View File

@ -1,170 +0,0 @@
// 'use strict';
// (function() {
// // Forms Controller Spec
// describe('ViewForm Controller Tests', function() {
// // Initialize global variables
// var ViewFormController,
// scope,
// $httpBackend,
// $stateParams,
// $location;
// // The $resource service augments the response object with methods for updating and deleting the resource.
// // If we were to use the standard toEqual matcher, our tests would fail because the test values would not match
// // the responses exactly. To solve the problem, we define a new toEqualData Jasmine matcher.
// // When the toEqualData matcher compares two objects, it takes only object properties into
// // account and ignores methods.
// beforeEach(function() {
// jasmine.addMatchers({
// toEqualData: function(util, customEqualityTesters) {
// return {
// compare: function(actual, expected) {
// return {
// pass: angular.equals(actual, expected)
// };
// }
// };
// }
// });
// });
// // Then we can start by loading the main application module
// beforeEach(module(ApplicationConfiguration.applicationModuleName));
// // 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.
// beforeEach(inject(function($controller, $rootScope, _$location_, _$stateParams_, _$httpBackend_) {
// // Set a new global scope
// scope = $rootScope.$new();
// // Point global variables to injected services
// $stateParams = _$stateParams_;
// $httpBackend = _$httpBackend_;
// $location = _$location_;
// // Initialize the Forms controller.
// FormsController = $controller('FormsController', {
// $scope: scope
// });
// }));
// it('$scope.find() should create an array with at least one article object fetched from XHR', inject(function(Forms) {
// // Create sample article using the Forms service
// var sampleArticle = new Forms({
// title: 'An Article about MEAN',
// content: 'MEAN rocks!'
// });
// // Create a sample Forms array that includes the new article
// var sampleForms = [sampleForm];
// // Set GET response
// $httpBackend.expectGET('Forms').respond(sampleForms);
// // Run controller functionality
// scope.find();
// $httpBackend.flush();
// // Test scope value
// expect(scope.Forms).toEqualData(sampleForms);
// }));
// it('$scope.findOne() should create an array with one article object fetched from XHR using a articleId URL parameter', inject(function(Forms) {
// // Define a sample article object
// var sampleArticle = new Forms({
// title: 'An Article about MEAN',
// content: 'MEAN rocks!'
// });
// // Set the URL parameter
// $stateParams.articleId = '525a8422f6d0f87f0e407a33';
// // Set GET response
// $httpBackend.expectGET(/Forms\/([0-9a-fA-F]{24})$/).respond(sampleArticle);
// // Run controller functionality
// scope.findOne();
// $httpBackend.flush();
// // Test scope value
// expect(scope.article).toEqualData(sampleArticle);
// }));
// it('$scope.create() with valid form data should send a POST request with the form input values and then locate to new object URL', inject(function(Forms) {
// // Create a sample article object
// var sampleArticlePostData = new Forms({
// title: 'An Article about MEAN',
// content: 'MEAN rocks!'
// });
// // Create a sample article response
// var sampleArticleResponse = new Forms({
// _id: '525cf20451979dea2c000001',
// title: 'An Article about MEAN',
// content: 'MEAN rocks!'
// });
// // Fixture mock form input values
// scope.title = 'An Article about MEAN';
// scope.content = 'MEAN rocks!';
// // Set POST response
// $httpBackend.expectPOST('Forms', sampleArticlePostData).respond(sampleArticleResponse);
// // Run controller functionality
// scope.create();
// $httpBackend.flush();
// // Test form inputs are reset
// expect(scope.title).toEqual('');
// expect(scope.content).toEqual('');
// // Test URL redirection after the article was created
// expect($location.path()).toBe('/Forms/' + sampleArticleResponse._id);
// }));
// it('$scope.update() should update a valid article', inject(function(Forms) {
// // Define a sample article put data
// var sampleArticlePutData = new Forms({
// _id: '525cf20451979dea2c000001',
// title: 'An Article about MEAN',
// content: 'MEAN Rocks!'
// });
// // Mock article in scope
// scope.article = sampleArticlePutData;
// // Set PUT response
// $httpBackend.expectPUT(/Forms\/([0-9a-fA-F]{24})$/).respond();
// // Run controller functionality
// scope.update();
// $httpBackend.flush();
// // Test URL location to new object
// expect($location.path()).toBe('/Forms/' + sampleArticlePutData._id);
// }));
// it('$scope.remove() should send a DELETE request with a valid articleId and remove the article from the scope', inject(function(Forms) {
// // Create new article object
// var sampleArticle = new Forms({
// _id: '525a8422f6d0f87f0e407a33'
// });
// // Create new Forms array and include the article
// scope.Forms = [sampleArticle];
// // Set expected DELETE response
// $httpBackend.expectDELETE(/Forms\/([0-9a-fA-F]{24})$/).respond(204);
// // Run controller functionality
// scope.remove(sampleArticle);
// $httpBackend.flush();
// // Test array after successful delete
// expect(scope.Forms.length).toBe(0);
// }));
// });
// }());

View File

@ -1,4 +1,4 @@
<section data-ng-controller="ViewFormController" data-ng-init="findOne()" class="container admin-form">
<section data-ng-controller="AdminFormController" data-ng-init="findOne()" class="container admin-form">
<!-- Modal Delete Dialog Template -->
<script type="text/ng-template" id="myModalContent.html">
@ -61,14 +61,14 @@
</div>
</div>
<div class="row" cg-busy="{promise:updatePromise,message:'Updating form...',backdrop:true}">
<!-- <div > -->
<div class="row" cg-busy="{promise:updatePromise,templateUrl:'modules/forms/views/directiveViews/cgBusy/update-form-message-TypeB.html',message:'Updating form...',backdrop:false}">
<tabset class="col-xs-12">
<tab>
<tab-heading>
Edit Form Fields
</tab-heading>
<edit-form-directive myform="myform"></edit-form-directive>
<edit-form-directive myform="myform">
</edit-form-directive>
</tab>
<tab disabled="true">
<tab-heading >
@ -82,82 +82,65 @@
<configure-form-directive myform="myform" user="user">
</configure-form-directive>
</tab>
<tab data-ng-click="showSubmissions()">
<tab>
<tab-heading>
View Submissions
</tab-heading>
<div class="submissions-table row container" ng-show="viewSubmissions">
<div class="row">
<div class="col-xs-2">
<button class="btn btn-danger" ng-click="deleteSelectedSubmissions()" ng-disabled="!isAtLeastOneChecked();">
<i class="fa fa-trash-o"></i> Delete Selected
</button>
</div>
<div class="col-xs-2">
<button class="btn btn-default" ng-click="exportSubmissions()">
Export to XLS
</button>
</div>
</div>
<div class="row table-outer">
<div class="col-xs-12">
<table id="table-submission-data" class="table table-striped table-hover table-condensed">
<thead>
<tr>
<th>
<input ng-model="table.masterChecker" ng-change="toggleAllCheckers()" type="checkbox"/>
</th>
<th>#</th>
<th data-ng-repeat="(key, value) in myform.form_fields">
{{value.title}}
</th>
<th>
Percentage Complete
</th>
<th>
Time Elapsed
</th>
<th>
Date Submitted (UTC)
</th>
<th ng-if="myform.autofillPDFs">
Generated PDF
</th>
</tr>
</thead>
<tbody>
<tr data-ng-repeat="row in table.rows" ng-click="rowClicked($index)" ng-class="{selected: row.selected === true}">
<td>
<input ng-model="row.selected" type="checkbox"/>
</td>
<th class="scope">
{{$index+1}}
</th>
<td data-ng-repeat="(key, value) in row.form_fields">
{{value.fieldValue}}
</td>
<td>
{{row.percentageComplete}}%
</td>
<td>
{{row.timeElapsed}}
</td>
<td>
{{row.created | date:'yyyy-MM-dd HH:mm:ss'}}
</td>
<td ng-if="row.pdf">
<a href="{{row.pdfFilePath}}" download="{{row.pdf.name}}" target="_self">Generated PDF</a>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<submissions-form-directive myform="myform" user="user">
</submissions-form-directive>
</tab>
</tabset>
<!-- </div> -->
<div class="cg-busy cg-busy-backdrop cg-busy-backdrop-animation ng-show ng-scope"></div>
<!--
<div class="cg-busy cg-busy-animation cg-busy-default-wrapper">
<div class="cg-busy-default-sign">
<div class="cg-busy-default-spinner">
<div class="bar1"></div>
<div class="bar2"></div>
<div class="bar3"></div>
<div class="bar4"></div>
<div class="bar5"></div>
<div class="bar6"></div>
<div class="bar7"></div>
<div class="bar8"></div>
<div class="bar9"></div>
<div class="bar10"></div>
<div class="bar11"></div>
<div class="bar12"></div>
</div>
<div class="cg-busy-default-text">Updating form...</div>
</div>
</div> -->
<!-- <div class="cg-busy cg-busy-animation cg-busy-default-wrapper">
<div style="position: absolute; top: 0px; right: 0px;">
<div class="cg-busy-default-spinner">
<div class="bar1"></div>
<div class="bar2"></div>
<div class="bar3"></div>
<div class="bar4"></div>
<div class="bar5"></div>
<div class="bar6"></div>
<div class="bar7"></div>
<div class="bar8"></div>
<div class="bar9"></div>
<div class="bar10"></div>
<div class="bar11"></div>
<div class="bar12"></div>
</div>
<div class="cg-busy-default-text" style="">Updating form...</div>
</div>
</div> -->
<div class="cg-busy cg-busy-backdrop cg-busy-backdrop-animation ng-show ng-scope"></div>
<div class="cg-busy cg-busy-animation">
<div style="position: absolute; top: 0px; left: 0px; right: 0px; bottom: 0px;">
<div style="text-align: center; font-size: 20px;position: fixed; bottom: 0; left: 45px; background-color: gray; color: white; padding: 5px 15px 5px 10px;">Updating Form...</div>
</div>
</div>
</div>
</section>

View File

@ -0,0 +1,3 @@
<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>

View File

@ -0,0 +1,426 @@
<form class="row container" name="editForm" auto-save-form auto-save-watch="myform" auto-save-callback="update">
<div class="col-xs-2 col-sm-4 col-md-5 add-field">
<div class="row add-field-title">
<h3 class="col-md-12 hidden-sm hidden-xs">Click to Add New Field</h3>
<h4 class="col-sm-12 hidden-xs hidden-md hidden-lg">Add New Field</h5>
<h5 class="col-sm-12 hidden-sm hidden-md hidden-lg">Add Field</h5>
</div>
<div class="panel-group row" class="draggable" ng-model="addField.types">
<div class="col-xs-12 col-sm-12 col-md-6" ng-repeat="type in addField.types" style="padding-top:7.5px;">
<div class="panel panel-default" style="background-color:#f5f5f5;">
<div class="panel-heading" ng-click="addNewField(true, type.name)" style="cursor: pointer; font-size:14px;">
<span>
<field-icon-directive type-name="{{type.name}}">
</field-icon-directive>
</span>
<span class="hidden-xs" style="padding-left:0.3em;">{{type.value}}</span>
</div>
</div>
</div>
</div>
</div>
<div class="col-xs-10 col-sm-8 col-md-7 current-fields container">
<div class="row">
<div class="col-sm-12 col-md-10">
<div class="panel panel-default startPage">
<div class="panel-heading accordion-toggle collapsed" data-toggle="collapse" data-target="#collapseStart">
<h4 class="text-center">
Start Page
<span class="pull-right">
<i class="fa fa-chevron-right" ng-hide="startPage.isOpen">
</i>
<i class="fa fa-chevron-down" ng-show="startPage.isOpen">
</i>
</span>
</h4>
</div>
<div id="collapseStart" class="panel-collapse collapse">
<div class="panel-body">
<div class="row hidden-sm hidden-xs">
<div class="col-md-12">
<h4>Preview Start Page</h4>
</div>
<ul class="col-md-12 container" style="list-style:none;border:2px lightgray solid;">
<div class="field row text-center">
<div class="col-xs-12 text-center">
<h1>{{myform.startPage.introTitle}}</h1>
</div>
<div class="col-xs-10 col-xs-offset-1 text-left">
<p style="color:#ddd;">{{myform.startPage.introParagraph}}</p>
</div>
</div>
<div class="row form-actions" style="padding-bottom:3em; padding-left: 1em; padding-right: 1em;">
<p ng-repeat="button in myform.startPage.buttons" class="text-center" style="display:inline;">
<button class="btn btn-info" type="button" ng-style="{'background-color':button.bgColor, 'color':button.color}">
<a href="{{button.url}}" style="font-size: 1.6em; text-decoration: none; color: inherit;" >
{{button.text}}
</a>
</button>
</p>
</div>
<div class="row form-actions">
<p class="col-xs-3 col-xs-offset-3 text-center">
<button class="btn btn-info" type="button">
<a ng-click="exitstartPage()" style="color:white; font-size: 1.6em; text-decoration: none;">Continue to Form</a>
</button>
</p>
</div>
</ul>
<hr>
</div>
<div class="row">
<div class="col-xs-12">
<h4>Edit Start Page</h4>
<br>
</div>
</div>
<div class="row question">
<div class="col-md-4 col-sm-12">Intro Title:</div>
<div class="col-md-8 col-sm-12">
<input type="text"
ng-model="myform.startPage.introTitle"
name="introTitleStartPage"
value="{{myform.startPage.introTitle}}" required>
</div>
</div>
<div class="row question">
<div class="col-md-4 col-sm-12">Intro Paragraph:</div>
<div class="col-md-8 col-sm-12">
<textarea type="text"
ng-model="myform.startPage.introParagraph"
name="introParagraphStartPage"
value="{{myform.startPage.introParagraph}}"/>
</div>
</div>
<div class="row"><br><br></div>
<div class="row options buttons">
<div class="col-md-3 col-xs-12">Buttons:</div>
<div class="col-md-9 col-xs-12">
<div ng-repeat="button in myform.startPage.buttons" class="row" style="padding-bottom:1em;">
<div class="col-xs-5">
<span>Text</span>
<input type="text"
name="{{button.text}}_buttonText_startPage"
ng-model="button.text"
value="{{button.text}}"
placeholder="Button Text">
</div>
<div class="col-xs-5">
<span>Link</span>
<input type="text"
name="{{button.url}}_url_startPage"
ng-model="button.url"
value="{{button.url}}"
placeholder="http://aeouaou.com/aoeuoa">
</div>
<div class="col-xs-2">
<a class="btn btn-danger btn-mini right" type="button" ng-click="deleteButton(button)">
<i class="fa fa-trash-o"></i>
</a>
</div>
</div>
<div class="row"><br></div>
<div class="row">
<button class="btn btn-primary btn-small col-md-offset-6 col-md-6 col-sm-4 col-sm-offset-8 col-xs-4 col-xs-offset-8" type="button" ng-click="addButton()">
<i class="icon-plus icon-white"></i> Add Button
</button>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-sm-12 col-md-10"><hr></div>
</div>
<div class="row">
<div class="col-sm-12 col-md-10">
<accordion close-others="accordion.oneAtATime" ui-sortable="dropzone" ng-model="myform.form_fields" class="dropzone">
<accordion-group ng-repeat="field in myform.form_fields" is-open="accordion[$index].isOpen" on-finish-render="editFormFields" ng-if="!field.deletePreserved">
<accordion-heading>
<div class="handle">
<span class="pull-left" ng-switch="field.fieldType">
<field-icon-directive type-name="{{field.fieldType}}"></field-icon-directive>
</span>
<span style="padding-left:1.2em;">
{{field.title}}
<span ng-show="field.required">*</span>
</span>
<span class="pull-right">
<i class="fa fa-chevron-right" ng-hide="accordion[$index].isOpen">
</i>
<i class="fa fa-chevron-down" ng-show="accordion[$index].isOpen">
</i>
</span>
</div>
</accordion-heading>
<div class="accordion-edit container">
<div class="row hidden-sm hidden-xs">
<div class="col-md-12">
<h4>Preview Field</h4>
</div>
<ul class="col-md-12 container" style="list-style:none;border:2px lightgray solid;">
<field-directive field="field" validate="false">
</field-directive>
</ul>
<hr>
</div>
<div class="row">
<div class="col-xs-12">
<h4>Edit Field</h4>
<br>
</div>
</div>
<div class="row question">
<div class="col-md-4 col-sm-12">Question Title:</div>
<div class="col-md-8 col-sm-12">
<input type="text" ng-model="field.title" name="title{{field._id}}" value="{{field.title}}" required></div>
</div>
<div class="row"><br></div>
<div class="row description">
<div class="col-md-4 col-sm-12">Description:</div>
<div class="col-md-8 col-sm-12"><textarea type="text" ng-model="field.description" name="description{{field._id}}"value="{{field.description}}"></textarea> </div>
</div>
<div class="row" ng-show="showAddOptions(field)"><br></div>
<div class="row options" ng-show="showAddOptions(field)">
<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">
<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)">
<i class="icon-plus icon-white"></i> Add Option
</button>
</div>
</div>
</div>
<div class="row"><br></div>
<div class="row">
<div class="col-md-4 col-xs-12 field-title">Required:</div>
<div class="col-md-8 col-xs-12 field-input">
<label class="btn col-xs-5">
<input type="radio" ng-value="true" ng-model="field.required" name="required{{field._id}}"/>
<span> &nbsp; Yes</span>
</label>
<label class="btn col-xs-5 col-xs-offset-1">
<input type="radio" ng-value="false" ng-model="field.required" name="required{{field._id}}"/>
<span> &nbsp; No</span>
</label>
</div>
</div>
<div class="row">
<div class="col-md-4 col-xs-12 field-input">Disabled:</div>
<div class="col-md-8 col-xs-12 field-input">
<label class="btn col-xs-5">
<input type="radio" ng-value="true"
ng-model="field.disabled" name="disabled{{field._id}}"/>
<span> &nbsp; Yes</span>
</label>
<label class="btn col-xs-5 col-xs-offset-1">
<input type="radio" ng-value="false"
ng-model="field.disabled" name="disabled{{field._id}}"/>
<span> &nbsp; No</span>
</label>
</div>
</div>
<!-- <div class="row"><br><hr></div>
<div class="row">
<div class="col-sm-4 col-sm-offset-4">
<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>
</accordion-group>
<div class="panel panel-default" style="border-style: dashed; border-color: #a9a9a9;">
<div class="panel-heading">
<h4 class="panel-title text-center" style="color: #a9a9a9;">
Drag and Drop new fields here
</h4>
</div>
</div>
<hr>
<!-- <accordion-group is-open="endPage.isOpen" ng-if="myform.endPage.showStart">
<accordion-heading>
<div class="handle">
<h4 class="text-center">
End Page
<span class="pull-right">
<i class="fa fa-chevron-right" ng-hide="endPage.isOpen">
</i>
<i class="fa fa-chevron-down" ng-show="endPage.isOpen">
</i>
</span>
</h4>
</div>
</accordion-heading>
<div class="accordion-edit container">
<div class="row hidden-sm hidden-xs">
<div class="col-md-12">
<h4>Preview Field</h4>
</div>
<ul class="col-md-12 container" style="list-style:none;border:2px lightgray solid;">
<div class="field row text-center">
<div class="col-xs-12 text-center">
<h1>Welcome to {{myform.endPage.title}}</h1>
</div>
<div class="col-xs-10 col-xs-offset-1 text-center">
<p>{{form.endPage.description}}</p>
</div>
</div>
<div class="row form-actions">
<p ng-repeat="button in form.endPage.buttons" class="col-xs-6 col-xs-offset-3 text-center">
<button class="btn btn-info" type="button" ng-style="{background-color:button.bgColor; color:button.color;}">
<a href="{{button.url}}" style="font-size: 1.6em; text-decoration: none;"> {{button.title}}</a>
</button>
</p>
</div>
<div class="row form-actions">
<p class="col-xs-6 col-xs-offset-3 text-center">
<button class="btn btn-info" type="button">
<a ng-click="exitEndPage()" style="color:white; font-size: 1.6em; text-decoration: none;">Continue to Form</a>
</button>
</p>
</div>
</ul>
<hr>
</div>
<div class="row">
<div class="col-xs-12">
<h4>Edit endPage</h4>
<br>
</div>
</div>
<div class="row question">
<div class="col-md-4 col-sm-12">Intro Text:</div>
<div class="col-md-8 col-sm-12">
<input type="text"
ng-model="myform.endPage.introText"
name="introTextEndPage"
value="{{myform.endPage.introText}}" required>
</div>
</div>
<div class="row"><br></div>
<div class="row options">
<div class="col-md-4 col-xs-12">Buttons:</div>
<div class="col-md-8 col-xs-12">
<div ng-repeat="button in myform.endPage.buttons" class="row">
<input type="text"
name="{{button.buttonText}}_buttonText_endPage"
ng-model="button.buttonText"
value="{{button.buttonText}}"
placeholder="My Button"
class="col-xs-4">
<input type="text"
name="{{button.url}}_url_endPage"
ng-model="button.url"
value="{{button.url}}"
placeholder="http://aeouaou.com/aoeuoa"
class="col-xs-6">
<a class="btn btn-danger btn-mini right" type="button" ng-click="deleteButton(button)" class="col-xs-2">
<i class="fa fa-trash-o"></i>
</a>
</div>
<div class="row"><br></div>
<div class="row">
<button class="btn btn-primary btn-small ol-md-12 col-sm-6 col-sm-offset-6 col-xs-6 col-xs-offset-6" type="button" ng-click="addButton()">
<i class="icon-plus icon-white"></i> Add Button
</button>
</div>
</div>
</div>
</div>
</accordion-group> -->
</accordion>
</div>
<div class="col-md-1 hidden-xs hidden-sm" style="padding:0 5px;" >
<div class="panel-group tool-panel text-center">
<div class="panel panel-default" ng-repeat="field in myform.form_fields" ng-if="!field.deletePreserved">
<div class="panel-heading" style="padding: 10px 10px; height: 37px;" ng-click="deleteField(field.$$hashKey)">
<span class="text-center">
<a href="" class="fa fa-trash-o"></a>
</span>
</div>
</div>
</div>
</div>
<div class="col-md-1 hidden-xs hidden-sm" style="padding:0 5px;">
<div class="panel-group tool-panel text-center">
<div class="panel panel-default" ng-repeat="field in myform.form_fields" ng-if="!field.deletePreserved">
<div class="panel-heading" style="padding: 10px 10px; height: 37px;" ng-click="duplicateField($index)">
<span class="text-center">
<a href="" class="fa fa-files-o"></a>
</span>
</div>
</div>
</div>
</div>
</div>
</div>
</form>

View File

@ -1,296 +0,0 @@
<form class="row container" name="editForm" auto-save-form auto-save-watch="myform.form_fields" auto-save-callback="update">
<div class="col-xs-2 col-sm-4 col-md-5 add-field" id="hello">
<div class="row add-field-title">
<h3 class="col-md-12 hidden-sm hidden-xs">Click to Add New Field</h3>
<h4 class="col-sm-12 hidden-xs hidden-md hidden-lg">Add New Field</h5>
<h5 class="col-sm-12 hidden-sm hidden-md hidden-lg">Add Field</h5>
</div>
<div class="panel-group row" class="draggable" ng-model="addField.types">
<div class="col-xs-12 col-sm-12 col-md-6" ng-repeat="type in addField.types">
<div class="panel panel-default" style="background-color:#f5f5f5;">
<div class="panel-heading" ng-click="addNewField(true, type.name)" style="cursor: pointer; font-size:14px;">
<span>
<field-icon-directive type-name="{{type.name}}"></field-icon-directive>
</span>
<span class="hidden-xs" style="padding-left:0.3em;">{{type.value}}</span>
</div>
</div>
</div>
</div>
</div>
<div class="col-xs-10 col-sm-8 col-md-7 current-fields container">
<div class="row">
<div class="col-sm-12 col-md-10">
<accordion close-others="accordion.oneAtATime" ui-sortable="dropzone" ng-model="myform.form_fields" class="dropzone">
<!-- <accordion-group is-open="accordion[$index].isOpen" ng-if="myform.startPage.showStart">
<accordion-heading>
<div class="handle">
<span style="padding-left:1.2em;">
Start Page
<span ng-show="field.required">*</span>
</span>
<span class="pull-right">
<i class="fa fa-chevron-right" ng-hide="accordion[$index].isOpen">
</i>
<i class="fa fa-chevron-down" ng-show="accordion[$index].isOpen">
</i>
</span>
</div>
</accordion-heading>
<div class="accordion-edit container">
<div class="row hidden-sm hidden-xs">
<div class="col-md-12">
<h4>Preview Field</h4>
</div>
<ul class="col-md-12 container" style="list-style:none;border:2px lightgray solid;">
<div class="field row text-center">
<div class="col-xs-12 text-center">
<h1>Welcome to {{myform.title}}</h1>
</div>
<div class="col-xs-10 col-xs-offset-1 text-center">
<p>{{form.startPage.introText}}</p>
</div>
</div>
<div class="row form-actions">
<p ng-repeat="button in form.startPage.buttons" class="col-xs-6 col-xs-offset-3 text-center">
<button class="btn btn-info" type="button" ng-style="{background-color:button.backgroundColor; color:button.color;}">
<a href="{{button.url}}" style="font-size: 1.6em; text-decoration: none;"> {{button.buttonText}}</a>
</button>
</p>
</div>
<div class="row form-actions">
<p class="col-xs-6 col-xs-offset-3 text-center">
<button class="btn btn-info" type="button">
<a ng-click="exitStartPage()" style="color:white; font-size: 1.6em; text-decoration: none;">Continue to Form</a>
</button>
</p>
</div>
</ul>
<hr>
</div>
<div class="row">
<div class="col-xs-12">
<h4>Edit StartPage</h4>
<br>
</div>
</div>
<div class="row question">
<div class="col-md-4 col-sm-12">Intro Text:</div>
<div class="col-md-8 col-sm-12">
<input type="text"
ng-model="myform.startPage.introText"
name="introTextStartPage"
value="{{myform.startPage.introText}}" required>
</div>
</div>
<div class="row"><br></div>
<div class="row options">
<div class="col-md-4 col-xs-12">Buttons:</div>
<div class="col-md-8 col-xs-12">
<div ng-repeat="button in myform.startPage.buttons" class="row">
<input type="text"
name="{{button.buttonText}}_buttonText_StartPage"
ng-model="button.buttonText"
value="{{button.buttonText}}"
placeholder="My Button"
class="col-xs-4">
<input type="text"
name="{{button.url}}_url_StartPage"
ng-model="button.url"
value="{{button.url}}"
placeholder="http://aeouaou.com/aoeuoa"
class="col-xs-6">
<a class="btn btn-danger btn-mini right" type="button" ng-click="deleteButton(button)" class="col-xs-2">
<i class="fa fa-trash-o"></i>
</a>
</div>
<div class="row">
<button class="btn btn-primary btn-small ol-md-12 col-sm-6 col-sm-offset-6 col-xs-6 col-xs-offset-6" type="button" ng-click="addButton(field)">
<i class="icon-plus icon-white"></i> Add Button
</button>
</div>
</div>
</div>
</div>
</accordion-group> -->
<accordion-group ng-repeat="field in myform.form_fields" is-open="accordion[$index].isOpen" on-finish-render="editFormFields" ng-if="!field.deletePreserved">
<accordion-heading>
<div class="handle">
<span class="pull-left" ng-switch="field.fieldType">
<field-icon-directive type-name="{{field.fieldType}}"></field-icon-directive>
</span>
<span style="padding-left:1.2em;">
{{field.title}}
<span ng-show="field.required">*</span>
</span>
<span class="pull-right">
<i class="fa fa-chevron-right" ng-hide="accordion[$index].isOpen">
</i>
<i class="fa fa-chevron-down" ng-show="accordion[$index].isOpen">
</i>
</span>
</div>
</accordion-heading>
<div class="accordion-edit container">
<div class="row hidden-sm hidden-xs">
<div class="col-md-12">
<h4>Preview Field</h4>
</div>
<ul class="col-md-12 container" style="list-style:none;border:2px lightgray solid;">
<field-directive field="field" validate="false">
</field-directive>
</ul>
<hr>
</div>
<div class="row">
<div class="col-xs-12">
<h4>Edit Field</h4>
<br>
</div>
</div>
<div class="row question">
<div class="col-md-4 col-sm-12">Question Title:</div>
<div class="col-md-8 col-sm-12">
<input type="text" ng-model="field.title" name="title{{field._id}}" value="{{field.title}}" required></div>
</div>
<div class="row"><br></div>
<div class="row description">
<div class="col-md-4 col-sm-12">Description:</div>
<div class="col-md-8 col-sm-12"><textarea type="text" ng-model="field.description" name="description{{field._id}}"value="{{field.description}}"></textarea> </div>
</div>
<div class="row" ng-show="showAddOptions(field)"><br></div>
<div class="row options" ng-show="showAddOptions(field)">
<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">
<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)">
<i class="icon-plus icon-white"></i> Add Option
</button>
</div>
</div>
</div>
<div class="row"><br></div>
<div class="row">
<div class="col-md-4 col-xs-12 field-title">Required:</div>
<div class="col-md-8 col-xs-12 field-input">
<label class="btn col-xs-5">
<input type="radio" ng-value="true" ng-model="field.required" name="required{{field._id}}"/>
<span> &nbsp; Yes</span>
</label>
<label class="btn col-xs-5 col-xs-offset-1">
<input type="radio" ng-value="false" ng-model="field.required" name="required{{field._id}}"/>
<span> &nbsp; No</span>
</label>
</div>
</div>
<div class="row">
<div class="col-md-4 col-xs-12 field-input">Disabled:</div>
<div class="col-md-8 col-xs-12 field-input">
<label class="btn col-xs-5">
<input type="radio" ng-value="true"
ng-model="field.disabled" name="disabled{{field._id}}"/>
<span> &nbsp; Yes</span>
</label>
<label class="btn col-xs-5 col-xs-offset-1">
<input type="radio" ng-value="false"
ng-model="field.disabled" name="disabled{{field._id}}"/>
<span> &nbsp; No</span>
</label>
</div>
</div>
<!-- <div class="row"><br><hr></div>
<div class="row">
<div class="col-sm-4 col-sm-offset-4">
<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>
</accordion-group>
<div class="panel panel-default" style="border-style: dashed; border-color: #a9a9a9;">
<div class="panel-heading">
<h4 class="panel-title text-center" style="color: #a9a9a9;">
Drag and Drop new fields here
</h4>
</div>
</div>
</accordion>
</div>
<div class="col-md-1 hidden-xs hidden-sm" style="padding:0 5px;" >
<div class="panel-group tool-panel text-center">
<div class="panel panel-default" ng-repeat="field in myform.form_fields" ng-if="!field.deletePreserved">
<div class="panel-heading" style="padding: 10px 10px; height: 37px;" ng-click="deleteField(field.$$hashKey)">
<span class="text-center">
<a href="" class="fa fa-trash-o"></a>
</span>
</div>
</div>
</div>
</div>
<div class="col-md-1 hidden-xs hidden-sm" style="padding:0 5px;">
<div class="panel-group tool-panel text-center">
<div class="panel panel-default" ng-repeat="field in myform.form_fields" ng-if="!field.deletePreserved">
<div class="panel-heading" style="padding: 10px 10px; height: 37px;" ng-click="duplicateField($index)">
<span class="text-center">
<a href="" class="fa fa-files-o"></a>
</span>
</div>
</div>
</div>
</div>
</div>
</div>
</form>

View File

@ -0,0 +1,80 @@
<div class="submissions-table row container">
<div class="row">
<div class="col-xs-2">
<button class="btn btn-danger" ng-click="deleteSelectedSubmissions()" ng-disabled="!isAtLeastOneChecked();">
<i class="fa fa-trash-o"></i> Delete Selected
</button>
</div>
<div class="col-xs-2 col-xs-offset-4 text-right">
<button class="btn btn-default" ng-click="exportSubmissions('xls')">
<small>Export to Excel</small>
</button>
</div>
<div class="col-md-2 text-right">
<button class="btn btn-default" ng-click="exportSubmissions('csv')">
<small>Export to CSV</small>
</button>
</div>
<div class="col-md-2 text-right">
<button class="btn btn-default" ng-click="exportSubmissions('json')">
<small>Export to JSON</small>
</button>
</div>
</div>
<div class="row table-outer">
<div class="col-xs-12">
<table id="table-submission-data" class="table table-striped table-hover table-condensed">
<thead>
<tr>
<th>
<input ng-model="table.masterChecker" ng-change="toggleAllCheckers()" type="checkbox"/>
</th>
<th>#</th>
<th data-ng-repeat="(key, value) in myform.form_fields">
{{value.title}}
</th>
<th>
Percentage Complete
</th>
<th>
Time Elapsed
</th>
<th>
Date Submitted (UTC)
</th>
<th ng-if="myform.autofillPDFs">
Generated PDF
</th>
</tr>
</thead>
<tbody>
<tr data-ng-repeat="row in table.rows" ng-click="rowClicked($index)" ng-class="{selected: row.selected === true}">
<td>
<input ng-model="row.selected" type="checkbox"/>
</td>
<th class="scope">
{{$index+1}}
</th>
<td data-ng-repeat="(key, value) in row.form_fields">
{{value.fieldValue}}
</td>
<td>
{{row.percentageComplete}}%
</td>
<td>
{{row.timeElapsed}}
</td>
<td>
{{row.created | date:'yyyy-MM-dd HH:mm:ss'}}
</td>
<td ng-if="row.pdf">
<a href="{{row.pdfFilePath}}" download="{{row.pdf.name}}" target="_self">Generated PDF</a>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>

View File

@ -21,7 +21,7 @@
<div class="row form-actions">
<p class="col-xs-6 col-xs-offset-3 text-center">
<button class="btn btn-info" type="button">
<a ng-click="exitStartPage()" style="font-size: 1.6em; text-decoration: none;">Continue to Form</a>
<a ng-click="exitstartPage()" style="font-size: 1.6em; text-decoration: none;">Continue to Form</a>
</button>
</p>
</div>

View File

@ -1,8 +1,7 @@
'use strict';
angular.module('users').factory('Auth', function($window) {
var userState =
{
var userState = {
isLoggedIn: false
};

View File

@ -1,172 +1,172 @@
'use strict';
// 'use strict';
(function() {
// (function() {
// Principal controller Spec for E2E Tests
describe('AuthenticationController E2E Tests', 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');
});
// 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');
});
// 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'));
// //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');
// 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');
});
// //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
describe('AuthenticationController Unit Tests', function() {
// Initialize global variables
var AuthenticationController,
scope,
$httpBackend,
$stateParams,
$location;
// // Principal controller Spec
// describe('AuthenticationController Unit Tests', function() {
// // Initialize global variables
// var AuthenticationController,
// scope,
// $httpBackend,
// $stateParams,
// $location;
beforeEach(function() {
jasmine.addMatchers({
toEqualData: function(util, customEqualityTesters) {
return {
compare: function(actual, expected) {
return {
pass: angular.equals(actual, expected)
};
}
};
}
});
});
// beforeEach(function() {
// jasmine.addMatchers({
// toEqualData: function(util, customEqualityTesters) {
// return {
// compare: function(actual, expected) {
// return {
// pass: angular.equals(actual, expected)
// };
// }
// };
// }
// });
// });
// Load the main application module
beforeEach(module(ApplicationConfiguration.applicationModuleName));
// // Load the main application module
// beforeEach(module(ApplicationConfiguration.applicationModuleName));
// 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.
beforeEach(inject(function($controller, $rootScope, _$location_, _$stateParams_, _$httpBackend_) {
// Set a new global scope
scope = $rootScope.$new();
// // 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.
// beforeEach(inject(function($controller, $rootScope, _$location_, _$stateParams_, _$httpBackend_) {
// // Set a new global scope
// scope = $rootScope.$new();
// Point global variables to injected services
$stateParams = _$stateParams_;
$httpBackend = _$httpBackend_;
$location = _$location_;
// // Point global variables to injected services
// $stateParams = _$stateParams_;
// $httpBackend = _$httpBackend_;
// $location = _$location_;
// Initialize the Principal controller
AuthenticationController = $controller('AuthenticationController', {
$scope: scope
});
}));
// // Initialize the Principal controller
// AuthenticationController = $controller('AuthenticationController', {
// $scope: scope
// });
// }));
it('$scope.signin() should login with a correct user and password', function() {
// Test expected GET request
$httpBackend.when('POST', '/auth/signin').respond(200, 'Fred');
// it('$scope.signin() should login with a correct user and password', function() {
// // Test expected GET request
// $httpBackend.when('POST', '/auth/signin').respond(200, 'Fred');
scope.signin();
$httpBackend.flush();
// scope.signin();
// $httpBackend.flush();
// Test scope value
expect(scope.authentication.user).toEqual('Fred');
expect($location.url()).toEqual('/');
});
// // Test scope value
// expect(scope.authentication.user).toEqual('Fred');
// expect($location.url()).toEqual('/');
// });
it('$scope.signin() should fail to log in with nothing', function() {
// Test expected POST request
$httpBackend.expectPOST('/auth/signin').respond(400, {
'message': 'Missing credentials'
});
// it('$scope.signin() should fail to log in with nothing', function() {
// // Test expected POST request
// $httpBackend.expectPOST('/auth/signin').respond(400, {
// 'message': 'Missing credentials'
// });
scope.signin();
$httpBackend.flush();
// scope.signin();
// $httpBackend.flush();
// Test scope value
expect(scope.error).toEqual('Missing credentials');
});
// // Test scope value
// expect(scope.error).toEqual('Missing credentials');
// });
it('$scope.signin() should fail to log in with wrong credentials', function() {
// Foo/Bar combo assumed to not exist
scope.authentication.user = 'Foo';
scope.credentials = 'Bar';
// it('$scope.signin() should fail to log in with wrong credentials', function() {
// // Foo/Bar combo assumed to not exist
// scope.authentication.user = 'Foo';
// scope.credentials = 'Bar';
// Test expected POST request
$httpBackend.expectPOST('/auth/signin').respond(400, {
'message': 'Unknown user'
});
// // Test expected POST request
// $httpBackend.expectPOST('/auth/signin').respond(400, {
// 'message': 'Unknown user'
// });
scope.signin();
$httpBackend.flush();
// scope.signin();
// $httpBackend.flush();
// Test scope value
expect(scope.error).toEqual('Unknown user');
});
// // Test scope value
// expect(scope.error).toEqual('Unknown user');
// });
it('$scope.signup() should register with correct data', function() {
// Test expected GET request
scope.authentication.user = 'Fred';
$httpBackend.when('POST', '/auth/signup').respond(200, 'Fred');
// it('$scope.signup() should register with correct data', function() {
// // Test expected GET request
// scope.authentication.user = 'Fred';
// $httpBackend.when('POST', '/auth/signup').respond(200, 'Fred');
scope.signup();
$httpBackend.flush();
// scope.signup();
// $httpBackend.flush();
// test scope value
expect(scope.authentication.user).toBe('Fred');
expect(scope.error).toEqual(undefined);
expect($location.url()).toBe('/');
});
// // test scope value
// expect(scope.authentication.user).toBe('Fred');
// expect(scope.error).toEqual(undefined);
// expect($location.url()).toBe('/');
// });
it('$scope.signup() should fail to register with duplicate Username', function() {
// Test expected POST request
$httpBackend.when('POST', '/auth/signup').respond(400, {
'message': 'Username already exists'
});
// it('$scope.signup() should fail to register with duplicate Username', function() {
// // Test expected POST request
// $httpBackend.when('POST', '/auth/signup').respond(400, {
// 'message': 'Username already exists'
// });
scope.signup();
$httpBackend.flush();
// scope.signup();
// $httpBackend.flush();
// Test scope value
expect(scope.error).toBe('Username already exists');
});
});
}());
// // Test scope value
// expect(scope.error).toBe('Username already exists');
// });
// });
// }());