source: Dev/trunk/src/server/api/questions.js @ 527

Last change on this file since 527 was 527, checked in by hendrikvanantwerpen, 11 years ago
  • Dropped request module for a simple one we wrote ourselves using the native Node modules. Hopefully this one will not suffer from the problem that sometimes empty bodies are returned even when the statuscode and content-length of the request are ok & present.
  • Handle exceptions better in HTTPResult chain, they were hoisted in unknown responses before. Should we not include them in default processing, because they are special?
File size: 7.3 KB
Line 
1var express = require("express")
2  , HTTPResult = require("../util/http-result")
3  , _ = require("underscore")
4  , objF = require("../util/object")
5  , etags = require("../util/etags")
6  ;
7
8module.exports = function(couch,schema) {
9    var util = require('./util')(couch,schema);
10    var exports = {};
11
12    var app = exports.app = express();
13
14    var getQuestionsWithCode = exports.getQuestionsWithCode = function(code,sub) {
15        var url = '_design/questions/_view/'+(sub||'all')+'_by_code';
16        var query = {reduce:false,include_docs:true,key:code};
17        return couch.get(url,{query:query})
18        .handle({
19            '-1': _.identity,
20            200: util.handleRowDocs,
21            default: util.handleUnknownResponse
22        });
23    };
24    var getQuestions = exports.getQuestions = function(sub) {
25        var url = '_design/questions/_view/'+(sub||'all');
26        var query = {reduce:false,include_docs:true};
27        return couch.get(url,{query:query})
28        .handle({
29            '-1': _.identity,
30            200: util.handleRowDocs,
31            default: util.handleUnknownResponse
32        });
33    };
34    var getQuestionsAndCodes = exports.getQuestionsAndCodes = function(sub) {
35        var url = '_design/questions/_view/'+(sub||'all')+'_by_code';
36        var query = {};
37        return couch.get(url,{query:query})
38        .handle({
39            '-1': _.identity,
40            200: util.handleRowDictOfValues,
41            default: util.handleUnknownResponse
42        });
43    };
44    var getQuestionsWithTopic = exports.getQuestionsWithTopic = function(topic,sub) {
45        var url = '_design/questions/_view/'+(sub||'all')+'_topics';
46        var query = {reduce:false,include_docs:true,key:topic};
47        return couch.get(url,{query:query})
48        .handle({
49            '-1': _.identity,
50            200: util.handleRowDocs,
51            default: util.handleUnknownResponse
52        });
53    };
54    var getQuestionsWithCategoryAndTopic = exports.getQuestionsWithCategoryAndTopic = function(category,topic,sub) {
55        var hasTopic = typeof topic !== 'undefined';
56        var url = '_design/questions/_view/'+(sub||'all');
57        var query = {reduce:false,include_docs:true,
58                     startkey:hasTopic?[category,topic]:[category],
59                     endkey:hasTopic?[category,topic]:[category,{}]};
60        return couch.get(url,{query:query})
61        .handle({
62            '-1': _.identity,
63            200: util.handleRowDocs,
64            default: util.handleUnknownResponse
65        });
66    };
67    var areElementsUnique = exports.areElementsUnique = function(array) {
68        return _.uniq(array).length === array.length;
69    };
70    var getVariablesAndIds = exports.getVariablesAndIds = function(sub) {
71        var url = '_design/questions/_view/'+(sub||'all')+'_variables';
72        return couch.get(url)
73        .handle({
74            '-1': _.identity,
75            200: util.handleRowDictOfValues,
76            default: util.handleUnknownResponse
77        });
78    };
79    var collectVariables = exports.collectVariables = function(question) {
80        return _.chain(objF.collectFields('subcode',question.content))
81        .map(function(subcode){
82            return question.code+subcode;
83        }).value();
84    };
85
86    app.get('/',
87        util.ensureMIME(util.JSON_MIME),
88        function(req,res) {
89            var sub = 'published' in req.query && 'published';
90            var hr;
91            if ( 'category' in req.query ) {
92                hr = getQuestionsWithCategoryAndTopic(req.query.category,
93                                                      req.query.topic,sub);
94            } else if ( 'topic' in req.query ) {
95                hr = getQuestionsWithTopic(req.query.topic,sub);
96            } else if ( 'code' in req.query ) {
97                hr = getQuestionsWithCode(req.query.code,sub);
98            } else {
99                hr = getQuestions(sub);
100            }
101            hr.handle({'-1': util.handleException})
102              .handle(res.send.bind(res));
103        });
104    app.post('/',
105        util.ensureMIME(util.JSON_MIME),
106        function (req,res) {
107            var doc = req.body;
108            var ourVars = collectVariables(doc);
109            var hr;
110            var dups = objF.findDuplicates(ourVars);
111            if ( dups.length > 0 ) {
112                hr = new HTTPResult(400,{error:"Question defines variable(s) "+
113                                               dups.join(',')+
114                                               " multiple times (subcodes not unique)."});
115            } else {
116                hr = getVariablesAndIds()
117                .handle({
118                    200: function(vars) {
119                        vars = _.chain(vars).keys().uniq().value(); // don't punish us for others mistakes
120                        dups = objF.findDuplicates(vars.concat(ourVars));
121                        if ( dups.length > 0 ) {
122                            return new HTTPResult(400,{error:"Question redefines variable(s) "+
123                                                             dups.join(',')+
124                                                             " (already defined in other question(s))."});
125                        } else {
126                            return util.postDocument('Question',doc);
127                        }
128                    }
129                });
130            }
131            hr.handle({'-1': util.handleException})
132              .handle(res.send.bind(res));
133        });
134    app.get('/:id',
135        util.ensureMIME(util.JSON_MIME),
136        util.makeDocGet_id('Question'));
137    app.put('/:id',
138        util.ensureMIME(util.JSON_MIME),
139        function (req,res) {
140            var id = req.params.id;
141            var doc = req.body;
142            var rev = etags.parse(req.header('If-Match'))[0] || (doc && doc._rev);
143            var ourVars = collectVariables(doc);
144            var hr;
145            var dups = objF.findDuplicates(ourVars);
146            if ( dups.length > 0 ) {
147                hr = new HTTPResult(400,{error:"Question defines variable(s) "+
148                                               dups.join(',')+
149                                               " multiple times (subcodes not unique)."});
150            } else {
151                hr = getVariablesAndIds()
152                .handle({
153                    200: function(vars) {
154                        vars = _.chain(vars).map(function(otherId,otherVar){
155                            return otherId !== id ? otherVar : null;
156                        }).filter(function(otherCode){
157                            return otherCode !== null;
158                        }).uniq().value(); // don't punish us for others mistakes
159                        dups = objF.findDuplicates(vars.concat(ourVars));
160                        if ( dups.length > 0 ) {
161                            return new HTTPResult(400,{error:"Question redefines variable(s) "+
162                                                             dups.join(',')+
163                                                             " (already defined in other question(s))."});
164                        } else {
165                            return util.putDocument(id,rev,'Question',doc);
166                        }
167                    }
168                });
169            }
170            hr.handle({'-1': util.handleException})
171              .handle(res.send.bind(res));
172        });
173    app.delete('/:id',
174        util.ensureMIME(util.JSON_MIME),
175        util.makeDocDel_id('Question'));
176
177    return exports;
178};
Note: See TracBrowser for help on using the repository browser.