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

Last change on this file since 525 was 525, checked in by hendrikvanantwerpen, 11 years ago
  • Allow empty subcodes.
  • Use HTTPResult exclusively on server (no more q).
  • Set readonly & disabled on ourselves as well in _ComplexValueMixin
  • Split server into several modules.
  • Check codes on the variable level, not question level.
  • We can add modules in design documents now.
File size: 7.0 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            200: util.handleRowDocs,
20            default: util.handleUnknownResponse
21        });
22    };
23    var getQuestions = exports.getQuestions = function(sub) {
24        var url = '_design/questions/_view/'+(sub||'all');
25        var query = {reduce:false,include_docs:true};
26        return couch.get(url,{query:query})
27        .handle({
28            200: util.handleRowDocs,
29            default: util.handleUnknownResponse
30        });
31    };
32    var getQuestionsAndCodes = exports.getQuestionsAndCodes = function(sub) {
33        var url = '_design/questions/_view/'+(sub||'all')+'_by_code';
34        var query = {};
35        return couch.get(url,{query:query})
36        .handle({
37            200: util.handleRowDictOfValues,
38            default: util.handleUnknownResponse
39        });
40    };
41    var getQuestionsWithTopic = exports.getQuestionsWithTopic = function(topic,sub) {
42        var url = '_design/questions/_view/'+(sub||'all')+'_topics';
43        var query = {reduce:false,include_docs:true,key:topic};
44        return couch.get(url,{query:query})
45        .handle({
46            200: util.handleRowDocs,
47            default: util.handleUnknownResponse
48        });
49    };
50    var getQuestionsWithCategoryAndTopic = exports.getQuestionsWithCategoryAndTopic = function(category,topic,sub) {
51        var hasTopic = typeof topic !== 'undefined';
52        var url = '_design/questions/_view/'+(sub||'all');
53        var query = {reduce:false,include_docs:true,
54                     startkey:hasTopic?[category,topic]:[category],
55                     endkey:hasTopic?[category,topic]:[category,{}]};
56        return couch.get(url,{query:query})
57        .handle({
58            200: util.handleRowDocs,
59            default: util.handleUnknownResponse
60        });
61    };
62    var areElementsUnique = exports.areElementsUnique = function(array) {
63        return _.uniq(array).length === array.length;
64    };
65    var getVariablesAndIds = exports.getVariablesAndIds = function(sub) {
66        var url = '_design/questions/_view/'+(sub||'all')+'_variables';
67        return couch.get(url)
68        .handle({
69            200: util.handleRowDictOfValues,
70            default: util.handleUnknownResponse
71        });
72    };
73    var collectVariables = exports.collectVariables = function(question) {
74        return _.chain(objF.collectFields('subcode',question.content))
75        .map(function(subcode){
76            return question.code+subcode;
77        }).value();
78    };
79
80    app.get('/',
81        util.ensureMIME(util.JSON_MIME),
82        function(req,res) {
83            var sub = 'published' in req.query && 'published';
84            var hr;
85            if ( 'category' in req.query ) {
86                hr = getQuestionsWithCategoryAndTopic(req.query.category,
87                                                      req.query.topic,sub);
88            } else if ( 'topic' in req.query ) {
89                hr = getQuestionsWithTopic(req.query.topic,sub);
90            } else if ( 'code' in req.query ) {
91                hr = getQuestionsWithCode(req.query.code,sub);
92            } else {
93                hr = getQuestions(sub);
94            }
95            hr.handle(res.send.bind(res));
96        });
97    app.post('/',
98        util.ensureMIME(util.JSON_MIME),
99        function (req,res) {
100            var doc = req.body;
101            var ourVars = collectVariables(doc);
102            var hr;
103            var dups = objF.findDuplicates(ourVars);
104            if ( dups.length > 0 ) {
105                hr = new HTTPResult(400,{error:"Question defines variable(s) "+
106                                               dups.join(',')+
107                                               " multiple times (subcodes not unique)."});
108            } else {
109                hr = getVariablesAndIds()
110                .handle({
111                    200: function(vars) {
112                        vars = _.chain(vars).keys().uniq().value(); // don't punish us for others mistakes
113                        dups = objF.findDuplicates(vars.concat(ourVars));
114                        if ( dups.length > 0 ) {
115                            return new HTTPResult(400,{error:"Question redefines variable(s) "+
116                                                             dups.join(',')+
117                                                             " (already defined in other question(s))."});
118                        } else {
119                            return util.postDocument('Question',doc);
120                        }
121                    }
122                });
123            }
124            hr.handle(res.send.bind(res));
125        });
126    app.get('/:id',
127        util.ensureMIME(util.JSON_MIME),
128        util.makeDocGet_id('Question'));
129    app.put('/:id',
130        util.ensureMIME(util.JSON_MIME),
131        function (req,res) {
132            var id = req.params.id;
133            var doc = req.body;
134            var rev = etags.parse(req.header('If-Match'))[0] || (doc && doc._rev);
135            var ourVars = collectVariables(doc);
136            var hr;
137            var dups = objF.findDuplicates(ourVars);
138            if ( dups.length > 0 ) {
139                hr = new HTTPResult(400,{error:"Question defines variable(s) "+
140                                               dups.join(',')+
141                                               " multiple times (subcodes not unique)."});
142            } else {
143                hr = getVariablesAndIds()
144                .handle({
145                    200: function(vars) {
146                        vars = _.chain(vars).map(function(otherId,otherVar){
147                            return otherId !== id ? otherVar : null;
148                        }).filter(function(otherCode){
149                            return otherCode !== null;
150                        }).uniq().value(); // don't punish us for others mistakes
151                        dups = objF.findDuplicates(vars.concat(ourVars));
152                        if ( dups.length > 0 ) {
153                            return new HTTPResult(400,{error:"Question redefines variable(s) "+
154                                                             dups.join(',')+
155                                                             " (already defined in other question(s))."});
156                        } else {
157                            return util.putDocument(id,rev,'Question',doc);
158                        }
159                    }
160                });
161            }
162            hr.handle(res.send.bind(res));
163        });
164    app.delete('/:id',
165        util.ensureMIME(util.JSON_MIME),
166        util.makeDocDel_id('Question'));
167
168    return exports;
169};
Note: See TracBrowser for help on using the repository browser.