var express = require("express") , HTTPResult = require("../util/http-result") , _ = require("underscore") , objF = require("../util/object") , etags = require("../util/etags") ; module.exports = function(couch,schema) { var util = require('./util')(couch,schema); var exports = {}; var app = exports.app = express(); var getQuestionsWithCode = exports.getQuestionsWithCode = function(code,sub) { var url = '_design/questions/_view/'+(sub||'all')+'_by_code'; var query = {reduce:false,include_docs:true,key:code}; return couch.get(url,{query:query}) .handle({ 200: util.handleRowDocs, default: util.handleUnknownResponse }); }; var getQuestions = exports.getQuestions = function(sub) { var url = '_design/questions/_view/'+(sub||'all'); var query = {reduce:false,include_docs:true}; return couch.get(url,{query:query}) .handle({ 200: util.handleRowDocs, default: util.handleUnknownResponse }); }; var getQuestionsAndCodes = exports.getQuestionsAndCodes = function(sub) { var url = '_design/questions/_view/'+(sub||'all')+'_by_code'; var query = {}; return couch.get(url,{query:query}) .handle({ 200: util.handleRowDictOfValues, default: util.handleUnknownResponse }); }; var getQuestionsWithTopic = exports.getQuestionsWithTopic = function(topic,sub) { var url = '_design/questions/_view/'+(sub||'all')+'_topics'; var query = {reduce:false,include_docs:true,key:topic}; return couch.get(url,{query:query}) .handle({ 200: util.handleRowDocs, default: util.handleUnknownResponse }); }; var getQuestionsWithCategoryAndTopic = exports.getQuestionsWithCategoryAndTopic = function(category,topic,sub) { var hasTopic = typeof topic !== 'undefined'; var url = '_design/questions/_view/'+(sub||'all'); var query = {reduce:false,include_docs:true, startkey:hasTopic?[category,topic]:[category], endkey:hasTopic?[category,topic]:[category,{}]}; return couch.get(url,{query:query}) .handle({ 200: util.handleRowDocs, default: util.handleUnknownResponse }); }; var areElementsUnique = exports.areElementsUnique = function(array) { return _.uniq(array).length === array.length; }; var getVariablesAndIds = exports.getVariablesAndIds = function(sub) { var url = '_design/questions/_view/'+(sub||'all')+'_variables'; return couch.get(url) .handle({ 200: util.handleRowDictOfValues, default: util.handleUnknownResponse }); }; var collectVariables = exports.collectVariables = function(question) { return _.chain(objF.collectFields('subcode',question.content)) .map(function(subcode){ return question.code+subcode; }).value(); }; app.get('/', util.ensureMIME(util.JSON_MIME), function(req,res) { var sub = 'published' in req.query && 'published'; var hr; if ( 'category' in req.query ) { hr = getQuestionsWithCategoryAndTopic(req.query.category, req.query.topic,sub); } else if ( 'topic' in req.query ) { hr = getQuestionsWithTopic(req.query.topic,sub); } else if ( 'code' in req.query ) { hr = getQuestionsWithCode(req.query.code,sub); } else { hr = getQuestions(sub); } hr.handle(res.send.bind(res)); }); app.post('/', util.ensureMIME(util.JSON_MIME), function (req,res) { var doc = req.body; var ourVars = collectVariables(doc); var hr; var dups = objF.findDuplicates(ourVars); if ( dups.length > 0 ) { hr = new HTTPResult(400,{error:"Question defines variable(s) "+ dups.join(',')+ " multiple times (subcodes not unique)."}); } else { hr = getVariablesAndIds() .handle({ 200: function(vars) { vars = _.chain(vars).keys().uniq().value(); // don't punish us for others mistakes dups = objF.findDuplicates(vars.concat(ourVars)); if ( dups.length > 0 ) { return new HTTPResult(400,{error:"Question redefines variable(s) "+ dups.join(',')+ " (already defined in other question(s))."}); } else { return util.postDocument('Question',doc); } } }); } hr.handle(res.send.bind(res)); }); app.get('/:id', util.ensureMIME(util.JSON_MIME), util.makeDocGet_id('Question')); app.put('/:id', util.ensureMIME(util.JSON_MIME), function (req,res) { var id = req.params.id; var doc = req.body; var rev = etags.parse(req.header('If-Match'))[0] || (doc && doc._rev); var ourVars = collectVariables(doc); var hr; var dups = objF.findDuplicates(ourVars); if ( dups.length > 0 ) { hr = new HTTPResult(400,{error:"Question defines variable(s) "+ dups.join(',')+ " multiple times (subcodes not unique)."}); } else { hr = getVariablesAndIds() .handle({ 200: function(vars) { vars = _.chain(vars).map(function(otherId,otherVar){ return otherId !== id ? otherVar : null; }).filter(function(otherCode){ return otherCode !== null; }).uniq().value(); // don't punish us for others mistakes dups = objF.findDuplicates(vars.concat(ourVars)); if ( dups.length > 0 ) { return new HTTPResult(400,{error:"Question redefines variable(s) "+ dups.join(',')+ " (already defined in other question(s))."}); } else { return util.putDocument(id,rev,'Question',doc); } } }); } hr.handle(res.send.bind(res)); }); app.delete('/:id', util.ensureMIME(util.JSON_MIME), util.makeDocDel_id('Question')); return exports; };