Changeset 508 for Dev/trunk/src/server


Ignore:
Timestamp:
03/12/14 02:23:11 (11 years ago)
Author:
hendrikvanantwerpen
Message:
  • Server handles the new flat response format correctly.
  • Client widgets and survey rendering creates a flat structure.
  • Fixed logic error in checking if questions in survey are published.
  • Restrict accepted properties in answers and reject empty strings as properties.
Location:
Dev/trunk/src/server
Files:
1 added
3 edited

Legend:

Unmodified
Added
Removed
  • Dev/trunk/src/server/app.js

    r507 r508  
    154154    }
    155155    function areDocsPublished(docs) {
    156         return _.every(docs,isDocPublished);
     156        return _.every(docs, isDocPublished);
    157157    }
    158158    function isDocPublished(doc) {
     
    592592            if ( !areDocsUnique(doc.questions) ) {
    593593                hr = new HTTPResult(400,{error:"Survey contains duplicate questions."});
    594             } else if ( !areDocsPublished(doc.questions) || isDocPublished(doc) ) {
     594            } else if ( isDocPublished(doc) && !areDocsPublished(doc.questions) ) {
    595595                hr = new HTTPResult(400,{error:"Cannot publish Survey with unpublished questions."});
    596596            } else {
     
    610610            var doc = req.body;
    611611            var rev = etags.parse(req.header('If-Match'))[0] || (doc && doc._rev);
    612             var hr;
    613612            if ( !areDocsUnique(doc.questions) ) {
    614613                new HTTPResult(400,{error:"Survey contains duplicate questions."})
    615614                .handle(res.send.bind(res));
    616             } else if ( !areDocsPublished(doc.questions) || isDocPublished(doc) ) {
    617                 hr = new HTTPResult(400,{error:"Cannot publish Survey with unpublished questions."});
     615            } else if ( isDocPublished(doc) && !areDocsPublished(doc.questions) ) {
     616                new HTTPResult(400,{error:"Cannot publish Survey with unpublished questions."})
     617                .handle(res.send.bind(res));
    618618            } else {
    619619                putDocument(id,rev,'Survey',doc)
     
    718718            .handle({
    719719                200: function(responses) {
    720                     var flatResponses = responsesToVariables(responses);
     720                    var answers = _.map(responses,function(response){
     721                        return response.answers;
     722                    });
    721723                    res.set({
    722724                        'Content-Disposition': 'attachment; filename=surveyRun-'+id+'-responses.csv'
    723725                    });
    724726                    res.status(200);
    725                     writeObjectsToCSVStream(flatResponses, res);
     727                    writeObjectsToCSVStream(answers, res);
    726728                    res.end();
    727729                },
     
    953955}
    954956
    955 function responsesToVariables(responses) {
    956     return _.map(responses, responseToVariables);
    957 }
    958 
    959 function responseToVariables(response) {
    960     var result = flattenObject(response.answers);
    961     return result;
    962 }
    963 
    964 function flattenObject(value) {
    965     var result = {};
    966     (function agg(val,key,res){
    967         if ( _.isObject(val) ) {
    968             var keys = _.keys(val);
    969             // FIXME : dirty hack for questions with only one input
    970             if ( keys.length === 1 ) {
    971                 agg(val[keys[0]],key,res);
    972             } else {
    973                 _.forEach(val, function(v,k){
    974                     agg(v,(key ? key+'.' : '')+k,res);
    975                 });
    976             }
    977         } else if ( _.isArray(val) ) {
    978             // FIXME : dirty hack for questions with only one input
    979             if ( val.length === 1 ) {
    980                 agg(val[0],key,res);
    981             } else {
    982                 _.forEach(val, function(v,i){
    983                     agg(v,(key ? key+'.' : '')+i,res);
    984                 });
    985             }
    986         } else {
    987             res[key] = val;
    988         }
    989     })(value,null,result);
    990     return result;
    991 }
    992 
    993957function writeObjectsToCSVStream(objects, stream, prelude) {
    994958    var keys = _.chain(objects)
  • Dev/trunk/src/server/config/couchdb-design-docs.js

    r506 r508  
    1111
    1212    "qed/schemaInfo": {
    13         version: "3"
     13        version: "4"
    1414    },
    1515
  • Dev/trunk/src/server/config/couchdb-schema.json

    r506 r508  
    22  "$schema": "http://json-schema.org/draft-04/schema#",
    33  "title": "QED Object Schema",
    4   "version": "3",
     4  "version": "4",
    55  "type": "object",
    66  "oneOf": [
     
    1010  "definitions": {
    1111    "nonEmptyString": { "type": "string", "minLength": 1 },
     12    "codeString": { "type": "string", "pattern": "^[A-Za-z0-9]+$" },
    1213    "schemaInfo": {
    1314      "type": "object",
     
    3738          "_rev": { "$ref": "#/definitions/nonEmptyString" },
    3839          "categories": { "type": "array", "items": { "$ref": "#/definitions/nonEmptyString" } },
    39           "code": { "$ref": "#/definitions/nonEmptyString" },
     40          "code": { "$ref": "#/definitions/codeString" },
    4041          "content": { "type": "array", "items": { "$ref": "#/definitions/content/any" } },
    4142          "description": { "$ref": "#/definitions/nonEmptyString" },
     
    8687          "_id": { "$ref": "#/definitions/nonEmptyString" },
    8788          "_rev": { "$ref": "#/definitions/nonEmptyString" },
    88           "answers": { "type": "object" },
     89          "answers": {
     90              "type": "object",
     91              "patternProperties": {
     92                  "^[A-Za-z0-9]+$": {}
     93              },
     94              "additionalProperties": false
     95          },
    8996          "email": { "type": "string", "format": "email" },
    9097          "publicationDate": { "type": "string", "format": "datetime" },
     
    139146        "properties": {
    140147          "type": { "type": "string", "pattern": "^StringInput$" },
    141           "subcode": { "$ref": "#/definitions/nonEmptyString" },
     148          "subcode": { "$ref": "#/definitions/codeString" },
    142149          "text": { "$ref": "#/definitions/nonEmptyString" }
    143150        },
     
    150157          "type": { "type": "string", "pattern": "^TextInput$" },
    151158          "maxLength": { "type": "integer" },
    152           "subcode": { "$ref": "#/definitions/nonEmptyString" },
     159          "subcode": { "$ref": "#/definitions/codeString" },
    153160          "text": { "$ref": "#/definitions/nonEmptyString" }
    154161        },
     
    163170          "max": { "type": "integer" },
    164171          "places": { "type": "integer" },
    165           "subcode": { "$ref": "#/definitions/nonEmptyString" },
     172          "subcode": { "$ref": "#/definitions/codeString" },
    166173          "text": { "$ref": "#/definitions/nonEmptyString" }
    167174        },
     
    183190              "minLabel": { "$ref": "#/definitions/nonEmptyString" },
    184191              "maxLabel": { "$ref": "#/definitions/nonEmptyString" },
    185               "subcode": { "$ref": "#/definitions/nonEmptyString" },
     192              "subcode": { "$ref": "#/definitions/codeString" },
    186193              "text": { "$ref": "#/definitions/nonEmptyString" }
    187194            },
     
    201208              "type": "object",
    202209              "properties": {
    203                   "subcode": { "$ref": "#/definitions/nonEmptyString" },
     210                  "subcode": { "$ref": "#/definitions/codeString" },
    204211                  "text": { "$ref": "#/definitions/nonEmptyString" }
    205212              },
     
    210217              "type": "object",
    211218              "properties": {
    212                   "subcode": { "$ref": "#/definitions/nonEmptyString" },
     219                  "subcode": { "$ref": "#/definitions/codeString" },
    213220                  "text": { "$ref": "#/definitions/nonEmptyString" }
    214221              },
Note: See TracChangeset for help on using the changeset viewer.