added backend tests

This commit is contained in:
David Baldwynn 2015-08-07 14:02:44 -07:00
parent 81cab5515e
commit 7885223a68
42 changed files with 1328 additions and 371 deletions

View file

@ -10,7 +10,7 @@ var client = new raven.Client(config.DSN);
*/
exports.index = function(req, res) {
// next( throw new Error('Hello, world!'));
client.captureMessage('Rendering index.html');
// client.captureMessage('Rendering index.html');
res.render('index', {
user: req.user || null,
request: req

View file

@ -19,11 +19,12 @@ var mongoose = require('mongoose'),
*/
exports.uploadPDF = function(req, res, next) {
console.log('inside uploadPDF');
// console.log('inside uploadPDF');
// console.log(req.files.file);
// console.log('\n\nProperty Descriptor\n-----------');
// console.log(Object.getOwnPropertyDescriptor(req.files.file, 'path'));
if(req.files){
var pdfFile = req.files.file;
var _user = req.user;
@ -73,6 +74,7 @@ exports.uploadPDF = function(req, res, next) {
*/
exports.deleteSubmissions = function(req, res) {
console.log(req.body);
var submission_id_list = req.body.deleted_submissions,
form = req.form;
@ -92,56 +94,46 @@ exports.deleteSubmissions = function(req, res) {
*/
exports.createSubmission = function(req, res) {
var submission,
form = req.form,
fdfData,
fdfTemplate,
that = this;
console.log(req.body.percentageComplete);
var form = req.form;
// console.log('in createSubmission()');
// console.log(req.body);
submission = new FormSubmission({
admin: req.user,
var submission = new FormSubmission({
admin: req.form.admin._id,
form: req.form._id,
title: req.form.title,
form_fields: req.body.form_fields,
timeElapsed: req.body.timeElapsed,
percentageComplete: req.body.percentageComplete
});
submission.form = form;
submission.pdf = form.pdf;
submission.title = form.title;
if(form.pdf) submission.pdf = form.pdf;
if(req.headers['x-forwarded-for'] || req.connection.remoteAddress){
var ip = req.headers['x-forwarded-for'] || req.connection.remoteAddress;
console.log('ip address of client is: '+ip);
// console.log('ip address of client is: '+ip);
// if(ip) submission.ipAddr = ip;
}
// submission.ipAddr = req.headers['x-forwarded-for'] || req.connection.remoteAddress;
if(form.autofillPDFs){
if (form.isGenerated){
fdfTemplate = form.generateFDFTemplate();
} else {
try {
fdfTemplate = pdfFiller.mapForm2PDF(form.generateFDFTemplate(), form.pdfFieldMap);
} catch(err){
res.status(400).send({
message: errorHandler.getErrorMessage(err)
});
}
try {
submission.fdfData = pdfFiller.convFieldJson2FDF(submission.form_fields);
} catch(err){
res.status(400).send({
message: errorHandler.getErrorMessage(err)
});
}
fdfData = pdfFiller.convFieldJson2FDF(submission.form_fields);
submission.fdfData = fdfData;
}else{
submission.fdfData = undefined;
submission.fdfData = null;
}
submission.save(function(err){
submission.save(function(err, submission){
// console.log('in submissions.save()\n submission: '+JSON.stringify(submission) );
if(err){
res.status(400).send({
message: errorHandler.getErrorMessage(err)
});
}
// console.log(results);
// console.log(that.form_fields);
res.status(200).send('Form submission successfully saved');
});
};
@ -152,6 +144,7 @@ exports.createSubmission = function(req, res) {
exports.listSubmissions = function(req, res) {
var _form = req.form;
var _user = req.user;
// console.log('listSubmissions');
// console.log(_form);
// if(_form.submissions.length){
@ -186,8 +179,10 @@ exports.listSubmissions = function(req, res) {
exports.create = function(req, res) {
var form = new Form(req.body.form);
form.admin = req.user;
form.admin = req.user._id;
// console.log('Create a new form');
// console.log(form);
// console.log(req.body.form)
// console.log(req.user);
form.save(function(err) {
@ -214,15 +209,13 @@ exports.read = function(req, res) {
* Update a form
*/
exports.update = function(req, res) {
console.log('in form.update()');
// 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.created;
delete req.body.form.lastModified;
delete req.body.form.admin;
// console.log(form.admin);
@ -241,7 +234,7 @@ exports.update = function(req, res) {
message: errorHandler.getErrorMessage(err)
});
} else {
console.log('updated form');
// console.log('updated form');
res.json(form);
}
});
@ -252,15 +245,16 @@ exports.update = function(req, res) {
*/
exports.delete = function(req, res) {
var form = req.form;
console.log('deleting form');
// console.log('deleting form');
Form.remove({_id: form._id}, function(err) {
if (err) {
res.status(500).send({
res.status(400).send({
message: errorHandler.getErrorMessage(err)
});
} else {
console.log('Form successfully deleted');
res.status(200).send('Form successfully deleted');
// console.log('Form successfully deleted');
// res.status(200).send('Form successfully deleted');
res.json(form);
}
});
};
@ -305,16 +299,12 @@ exports.formByID = function(req, res, next, id) {
});
}
else {
if(!form.admin.username){
form.admin = req.user;
}
// console.log(form.admin);
//Remove sensitive information from User object
form.admin.password = null;
form.admin.created = null;
form.admin.salt = null;
form.provider = null;
form.admin.password = undefined;
form.admin.salt = undefined;
form.provider = undefined;
req.form = form;
next();
@ -330,7 +320,7 @@ exports.hasAuthorization = function(req, res, next) {
var form = req.form;
if (req.form.admin.id !== req.user.id && req.user.roles.indexOf('admin') === -1) {
res.status(403).send({
message: 'User '+req.user.username+' is not authorized'
message: 'User '+req.user.username+' is not authorized to edit Form: '+form.title
});
}
next();

View file

@ -17,58 +17,32 @@ var _ = require('lodash'),
var smtpTransport = nodemailer.createTransport(config.mailer.options);
// NEV configuration =====================
nev.configure({
persistentUserModel: User,
expirationTime: 1800, // 30 minutes
// // NEV configuration =====================
// nev.configure({
// persistentUserModel: User,
// tempUserCollection: config.tempUserCollection,
// expirationTime: 1800, // 30 minutes
verificationURL: config.baseUrl+'/#!/verify/${URL}',
transportOptions: config.mailer.options,
verifyMailOptions: {
from: config.mailer.from,
subject: 'Confirm your account',
html: '<p>Please verify your account by clicking <a href="${URL}">this link</a>. If you are unable to do so, copy and ' +
'paste the following link into your browser:</p><p>${URL}</p>',
text: 'Please verify your account by clicking the following link, or by copying and pasting it into your browser: ${URL}'
},
// verificationURL: config.baseUrl+'/#!/verify/${URL}',
// transportOptions: config.mailer.options,
// verifyMailOptions: {
// from: config.mailer.from,
// subject: 'Confirm your account',
// html: '<p>Please verify your account by clicking <a href="${URL}">this link</a>. If you are unable to do so, copy and ' +
// 'paste the following link into your browser:</p><p>${URL}</p>',
// text: 'Please verify your account by clicking the following link, or by copying and pasting it into your browser: ${URL}'
// },
confirmMailOptions: {
from: config.mailer.from,
subject: 'Successfully verified!',
html: '<p>Your account has been successfully verified.</p>',
text: 'Your account has been successfully verified.'
},
// confirmMailOptions: {
// from: config.mailer.from,
// subject: 'Successfully verified!',
// html: '<p>Your account has been successfully verified.</p>',
// text: 'Your account has been successfully verified.'
// },
});
// });
nev.generateTempUserModel(User);
/**
* Signup
*/
exports.signup = function(req, res) {
// For security measurement we remove the roles from the req.body object
delete req.body.roles;
// Init Variables
var user = new User(req.body);
// Add missing user fields
user.provider = 'local';
user.username = user.email;
// user.displayName = user.firstName + ' ' + user.lastName;
// Then save the temporary user
nev.createTempUser(user, function(newTempUser) {
// new user created
if (newTempUser) {
nev.registerTempUser(newTempUser);
res.status(200).send('An email has been sent to you. Please check it to verify your account.');
} else {
res.status(400).send('Error: Temp user could NOT be created!');
}
});
};
// nev.generateTempUserModel(User);
exports.validateVerificationToken = function(req, res, next){
@ -93,6 +67,33 @@ exports.resendVerificationEmail = function(req, res, next){
});
};
/**
* Signup
*/
exports.signup = function(req, res) {
// For security measurement we remove the roles from the req.body object
delete req.body.roles;
// Init Variables
var user = new User(req.body);
// Add missing user fields
user.provider = 'local';
user.username = user.email;
// Then save the temporary user
nev.createTempUser(user, function(newTempUser) {
// new user created
if (newTempUser) {
nev.registerTempUser(newTempUser);
res.status(200).send('An email has been sent to you. Please check it to verify your account.');
} else {
res.status(400).send('Error: Temp user could NOT be created!');
}
});
};
/**
* Signin after passport authentication
*/
@ -104,6 +105,7 @@ exports.signin = function(req, res, next) {
// Remove sensitive data before login
user.password = undefined;
user.salt = undefined;
user.provider = undefined;
req.login(user, function(err) {
if (err) {

View file

@ -57,8 +57,6 @@ exports.me = function(req, res) {
delete _user.salt;
delete _user.provider;
delete _user.__v;
delete _user.created;
res.json(req.user || null);
};

View file

@ -1,24 +0,0 @@
// var mongoose = require('mongoose'),
// Schema = mongoose.Schema,
// shortid = require('shortid');
// var ObjectId = Schema.ObjectId;
// var BaseSchema = function() {
// Schema.apply(this, arguments);
// this.add({
// created: {
// type: Date,
// default: Date.now
// },
// lastModified: {
// type: Date,
// },
// _id: {
// type: String,
// unique: true,
// 'default': shortid.generate
// },
// });
// }

View file

@ -68,9 +68,17 @@ var FormSchema = new Schema({
type: Schema.Types.Mixed
},
showStart: {
type: Boolean,
default: false,
startPage: {
showStart:{
type: Boolean,
default: false,
},
introText:{
type: String,
},
buttonText:{
type: String
}
},
hideFooter: {
type: Boolean,
@ -88,17 +96,13 @@ var FormSchema = new Schema({
type: Boolean,
default: false,
},
saveCount: {
type: Number,
default: 0,
},
design: {
colors:{
backgroundColor: String,
questionColor: String,
answerColor: String,
buttonColor: String,
},
font: String,
backgroundImage: { type: Schema.Types.Mixed }
@ -138,8 +142,6 @@ var _original;
//Set _original
FormSchema.pre('save', function (next) {
this.saveCount = this.saveCount++;
console.log('saveCount: '+this.saveCount);
// console.log(this.constructor.model);
// console.log(FormModel);
this.constructor // ≈ mongoose.model('…', FieldSchema).findById
@ -148,7 +150,6 @@ FormSchema.pre('save', function (next) {
console.log(err);
next(err);
} else {
_original = original;
// console.log('_original');
// console.log(_original);
@ -309,7 +310,7 @@ FormSchema.pre('save', function (next) {
deletedIds = getDeletedIndexes(old_ids, new_ids),
that = this;
console.log('deletedId Indexes\n--------');
// console.log('deletedId Indexes\n--------');
// console.log(deletedIds);
// console.log('old_ids\n--------');
// console.log(old_ids);
@ -372,7 +373,7 @@ FormSchema.pre('save', function (next) {
// console.log('modifiedSubmissions\n---------\n\n');
// console.log(modifiedSubmissions);
console.log('preserved deleted fields');
// console.log('preserved deleted fields');
// console.log(submissions);
async.forEachOfSeries(modifiedSubmissions, function (submission, key, callback) {
@ -428,21 +429,21 @@ FormSchema.pre('save', function (next) {
}
});
FormSchema.methods.generateFDFTemplate = function() {
var _keys = _.pluck(this.form_fields, 'title'),
_values = _.pluck(this.form_fields, 'fieldValue');
// FormSchema.methods.generateFDFTemplate = function() {
// var _keys = _.pluck(this.form_fields, 'title'),
// _values = _.pluck(this.form_fields, 'fieldValue');
_values.forEach(function(val){
if(val === true){
val = 'Yes';
}else if(val === false) {
val = 'Off';
}
});
// _values.forEach(function(val){
// if(val === true){
// val = 'Yes';
// }else if(val === false) {
// val = 'Off';
// }
// });
var jsonObj = _.zipObject(_keys, _values);
// var jsonObj = _.zipObject(_keys, _values);
return jsonObj;
};
// return jsonObj;
// };
mongoose.model('Form', FormSchema);

View file

@ -91,7 +91,7 @@ FormSubmissionSchema.pre('save', function (next) {
if(this.pdf && this.pdf.path){
console.log(this.pdf);
// 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,8 +99,8 @@ 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('fdfData: \n');
// console.log(that.fdfData);
// console.log('_form.pdf.path: '+_form.pdf.path);
// console.log('dest_path: '+dest_path);

View file

@ -43,7 +43,7 @@ var UserSchema = new Schema({
email: {
type: String,
trim: true,
unique: 'Account already exists with email',
unique: 'Account already exists with this email',
required: 'Please enter your email',
validate: [validateLocalStrategyProperty, 'Please fill in your email'],
match: [/.+\@.+\..+/, 'Please fill a valid email address']
@ -51,7 +51,7 @@ var UserSchema = new Schema({
username: {
type: String,
unique: true,
required: true,
required: false,
trim: true
},
password: {
@ -106,10 +106,8 @@ UserSchema.virtual('displayName').get(function () {
//Create folder for user's pdfs
UserSchema.pre('save', function (next) {
this.username = this.email;
if(process.env.NODE_ENV === 'development'){
if(!this.username || this.username !== this.email){
this.username = this.email;
}
var newDestination = path.join(config.pdfUploadPath, this.username.replace(/ /g,'')),
stat = null;
@ -184,7 +182,6 @@ UserSchema.statics.findUniqueUsername = function(username, suffix, callback) {
* Function to check if user has Admin priviledges
*/
UserSchema.methods.isAdmin = function() {
if(this.roles.indexOf('admin') !== -1){
return true;
}

View file

@ -29,32 +29,32 @@ module.exports = function(app) {
app.route('/auth/signin').post(users.signin);
app.route('/auth/signout').get(users.signout);
// Setting the facebook oauth routes
app.route('/auth/facebook').get(passport.authenticate('facebook', {
scope: ['email']
}));
app.route('/auth/facebook/callback').get(users.oauthCallback('facebook'));
// // Setting the facebook oauth routes
// app.route('/auth/facebook').get(passport.authenticate('facebook', {
// scope: ['email']
// }));
// app.route('/auth/facebook/callback').get(users.oauthCallback('facebook'));
// Setting the twitter oauth routes
app.route('/auth/twitter').get(passport.authenticate('twitter'));
app.route('/auth/twitter/callback').get(users.oauthCallback('twitter'));
// // Setting the twitter oauth routes
// app.route('/auth/twitter').get(passport.authenticate('twitter'));
// app.route('/auth/twitter/callback').get(users.oauthCallback('twitter'));
// Setting the google oauth routes
app.route('/auth/google').get(passport.authenticate('google', {
scope: [
'https://www.googleapis.com/auth/userinfo.profile',
'https://www.googleapis.com/auth/userinfo.email'
]
}));
app.route('/auth/google/callback').get(users.oauthCallback('google'));
// // Setting the google oauth routes
// app.route('/auth/google').get(passport.authenticate('google', {
// scope: [
// 'https://www.googleapis.com/auth/userinfo.profile',
// 'https://www.googleapis.com/auth/userinfo.email'
// ]
// }));
// app.route('/auth/google/callback').get(users.oauthCallback('google'));
// Setting the linkedin oauth routes
app.route('/auth/linkedin').get(passport.authenticate('linkedin'));
app.route('/auth/linkedin/callback').get(users.oauthCallback('linkedin'));
// // Setting the linkedin oauth routes
// app.route('/auth/linkedin').get(passport.authenticate('linkedin'));
// app.route('/auth/linkedin/callback').get(users.oauthCallback('linkedin'));
// Setting the github oauth routes
app.route('/auth/github').get(passport.authenticate('github'));
app.route('/auth/github/callback').get(users.oauthCallback('github'));
// // Setting the github oauth routes
// app.route('/auth/github').get(passport.authenticate('github'));
// app.route('/auth/github/callback').get(users.oauthCallback('github'));
// Finish by binding the user middleware
app.param('userId', users.userByID);

View file

@ -122,28 +122,28 @@ describe('Form Model Unit Tests:', function() {
});
});
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) {
@ -161,25 +161,25 @@ describe('Form Model Unit Tests:', function() {
// });
});
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({}, function() {

View file

@ -0,0 +1,496 @@
'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) {
// Set assertions
(res.body.message).should.equal('User is not logged in');
// 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);
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');
// 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);
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);
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) {
// Set assertions
should.not.exist(err);
(res.text).should.equal('Form submissions successfully deleted');
// 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) {
User.remove().exec(function() {
Form.remove().exec(done);
});
});
});

View file

@ -16,22 +16,20 @@ var user, user2;
* Unit tests
*/
describe('User Model Unit Tests:', function() {
before(function(done) {
beforeEach(function(done) {
user = new User({
firstName: 'Full',
lastName: 'Name',
displayName: 'Full Name',
email: 'test@test.com',
username: 'username',
username: 'test@test.com',
password: 'password',
provider: 'local'
});
user2 = new User({
firstName: 'Full',
lastName: 'Name',
displayName: 'Full Name',
email: 'test@test.com',
username: 'username',
username: 'test@test.com',
password: 'password',
provider: 'local'
});
@ -69,7 +67,24 @@ describe('User Model Unit Tests:', function() {
});
});
after(function(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();
});
});
});
afterEach(function(done) {
User.remove().exec(done);
});
});

View file

@ -0,0 +1,118 @@
'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'),
config = require('../../config/config'),
tmpUser = mongoose.model(config.tempUserCollection),
agent = request.agent(app),
mailosaur = require('mailosaur')(config.mailosaur.key),
mailbox = new mailosaur.Mailbox(config.mailosaur.mailbox_id);
/**
* Globals
*/
var credentials, _User, _Session;
/**
* Form routes tests
*/
describe('User CRUD tests', function() {
var userSession;
beforeEach(function(done) {
//Initialize Session
userSession = new Session();
// Create user credentials
credentials = {
username: 'test@test.com',
password: 'password'
};
// Create a new user
_User = {
firstName: 'Full',
lastName: 'Name',
email: credentials.username,
username: credentials.username,
password: credentials.password,
};
console.info('config.mailosaur.mailbox_id: '+config.mailosaur.mailbox_id)
done();
});
it('should be able to create a temporary (non-activated) User', function(done) {
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.');
tmpUser.findOne({username: _User.username}, function (err, user) {
should.not.exist(err);
should.exist(user);
console.log(user);
(_User.username).shoud.equal(user.username);
(_User.firstName).shoud.equal(user.firstName);
(_User.lastName).shoud.equal(user.lastName);
// Call the assertion callback
done();
});
});
});
it('should be able to create and activate/verify a User Account', function(done) {
credentials.username = _User.email = _User.username = 'testUserCreation.be1e58fb@mailosaur.in';
userSession.post('/auth/signup')
.send(_User)
.expect(200)
.end(function(FormSaveErr, FormSaveRes) {
should.not.exist(FormSaveErr);
(FormSaveRes.text).should.equal('An email has been sent to you. Please check it to verify your account.');
mailbox.getEmails(_User.email,
function(err, emails) {
should.not.exist(err);
email = emails[0];
console.log(email);
done();
// userSession.get('/auth/verify/'+token)
// .send(_User)
// .expect(200, 'User successfully verified')
// .end(function (VerifyErr, VerifyRes) {
// should.not.exist(VerifyErr);
// });
}
);
});
});
afterEach(function(done) {
User.remove().exec(function () {
tmpUser.remove().exec(function(){
mailbox.deleteAllEmail(function (err, body) {
console.log(err);
userSession.destroy();
});
});
});
});
});

View file

@ -64,7 +64,7 @@
<!-- </section> -->
</section>
<script src="https://rawgithub.com/eligrey/FileSaver.js/master/FileSaver.js" type="text/javascript"></script>
<script src="lib/file-saver.js/FileSaver.js" type="text/javascript"></script>
<!--Embedding The User Object-->
<script type="text/javascript">
var user = {{ user | json | safe }};

View file

@ -16,6 +16,8 @@ var _ = require('lodash'),
require('./env/all'),
require('./env/' + process.env.NODE_ENV) || {}
);
//Load keys from api_keys.js if file exists
if( fs.existsSync('./env/api_keys.js') ){
module.exports = _.merge(
exports,

8
config/env/all.js vendored
View file

@ -10,6 +10,12 @@ module.exports = {
templateEngine: 'swig',
baseUrl: '',
tempUserCollection: 'temporary_users',
mailosaur: {
key: process.env.MAILOSAUR_KEY || '',
mailbox_id: process.env.MAILOSAUR_MAILBOX || '',
},
//Sentry DSN Client Key
DSN: 'http://db01e03015ce48e2b68240ea8254b17c:5d878e9bb6c6488fbb70fb81295ee700@sentry.polydaic.com/1',
@ -33,7 +39,7 @@ module.exports = {
maxAge: null,
// To set the cookie in a specific domain uncomment the following
// setting:
// domain: 'yourdomain.com'
// domain: 'forms.polydaic.com'
},
/*

View file

@ -18,6 +18,9 @@ module.exports = {
stream: 'access.log'
}
},
sessionCookie: {
domain: 'forms.polydaic.com'
},
assets: {
// lib: {
// css: [

44
config/env/secure.js vendored
View file

@ -19,21 +19,37 @@ module.exports = {
stream: 'access.log'
}
},
sessionCookie: {
path: '/',
httpOnly: false,
// If secure is set to true then it will cause the cookie to be set
// only when SSL-enabled (HTTPS) is used, and otherwise it won't
// set a cookie. 'true' is recommended yet it requires the above
// mentioned pre-requisite.
secure: true,
// Only set the maxAge to null if the cookie shouldn't be expired
// at all. The cookie will expunge when the browser is closed.
maxAge: null,
// To set the cookie in a specific domain uncomment the following
// setting:
domain: 'forms.polydaic.com'
},
assets: {
lib: {
css: [
'public/lib/bootstrap/dist/css/bootstrap.min.css',
'public/lib/bootstrap/dist/css/bootstrap-theme.min.css',
],
js: [
'public/lib/angular/angular.min.js',
'public/lib/angular-resource/angular-resource.min.js',
'public/lib/angular-animate/angular-animate.min.js',
'public/lib/angular-ui-router/release/angular-ui-router.min.js',
'public/lib/angular-ui-utils/ui-utils.min.js',
'public/lib/angular-bootstrap/ui-bootstrap-tpls.min.js'
]
},
// lib: {
// css: [
// 'public/lib/bootstrap/dist/css/bootstrap.min.css',
// 'public/lib/bootstrap/dist/css/bootstrap-theme.min.css',
// ],
// js: [
// 'public/lib/angular/angular.min.js',
// 'public/lib/angular-resource/angular-resource.min.js',
// 'public/lib/angular-animate/angular-animate.min.js',
// 'public/lib/angular-ui-router/release/angular-ui-router.min.js',
// 'public/lib/angular-ui-utils/ui-utils.min.js',
// 'public/lib/angular-bootstrap/ui-bootstrap-tpls.min.js'
// ]
// },
css: 'public/dist/application.min.css',
js: 'public/dist/application.min.js'
},

View file

@ -27,17 +27,52 @@ var fs = require('fs-extra'),
path = require('path'),
client = new raven.Client(config.DSN);
// NEV setup and configuration ================
var config_nev = function () {
var nev = require('email-verification'),
mongoose = require('mongoose'),
User = mongoose.model('User');
nev.configure({
persistentUserModel: User,
tempUserCollection: config.tempUserCollection,
expirationTime: 1800, // 30 minutes
verificationURL: config.baseUrl+'/#!/verify/${URL}',
transportOptions: config.mailer.options,
verifyMailOptions: {
from: config.mailer.from,
subject: 'Confirm your account',
html: '<p>Please verify your account by clicking <a href="${URL}">this link</a>. If you are unable to do so, copy and ' +
'paste the following link into your browser:</p><p>${URL}</p>',
text: 'Please verify your account by clicking the following link, or by copying and pasting it into your browser: ${URL}'
},
confirmMailOptions: {
from: config.mailer.from,
subject: 'Successfully verified!',
html: '<p>Your account has been successfully verified.</p>',
text: 'Your account has been successfully verified.'
},
});
nev.generateTempUserModel(User);
};
module.exports = function(db) {
// Initialize express app
var app = express();
// Globbing model files
config.getGlobbedFiles('./app/models/**/*.js').forEach(function(modelPath) {
require(path.resolve(modelPath));
});
//Configure Node-Email-Verification
config_nev();
// Setting application local variables
app.locals.title = config.app.title;
app.locals.description = config.app.description;
@ -110,7 +145,6 @@ module.exports = function(db) {
app.use('/', express.static(path.resolve('./public')));
app.use('/uploads', express.static(path.resolve('./uploads')));
var formCtrl = require('../app/controllers/forms.server.controller');
// Setting the pdf upload route and folder
app.use(multer({ dest: config.tmpUploadPath,
rename: function (fieldname, filename) {
@ -156,7 +190,7 @@ module.exports = function(db) {
});
// Add headers for Sentry
app.use(function (req, res, next) {
app.use(function (req, res, next) {
// Website you wish to allow to connect
res.setHeader('Access-Control-Allow-Origin', 'http://sentry.polydaic.com');

View file

@ -0,0 +1,140 @@
<?xml version='1.0' encoding='UTF-8'?><wsdl:definitions name="DemographicWsService" targetNamespace="http://ws.oscarehr.org/" xmlns:ns1="http://schemas.xmlsoap.org/soap/http" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="http://ws.oscarehr.org/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<wsdl:types>
<xs:schema elementFormDefault="unqualified" targetNamespace="http://ws.oscarehr.org/" version="1.0" xmlns:tns="http://ws.oscarehr.org/" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="getDemographic" type="tns:getDemographic"/>
<xs:element name="getDemographicByMyOscarUserName" type="tns:getDemographicByMyOscarUserName"/>
<xs:element name="getDemographicByMyOscarUserNameResponse" type="tns:getDemographicByMyOscarUserNameResponse"/>
<xs:element name="getDemographicResponse" type="tns:getDemographicResponse"/>
<xs:complexType name="getDemographic">
<xs:sequence>
<xs:element minOccurs="0" name="arg0" type="xs:int"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="getDemographicResponse">
<xs:sequence>
<xs:element minOccurs="0" name="return" type="tns:demographicTransfer"/>
</xs:sequence>
</xs:complexType>
<xs:complexType final="extension restriction" name="demographicTransfer">
<xs:sequence>
<xs:element name="activeCount" type="xs:int"/>
<xs:element minOccurs="0" name="address" type="xs:string"/>
<xs:element minOccurs="0" name="alias" type="xs:string"/>
<xs:element minOccurs="0" name="anonymous" type="xs:string"/>
<xs:element minOccurs="0" name="chartNo" type="xs:string"/>
<xs:element minOccurs="0" name="children" type="xs:string"/>
<xs:element minOccurs="0" name="citizenship" type="xs:string"/>
<xs:element minOccurs="0" name="city" type="xs:string"/>
<xs:element minOccurs="0" name="dateJoined" type="xs:dateTime"/>
<xs:element minOccurs="0" name="dateOfBirth" type="xs:string"/>
<xs:element minOccurs="0" name="demographicNo" type="xs:int"/>
<xs:element minOccurs="0" name="displayName" type="xs:string"/>
<xs:element minOccurs="0" name="effDate" type="xs:dateTime"/>
<xs:element minOccurs="0" name="email" type="xs:string"/>
<xs:element minOccurs="0" name="endDate" type="xs:dateTime"/>
<xs:element minOccurs="0" name="familyDoctor" type="xs:string"/>
<xs:element minOccurs="0" name="firstName" type="xs:string"/>
<xs:element minOccurs="0" name="hcRenewDate" type="xs:dateTime"/>
<xs:element minOccurs="0" name="hcType" type="xs:string"/>
<xs:element minOccurs="0" name="headRecord" type="xs:int"/>
<xs:element minOccurs="0" name="hin" type="xs:string"/>
<xs:element name="hsAlertCount" type="xs:int"/>
<xs:element minOccurs="0" name="lastName" type="xs:string"/>
<xs:element minOccurs="0" name="lastUpdateDate" type="xs:dateTime"/>
<xs:element minOccurs="0" name="lastUpdateUser" type="xs:string"/>
<xs:element minOccurs="0" name="links" type="xs:string"/>
<xs:element minOccurs="0" name="monthOfBirth" type="xs:string"/>
<xs:element minOccurs="0" name="myOscarUserName" type="xs:string"/>
<xs:element minOccurs="0" name="officialLanguage" type="xs:string"/>
<xs:element minOccurs="0" name="patientStatus" type="xs:string"/>
<xs:element minOccurs="0" name="patientStatusDate" type="xs:dateTime"/>
<xs:element minOccurs="0" name="pcnIndicator" type="xs:string"/>
<xs:element minOccurs="0" name="phone" type="xs:string"/>
<xs:element minOccurs="0" name="phone2" type="xs:string"/>
<xs:element minOccurs="0" name="postal" type="xs:string"/>
<xs:element minOccurs="0" name="previousAddress" type="xs:string"/>
<xs:element minOccurs="0" name="providerNo" type="xs:string"/>
<xs:element minOccurs="0" name="province" type="xs:string"/>
<xs:element minOccurs="0" name="rosterDate" type="xs:dateTime"/>
<xs:element minOccurs="0" name="rosterStatus" type="xs:string"/>
<xs:element minOccurs="0" name="rosterTerminationDate" type="xs:dateTime"/>
<xs:element minOccurs="0" name="rosterTerminationReason" type="xs:string"/>
<xs:element minOccurs="0" name="sex" type="xs:string"/>
<xs:element minOccurs="0" name="sexDesc" type="xs:string"/>
<xs:element minOccurs="0" name="sin" type="xs:string"/>
<xs:element minOccurs="0" name="sourceOfIncome" type="xs:string"/>
<xs:element minOccurs="0" name="spokenLanguage" type="xs:string"/>
<xs:element minOccurs="0" name="title" type="xs:string"/>
<xs:element minOccurs="0" name="ver" type="xs:string"/>
<xs:element minOccurs="0" name="yearOfBirth" type="xs:string"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="getDemographicByMyOscarUserName">
<xs:sequence>
<xs:element minOccurs="0" name="arg0" type="xs:string"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="getDemographicByMyOscarUserNameResponse">
<xs:sequence>
<xs:element minOccurs="0" name="return" type="tns:demographicTransfer"/>
</xs:sequence>
</xs:complexType>
</xs:schema>
</wsdl:types>
<wsdl:message name="getDemographicByMyOscarUserNameResponse">
<wsdl:part element="tns:getDemographicByMyOscarUserNameResponse" name="parameters">
</wsdl:part>
</wsdl:message>
<wsdl:message name="getDemographicByMyOscarUserName">
<wsdl:part element="tns:getDemographicByMyOscarUserName" name="parameters">
</wsdl:part>
</wsdl:message>
<wsdl:message name="getDemographicResponse">
<wsdl:part element="tns:getDemographicResponse" name="parameters">
</wsdl:part>
</wsdl:message>
<wsdl:message name="getDemographic">
<wsdl:part element="tns:getDemographic" name="parameters">
</wsdl:part>
</wsdl:message>
<wsdl:portType name="DemographicWs">
<wsdl:operation name="getDemographic">
<wsdl:input message="tns:getDemographic" name="getDemographic">
</wsdl:input>
<wsdl:output message="tns:getDemographicResponse" name="getDemographicResponse">
</wsdl:output>
</wsdl:operation>
<wsdl:operation name="getDemographicByMyOscarUserName">
<wsdl:input message="tns:getDemographicByMyOscarUserName" name="getDemographicByMyOscarUserName">
</wsdl:input>
<wsdl:output message="tns:getDemographicByMyOscarUserNameResponse" name="getDemographicByMyOscarUserNameResponse">
</wsdl:output>
</wsdl:operation>
</wsdl:portType>
<wsdl:binding name="DemographicWsServiceSoapBinding" type="tns:DemographicWs">
<soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
<wsdl:operation name="getDemographic">
<soap:operation soapAction="" style="document"/>
<wsdl:input name="getDemographic">
<soap:body use="literal"/>
</wsdl:input>
<wsdl:output name="getDemographicResponse">
<soap:body use="literal"/>
</wsdl:output>
</wsdl:operation>
<wsdl:operation name="getDemographicByMyOscarUserName">
<soap:operation soapAction="" style="document"/>
<wsdl:input name="getDemographicByMyOscarUserName">
<soap:body use="literal"/>
</wsdl:input>
<wsdl:output name="getDemographicByMyOscarUserNameResponse">
<soap:body use="literal"/>
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<wsdl:service name="DemographicWsService">
<wsdl:port binding="tns:DemographicWsServiceSoapBinding" name="DemographicWsPort">
<soap:address location="https://secure11.oscarhost.ca/kensington/ws/DemographicService"/>
</wsdl:port>
</wsdl:service>
</wsdl:definitions>

8
docs/Oscar Credentials Normal file
View file

@ -0,0 +1,8 @@
SOAP API Oscar URL
https://secure11.oscarhost.ca/kensington/ws
OSCARHOST DEMO ACCOUNT:
username: davieb
password: Temppass1
2ndlevel: 6448

View file

@ -60,6 +60,7 @@
"karma-phantomjs-launcher": "~0.1.2",
"load-grunt-tasks": "~1.0.0",
"lodash": "~2.4.1",
"mailosaur": "^1.0.1",
"main-bower-files": "~2.8.2",
"method-override": "~2.3.0",
"mocha": ">=1.20.0",
@ -82,6 +83,7 @@
"shortid": "^2.2.2",
"should": "~4.1.0",
"supertest": "~0.14.0",
"supertest-session": "^1.0.0",
"swig": "~1.4.1",
"then-fs": "~2.0.0"
},

View file

@ -33,15 +33,28 @@ angular.module('forms').controller('ListFormsController', ['$rootScope', '$scope
$state.go(route, {'formId': id}, {reload: true});
};
$scope.duplicate = function(form, form_index){
delete form._id;
$http.post('/forms', {form: form})
.success(function(data, status, headers){
console.log('form duplicated');
$scope.myforms.splice(form_index, 0, data);
}).error(function(errorResponse){
console.log(errorResponse);
$scope.error = errorResponse.data.message;
});
}
// Create new Form
$scope.createNew = function(){
var form = {};
form.title = $scope.myform.name.$modelValue;
form.language = $scope.myform.language.$modelValue;
console.log(form);
// console.log(form);
$rootScope.showCreateModal = true;
console.log($scope.myform);
// console.log($scope.myform);
if($scope.myform.$valid && $scope.myform.$dirty){
$http.post('/forms', {form: form})
.success(function(data, status, headers){
@ -58,28 +71,17 @@ angular.module('forms').controller('ListFormsController', ['$rootScope', '$scope
}
};
$scope.remove = function(form_id) {
$scope.removeFromList = function(deleted_form_id) {
console.log('Remove existing form');
var form = {};
if(!form_id){
form = CurrentForm.getForm();
if(!form) form = $scope.myform;
}else {
form._id = form_id;
}
$http.delete('/forms/'+form._id)
$http.delete('/forms/'+deleted_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;
return myform._id !== deleted_form_id;
});
}

View file

@ -154,13 +154,16 @@ form .row.field {
box-shadow: inset 0 1px 1px rgba(0, 0, 0, .05);
}
div.config-form .row.field {
padding-top:1.5em;
}
div.config-form > .row > .container:nth-of-type(odd){
border-right: 1px #ddd solid;
/*padding-left: 1em;*/
}
div.config-form .row > .field-input {
padding-top:1.2em;
padding-left:0.1em;
}
div.config-form .row > .field-input label {
@ -292,15 +295,15 @@ section > section.public-form {
text-align: center;
border-bottom: 6px inset #ccc;
background-color: #eee;
/*width: 180px;*/
width: 180px;
/*width:100%;*/
position: relative;
height: 0;/*215px;*/
padding-bottom: 25%;
height: 215px;
/*padding-bottom: 25%;*/
margin-bottom: 45px;
}
.form-item.create-new input[type='text']{
width: inherit;
/*width: inherit;*/
}
.form-item.create-new {
@ -322,6 +325,15 @@ section > section.public-form {
}
/*Modal overlay (for lightbox effect)*/
.overlay {
position: fixed;
top: 0;
left: 0;
height: 100%;
width: 100%;
background-color: rgba(256,256,256,0.8);
z-index: 10;
}
.overlay {
position: fixed;
top: 0;
@ -354,35 +366,40 @@ section > section.public-form {
}
.form-item.create-new:hover {
/*color: #eee;*/
background-color: rgb(81,81,81);
}
.form-item > .title-row{
.form-item > .row.footer {
position: absolute;
bottom: 0;
left: 30%;
}
.form-item .title-row{
position: relative;
top: 15px;
padding-top:3em;
padding-bottom:3.65em;
}
.form-item > .title-row h4 {
.form-item .title-row h4 {
font-size: 1.3em;
}
.form-item.create-new > .title-row{
.form-item.create-new .title-row{
padding: 0;
/*margin-top:1em; */
}
.form-item.create-new > .title-row h4 {
.form-item.create-new .title-row h4 {
font-size: 7em;
}
.form-item > .details-row{
.form-item .details-row{
margin-top: 3.2em;
}
.form-item > .details-row small {
.form-item .details-row small {
font-size: 0.6em;
}
.form-item.create-new > .details-row small {
.form-item.create-new .details-row small {
font-size: 0.95em;
}

View file

@ -35,7 +35,7 @@ angular.module('forms').directive('autoSaveForm', ['$rootScope', '$timeout', fun
return false;
};
var updateFields = function () {
var debounceSave = function () {
$rootScope.saveInProgress = true;
$rootScope[$attrs.autoSaveCallback](false,
function(err){
@ -49,12 +49,12 @@ angular.module('forms').directive('autoSaveForm', ['$rootScope', '$timeout', fun
console.error(err);
}
});
}
};
$scope.$watch(function(newValue, oldValue) {
if($scope.anyDirtyAndTouched($scope.editForm) && !$rootScope.saveInProgress){
updateFields();
debounceSave();
}
});
@ -84,7 +84,7 @@ angular.module('forms').directive('autoSaveForm', ['$rootScope', '$timeout', fun
savePromise = $timeout(function() {
console.log('Saving Form');
updateFields();
debounceSave();
});
}else if($rootScope.finishedRender && $rootScope.saveInProgress){
$rootScope.saveInProgress = false;

View file

@ -11,10 +11,7 @@ angular.module('forms')
},
// transclude: true,
controller: function($scope){
// Log that the directive has been linked.
// console.log( "Linked: editForm Controller");
/*
** Initialize scope with variables
*/
@ -27,7 +24,7 @@ angular.module('forms')
return type;
});
// accordion settings
// Accordion settings
$scope.accordion = {};
$scope.accordion.oneAtATime = true;
@ -39,9 +36,8 @@ angular.module('forms')
*/
$scope.dropzone = {
handle: ' .handle'
}
};
// console.log($scope.myform);
// $scope.draggable = {
// connectWith: ".dropzone",

View file

@ -26,7 +26,7 @@ angular.module('forms').directive('fieldIconDirective', function($http, $compile
'statement': 'fa fa-quote-left',
'yes_no': 'fa fa-toggle-on',
'number': 'fa fa-slack'
}
};
$scope.typeIcon = iconTypeMap[$scope.typeName];
},

View file

@ -46,7 +46,7 @@ angular.module('forms').directive('fieldDirective', ['$http', '$compile', '$root
scope.dateOptions = {
changeYear: true,
changeMonth: true,
altFormat: "mm/dd/yyyy",
altFormat: 'mm/dd/yyyy',
yearRange: '1900:-0',
defaultDate: 0,
};

View file

@ -13,16 +13,17 @@ angular.module('forms').directive('formDirective', ['$http', '$timeout', 'timeCo
$scope.selected = null;
$scope.startPage = true;
timeCounter.startClock()
$rootScope.setActiveField = function (field_id) {
console.log('form field clicked: '+field_id);
$scope.selected = field_id;
console.log($scope.selected);
}
};
$scope.hideOverlay = function (){
$scope.selected = null;
console.log($scope.myForm);
}
};
$scope.submit = function(){
var _timeElapsed = timeCounter.stopClock();
@ -50,7 +51,7 @@ angular.module('forms').directive('formDirective', ['$http', '$timeout', 'timeCo
$scope.exitStartPage = function () {
$scope.startPage = false;
}
};
$scope.reloadForm = function(){
timeCounter.stopClock();

View file

@ -1,5 +1,5 @@
<div class="field row" ng-click="setActiveField(field._id)" ng-if="field.fieldOptions.length > 0">
<div class="col-xs-12 field-title field-title">{{field.title}} </div>
<div class="col-xs-12 field-title field-title">{{field.title}} <span class="required-error" ng-show="field.required && field.fieldValue == 0">(* required)</span> </div>
<div class="col-xs-12 field-input">
<div ng-repeat="option in field.fieldOptions" class="row-fluid">
<label class="btn btn-info col-xs-3">
@ -7,7 +7,7 @@
<span ng-bind="option.option_title"></span>
</label>
</div>
<span class="required-error" ng-show="field.required && field.fieldValue == 0">(* required)</span>
</div>
<div class="field row" ng-click="setActiveField(field._id)">

View file

@ -1,5 +1,11 @@
<div class="field row dropdown" ng-click="setActiveField(field._id)" ng-if="field.fieldOptions.length > 0">
<div class="col-xs-12 field-title"><h3><span class="fa fa-angle-double-right"></span> {{field.title}} <span class="required-error" ng-show="field.required && !field.fieldValue">*(required)</span></h3></div>
<div class="col-xs-12 field-title">
<h3>
<span class="fa fa-angle-double-right"></span>
{{field.title}}
<span class="required-error" ng-show="field.required && !field.fieldValue">*(required)</span>
</h3>
</div>
<div class="col-xs-12 field-input ">
<select ng-model="field.fieldValue" ng-model-options="{ debounce: 250 }" ng-required="field.required" ng-disabled="field.disabled">
<option ng-repeat="option in field.fieldOptions"
@ -8,7 +14,6 @@
{{option.option_title}}
</option>
</select>
<span class="required-error" ng-show="field.required && !field.fieldValue">* required</span>
</div>
</div>
<br>

View file

@ -9,6 +9,5 @@
ng-model-options="{ debounce: 250 }"
ng-required="field.required"
ng-disabled="field.disabled"/>
<span class="required-error" ng-show="field.required && !field.fieldValue">* required</span>
</div>
</div>

View file

@ -1,6 +1,6 @@
<div class="row field" ng-if="form.autofillPDFs">
<div class="col-sm-4 field-title">
<h5>{{field.title}}</h5>
<h5>{{field.title}} <span class="required-error" ng-show="field.required && field.fieldValue == 0">(* required)</span></h5>
</div>
<div class="col-sm-8 field-input">
<div class="input-group ">

View file

@ -2,6 +2,5 @@
<div class="col-xs-12 field-title"><h3><span class="fa fa-angle-double-right"></span> {{field.title}} <span class="required-error" ng-show="field.required && !field.fieldValue">*(required)</span></h3></div>
<div class="col-xs-12 field-input">
<input ng-focus="setActiveField(field._id)"type="url" class="text-field-input" placeholder="https://example.com/something" value="{{field.fieldValue}}" ng-model="field.fieldValue" ng-model-options="{ debounce: 250 }" ng-required="field.required" ng-disabled="field.disabled"/>
<span class="required-error" ng-show="field.required && !field.fieldValue">* required</span>
</div>
</div>

View file

@ -2,6 +2,5 @@
<div class="col-xs-12 field-title"><h3><span class="fa fa-angle-double-right"></span> {{field.title}} <span class="required-error" ng-show="field.required && !field.fieldValue">*(required)</span></h3></div>
<div class="col-xs-12 field-input">
<input ng-focus="setActiveField(field._id)"type="password" class="text-field-input" ng-model="field.fieldValue" ng-model-options="{ debounce: 250 }" value="{{field.fieldValue}}" ng-required="field.required" ng-disabled="field.disabled">
<span class="required-error" ng-show="field.required && !field.fieldValue">* required</span>
</div>
</div>

View file

@ -9,6 +9,5 @@
ng-required="field.required"
ng-disabled="field.disabled"
changeFocus focus-up-id="focusUpButton" focus-down-id="focusDownButton">
<span class="required-error" ng-show="field.required && !field.fieldValue">* required</span>
</div>
</div>

View file

@ -1,28 +1,12 @@
<div class="config-form container">
<div class="row">
<!-- PDF Generation/EMR Settings -->
<div class="col-md-6 col-sm-12 container">
<div class="row">
<div class="col-sm-12">
<h2 class="hidden-sm hidden-xs">PDF Generation</h2>
<h3 class="hidden-lg hidden-md">PDF Generation</h3>
</div>
</div>
<div class="row field">
<div class="field-title col-sm-6">
<h5>Hide Form Footer?</h5>
</div>
<div class="field-input col-sm-6">
<label>
<input type="radio" data-ng-value="true" ng-model="myform.hideFooter" ng-required="true" />
&nbsp;<span>Yes</span>
</label>
<label>
<input type="radio" data-ng-value="false" ng-model="myform.hideFooter" ng-required="true" />
&nbsp;<span>No</span>
</label>
<h2 class="hidden-sm hidden-xs">PDF Generation/EMR</h2>
<h3 class="hidden-lg hidden-md">PDF Generation/EMR</h3>
</div>
</div>
@ -100,6 +84,74 @@
</div>
</div>
<div class="row field">
<div class="field-title col-sm-4">
<h5>EMR API Key</h5>
</div>
<div class="col-sm-8">
<input type="text"
ng-model="myform.EMR.api_key"
value="{{myform.EMR.api_key}}"
style="width: 100%;">
</div>
</div>
<div class="row field">
<div class="field-title col-sm-4">
<h5>EMR URL</h5>
</div>
<div class="col-sm-8">
<input type="link"
ng-model="myform.EMR.url"
value="{{myform.EMR.url}}"
style="width: 100%;">
</div>
</div>
<!-- generate typeform from MedForm yes/no field -->
<div class="row field">
<div class="col-sm-6 field-title">
<h5>Autogenerate Typeform?</h5>
</div>
<div class="col-sm-6 field-input">
<label>
<input type="radio" data-ng-value="true" ng-model="myform.Typeform.isGenerated" ng-required="true" />
&nbsp;<span>Yes</span>
</label>
<label>
<input type="radio" data-ng-value="false" ng-model="myform.Typeform.isGenerated" ng-required="true" />
&nbsp;<span>No</span>
</label>
</div>
</div>
<div class="row field" ng-if="myform.Typeform.isGenerated">
<div class="field-title col-sm-4">
<h5>Typeform.IO Build API Key</h5>
</div>
<div class="col-sm-8">
<input type="text"
ng-model="myform.Typeform.build_api_key"
value="{{myform.Typeform.build_api_key}}"
style="width: 100%;">
</div>
</div>
<div class="row field" ng-if="myform.Typeform.isGenerated">
<div class="field-title col-sm-4">
<h5>Generated Typeform URL</h5>
</div>
<div class="col-sm-8">
<span type="text" ng-bind="myform.Typeform.url"></span>
</div>
</div>
<!-- !!!!!!DAVID: TODO: Finish this so we can upload pdfFieldMap!!!!!!!!! -->
<!-- Map form inputs to PDF inputs Field -->
@ -126,11 +178,12 @@
<hr>
</div>
<!-- Advanced Settings -->
<div class="col-md-5 col-md-offset-1 col-sm-12 container">
<div class="row">
<div class="col-sm-12">
<h2 class="hidden-sm hidden-xs">Advanced Settings</h2>
<h3 class="hidden-lg hidden-md">PDF Generation</h3>
<h3 class="hidden-lg hidden-md">Advanced Settings</h3>
</div>
</div>
@ -167,26 +220,7 @@
<!-- <span class="required-error" ng-show="field.required && !field.fieldValue">* required</span> -->
</div>
</div>
<div class="row field">
<div class="field-title col-sm-6">
<h5>Display Start Page?</h5>
</div>
<div class="field-input col-sm-6">
<label>
<input type="radio" data-ng-value="true" ng-model="myform.showStart" ng-required="true" style="background-color:#33CC00;"/>
&nbsp;<span>Yes</span>
</label>
<label>
<input type="radio" data-ng-value="false" ng-model="myform.showStart" ng-required="true" />
&nbsp;<span>No</span>
</label>
<!-- <span class="required-error" ng-show="field.required && !field.fieldValue">* required</span> -->
</div>
</div>
<div class="row field">
<div class="col-xs-6 field-title">Language</div>
<div class="col-xs-4 field-input">
@ -200,6 +234,44 @@
<span class="required-error" ng-show="field.required && !field.fieldValue">* required</span>
</div>
</div>
<div class="row field">
<div class="field-title col-sm-6">
<h5>Hide Form Footer?</h5>
</div>
<div class="field-input col-sm-6">
<label>
<input type="radio" data-ng-value="true" ng-model="myform.hideFooter" ng-required="true" />
&nbsp;<span>Yes</span>
</label>
<label>
<input type="radio" data-ng-value="false" ng-model="myform.hideFooter" ng-required="true" />
&nbsp;<span>No</span>
</label>
</div>
</div>
<div class="row field">
<div class="field-title col-sm-6">
<h5>Display Start Page?</h5>
</div>
<div class="field-input col-sm-6">
<label>
<input type="radio" data-ng-value="true" ng-model="myform.startPage.showStart" ng-required="true" style="background-color:#33CC00;"/>
&nbsp;<span>Yes</span>
</label>
<label>
<input type="radio" data-ng-value="false" ng-model="myform.startPage.showStart" ng-required="true" />
&nbsp;<span>No</span>
</label>
<!-- <span class="required-error" ng-show="field.required && !field.fieldValue">* required</span> -->
</div>
</div>
</div>
</div>
<div class="row">

View file

@ -5,6 +5,7 @@
<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">
@ -27,6 +28,59 @@
<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" on-finish-render="editFormFields" ng-if="form.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">
<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="form.startPage.introText" name="titleStartPage" value="{{form.startPage.introText}}" required></div>
</div>
<div class="row"><br></div>
<div class="row description">
<div class="col-md-4 col-sm-12">Intro Description:</div>
<div class="col-md-8 col-sm-12">
<textarea type="text" ng-model="form.startPage.introDescription" name="descriptionStartPage" value="{{form.startPage.introDescription}}"></textarea>
</div>
</div>
<<div class="row"><br></div>
<div class="row description">
<div class="col-md-4 col-sm-12">Button Text:</div>
<div class="col-md-8 col-sm-12">
<textarea type="text" ng-model="form.startPage.buttonText" name="buttonStartPage" value="{{form.startPage.buttonText}}"></textarea>
</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>

View file

@ -4,20 +4,23 @@
<div ng-show="!form.submitted && startPage && form.showStart" class="form-submitted">
<div class="field row text-center">
<div class="col-xs-6 col-xs-offset-3 text-center">
<div class="col-xs-12 text-center">
<h1>Welcome to {{form.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 class="text-center col-xs-4 col-xs-offset-4">
<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>
<a ng-click="exitStartPage()" style="color:white; font-size: 1.6em; text-decoration: none;">Continue to Form</a>
</button>
</p>
</div>
</div>
<div ng-hide="form.submitted || startPage" data-ng-init="initFocus()">
<div ng-show="!form.submitted && !(startPage && form.showStart)" data-ng-init="initFocus()">
<div class="field row" style="padding-bottom:5em;">
<div class="col-sm-10 col-sm-offset-1">
<h1>{{ form.title }} <span style="font-size:0.8em; color: #bbb;" ng-if="!form.isLive">(private preview)</span></h1>
@ -42,7 +45,7 @@
</div>
</div>
<div ng-show="form.submitted && !startPage" class="form-submitted">
<div ng-show="form.submitted" class="form-submitted">
<!-- <div class="field row">
<div class="col-sm-11 col-sm-offset-1"><h1>{{ form.title }}</h1>

View file

@ -21,7 +21,7 @@
</div>
</div>
<form name="createForm" class="col-xs-6 col-xs-offset-3 col-sm-4 col-sm-offset-1 col-md-3 col-md-offset-1 form-item create-new new-form" ng-show="showCreateModal">
<form name="createForm" class="col-xs-6 col-xs-offset-3 col-sm-4 col-sm-offset-1 col-md-3 col-md-offset-1 form-item create-new new-form" ng-if="showCreateModal">
<div ng-init="setForm(createForm);" style="display:none;"></div>
<div class="title-row row">
<div class="col-xs-5 field-title">Name </div>
@ -50,22 +50,34 @@
</div>
</form>
<div data-ng-repeat="form in myforms" class="col-xs-6 col-xs-offset-3 col-sm-4 col-sm-offset-1 col-md-3 col-md-offset-1 form-item">
<div data-ng-repeat="form in myforms" class="col-xs-6 col-xs-offset-3 col-sm-4 col-sm-offset-1 col-md-3 col-md-offset-1 form-item container">
<div class="row">
<span class="pull-right">
<i style="cursor:pointer;" class="fa fa-trash-o" ng-click="remove(form._id)"></i>
<i style="cursor:pointer;" class="fa fa-trash-o" ng-click="removeFromList(form._id)"></i>
<i style="cursor:pointer;" class="fa fa-files-o" ng-click="duplicate(form)"></i>
</span>
</div>
<div class="row">
<a data-ng-href="#!/forms/{{form._id}}/admin" class="title-row col-xs-12">
<h4 class="list-group-item-heading" data-ng-bind="form.title"></h4>
</a>
<div class="col-xs-12 details-row">
<!-- <small class="list-group-item-text">
Created on
<span data-ng-bind="form.created | date:'shortDate'"></span>
by
<span data-ng-bind="form.admin.username"></span>
</small> -->
</div>
<div class="row footer">
<div class="col-xs-12 details-row">
<small class="list-group-item-text">
Created on
<span data-ng-bind="form.created | date:'shortDate'"></span>
</small>
<!--by
<span data-ng-bind="form.admin.username"></span>
</small> -->
</div>
</div>
</div>
</div>

View file

@ -1,33 +1,28 @@
<!-- <link rel="stylesheet" href="./modules/forms/css/myform.css">
-->
<section data-ng-controller="SubmitFormController" class="public-form">
<form-directive form="myform"></form-directive>
<section ng-if="!myform.hideFooter" class="navbar navbar-fixed-bottom" style="background-color:rgba(242,242,242,0.5); padding-top:15px;">
<div class="container" >
<nav role="navigation">
<ul class="nav navbar-nav navbar-left" >
<li ng-show="!myform.submitted">
<div class="row">
<div class="col-xs-4 col-xs-offset-4 col-sm-4 col-sm-offset-4 text-center col-md-3 col-md-offset-0" ng-show="!myform.submitted">
<p class="lead">{{myform | formValidity}} out of {{myform.visible_form_fields.length}} answered</p>
</li>
</ul>
<ul class="nav navbar-nav navbar-right">
<li style="padding-right:20px" >
<a href="/#!/forms" class="btn btn-default" ng-hide="authentication.isAuthenticated()">Create a Medform</a>
</li>
<li style="padding-right:20px; padding-bottom:10px;" ng-show="authentication.isAuthenticated()">
</div>
<div class="hidden-xs hidden-sm col-md-6 col-md-offset-3 row">
<div class="col-md-4 col-md-offset-2" ng-if="!authentication.isAuthenticated()">
<a href="/#!/forms" class="btn btn-default">Create a Medform</a>
</div>
<div class="col-md-4 col-md-offset-2" ng-if="authentication.isAuthenticated()" class="hidden-sm hidden-xs">
<a href="/#!/forms/{{myform._id}}/admin" class="btn btn-default">Edit this Medform</a>
</li>
<li style="padding-left:5px">
<div class="btn btn-info" id="focusDownButton" style="padding: 15px;">\/</div>
</li>
<li style="padding-left:5px">
<div class="btn btn-info" id="focusUpButton" style="padding: 15px">/\</div>
</li>
</ul>
</nav>
</div>
<div class="col-md-1 col-md-offset-2" style="padding-left:5px" class="hidden-sm hidden-xs">
<div class="btn btn-info" id="focusDownButton">\/</div>
</div>
<div class="col-md-1" class="hidden-sm hidden-xs">
<div class="btn btn-info" id="focusUpButton">/\</div>
</div>
</div>
</div>
</div>
</section>
</section>

View file

@ -10,7 +10,7 @@ angular.module('users').controller('AuthenticationController', ['$scope', '$loca
$scope.signin = function() {
User.login($scope.credentials).then(
function(response) {
console.log(response)
// console.log(response);
Auth.login(response);
$scope.user = $rootScope.user = Auth.ensureHasCurrentUser(User);