Merge branch 'api' into stage
This commit is contained in:
commit
2455f5dd9a
|
@ -21,3 +21,11 @@ exports.form = function(req, res) {
|
|||
request: req
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
exports.redoc = function(req, res) {
|
||||
res.render('redoc', {
|
||||
request: req
|
||||
});
|
||||
};
|
||||
|
||||
|
|
|
@ -118,8 +118,6 @@ exports.createSubmission = function(req, res) {
|
|||
percentageComplete: req.body.percentageComplete
|
||||
});
|
||||
|
||||
if(!!form.plugins.oscarhost.baseUrl) submission.hasPlugins.oscarhost = true;
|
||||
|
||||
if(form.pdf) submission.pdf = form.pdf;
|
||||
|
||||
//Save submitter's IP Address
|
||||
|
@ -189,23 +187,27 @@ exports.listSubmissions = function(req, res) {
|
|||
* Create a new form
|
||||
*/
|
||||
exports.create = function(req, res) {
|
||||
|
||||
|
||||
if(!req.body.form){
|
||||
console.log(err);
|
||||
return res.status(400).send({
|
||||
message: "Invalid Input"
|
||||
});
|
||||
}
|
||||
var form = new Form(req.body.form);
|
||||
|
||||
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) {
|
||||
if (err) {
|
||||
console.log(err);
|
||||
res.status(400).send({
|
||||
return res.status(405).send({
|
||||
message: errorHandler.getErrorMessage(err)
|
||||
});
|
||||
} else {
|
||||
res.json(form);
|
||||
}
|
||||
|
||||
res.json(form);
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -213,10 +215,7 @@ exports.create = function(req, res) {
|
|||
* Show the current form
|
||||
*/
|
||||
exports.read = function(req, res) {
|
||||
var validUpdateTypes= Form.schema.path('plugins.oscarhost.settings.updateType').enumValues;
|
||||
|
||||
var newForm = req.form.toJSON({virtuals : true});
|
||||
newForm.plugins.oscarhost.settings.validUpdateTypes = validUpdateTypes;
|
||||
|
||||
if (req.userId) {
|
||||
if(req.form.admin._id+'' === req.userId+''){
|
||||
|
@ -239,6 +238,7 @@ exports.update = function(req, res) {
|
|||
delete req.body.form.__v;
|
||||
delete req.body.form._id;
|
||||
*/
|
||||
if(req.user.roles.indexOf('admin') === -1) delete req.body.form.admin;
|
||||
|
||||
if(req.body.changes){
|
||||
var formChanges = req.body.changes;
|
||||
|
@ -248,7 +248,6 @@ exports.update = function(req, res) {
|
|||
});
|
||||
} else {
|
||||
//Unless we have 'admin' privileges, updating form admin is disabled
|
||||
if(req.user.roles.indexOf('admin') === -1) delete req.body.form.admin;
|
||||
|
||||
//Do this so we can create duplicate fields
|
||||
var checkForValidId = new RegExp('^[0-9a-fA-F]{24}$');
|
||||
|
@ -265,7 +264,7 @@ exports.update = function(req, res) {
|
|||
form.save(function(err, form) {
|
||||
if (err) {
|
||||
console.log(err);
|
||||
res.status(400).send({
|
||||
res.status(405).send({
|
||||
message: errorHandler.getErrorMessage(err)
|
||||
});
|
||||
} else {
|
||||
|
@ -325,7 +324,7 @@ exports.formByID = function(req, res, next, id) {
|
|||
if (err) {
|
||||
return next(err);
|
||||
} else if (form === undefined || form === null) {
|
||||
res.status(400).send({
|
||||
res.status(404).send({
|
||||
message: 'Form not found'
|
||||
});
|
||||
}
|
||||
|
|
|
@ -11,7 +11,9 @@ var _ = require('lodash'),
|
|||
config = require('../../../config/config'),
|
||||
nodemailer = require('nodemailer'),
|
||||
crypto = require('crypto'),
|
||||
User = mongoose.model('User');
|
||||
User = mongoose.model('User'),
|
||||
tokgen = require("../../libs/tokenGenerator");
|
||||
|
||||
|
||||
var nev = require('email-verification')(mongoose);
|
||||
|
||||
|
@ -172,7 +174,6 @@ exports.signin = function(req, res, next) {
|
|||
*/
|
||||
exports.signout = function(req, res) {
|
||||
req.logout();
|
||||
//res.redirect('/');
|
||||
return res.status(200).send('You have successfully logged out.');
|
||||
|
||||
};
|
||||
|
@ -304,3 +305,43 @@ exports.removeOAuthProvider = function(req, res, next) {
|
|||
});
|
||||
}
|
||||
};
|
||||
|
||||
/* Generate API Key for User */
|
||||
exports.generateAPIKey = function(req, res) {
|
||||
if (!req.isAuthenticated()){
|
||||
return res.status(400).send({
|
||||
message: 'User is not Authorized'
|
||||
});
|
||||
}
|
||||
|
||||
User.findById(req.user.id)
|
||||
.exec( function(err, user) {
|
||||
if (err) return res.status(400).send(err);
|
||||
|
||||
if (!user) {
|
||||
return res.status(400).send({
|
||||
message: 'User does not Exist'
|
||||
});
|
||||
}
|
||||
|
||||
user.apiKey = tokgen();
|
||||
|
||||
user.save(function(err, _user) {
|
||||
if (err) {
|
||||
return res.status(400).send({
|
||||
message: errorHandler.getErrorMessage(err)
|
||||
});
|
||||
}
|
||||
|
||||
var newUser = _user.toObject();
|
||||
delete newUser.salt;
|
||||
delete newUser.__v;
|
||||
delete newUser.passwordHash;
|
||||
delete newUser.provider;
|
||||
|
||||
console.log(newUser);
|
||||
return res.json(newUser);
|
||||
});
|
||||
|
||||
});
|
||||
};
|
||||
|
|
|
@ -23,7 +23,9 @@ exports.userByID = function (req, res, next, id) {
|
|||
if (err) {
|
||||
return next(err);
|
||||
} else if (!user) {
|
||||
return next(new Error('Failed to load User ' + id));
|
||||
return res.status(404).send({
|
||||
message: 'User does not exist'
|
||||
});
|
||||
}
|
||||
|
||||
req.profile = user;
|
||||
|
|
|
@ -27,13 +27,13 @@ exports.update = function(req, res) {
|
|||
|
||||
user.save(function(err) {
|
||||
if (err) {
|
||||
return res.status(400).send({
|
||||
return res.status(500).send({
|
||||
message: errorHandler.getErrorMessage(err)
|
||||
});
|
||||
} else {
|
||||
req.login(user, function(err) {
|
||||
if (err) {
|
||||
res.status(400).send(err);
|
||||
res.status(500).send(err);
|
||||
} else {
|
||||
res.json(user);
|
||||
}
|
||||
|
@ -41,7 +41,7 @@ exports.update = function(req, res) {
|
|||
}
|
||||
});
|
||||
} else {
|
||||
res.status(400).send({
|
||||
res.status(401).send({
|
||||
message: 'User is not signed in'
|
||||
});
|
||||
}
|
||||
|
|
8
app/libs/tokenGenerator.js
Normal file
8
app/libs/tokenGenerator.js
Normal file
|
@ -0,0 +1,8 @@
|
|||
"use strict";
|
||||
|
||||
let TokenGenerator = require("uuid-token-generator");
|
||||
let tokgen = new TokenGenerator(256, TokenGenerator.BASE62);
|
||||
|
||||
module.exports = function() {
|
||||
return tokgen.generate();
|
||||
};
|
|
@ -92,11 +92,6 @@ var FormSchema = new Schema({
|
|||
default: 'en',
|
||||
required: 'Form must have a language'
|
||||
},
|
||||
description: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
|
||||
analytics:{
|
||||
gaCode: {
|
||||
type: String
|
||||
|
@ -187,8 +182,7 @@ var FormSchema = new Schema({
|
|||
default: '#333'
|
||||
}
|
||||
},
|
||||
font: String,
|
||||
backgroundImage: { type: Schema.Types.Mixed }
|
||||
font: String
|
||||
},
|
||||
|
||||
plugins: {
|
||||
|
@ -367,11 +361,6 @@ FormSchema.pre('save', function (next) {
|
|||
}
|
||||
});
|
||||
}, function(cb) {
|
||||
//DAVID: TODO: Make this so we don't have to update the validFields property ever save
|
||||
if (that.plugins.oscarhost.hasOwnProperty('baseUrl')) {
|
||||
var validUpdateTypes = mongoose.model('Form').schema.path('plugins.oscarhost.settings.updateType').enumValues;
|
||||
that.plugins.oscarhost.settings.validUpdateTypes = validUpdateTypes;
|
||||
}
|
||||
return cb(null);
|
||||
},
|
||||
function(cb) {
|
||||
|
|
|
@ -157,88 +157,7 @@ FormSubmissionSchema.pre('save', function (next) {
|
|||
// console.log(_form);
|
||||
// console.log('should push to api');
|
||||
// console.log( (!this.oscarDemoNum && !!_form.plugins.oscarhost.baseUrl && !!_form.plugins.oscarhost.settings.fieldMap) );
|
||||
if(!this.oscarDemoNum && _form.plugins.oscarhost.baseUrl && _form.plugins.oscarhost.settings.fieldMap){
|
||||
console.log('OSCARHOST API HOOK');
|
||||
var url_login = _form.plugins.oscarhost.baseUrl+'/LoginService?wsdl',
|
||||
url_demo = _form.plugins.oscarhost.baseUrl+'/DemographicService?wsdl';
|
||||
|
||||
var args_login = {arg0: config.oscarhost.auth.user, arg1: config.oscarhost.auth.pass};
|
||||
|
||||
var options = {
|
||||
ignoredNamespaces: {
|
||||
namespaces: ['targetNamespace', 'typedNamespace'],
|
||||
override: true
|
||||
}
|
||||
};
|
||||
// console.log(self.form_fields);
|
||||
|
||||
//Generate demographics from hashmap
|
||||
var generateDemo = function(formFields, conversionMap, demographicsTemplate){
|
||||
console.log('generating Demo fields');
|
||||
console.log(conversionMap);
|
||||
var _generatedDemo = {}, currField, propertyName;
|
||||
|
||||
for(var y=0; y<formFields.length; y++){
|
||||
currField = formFields[y];
|
||||
propertyName = conversionMap[currField._id];
|
||||
|
||||
if(demographicsTemplate.hasOwnProperty(conversionMap[currField._id])){
|
||||
_generatedDemo[propertyName] = currField.fieldValue+'';
|
||||
}else if(propertyName === 'DOB'){
|
||||
var date = new Date(currField.fieldValue);
|
||||
_generatedDemo.dateOfBirth = date.getDate()+'';
|
||||
_generatedDemo.yearOfBirth = date.getFullYear()+'';
|
||||
_generatedDemo.monthOfBirth = date.getMonth()+'';
|
||||
}
|
||||
}
|
||||
var currDate = new Date();
|
||||
var dateString = currDate.toISOString().split('T')[0] + ' ' + currDate.toISOString().split('T')[1].slice(0,8);
|
||||
_generatedDemo.lastUpdateDate = currDate.toISOString();
|
||||
return _generatedDemo;
|
||||
};
|
||||
|
||||
var submissionDemographic = generateDemo(self.form_fields, _form.plugins.oscarhost.settings.fieldMap, newDemoTemplate);
|
||||
|
||||
console.log(submissionDemographic);
|
||||
async.waterfall([
|
||||
function (callback) {
|
||||
//Authenticate with API
|
||||
soap.createClient(url_login, options, function(err, client) {
|
||||
client.login(args_login, function (err, result) {
|
||||
if(err) return callback(err);
|
||||
console.log('SOAP authenticated');
|
||||
return callback(null, result.return);
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
function (security_obj, callback) {
|
||||
//Force Add Demographic
|
||||
if(_form.plugins.oscarhost.settings.updateType === 'force_add'){
|
||||
soap.createClient(url_demo, options, function(err, client) {
|
||||
if(err) return callback(err);
|
||||
client.setSecurity(new OscarSecurity(security_obj.securityId, security_obj.securityTokenKey) );
|
||||
|
||||
client.addDemographic({ arg0: submissionDemographic }, function (err, result) {
|
||||
console.log('FORCE ADDING DEMOGRAPHIC \n');
|
||||
// console.log(result.return);
|
||||
if(err) return callback(err);
|
||||
return callback(null, result);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
], function(err, result) {
|
||||
if(err) return next(err);
|
||||
|
||||
self.oscarDemoNum = parseInt(result.return, 10);
|
||||
console.log('self.oscarDemoNum: '+self.oscarDemoNum);
|
||||
return next();
|
||||
});
|
||||
}else{
|
||||
return next();
|
||||
}
|
||||
return next();
|
||||
});
|
||||
}else{
|
||||
return next();
|
||||
|
|
|
@ -119,7 +119,13 @@ var UserSchema = new Schema({
|
|||
resetPasswordExpires: {
|
||||
type: Date
|
||||
},
|
||||
token: String
|
||||
token: String,
|
||||
apiKey: {
|
||||
type: String,
|
||||
unique: true,
|
||||
index: true,
|
||||
sparse: true
|
||||
},
|
||||
});
|
||||
|
||||
UserSchema.virtual('displayName').get(function () {
|
||||
|
|
|
@ -9,8 +9,9 @@ var forms = require('../../app/controllers/forms.server.controller'),
|
|||
module.exports = function(app) {
|
||||
// Root routing
|
||||
app.route('/').get(core.index);
|
||||
app.route('/subdomain/([a-zA-Z0-9]+)/').get(core.form);
|
||||
app.route('/subdomain/*/forms/:formId([a-zA-Z0-9]+)')
|
||||
app.route('/subdomain/api/').get(core.redoc);
|
||||
app.route('/subdomain/^(?!api$)[A-Za-z0-9]*/').get(core.form);
|
||||
app.route('/subdomain/^(?!api$)[A-Za-z0-9]*/forms/:formId([a-zA-Z0-9]+)')
|
||||
.get(forms.read)
|
||||
.post(forms.createSubmission);
|
||||
};
|
||||
|
|
|
@ -6,7 +6,8 @@
|
|||
var users = require('../../app/controllers/users.server.controller'),
|
||||
forms = require('../../app/controllers/forms.server.controller'),
|
||||
multer = require('multer'),
|
||||
config = require('../../config/config');
|
||||
config = require('../../config/config'),
|
||||
auth = require('../../config/passport_helpers');
|
||||
|
||||
// Setting the pdf upload route and folder
|
||||
var storage = multer.diskStorage({
|
||||
|
@ -27,21 +28,21 @@ var upload = multer({
|
|||
module.exports = function(app) {
|
||||
// Form Routes
|
||||
app.route('/upload/pdf')
|
||||
.post(users.requiresLogin, upload.single('file'), forms.uploadPDF);
|
||||
.post(auth.isAuthenticatedOrApiKey, upload.single('file'), forms.uploadPDF);
|
||||
|
||||
app.route('/forms')
|
||||
.get(users.requiresLogin, forms.list)
|
||||
.post(users.requiresLogin, forms.create);
|
||||
.get(auth.isAuthenticatedOrApiKey, forms.list)
|
||||
.post(auth.isAuthenticatedOrApiKey, forms.create);
|
||||
|
||||
app.route('/forms/:formId([a-zA-Z0-9]+)')
|
||||
.get(forms.read)
|
||||
.post(forms.createSubmission)
|
||||
.put(users.requiresLogin, forms.hasAuthorization, forms.update)
|
||||
.delete(users.requiresLogin, forms.hasAuthorization, forms.delete);
|
||||
.put(auth.isAuthenticatedOrApiKey, forms.hasAuthorization, forms.update)
|
||||
.delete(auth.isAuthenticatedOrApiKey, forms.hasAuthorization, forms.delete);
|
||||
|
||||
app.route('/forms/:formId([a-zA-Z0-9]+)/submissions')
|
||||
.get(users.requiresLogin, forms.hasAuthorization, forms.listSubmissions)
|
||||
.delete(users.requiresLogin, forms.hasAuthorization, forms.deleteSubmissions);
|
||||
.get(auth.isAuthenticatedOrApiKey, forms.hasAuthorization, forms.listSubmissions)
|
||||
.delete(auth.isAuthenticatedOrApiKey, forms.hasAuthorization, forms.deleteSubmissions);
|
||||
|
||||
// Finish by binding the form middleware
|
||||
app.param('formId', forms.formByID);
|
||||
|
|
|
@ -3,16 +3,17 @@
|
|||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
var passport = require('passport');
|
||||
var config = require('../../config/config');
|
||||
var passport = require('passport'),
|
||||
config = require('../../config/config'),
|
||||
auth = require('../../config/passport_helpers');
|
||||
|
||||
module.exports = function(app) {
|
||||
// User Routes
|
||||
var users = require('../../app/controllers/users.server.controller');
|
||||
|
||||
// Setting up the users profile api
|
||||
app.route('/users/me').get(users.requiresLogin, users.getUser);
|
||||
app.route('/users').put(users.requiresLogin, users.update);
|
||||
app.route('/users/me').get(auth.isAuthenticatedOrApiKey, users.getUser);
|
||||
app.route('/users').put(auth.isAuthenticatedOrApiKey, users.update);
|
||||
app.route('/users/accounts').delete(users.requiresLogin, users.removeOAuthProvider);
|
||||
|
||||
// Setting up the users account verification api
|
||||
|
@ -32,6 +33,8 @@ module.exports = function(app) {
|
|||
app.route('/auth/signin').post(users.signin);
|
||||
app.route('/auth/signout').get(users.signout);
|
||||
|
||||
app.route('/auth/genkey').get(users.requiresLogin, users.generateAPIKey);
|
||||
|
||||
// // Setting the facebook oauth routes
|
||||
// app.route('/auth/facebook').get(passport.authenticate('facebook', {
|
||||
// scope: ['email']
|
||||
|
|
|
@ -150,13 +150,6 @@ describe('FormSubmission Model Unit Tests:', function() {
|
|||
beforeEach(function(done){
|
||||
|
||||
var myFieldMap = {};
|
||||
myFieldMap[myForm.form_fields[0]._id+''] = 'firstName';
|
||||
myFieldMap[myForm.form_fields[1]._id+''] = 'lastName';
|
||||
myFieldMap[myForm.form_fields[2]._id+''] = 'sex';
|
||||
myFieldMap[myForm.form_fields[3]._id+''] = 'DOB';
|
||||
myFieldMap[myForm.form_fields[4]._id+''] = 'phone';
|
||||
|
||||
myForm.plugins.oscarhost.settings.fieldMap = myFieldMap;
|
||||
|
||||
myForm.save(function(err, form){
|
||||
if(err) done(err);
|
||||
|
@ -175,49 +168,6 @@ describe('FormSubmission Model Unit Tests:', function() {
|
|||
});
|
||||
});
|
||||
|
||||
// it('should add Patient to OscarHost EMR after save', function(done){
|
||||
// var url_login = myForm.plugins.oscarhost.baseUrl+'/LoginService?wsdl',
|
||||
// url_demo = myForm.plugins.oscarhost.baseUrl+'/DemographicService?wsdl',
|
||||
// args_login = {arg0: config.oscarhost.auth.user, arg1: config.oscarhost.auth.pass};
|
||||
|
||||
// var options = {
|
||||
// ignoredNamespaces: {
|
||||
// namespaces: ['targetNamespace', 'typedNamespace'],
|
||||
// override: true
|
||||
// }
|
||||
// };
|
||||
|
||||
// async.waterfall([
|
||||
// function (callback) {
|
||||
// //Authenticate with API
|
||||
// soap.createClient(url_login, options, function(err, client) {
|
||||
// client.login(args_login, function (err, result) {
|
||||
// if(err) callback(err);
|
||||
// callback(null, result.return);
|
||||
// });
|
||||
// });
|
||||
// },
|
||||
|
||||
// function (security_obj, callback) {
|
||||
// soap.createClient(url_demo, options, function(err, client) {
|
||||
// client.setSecurity(new OscarSecurity(security_obj.securityId, security_obj.securityTokenKey) );
|
||||
|
||||
// client.getDemographic({ arg0: oscar_demo_num }, function (err, result) {
|
||||
// if(err) callback(err);
|
||||
// callback(null, result);
|
||||
// });
|
||||
// });
|
||||
// },
|
||||
|
||||
// ], function(err, result) {
|
||||
// if(err) done(err);
|
||||
|
||||
// should.exist(result);
|
||||
// console.log(result.return);
|
||||
|
||||
// done();
|
||||
// });
|
||||
// });
|
||||
});
|
||||
|
||||
describe('Method Find', function(){
|
||||
|
|
94
app/views/redoc.server.view.html
Normal file
94
app/views/redoc.server.view.html
Normal file
|
@ -0,0 +1,94 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
|
||||
|
||||
<head>
|
||||
<title>{{title}}</title>
|
||||
|
||||
<!-- General META -->
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="Content-type" content="text/html;charset=UTF-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1">
|
||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||
<meta name="apple-mobile-web-app-status-bar-style" content="black">
|
||||
|
||||
<!-- Semantic META -->
|
||||
<meta name="keywords" content="{{keywords}}">
|
||||
<meta name="description" content="{{description}}">
|
||||
|
||||
<!-- Facebook META -->
|
||||
<meta property="og:site_name" content="{{title}}">
|
||||
<meta property="og:title" content="{{title}}">
|
||||
<meta property="og:description" content="{{description}}">
|
||||
<meta property="og:url" content="{{url}}">
|
||||
<meta property="og:image" content="/img/brand/logo.png">
|
||||
<meta property="og:type" content="website">
|
||||
|
||||
<!-- Twitter META -->
|
||||
<meta name="twitter:title" content="{{title}}">
|
||||
<meta name="twitter:description" content="{{description}}">
|
||||
<meta name="twitter:url" content="{{url}}">
|
||||
<meta name="twitter:image" content="/img/brand/logo.png">
|
||||
|
||||
<!-- Fav Icon -->
|
||||
<link href="/static/modules/core/img/brand/favicon.ico" rel="shortcut icon" type="image/x-icon">
|
||||
<link rel='stylesheet' href='https://fonts.googleapis.com/css?family=Source+Sans+Pro:300,400,600,700,900'>
|
||||
|
||||
<!--Bower CSS dependencies-->
|
||||
|
||||
<!-- end Bower CSS dependencies-->
|
||||
|
||||
<!--Application CSS Files-->
|
||||
{% for cssFile in cssFiles %}
|
||||
<link rel="stylesheet" href="{{cssFile}}">
|
||||
{% endfor %}
|
||||
<!-- end Application CSS Files-->
|
||||
|
||||
|
||||
<!-- HTML5 Shim -->
|
||||
<!--[if lt IE 9]>
|
||||
<script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
|
||||
<![endif]-->
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<redoc spec-url='/static/swagger.json'></redoc>
|
||||
<script src="https://rebilly.github.io/ReDoc/releases/latest/redoc.min.js"> </script>
|
||||
|
||||
<!--Bower JS dependencies-->
|
||||
{% for bowerJSFile in bowerJSFiles %}
|
||||
<script type="text/javascript" src="{{bowerJSFile}}"></script>
|
||||
{% endfor %}
|
||||
<!-- end Bower JS dependencies-->
|
||||
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/angular-strap/2.3.8/angular-strap.min.js"></script>
|
||||
|
||||
{% if process.env.NODE_ENV === 'development' %}
|
||||
|
||||
<script src="https://cdn.ravenjs.com/2.3.0/angular/raven.min.js"></script>
|
||||
|
||||
<script>
|
||||
Raven.config('https://825fefd6b4ed4a4da199c1b832ca845c@sentry.tellform.com/2').install();
|
||||
</script>
|
||||
|
||||
<!-- [if lt IE 9]>
|
||||
<section class="browsehappy jumbotron hide">
|
||||
<h1>Hello there!</h1>
|
||||
<p>You are using an old browser which we unfortunately do not support.</p>
|
||||
<p>Please <a href="http://browsehappy.com/">click here</a> to update your browser before using the website.</p>
|
||||
<p><a href="http://browsehappy.com" class="btn btn-primary btn-lg" role="button">Yes, upgrade my browser!</a></p>
|
||||
</section>
|
||||
<![endif] -->
|
||||
|
||||
<script>
|
||||
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
|
||||
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
|
||||
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
|
||||
})(window,document,'script','https://www.google-analytics.com/analytics.js','ga');
|
||||
|
||||
ga('create', '{{google_analytics_id}}', 'auto');
|
||||
ga('send', 'pageview');
|
||||
</script>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
|
@ -36,16 +36,11 @@
|
|||
"js-yaml": "^3.6.1",
|
||||
"angular-ui-select": "https://github.com/whitef0x0/ui-select.git#compiled",
|
||||
"angular-translate": "~2.11.0",
|
||||
<<<<<<< HEAD
|
||||
"ng-device-detector": "^3.0.1",
|
||||
"ng-translate": "*",
|
||||
"deep-diff": "^0.3.4"
|
||||
=======
|
||||
"ng-device-detector": "~3.0.1",
|
||||
"ng-translate": "*",
|
||||
"deep-diff": "^0.3.4",
|
||||
"mathjs": "^3.4.1",
|
||||
"jsep": "^0.3.1"
|
||||
>>>>>>> logic_jump
|
||||
},
|
||||
"resolutions": {
|
||||
"angular-bootstrap": "^0.14.0",
|
||||
|
|
|
@ -72,8 +72,6 @@ module.exports = function(db) {
|
|||
var subdomains = req.subdomains;
|
||||
var host = req.hostname;
|
||||
|
||||
console.log(subdomains);
|
||||
|
||||
if(subdomains.slice(0, 4).join('.')+'' === '1.0.0.127'){
|
||||
subdomains = subdomains.slice(4);
|
||||
}
|
||||
|
@ -92,6 +90,20 @@ module.exports = function(db) {
|
|||
return next();
|
||||
}
|
||||
|
||||
//console.log(subdomains);
|
||||
//console.log("is api subdomain: "+ (subdomains.indexOf("api") > -1));
|
||||
//console.log(req.url);
|
||||
if(subdomains.indexOf('api') > -1){
|
||||
// rebuild url
|
||||
path += 'api' + req.url;
|
||||
console.log(req.url);
|
||||
// TODO: check path and query strings are preserved
|
||||
// reassign url
|
||||
req.url = path;
|
||||
console.log(req.url);
|
||||
return next();
|
||||
}
|
||||
|
||||
User.findOne({username: req.subdomains.reverse()[0]}).exec(function (err, user) {
|
||||
console.log(user);
|
||||
if (err) {
|
||||
|
|
54
config/passport_helpers.js
Normal file
54
config/passport_helpers.js
Normal file
|
@ -0,0 +1,54 @@
|
|||
"use strict";
|
||||
|
||||
var config = require("./config");
|
||||
var passport = require("passport");
|
||||
|
||||
var User = require('mongoose').model('User');
|
||||
|
||||
module.exports.isAuthenticatedOrApiKey = function isAuthenticated(req, res, next) {
|
||||
debugger;
|
||||
if (req.isAuthenticated()) {
|
||||
return next();
|
||||
} else {
|
||||
// Try authenticate with API KEY
|
||||
if (req.headers.apikey || req.query.apikey || req.body.apikey) {
|
||||
passport.authenticate("localapikey", function (err, user, info) {
|
||||
if (err)
|
||||
return res.sendStatus(500);
|
||||
|
||||
if (!user)
|
||||
return res.status(401).send(info.message || "");
|
||||
|
||||
req.login(user, function(err) {
|
||||
if (err) return res.sendStatus(500);
|
||||
|
||||
req.user = user;
|
||||
return next();
|
||||
});
|
||||
|
||||
})(req, res, next);
|
||||
} else {
|
||||
return res.sendStatus(401);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
module.exports.hasRole = function hasRole(roleRequired) {
|
||||
if (!roleRequired)
|
||||
throw new Error("Required role needs to be set");
|
||||
|
||||
return function(req, res, next) {
|
||||
return module.exports.isAuthenticated(req, res, function() {
|
||||
if (req.user && req.user.roles && req.user.roles.indexOf(roleRequired) !== -1)
|
||||
next();
|
||||
else
|
||||
res.sendStatus(403);
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
module.exports.hasAdminRole = function hasAdminRole() {
|
||||
return module.exports.hasRole("admin");
|
||||
};
|
||||
|
25
config/strategies/apikey.js
Normal file
25
config/strategies/apikey.js
Normal file
|
@ -0,0 +1,25 @@
|
|||
"use strict";
|
||||
|
||||
var passport = require("passport");
|
||||
var LocalAPIKeyStrategy = require("passport-localapikey-update").Strategy;
|
||||
var User = require('mongoose').model('User');
|
||||
|
||||
module.exports = function() {
|
||||
passport.use(new LocalAPIKeyStrategy({
|
||||
passReqToCallback : true
|
||||
}, function(req, apiKey, done) {
|
||||
return User.findOne({
|
||||
"apiKey": apiKey
|
||||
}, function(err, user) {
|
||||
if (err)
|
||||
return done(err);
|
||||
|
||||
if (!user)
|
||||
return done(null, false, {
|
||||
message: "Unknown API Key"
|
||||
});
|
||||
|
||||
return done(null, user);
|
||||
});
|
||||
}));
|
||||
};
|
|
@ -94,6 +94,7 @@
|
|||
"socket.io": "^1.4.6",
|
||||
"socket.io-redis": "^1.0.0",
|
||||
"swig": "~1.4.1",
|
||||
"uuid-token-generator": "^0.5.0",
|
||||
"wildcard-subdomains": "github:whitef0x0/wildcard-subdomains"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
|
103
public/dist/application.js
vendored
103
public/dist/application.js
vendored
File diff suppressed because one or more lines are too long
4
public/dist/application.min.css
vendored
4
public/dist/application.min.css
vendored
File diff suppressed because one or more lines are too long
31
public/dist/application.min.js
vendored
31
public/dist/application.min.js
vendored
File diff suppressed because one or more lines are too long
303
public/dist/form-application.js
vendored
303
public/dist/form-application.js
vendored
File diff suppressed because one or more lines are too long
24
public/dist/form-application.min.js
vendored
24
public/dist/form-application.min.js
vendored
File diff suppressed because one or more lines are too long
|
@ -55,6 +55,15 @@ section.auth {
|
|||
color: #4c4c4c;
|
||||
}
|
||||
|
||||
section.auth .btn {
|
||||
border-radius: 100px;
|
||||
font-size: 14px;
|
||||
padding: 12px 28px;
|
||||
margin-top: 1em;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
|
||||
.btn-rounded.btn-signup {
|
||||
background-color: #FFD747;
|
||||
color: #896D0B;
|
||||
|
|
882
public/swagger.json
Normal file
882
public/swagger.json
Normal file
|
@ -0,0 +1,882 @@
|
|||
{
|
||||
"swagger": "2.0",
|
||||
"info": {
|
||||
"version": "1.0.0",
|
||||
"title": "TellForm API",
|
||||
"contact": {
|
||||
"name": "TellForm Team",
|
||||
"email": "team@tellform.com"
|
||||
}
|
||||
},
|
||||
"externalDocs": {
|
||||
"description": "Find out how to host your own TellForm instance.",
|
||||
"url": "https://github.com/whitef0x0/tellform"
|
||||
},
|
||||
"host": "api.tellform.com",
|
||||
"basePath": "/",
|
||||
"schemes": [
|
||||
"http",
|
||||
"https"
|
||||
],
|
||||
"tags": [
|
||||
{
|
||||
"name": "form",
|
||||
"description": "Everything about your Forms"
|
||||
},
|
||||
{
|
||||
"name": "user",
|
||||
"description": "Everything about your Account"
|
||||
}
|
||||
],
|
||||
"securityDefinitions": {
|
||||
"api_key": {
|
||||
"type": "apiKey",
|
||||
"name": "apikey",
|
||||
"in": "header"
|
||||
}
|
||||
},
|
||||
"paths": {
|
||||
"/forms": {
|
||||
"get": {
|
||||
"tags": [
|
||||
"form"
|
||||
],
|
||||
"summary": "Find all forms",
|
||||
"responses": {
|
||||
"405": {
|
||||
"description": "Missing Form Input"
|
||||
},
|
||||
"400": {
|
||||
"description": "Form is Invalid"
|
||||
},
|
||||
"404": {
|
||||
"description": "Form not Found"
|
||||
},
|
||||
"200": {
|
||||
"description": "forms response",
|
||||
"schema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/Form"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"security": [
|
||||
{
|
||||
"api_key": []
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"/form/:form_id": {
|
||||
"get": {
|
||||
"tags": [
|
||||
"form"
|
||||
],
|
||||
"summary": "Find form by ID",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "forms response",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/Form"
|
||||
},
|
||||
"headers": {
|
||||
"x-expires": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"security": [
|
||||
{
|
||||
"api_key": []
|
||||
}
|
||||
]
|
||||
},
|
||||
"post": {
|
||||
"tags": [
|
||||
"form"
|
||||
],
|
||||
"summary": "Create a new form",
|
||||
"description": "Create and save a new form",
|
||||
"operationId": "addForm",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"parameters": [
|
||||
{
|
||||
"in": "body",
|
||||
"name": "body",
|
||||
"description": "Form object that is to be created",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/Form"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"405": {
|
||||
"description": "Missing Form Input"
|
||||
},
|
||||
"400": {
|
||||
"description": "Form is Invalid"
|
||||
},
|
||||
"404": {
|
||||
"description": "Form not Found"
|
||||
},
|
||||
"200": {
|
||||
"description": "successful operation",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/Form"
|
||||
}
|
||||
}
|
||||
},
|
||||
"security": [
|
||||
{
|
||||
"api_key": []
|
||||
}
|
||||
],
|
||||
"x-code-samples": [
|
||||
]
|
||||
},
|
||||
"put": {
|
||||
"tags": [
|
||||
"form"
|
||||
],
|
||||
"summary": "Update an existing form",
|
||||
"description": "",
|
||||
"operationId": "updateForm",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"parameters": [
|
||||
{
|
||||
"in": "body",
|
||||
"name": "form",
|
||||
"description": "Form object that needs to be updated",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/Form"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"405": {
|
||||
"description": "Missing Form Input"
|
||||
},
|
||||
"400": {
|
||||
"description": "Form is Invalid"
|
||||
},
|
||||
"404": {
|
||||
"description": "Form not Found"
|
||||
},
|
||||
"200": {
|
||||
"description": "successful operation",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/Form"
|
||||
}
|
||||
}
|
||||
},
|
||||
"security": [
|
||||
{
|
||||
"api_key": []
|
||||
}
|
||||
],
|
||||
"x-code-samples": [
|
||||
]
|
||||
}
|
||||
},
|
||||
"/users/me": {
|
||||
"get": {
|
||||
"tags": [
|
||||
"user"
|
||||
],
|
||||
"summary": "Retrieve current User",
|
||||
"description": "",
|
||||
"operationId": "getUser",
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"responses": {
|
||||
"500": {
|
||||
"description": "Could not Update User"
|
||||
},
|
||||
"401": {
|
||||
"description": "User is not Signed in"
|
||||
},
|
||||
"403": {
|
||||
"description": "User is not Authorized"
|
||||
},
|
||||
"404": {
|
||||
"description": "User does not exsit"
|
||||
},
|
||||
"200": {
|
||||
"description": "successful operation",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/User"
|
||||
}
|
||||
}
|
||||
},
|
||||
"security": [
|
||||
{
|
||||
"api_key": []
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"/users": {
|
||||
"put": {
|
||||
"tags": [
|
||||
"user"
|
||||
],
|
||||
"summary": "Update the current user",
|
||||
"description": "",
|
||||
"operationId": "updateUser",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"parameters": [
|
||||
{
|
||||
"in": "body",
|
||||
"name": "body",
|
||||
"description": "User object that needs to be updated",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/User"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"500": {
|
||||
"description": "Could not Update User"
|
||||
},
|
||||
"401": {
|
||||
"description": "User is not Signed in"
|
||||
},
|
||||
"403": {
|
||||
"description": "User is not Authorized"
|
||||
},
|
||||
"404": {
|
||||
"description": "User does not exsit"
|
||||
},
|
||||
"200": {
|
||||
"description": "successful operation",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/User"
|
||||
}
|
||||
}
|
||||
},
|
||||
"security": [
|
||||
{
|
||||
"api_key": []
|
||||
}
|
||||
],
|
||||
"x-code-samples": [
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
},
|
||||
"definitions": {
|
||||
"User": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"language",
|
||||
"email",
|
||||
"username"
|
||||
],
|
||||
"properties": {
|
||||
"firstName": {
|
||||
"type": "string",
|
||||
"description": "First name of User",
|
||||
"example": "John"
|
||||
},
|
||||
"lastName": {
|
||||
"type": "string",
|
||||
"description": "First name of User",
|
||||
"example": "Doe"
|
||||
},
|
||||
"language": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"en",
|
||||
"fr",
|
||||
"es",
|
||||
"it",
|
||||
"de"
|
||||
],
|
||||
"default": "en",
|
||||
"required": "User must have a language",
|
||||
"description": "Language of User (for internationalization)",
|
||||
"example": "fr"
|
||||
},
|
||||
"email": {
|
||||
"type": "string",
|
||||
"format": "email",
|
||||
"required": "User email cannot be blank",
|
||||
"unique": "true",
|
||||
"description": "Email of User",
|
||||
"example": "john.doe@somewhere.com"
|
||||
},
|
||||
"username": {
|
||||
"type": "string",
|
||||
"required": "Username cannot be blank",
|
||||
"unique": "true",
|
||||
"description": "Username of User",
|
||||
"example": "johndoe"
|
||||
},
|
||||
"roles": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"user",
|
||||
"admin",
|
||||
"superuser"
|
||||
]
|
||||
},
|
||||
"default": [ "user" ],
|
||||
"description": "Security Roles of User"
|
||||
}
|
||||
},
|
||||
"lastModified": {
|
||||
"type": "date",
|
||||
"description": "Date that user was last modified",
|
||||
"example": "2016-08-26T20:19:30.146Z"
|
||||
},
|
||||
"created": {
|
||||
"type": "date",
|
||||
"description": "Date that user was created on",
|
||||
"example": "5dHuKJgeCZmFOdJTnmg0lrxApmz0tbbBrM59rTv4k79"
|
||||
},
|
||||
"resetPasswordToken": {
|
||||
"type": "string",
|
||||
"description": "Reset password token of User",
|
||||
"example": "5dHuKJgeCZmFOdJTnmg0lrxApmz0tbbBrM59rTv4k79"
|
||||
},
|
||||
"resetPasswordExpires": {
|
||||
"type": "date",
|
||||
"example": "2016-08-26T20:19:30.146Z",
|
||||
"description": "Date that the User's password reset token expires"
|
||||
},
|
||||
"token": {
|
||||
"type": "string",
|
||||
"description": "Verification token of User",
|
||||
"example": "5dHuKJgeCZmFOdJTnmg0lrxApmz0tbbBrM59rTv4k79"
|
||||
},
|
||||
"apiKey": {
|
||||
"type": "string",
|
||||
"unique": true,
|
||||
"index": true,
|
||||
"sparse": true,
|
||||
"description": "API Key of User",
|
||||
"example": "5dHuKJgeCZmFOdJTnmg0lrxApmz0tbbBrM59rTv4k79"
|
||||
}
|
||||
},
|
||||
"LogicJump": {
|
||||
"expressionString": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"field == static",
|
||||
"field != static",
|
||||
"field > static",
|
||||
"field >= static",
|
||||
"field <= static",
|
||||
"field < static",
|
||||
"field contains static",
|
||||
"field !contains static",
|
||||
"field begins static",
|
||||
"field !begins static",
|
||||
"field ends static",
|
||||
"field !ends static"
|
||||
]
|
||||
},
|
||||
"fieldA": {
|
||||
"$ref": "#/definitions/FormField"
|
||||
},
|
||||
"valueB": {
|
||||
"type": "string"
|
||||
},
|
||||
"jumpTo": {
|
||||
"$ref": "#/definitions/FormField"
|
||||
}
|
||||
},
|
||||
"FieldOption": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"option_id": {
|
||||
"type": "number"
|
||||
},
|
||||
"option_title": {
|
||||
"type": "string"
|
||||
},
|
||||
"option_value": {
|
||||
"type": "string",
|
||||
"trim": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"RatingField": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"steps": {
|
||||
"type": "number",
|
||||
"min": 1,
|
||||
"max": 10
|
||||
},
|
||||
"shape": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Heart",
|
||||
"Star",
|
||||
"thumbs-up",
|
||||
"thumbs-down",
|
||||
"Circle",
|
||||
"Square",
|
||||
"Check Circle",
|
||||
"Smile Outlined",
|
||||
"Hourglass",
|
||||
"bell",
|
||||
"Paper Plane",
|
||||
"Comment",
|
||||
"Trash"
|
||||
]
|
||||
},
|
||||
"validShapes": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"FormField": {
|
||||
"required": [
|
||||
"title",
|
||||
"fieldType"
|
||||
],
|
||||
"properties": {
|
||||
"isSubmission": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "Specifies whether Field is part of a Submission or not",
|
||||
"example": true
|
||||
},
|
||||
"submissionId": {
|
||||
"type": "string",
|
||||
"description": "ID of Submission that this Field belongs to",
|
||||
"example": "57bca0969ca8e18b825bcc2b"
|
||||
},
|
||||
"title": {
|
||||
"type": "string",
|
||||
"trim": true,
|
||||
"required": "Field Title cannot be blank",
|
||||
"description": "Description of Field",
|
||||
"example": "Your Current University"
|
||||
},
|
||||
"description": {
|
||||
"type": "string",
|
||||
"default": "",
|
||||
"description": "Description of Field",
|
||||
"example": "Please do not use abbreviations for your school name"
|
||||
},
|
||||
"logicJump": {
|
||||
"$ref": "#/definitions/FormField"
|
||||
},
|
||||
"ratingOptions": {
|
||||
"type": "#/definitions/RatingField"
|
||||
},
|
||||
"fieldOptions": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "FieldOption"
|
||||
}
|
||||
},
|
||||
"required": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "Specifies whether Field is required",
|
||||
"example": true
|
||||
},
|
||||
"disabled": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "Specifies whether Field is disabled",
|
||||
"example": true
|
||||
},
|
||||
"deletePreserved": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "Specifies whether Field should be preserved if it is deleted",
|
||||
"example": false
|
||||
},
|
||||
"validFieldTypes": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"fieldType": {
|
||||
"type": "string",
|
||||
"required": true,
|
||||
"enum": [
|
||||
"textfield",
|
||||
"date",
|
||||
"email",
|
||||
"link",
|
||||
"legal",
|
||||
"url",
|
||||
"textarea",
|
||||
"statement",
|
||||
"welcome",
|
||||
"thankyou",
|
||||
"file",
|
||||
"dropdown",
|
||||
"scale",
|
||||
"rating",
|
||||
"radio",
|
||||
"checkbox",
|
||||
"hidden",
|
||||
"yes_no",
|
||||
"natural",
|
||||
"stripe",
|
||||
"number"
|
||||
],
|
||||
"description": "Type of Field",
|
||||
"example": "textfield"
|
||||
},
|
||||
"fieldValue": {
|
||||
"type": "string",
|
||||
"description": "Value of Field",
|
||||
"example": "University of British Columbia"
|
||||
}
|
||||
}
|
||||
},
|
||||
"VisitorData": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"referrer": {
|
||||
"type": "string",
|
||||
"description": "Referring site of Form Visitor",
|
||||
"example": "http://google.com"
|
||||
},
|
||||
"lastActiveField": {
|
||||
"type": "string",
|
||||
"description": "ID of Last Active Field",
|
||||
"example": "57bca0969ca8e18b825bcc2b"
|
||||
},
|
||||
"timeElapsed": {
|
||||
"type": "number",
|
||||
"description": "Time Elasped for Visitor on Form (in seconds)",
|
||||
"example": "333.33"
|
||||
},
|
||||
"isSubmitted": {
|
||||
"type": "boolean",
|
||||
"description": "Specifies whether user submitted form before leaving page",
|
||||
"example": false
|
||||
},
|
||||
"language": {
|
||||
"type": "string",
|
||||
"description": "Language of User using form",
|
||||
"example": "en"
|
||||
},
|
||||
"ipAddr": {
|
||||
"type": "string",
|
||||
"default": "",
|
||||
"description": "IP Address of User",
|
||||
"example": "324.332.322.333"
|
||||
},
|
||||
"deviceType": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"desktop",
|
||||
"phone",
|
||||
"tablet",
|
||||
"other"
|
||||
],
|
||||
"default": "other",
|
||||
"description": "Device Type of User",
|
||||
"example": "phone"
|
||||
},
|
||||
"userAgent": {
|
||||
"type": "string",
|
||||
"description": "User Agent of User",
|
||||
"example": "Mozilla/5.0 (Linux; <Android Version>; <Build Tag etc.>) AppleWebKit/<WebKit Rev> (KHTML, like Gecko) Chrome/<Chrome Rev> Mobile Safari/<WebKit Rev>"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Button": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"url": {
|
||||
"type": "string",
|
||||
"format": "url",
|
||||
"description": "URL of Button Link",
|
||||
"example": "http://you-are-awesome.com"
|
||||
},
|
||||
"action": {
|
||||
"type": "string",
|
||||
"description": "Angular Action fired during Button click",
|
||||
"example": "openModal()"
|
||||
},
|
||||
"text": {
|
||||
"type": "string",
|
||||
"description": "Text of Button",
|
||||
"example": "Go to HomePage"
|
||||
},
|
||||
"bgColor": {
|
||||
"type": "string",
|
||||
"pattern": "/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/",
|
||||
"default": "#5bc0de",
|
||||
"description": "Background Color of Button (in hex)",
|
||||
"example": "#5bc0de"
|
||||
},
|
||||
"color": {
|
||||
"type": "string",
|
||||
"pattern": "/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/",
|
||||
"default": "#ffffff",
|
||||
"description": "Font Color of Button (in hex)",
|
||||
"example": "#ffffff"
|
||||
}
|
||||
}
|
||||
},
|
||||
"FormSubmission": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"language",
|
||||
"admin",
|
||||
"title"
|
||||
],
|
||||
"properties": {
|
||||
"title": {
|
||||
"type": "string",
|
||||
"required": "Form Title cannot be blank"
|
||||
},
|
||||
"language": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"en",
|
||||
"fr",
|
||||
"es",
|
||||
"it",
|
||||
"de"
|
||||
],
|
||||
"default": "en",
|
||||
"required": "Form must have a language"
|
||||
},
|
||||
"admin": {
|
||||
"$ref": "#/definitions/User",
|
||||
},
|
||||
"ipAddr": {
|
||||
"type": "string"
|
||||
},
|
||||
"geoLocation": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"Country": {
|
||||
"type": "string"
|
||||
},
|
||||
"Region": {
|
||||
"type": "string"
|
||||
},
|
||||
"City": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"device": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"pdfFilePath": {
|
||||
"type": "string"
|
||||
},
|
||||
"pdf": {
|
||||
"type": "string"
|
||||
},
|
||||
|
||||
"timeElapsed": {
|
||||
"type": "number"
|
||||
},
|
||||
"percentageComplete": {
|
||||
"type": "number"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Form": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"language",
|
||||
"admin",
|
||||
"title"
|
||||
],
|
||||
"properties": {
|
||||
|
||||
"title": {
|
||||
"type": "string",
|
||||
"required": "Form Title cannot be blank",
|
||||
"description": "Public Title of Form",
|
||||
"example": "UBC CPSC221 Course Waitlist Form"
|
||||
},
|
||||
"language": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"en",
|
||||
"fr",
|
||||
"es",
|
||||
"it",
|
||||
"de"
|
||||
],
|
||||
"default": "en",
|
||||
"required": "Form must have a language",
|
||||
"description": "Language of Form",
|
||||
"example": "en"
|
||||
},
|
||||
"analytics": {
|
||||
"type": "object",
|
||||
"description": "Analytics of Form",
|
||||
"properties": {
|
||||
"gaCode": {
|
||||
"type": "string",
|
||||
"description": "Analytics of Form",
|
||||
"example": "UA-000000-01"
|
||||
},
|
||||
"visitors": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "#/definitions/VisitorData"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"form_fields": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "FormField"
|
||||
}
|
||||
},
|
||||
"submissions": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/FormSubmission"
|
||||
}
|
||||
},
|
||||
"admin": {
|
||||
"type": "User",
|
||||
"description": "User that this Form belongs to"
|
||||
},
|
||||
"startPage": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"showStart": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "Specifies whether Form StarPage should be displayed",
|
||||
"example": false
|
||||
},
|
||||
"introTitle": {
|
||||
"type": "string",
|
||||
"default": "Welcome to Form",
|
||||
"description": "Title of Form's StartPage",
|
||||
"example": "Welcome to our Awesome Form!"
|
||||
},
|
||||
"introParagraph": {
|
||||
"type": "string",
|
||||
"description": "Introduction paragraph for Form's StartPage.",
|
||||
"example": "Welcome to our Awesome Form!"
|
||||
},
|
||||
"introButtonText": {
|
||||
"type": "string",
|
||||
"default": "Start",
|
||||
"description": "StartPage Continue Button",
|
||||
"example": "Continue"
|
||||
},
|
||||
"buttons": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
type: "Button"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"hideFooter": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "Specifies whether to hide or show Form Footer",
|
||||
"example": true
|
||||
},
|
||||
"isLive": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "Specifies whether form is Publically available or Private",
|
||||
"example": true
|
||||
},
|
||||
"design": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"colors": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"backgroundColor": {
|
||||
"type": "string",
|
||||
"pattern": "/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/",
|
||||
"default": "#fff",
|
||||
"description": "Background color of Form",
|
||||
"example": "#4c4c4c"
|
||||
},
|
||||
"questionColor": {
|
||||
"type": "string",
|
||||
"match": "/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/",
|
||||
"default": "#333",
|
||||
"description": "Question text font color (in hex)",
|
||||
"example": "#fff"
|
||||
},
|
||||
"answerColor": {
|
||||
"type": "string",
|
||||
"match": "/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/",
|
||||
"default": "#333",
|
||||
"description": "Answer text font color (in hex)",
|
||||
"example": "#f9f9f9"
|
||||
},
|
||||
"buttonColor": {
|
||||
"type": "string",
|
||||
"match": "/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/",
|
||||
"default": "#fff",
|
||||
"description": "Background color of Form Buttons (in hex)",
|
||||
"example": "#555"
|
||||
},
|
||||
"buttonTextColor": {
|
||||
"type": "string",
|
||||
"pattern": "/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/",
|
||||
"default": "#333",
|
||||
"description": "Font color of Form Buttons (in hex)",
|
||||
"example": "#fff"
|
||||
}
|
||||
}
|
||||
},
|
||||
"font": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue