|
| 1 | +var express = require('express'); |
| 2 | +var exphbs = require('express-handlebars'); |
| 3 | +var http = require('http'); |
| 4 | +var path = require('path'); |
| 5 | +var favicon = require('static-favicon'); |
| 6 | +var logger = require('morgan'); |
| 7 | +var cookieParser = require('cookie-parser'); |
| 8 | +var bodyParser = require('body-parser'); |
| 9 | +var debug = require('debug')('my-application'); |
| 10 | +var _ = require("lodash"); |
| 11 | +var request = require('request'); |
| 12 | +var moment = require('moment'); |
| 13 | +var RSS = require('rss'); |
| 14 | + |
| 15 | +// config settings for the minisite |
| 16 | +var challengesEndpoint = process.env.CHALLENGES_ENDPOINT || "http://tc-search.herokuapp.com/challenges/v2/search?q=challengeName:IDOL"; |
| 17 | +var leaderboardEndpoint = process.env.LEADERBOARD_ENDPOINT || "http://tc-leaderboard.herokuapp.com/demo"; |
| 18 | +var communityName = process.env.COMMUNITY_NAME || "Community Template"; |
| 19 | +// don't show challenges with the follow statuses |
| 20 | +var challengeFilter = ['Completed','Cancelled - Zero Submissions']; |
| 21 | + |
| 22 | +var port = process.env.PORT || 3000; |
| 23 | +var app = express(); |
| 24 | + |
| 25 | +// register handlebars & some helpers for the views |
| 26 | +var hbs = exphbs.create({ |
| 27 | + defaultLayout: 'main', |
| 28 | + helpers: { |
| 29 | + ordinal: function (rank) { |
| 30 | + var s=["th","st","nd","rd"]; |
| 31 | + var v=rank%100; |
| 32 | + return rank+(s[(v-20)%10]||s[v]||s[0]); |
| 33 | + }, |
| 34 | + arrayToList: function (array) { |
| 35 | + return array.join(', '); |
| 36 | + }, |
| 37 | + dateFormatUTC: function(d) { |
| 38 | + return moment.utc(d).format('MMMM Do YYYY, h:mm:ss a'); |
| 39 | + } |
| 40 | + } |
| 41 | +}); |
| 42 | + |
| 43 | +// view engine setup |
| 44 | +app.set('views', path.join(__dirname, 'views')); |
| 45 | +app.engine('handlebars', hbs.engine); |
| 46 | +app.set('view engine', 'handlebars'); |
| 47 | +app.set('port', port); |
| 48 | + |
| 49 | +app.use(favicon()); |
| 50 | +app.use(logger('dev')); |
| 51 | +app.use(bodyParser.json()); |
| 52 | +app.use(bodyParser.urlencoded()); |
| 53 | +app.use(cookieParser()); |
| 54 | +app.use(express.static(path.join(__dirname, 'public'))); |
| 55 | +app.use(app.router); |
| 56 | + |
| 57 | +// fetches a list of challenges as json and exposes it to the ejs |
| 58 | +var challenges = function(req, res, next) { |
| 59 | + request(challengesEndpoint, function (error, response, body) { |
| 60 | + if (!error && response.statusCode == 200) { |
| 61 | + var challenges = []; |
| 62 | + _(JSON.parse(body)).forEach(function(c) { |
| 63 | + // filter out challenges by types we don't want |
| 64 | + if (challengeFilter.indexOf(c._source.status) == -1) { |
| 65 | + challenges.push(c); |
| 66 | + } |
| 67 | + }); |
| 68 | + req.challenges = challenges; |
| 69 | + } else { |
| 70 | + req.challenges = []; |
| 71 | + } |
| 72 | + return next(); |
| 73 | + }); |
| 74 | +}; |
| 75 | + |
| 76 | +// fetches a leaderboard as json and exposes it to the ejs |
| 77 | +var leaderboard = function(req, res, next) { |
| 78 | + request(leaderboardEndpoint, function (error, response, body) { |
| 79 | + if (!error && response.statusCode == 200) { |
| 80 | + var leaderboard = JSON.parse(body); |
| 81 | + // create an array with left and right columns |
| 82 | + var leaders = []; |
| 83 | + for (i=0; i <= leaderboard.length-1; i += 2){ |
| 84 | + var left = leaderboard[i]; |
| 85 | + var right = leaderboard[i+1]; |
| 86 | + leaders.push({left: left, right: right}); |
| 87 | + } |
| 88 | + req.leaderboard = leaders; |
| 89 | + } else { |
| 90 | + req.leaderboard = []; |
| 91 | + } |
| 92 | + return next(); |
| 93 | + }); |
| 94 | +}; |
| 95 | + |
| 96 | +app.get('/', challenges, leaderboard, function(req, res){ |
| 97 | + res.render('index', { |
| 98 | + communityName: communityName, |
| 99 | + challenges: req.challenges, |
| 100 | + leaderboard: req.leaderboard |
| 101 | + }); |
| 102 | +}); |
| 103 | + |
| 104 | +app.get('/challenges/rss', challenges, leaderboard, function(req, res){ |
| 105 | + |
| 106 | + var feed = new RSS({ |
| 107 | + title: communityName + ' Community Challenges', |
| 108 | + description: 'Open challenges for the ' + communityName + ' community.', |
| 109 | + feed_url: 'http://' + req.headers.host + '/challenges/rss', |
| 110 | + site_url: 'http://' + req.headers.host, |
| 111 | + image_url: 'http://www.topcoder.com/i/logo.png', |
| 112 | + author: '[topcoder]', |
| 113 | + copyright: '2014 Appirio', |
| 114 | + ttl: '60' |
| 115 | + }); |
| 116 | + |
| 117 | + var challenges = []; |
| 118 | + request(challengesEndpoint, function (error, response, body) { |
| 119 | + if (!error && response.statusCode == 200) { |
| 120 | + challenges = JSON.parse(body); |
| 121 | + _(challenges).forEach(function(c) { |
| 122 | + |
| 123 | + feed.item({ |
| 124 | + title: c._source.challengeName, |
| 125 | + description: communityName + ' community '+c._type+' challenge: ' + c._source.challengeName, |
| 126 | + url: "http://www.topcoder.com/challenge-details/"+c._source.challengeId+"?type="+c._type, |
| 127 | + date: c._source.postingDate |
| 128 | + }); |
| 129 | + |
| 130 | + }); |
| 131 | + } |
| 132 | + res.set('Content-Type', 'text/xml'); |
| 133 | + res.send(feed.xml()); |
| 134 | + }); |
| 135 | + |
| 136 | +}); |
| 137 | + |
| 138 | +/// catch 404 and forwarding to error handler |
| 139 | +app.use(function(req, res, next) { |
| 140 | + var err = new Error('Not Found'); |
| 141 | + err.status = 404; |
| 142 | + next(err); |
| 143 | +}); |
| 144 | + |
| 145 | +/// error handlers |
| 146 | + |
| 147 | +// development error handler |
| 148 | +// will print stacktrace |
| 149 | +if (app.get('env') === 'development') { |
| 150 | + app.use(function(err, req, res, next) { |
| 151 | + res.render('error', { |
| 152 | + message: err.message, |
| 153 | + error: err |
| 154 | + }); |
| 155 | + }); |
| 156 | +} |
| 157 | + |
| 158 | +// production error handler |
| 159 | +// no stacktraces leaked to user |
| 160 | +app.use(function(err, req, res, next) { |
| 161 | + res.render('error', { |
| 162 | + message: err.message, |
| 163 | + error: {} |
| 164 | + }); |
| 165 | +}); |
| 166 | + |
| 167 | +var server = app.listen(app.get('port'), function() { |
| 168 | + console.log('Express server listening on port ' + server.address().port); |
| 169 | +}); |
0 commit comments