source: Dev/trunk/src/server/app.js @ 475

Last change on this file since 475 was 475, checked in by hendrikvanantwerpen, 12 years ago
  • Added CouchDB script to make interacting with couch easier.
  • Use this script in the database configuration.
  • Get CSV export to work.
File size: 5.2 KB
RevLine 
[475]1var express = require("express")
2  , passport = require("passport")
3  , passportLocal = require("passport-local")
4  , fs = require("fs")
5  , path = require("path")
6  , proxy = require("./util/simple-http-proxy")
7  , CSV = require("ya-csv")
8  , CouchDB = require('./util/couch').CouchDB
9  , _ = require("underscore")
10  ;
[443]11
[463]12function assertSetting(name, settings, validate) {
13    if ( typeof settings[name] === 'undefined' ) {
14        throw new Error("Required setting '"+name+"' undefined.");
15    }
16    if ( _.isFunction(validate) && !validate(settings[name]) ) {
17        throw new Error("Setting '"+name+"' with value '"+settings[name]+"' is invalid.");
18    }
[451]19}
[443]20
[463]21exports.App = function(settings) {
[451]22
[463]23    assertSetting("couchDbURL", settings, _.isString);
[475]24    var couch = new CouchDB(settings.couchDbURL);
[463]25   
26    function clientPath(relativePath) {
27        return path.resolve(__dirname+'/../client/'+relativePath);
28    }
[451]29
[463]30    passport.use(new passportLocal.Strategy(function(username, password, done){
31        if ( username === "igor" && password === "mayer" ) {
32            done(null,{ username: "igor" });
33        } else {
34            done(null,false,{ message: 'Invalid credentials.' });
35        }
36    }));
[466]37    passport.serializeUser(function(user, done) {
38        done(null, user.username);
39    });
40    passport.deserializeUser(function(id, done) {
41        done(null, {username: id});
42    });
[451]43
[463]44    var app = express();
45    app.use(express.logger());
46    app.use(express.compress());
47    app.use(express.favicon());
48
[470]49    // cookies and session
50    app.use('/api/login',express.bodyParser());
[463]51    app.use(express.cookieParser());
52    app.use(express.session({ secret: "quasi experimental design" }));
53
[470]54    // passport
[463]55    app.use(passport.initialize());
56    app.use(passport.session());
[470]57    function ensureAuthenticated(req,res,next){
58        if (!req.user) {
59            return res.send(401,{error:"Login before accessing API."});
60        } else {
61            return next();
62        }
63    }
64    function returnUser(req,res) {
65        res.send(200, req.user);
66    }
[463]67
68    // static resources
69    app.get('/', function(request, response){
70        response.sendfile(clientPath('index.html'));
71    });
72    app.get('/*.html', function(request, response) {
73        response.sendfile(clientPath(request.path));
74    });
75    _.each(['/dojo', '/dijit', '/dojox', '/qed', '/qed-client'], function(dir){
76        app.use(dir, express.static(clientPath(dir)));
77    });
78
[470]79
80    // post to this url to login
[466]81    app.post(
82        '/api/login',
83        passport.authenticate('local'),
84        returnUser);
[463]85
[470]86    // return the info for the current logged in user
[466]87    app.get(
88        '/api/login',
[467]89        ensureAuthenticated,
[466]90        returnUser);
91
[470]92    // explicitly logout this user
[466]93    app.post(
[467]94        '/api/logout',
95        ensureAuthenticated,
96        function(req,res){
[466]97            req.logout();
98            res.send(200,{});
99        });
100
[470]101    // data is proxied to couch
102    app.use('/api/data', ensureAuthenticated);
103    app.use('/api/data', proxy(settings.couchDbURL));
104
105    // generate CSV download of responses
[467]106    app.get(
107        '/api/surveyRuns/:id/responses.csv',
108        ensureAuthenticated,
109        function(req, res) {
110            var id = req.params.id;
[475]111            var url = '_design/responses/_view/by_surveyrun?key='+JSON.stringify(id);
112            couch.get(url).then(function(result){
113                var responses = _.map(result.rows, function(item) { return item.value; });
114                var flatResponses = responsesToVariables(responses);
115                res.set({
116                    'Content-Type': 'text/csv',
117                    'Content-Disposition': 'attachment; filename=surveyRun-'+id+'-responses.csv'
118                });
119                res.status(200);
120                writeObjectsToCSVStream(flatResponses, res);
121                res.end();
122            }, function(error){
123                res.send(404, {error: "Cannot find responses for survey run "+id});
[466]124            });
[467]125        });
[466]126   
[463]127    return app;
128
129};
[475]130
131function responsesToVariables(responses) {
132    return _.map(responses, responseToVariables);
133}
134
135function responseToVariables(response) {
136    var result = flattenObject(response.answers);
137    result.respondent = response.id;
138    return result;
139}
140
141function flattenObject(value) {
142    var result = {};
143    (function agg(val,key,res){
144        if ( _.isObject(val) ) {
145            _.forEach(val, function(v,k){
146                agg(v,(key ? key+'.' : '')+k,res);
147            });
148        } else if ( _.isArray(val) ) {
149            _.forEach(val, function(v,i){
150                agg(v,(key ? key+'.' : '')+i,res);
151            });
152        } else {
153            res[key] = val;
154        }
155    })(value,null,result);
156    return result;
157}
158
159function writeObjectsToCSVStream(objects, stream) {
160    var keys = _.chain(objects)
161                .map(_.keys)
162                .flatten()
163                .uniq()
164                .value();
165    var idxs = {};
166    _.forEach(keys, function(key,idx){
167        idxs[key] = idx;
168    });
169    var writer = new CSV.CsvWriter(stream);
170    writer.writeRecord(keys);
171    _.forEach(objects, function(obj){
172        var row = [];
173        _.forEach(obj, function(val,key){
174            row[idxs[key]] = val;
175        });
176        writer.writeRecord(row);
177    });
178}
Note: See TracBrowser for help on using the repository browser.