From 74c4f0b4169426873031db74a12cc81c85ea7044 Mon Sep 17 00:00:00 2001 From: David Baldwynn Date: Fri, 26 Aug 2016 13:43:37 -0700 Subject: [PATCH] got api subdomain to work with docs --- app/controllers/core.server.controller.js | 10 +- app/controllers/forms.server.controller.js | 92 +----- app/routes/core.server.routes.js | 5 +- app/views/redoc.server.view.html | 100 +++++++ config/express.js | 18 +- swagger.json => public/swagger.json | 326 +++++++++++++++++---- 6 files changed, 414 insertions(+), 137 deletions(-) create mode 100644 app/views/redoc.server.view.html rename swagger.json => public/swagger.json (60%) diff --git a/app/controllers/core.server.controller.js b/app/controllers/core.server.controller.js index 1ad1306c..049e1d64 100755 --- a/app/controllers/core.server.controller.js +++ b/app/controllers/core.server.controller.js @@ -14,10 +14,18 @@ exports.index = function(req, res) { exports.form = function(req, res) { //Allow form to be embeded - res.removeHeader('X-Frame-Options'); + res.removeHeader('X-Frame-Options'); res.render('form', { user: req.user || null, request: req }); }; + + +exports.redoc = function(req, res) { + res.render('redoc', { + request: req + }); +}; + diff --git a/app/controllers/forms.server.controller.js b/app/controllers/forms.server.controller.js index af63e416..6d5f2424 100644 --- a/app/controllers/forms.server.controller.js +++ b/app/controllers/forms.server.controller.js @@ -69,74 +69,6 @@ exports.uploadPDF = function(req, res, next) { } }; -/** - * Upload PDF - */ -/* -exports.uploadSubmissionFile = function(req, res, next) { - - console.log('inside uploadPDF'); - - // console.log('\n\nProperty Descriptor\n-----------'); - // console.log(Object.getOwnPropertyDescriptor(req.files.file, 'path')); - - console.log(req.files); - - if(req.files){ - var file, _user, _path; - - for(var i=0; i 100000000){ - return next(new Error('File uploaded exceeds MAX SIZE of 100MB')); - }else { - fs.exists(_path, function(exists) { - - //If file exists move to user's form directory - if(exists) { - var newDestination = config.tmpUploadPath+_user.username; - var stat = null; - try { - stat = fs.statSync(newDestination); - } catch (err) { - fs.mkdirSync(newDestination); - } - - if (stat && !stat.isDirectory()) { - console.log('Directory cannot be created'); - return next(new Error('Directory cannot be created because an inode of a different type exists at "' + newDestination + '"')); - } - - console.log(path.join(newDestination, pdfFile.filename)); - - fs.move(pdfFile.path, path.join(newDestination, pdfFile.filename), function (err) { - if (err) { - return next(new Error(err.message)); - } - pdfFile.path = path.join(newDestination, pdfFile.filename); - console.log(pdfFile.filename + ' uploaded to ' + pdfFile.path); - res.json(pdfFile); - }); - - } else { - return next(new Error('Did NOT get your file!')); - } - }); - } - } - - }else { - return next(new Error('Uploaded files were NOT detected')); - } -}; -*/ - /** * Delete a forms submissions */ @@ -254,23 +186,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); }); }; @@ -300,7 +236,7 @@ exports.update = function(req, res) { delete req.body.form.__v; delete req.body.form._id; - //Unless we have 'admin' priviledges, updating form admin is disabled + //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 @@ -317,7 +253,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 { @@ -377,7 +313,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' }); } diff --git a/app/routes/core.server.routes.js b/app/routes/core.server.routes.js index c8077872..cfc01c94 100755 --- a/app/routes/core.server.routes.js +++ b/app/routes/core.server.routes.js @@ -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); }; diff --git a/app/views/redoc.server.view.html b/app/views/redoc.server.view.html new file mode 100644 index 00000000..9a8ed28c --- /dev/null +++ b/app/views/redoc.server.view.html @@ -0,0 +1,100 @@ + + + + + {{title}} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {% for bowerCssFile in bowerCssFiles %} + + {% endfor %} + + + + + + {% for cssFile in cssFiles %} + + {% endfor %} + + + + + + + + + + + + + {% for bowerJSFile in bowerJSFiles %} + + {% endfor %} + + + + {% if process.env.NODE_ENV === 'development' %} + + + + + + + + + + + + diff --git a/config/express.js b/config/express.js index 57e3b439..f8944d96 100755 --- a/config/express.js +++ b/config/express.js @@ -72,7 +72,6 @@ module.exports = function(db) { var subdomains = req.subdomains; var host = req.hostname; - if(subdomains.slice(0, 4).join('.')+'' === '1.0.0.127'){ subdomains = subdomains.slice(4); } @@ -81,16 +80,29 @@ module.exports = function(db) { if (!subdomains.length) return next(); var urlPath = url.parse(req.url).path.split('/'); - if(urlPath.indexOf('static')){ + if(urlPath.indexOf('static') > -1){ urlPath.splice(1,1); req.root = 'https://' + config.baseUrl + urlPath.join('/'); return next(); } - if(subdomains.indexOf('stage') || subdomains.indexOf('admin')){ + if(subdomains.indexOf('stage') > -1 || subdomains.indexOf('admin') > -1){ 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) { if (err) { diff --git a/swagger.json b/public/swagger.json similarity index 60% rename from swagger.json rename to public/swagger.json index 96164b76..efdb4f6a 100644 --- a/swagger.json +++ b/public/swagger.json @@ -5,14 +5,10 @@ "title": "TellForm API", "contact": { "name": "TellForm Team", - "url": "http://tellform.com" - }, - "license": { - "name": "Creative Commons 4.0 International", - "url": "http://creativecommons.org/licenses/by/4.0/" + "url": "http://www.tellform.com" } }, - "host": "tellform.com", + "host": "api.tellform.com", "basePath": "/api", "schemes": [ "http" @@ -23,8 +19,17 @@ "tags": [ "Form Operations" ], - "summary": "Finds forms in the system", + "summary": "Finds all forms", "responses": { + "405": { + "description": "Missing Form Input" + }, + "400": { + "description": "Form is Invalid" + }, + "404": { + "description": "Form not Found" + }, "200": { "description": "forms response", "schema": { @@ -41,7 +46,125 @@ } } } + }, + "/form/:form_id": { + "get": { + "tags": [ + "Form Operations" + ], + "summary": "Find form by ID", + "responses": { + "200": { + "description": "forms response", + "schema": { + "$ref": "#/definitions/Form" + }, + "headers": { + "x-expires": { + "type": "string" + } + } + } + } + }, + "post": { + "tags": [ + "Form Operations" + ], + "summary": "Create a new form", + "description": "Create and save a new form", + "operationId": "addForm", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "in": "body", + "name": "form", + "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": [ + ], + "x-code-samples": [ + ] + }, + "put": { + "tags": [ + "Form Operations" + ], + "summary": "Update an existing form", + "description": "", + "operationId": "updateForm", + "consumes": [ + "application/json", + "application/xml" + ], + "produces": [ + "application/xml", + "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": [ + { + } + ], + "x-code-samples": [ + ] + } } + }, "definitions": { "User": { @@ -63,7 +186,13 @@ }, "language": { "type": "string", - "enum": ["en", "fr", "es", "it", "de"], + "enum": [ + "en", + "fr", + "es", + "it", + "de" + ], "default": "en", "required": "User must have a language" }, @@ -75,7 +204,7 @@ }, "username": { "type": "string", - "required": "Username cannot be blank" + "required": "Username cannot be blank", "unique": "true" }, "passwordHash": { @@ -86,9 +215,9 @@ "type": "string" }, "provider": { - "type": "string", - "required": "provider is required", - "default": "local" + "type": "string", + "required": "provider is required", + "default": "local" }, "providerData": { "type": "object" @@ -100,11 +229,17 @@ "type": "array", "items": { "type": "string", - "enum": ["user", "admin", "superuser"] + "enum": [ + "user", + "admin", + "superuser" + ] }, - "default": ["user"] + "default": [ + "user" + ] } - } + }, "lastModified": { "type": "date" }, @@ -127,9 +262,34 @@ "sparse": true } }, - - "LogicJump": - + "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": { @@ -145,7 +305,6 @@ } } }, - "RatingField": { "type": "object", "properties": { @@ -174,20 +333,18 @@ }, "validShapes": { "type": "array", - "items": { + "items": { "type": "string" } } } }, - "FormField": { - "required":[ + "required": [ "title", "fieldType" ], "properties": { - "isSubmission": { "type": "boolean", "default": false @@ -204,11 +361,9 @@ "type": "string", "default": "" }, - "logicJump": { - "$ref": "#/definitions/FormFields" + "$ref": "#/definitions/FormField" }, - "ratingOptions": { "type": "#/definitions/RatingField", }, @@ -224,7 +379,6 @@ "type": "boolean", "default": false }, - "deletePreserved": { "type": "boolean", "default": false @@ -265,10 +419,8 @@ "fieldValue": { "type": "string" } - } }, - "VisitorData": { "type": "object", "properties": { @@ -293,7 +445,12 @@ }, "deviceType": { "type": "string", - "enum": ["desktop", "phone", "tablet", "other"], + "enum": [ + "desktop", + "phone", + "tablet", + "other" + ], "default": "other" }, "userAgent": { @@ -306,7 +463,7 @@ "properties": { "url": { "type": "string", - "pattern": "/((([A-Za-z]{3,9}:(?:\/\/)?)(?:[-;:&=\+\$,\w]+@)?[A-Za-z0-9.-]+|(?:www.|[-;:&=\+\$,\w]+@)[A-Za-z0-9.-]+)((?:\/[\+~%\/.\w-_]*)?\??(?:[-\+=&;%@.\w_]*)#?(?:[\w]*))?)/" + "format": "url" }, "action": { "type": "string" @@ -326,6 +483,76 @@ } } }, + "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": [ @@ -343,11 +570,18 @@ }, "language": { "type": "string", - "enum": ["en", "fr", "es", "it", "de"], + "enum": [ + "en", + "fr", + "es", + "it", + "de" + ], "default": "en", "required": "Form must have a language" }, "analytics": { + "type": "object", "properties": { "gaCode": { "type": "string" @@ -360,10 +594,9 @@ } } }, - "form_fields": { "type": "array", - "items": "#/definitions/FormFields" + "items": "#/definitions/FormField" }, "submissions": { "type": "array", @@ -371,19 +604,15 @@ "$ref": "#/definitions/FormSubmission" } }, - "admin": { - "$ref": "#/definitions/User", - "required": "Form must have an Admin" + "$ref": "#/definitions/User" }, - "pdf": { "type": "object" }, "pdfFieldMap": { "type": "object" }, - "startPage": { "properties": { "showStart": { @@ -407,7 +636,6 @@ } } }, - "hideFooter": { "type": "boolean", "default": false @@ -424,9 +652,8 @@ "type": "boolean", "default": false }, - "design": { - "colors":{ + "colors": { "backgroundColor": { "type": "string", "pattern": "/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/", @@ -437,32 +664,25 @@ "match": "/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/", "default": "#333" }, - "answerColor"": { + "answerColor": { "type": "string", "match": "/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/", "default": "#333" }, "buttonColor": { - "type": "string" + "type": "string", "match": "/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/", "default": "#fff" }, "buttonTextColor": { "type": "string", - "pattern": "[/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/]", + "pattern": "/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/", "default": "#333" } }, "font": "string" } - }, - "Address": { - "type": "object", - "properties": { - "addressLine1": { - "type": "string" - } } - }, + } } }