refactor all boot to export func and use loopback

This commit is contained in:
Berkeley Martinez
2015-06-03 16:19:23 -07:00
parent 65cde59f0d
commit 8165105b29
9 changed files with 2028 additions and 1951 deletions

View File

@ -79,6 +79,7 @@
"passport-twitter": "~1.0.2", "passport-twitter": "~1.0.2",
"ramda": "~0.10.0", "ramda": "~0.10.0",
"request": "~2.53.0", "request": "~2.53.0",
"rx": "^2.5.3",
"sanitize-html": "~1.6.1", "sanitize-html": "~1.6.1",
"sitemap": "~0.7.4", "sitemap": "~0.7.4",
"twit": "~1.1.20", "twit": "~1.1.20",

View File

@ -1,16 +1,18 @@
var R = require('ramda'), var R = require('ramda'),
express = require('express'), // Rx = require('rx'),
// debug = require('debug')('freecc:fieldguides'), // debug = require('debug')('freecc:fieldguides'),
resources = require('../resources/resources'); resources = require('../resources/resources');
var router = express.Router(); module.exports = function(app) {
var router = app.Router();
var FieldGuide = app.models.FieldGuide;
router.get('/field-guide/all-articles', showAllFieldGuides); router.get('/field-guide/all-articles', showAllFieldGuides);
router.get('/field-guide/:fieldGuideName', returnIndividualFieldGuide); router.get('/field-guide/:fieldGuideName', returnIndividualFieldGuide);
router.get('/field-guide/', returnNextFieldGuide); router.get('/field-guide/', returnNextFieldGuide);
router.post('/completed-field-guide/', completedFieldGuide); router.post('/completed-field-guide/', completedFieldGuide);
function returnIndividualFieldGuide(req, res, next) { function returnIndividualFieldGuide(req, res, next) {
var dashedName = req.params.fieldGuideName; var dashedName = req.params.fieldGuideName;
if (req.user) { if (req.user) {
var completed = req.user.completedFieldGuides; var completed = req.user.completedFieldGuides;
@ -23,9 +25,12 @@ function returnIndividualFieldGuide(req, res, next) {
}); });
req.user.uncompletedFieldGuides = uncompletedFieldGuides; req.user.uncompletedFieldGuides = uncompletedFieldGuides;
// TODO(berks): handle callback properly // TODO(berks): handle callback properly
req.user.save(); req.user.save(function(err) {
if (err) { return next(err); }
});
} }
// NOTE(berks): loopback might have issue with regex here.
FieldGuide.find( FieldGuide.find(
{ dashedName: new RegExp(dashedName, 'i') }, { dashedName: new RegExp(dashedName, 'i') },
function(err, fieldGuideFromMongo) { function(err, fieldGuideFromMongo) {
@ -55,9 +60,9 @@ function returnIndividualFieldGuide(req, res, next) {
}); });
} }
); );
} }
function showAllFieldGuides(req, res) { function showAllFieldGuides(req, res) {
var allFieldGuideNamesAndIds = resources.allFieldGuideNamesAndIds(); var allFieldGuideNamesAndIds = resources.allFieldGuideNamesAndIds();
var completedFieldGuides = []; var completedFieldGuides = [];
@ -68,9 +73,9 @@ function showAllFieldGuides(req, res) {
allFieldGuideNamesAndIds: allFieldGuideNamesAndIds, allFieldGuideNamesAndIds: allFieldGuideNamesAndIds,
completedFieldGuides: completedFieldGuides completedFieldGuides: completedFieldGuides
}); });
} }
function returnNextFieldGuide(req, res, next) { function returnNextFieldGuide(req, res, next) {
if (!req.user) { if (!req.user) {
return res.redirect('/field-guide/how-do-i-use-this-guide'); return res.redirect('/field-guide/how-do-i-use-this-guide');
} }
@ -98,9 +103,9 @@ function returnNextFieldGuide(req, res, next) {
var nameString = fieldGuide.name.toLowerCase().replace(/\s/g, '-'); var nameString = fieldGuide.name.toLowerCase().replace(/\s/g, '-');
return res.redirect('../field-guide/' + nameString); return res.redirect('../field-guide/' + nameString);
}); });
} }
function completedFieldGuide(req, res, next) { function completedFieldGuide(req, res, next) {
var fieldGuideId = req.body.fieldGuideInfo.fieldGuideId; var fieldGuideId = req.body.fieldGuideInfo.fieldGuideId;
req.user.completedFieldGuides.push(fieldGuideId); req.user.completedFieldGuides.push(fieldGuideId);
@ -117,6 +122,5 @@ function completedFieldGuide(req, res, next) {
} }
res.send(true); res.send(true);
}); });
} }
};
module.exports = router;

View File

@ -1,11 +1,11 @@
var express = require('express');
var router = express.Router();
var message = var message =
'Learn to Code JavaScript and get a Coding Job by Helping Nonprofits'; 'Learn to Code JavaScript and get a Coding Job by Helping Nonprofits';
router.get('/', index); module.exports = function(app) {
var router = app.Router();
router.get('/', index);
function index(req, res, next) { function index(req, res, next) {
if (req.user && !req.user.profile.picture) { if (req.user && !req.user.profile.picture) {
req.user.profile.picture = req.user.profile.picture =
'https://s3.amazonaws.com/freecodecamp/camper-image-placeholder.png'; 'https://s3.amazonaws.com/freecodecamp/camper-image-placeholder.png';
@ -17,6 +17,5 @@ function index(req, res, next) {
} else { } else {
res.render('home', { title: message }); res.render('home', { title: message });
} }
} }
};
module.exports = router;

View File

@ -1,28 +1,31 @@
var express = require('express'),
Nonprofit = require('../../common/models/Nonprofit');
var router = express.Router(); module.exports = function(app) {
var router = app.Router();
var Nonprofit = app.models.Nonprofit;
router.get('/nonprofits/directory', nonprofitsDirectory); router.get('/nonprofits/directory', nonprofitsDirectory);
router.get('/nonprofits/:nonprofitName', returnIndividualNonprofit); router.get('/nonprofits/:nonprofitName', returnIndividualNonprofit);
function nonprofitsDirectory(req, res, next) { function nonprofitsDirectory(req, res, next) {
Nonprofit.find({ estimatedHours: { $gt: 0 } }, function(err, nonprofits) { Nonprofit.find(
{ where: { estimatedHours: { $gt: 0 } } },
function(err, nonprofits) {
if (err) { return next(err); } if (err) { return next(err); }
res.render('nonprofits/directory', { res.render('nonprofits/directory', {
title: 'Nonprofits we help', title: 'Nonprofits we help',
nonprofits: nonprofits nonprofits: nonprofits
}); });
}); }
} );
}
function returnIndividualNonprofit(req, res, next) { function returnIndividualNonprofit(req, res, next) {
var dashedName = req.params.nonprofitName; var dashedName = req.params.nonprofitName;
var nonprofitName = dashedName.replace(/\-/g, ' '); var nonprofitName = dashedName.replace(/\-/g, ' ');
Nonprofit.find( Nonprofit.find(
{ name: new RegExp(nonprofitName, 'i') }, { where: { name: new RegExp(nonprofitName, 'i') } },
function(err, nonprofit) { function(err, nonprofit) {
if (err) { if (err) {
return next(err); return next(err);
@ -95,10 +98,10 @@ function returnIndividualNonprofit(req, res, next) {
}); });
} }
); );
} }
/* /*
function interestedInNonprofit(req, res, next) { function interestedInNonprofit(req, res, next) {
if (req.user) { if (req.user) {
Nonprofit.findOne( Nonprofit.findOne(
{ name: new RegExp(req.params.nonprofitName.replace(/-/, ' '), 'i') }, { name: new RegExp(req.params.nonprofitName.replace(/-/, ' '), 'i') },
@ -120,7 +123,6 @@ function interestedInNonprofit(req, res, next) {
} }
); );
} }
} }
*/ */
};
module.exports = router;

View File

@ -1,68 +1,67 @@
var express = require('express'), var passport = require('passport'),
passport = require('passport'),
passportConf = require('../../config/passport'); passportConf = require('../../config/passport');
var router = express.Router(); module.exports = function(app) {
var passportOptions = { var router = app.Router();
var passportOptions = {
successRedirect: '/', successRedirect: '/',
failureRedirect: '/login' failureRedirect: '/login'
}; };
router.all('/account', passportConf.isAuthenticated); router.all('/account', passportConf.isAuthenticated);
router.get('/auth/twitter', passport.authenticate('twitter')); router.get('/auth/twitter', passport.authenticate('twitter'));
router.get( router.get(
'/auth/twitter/callback', '/auth/twitter/callback',
passport.authenticate('twitter', { passport.authenticate('twitter', {
successRedirect: '/', successRedirect: '/',
failureRedirect: '/login' failureRedirect: '/login'
}) })
); );
router.get( router.get(
'/auth/linkedin', '/auth/linkedin',
passport.authenticate('linkedin', { passport.authenticate('linkedin', {
state: 'SOME STATE' state: 'SOME STATE'
}) })
); );
router.get( router.get(
'/auth/linkedin/callback', '/auth/linkedin/callback',
passport.authenticate('linkedin', passportOptions) passport.authenticate('linkedin', passportOptions)
); );
router.get( router.get(
'/auth/facebook', '/auth/facebook',
passport.authenticate('facebook', {scope: ['email', 'user_location']}) passport.authenticate('facebook', {scope: ['email', 'user_location']})
); );
router.get( router.get(
'/auth/facebook/callback', '/auth/facebook/callback',
passport.authenticate('facebook', passportOptions), function (req, res) { passport.authenticate('facebook', passportOptions), function (req, res) {
res.redirect(req.session.returnTo || '/'); res.redirect(req.session.returnTo || '/');
} }
); );
router.get('/auth/github', passport.authenticate('github')); router.get('/auth/github', passport.authenticate('github'));
router.get( router.get(
'/auth/github/callback', '/auth/github/callback',
passport.authenticate('github', passportOptions), function (req, res) { passport.authenticate('github', passportOptions), function (req, res) {
res.redirect(req.session.returnTo || '/'); res.redirect(req.session.returnTo || '/');
} }
); );
router.get( router.get(
'/auth/google', '/auth/google',
passport.authenticate('google', {scope: 'profile email'}) passport.authenticate('google', {scope: 'profile email'})
); );
router.get( router.get(
'/auth/google/callback', '/auth/google/callback',
passport.authenticate('google', passportOptions), function (req, res) { passport.authenticate('google', passportOptions), function (req, res) {
res.redirect(req.session.returnTo || '/'); res.redirect(req.session.returnTo || '/');
} }
); );
};
module.exports = router;

View File

@ -1,47 +1,48 @@
var express = require('express'); module.exports = function(app) {
var router = express.Router(); var router = app.Router();
router.get('/nonprofit-project-instructions', function(req, res) { router.get('/nonprofit-project-instructions', function(req, res) {
res.redirect( res.redirect(
301, 301,
'/field-guide/how-do-free-code-camp\'s-nonprofit-projects-work' '/field-guide/how-do-free-code-camp\'s-nonprofit-projects-work'
); );
}); });
router.get('/agile', function(req, res) { router.get('/agile', function(req, res) {
res.redirect(301, '/pmi-acp-agile-project-managers'); res.redirect(301, '/pmi-acp-agile-project-managers');
}); });
router.get('/live-pair-programming', function(req, res) { router.get('/live-pair-programming', function(req, res) {
res.redirect(301, '/field-guide/live-stream-pair-programming-on-twitch.tv'); res.redirect(301, '/field-guide/live-stream-pair-programming-on-twitch.tv');
}); });
router.get('/install-screenhero', function(req, res) { router.get('/install-screenhero', function(req, res) {
res.redirect(301, '/field-guide/install-screenhero'); res.redirect(301, '/field-guide/install-screenhero');
}); });
router.get('/guide-to-our-nonprofit-projects', function(req, res) { router.get('/guide-to-our-nonprofit-projects', function(req, res) {
res.redirect(301, '/field-guide/a-guide-to-our-nonprofit-projects'); res.redirect(301, '/field-guide/a-guide-to-our-nonprofit-projects');
}); });
router.get('/chromebook', function(req, res) { router.get('/chromebook', function(req, res) {
res.redirect(301, '/field-guide/chromebook'); res.redirect(301, '/field-guide/chromebook');
}); });
router.get('/deploy-a-website', function(req, res) { router.get('/deploy-a-website', function(req, res) {
res.redirect(301, '/field-guide/deploy-a-website'); res.redirect(301, '/field-guide/deploy-a-website');
}); });
router.get('/gmail-shortcuts', function(req, res) { router.get('/gmail-shortcuts', function(req, res) {
res.redirect(301, '/field-guide/gmail-shortcuts'); res.redirect(301, '/field-guide/gmail-shortcuts');
}); });
router.get('/nodeschool-challenges', function(req, res) { router.get('/nodeschool-challenges', function(req, res) {
res.redirect(301, '/field-guide/nodeschool-challenges'); res.redirect(301, '/field-guide/nodeschool-challenges');
}); });
router.get('/privacy', function(req, res) { router.get('/privacy', function(req, res) {
res.redirect(301, '/field-guide/what-is-the-free-code-camp-privacy-policy?'); res.redirect(
}); 301, '/field-guide/what-is-the-free-code-camp-privacy-policy?'
);
module.exports = router; });
};

View File

@ -1,33 +1,33 @@
var nodemailer = require('nodemailer'), var nodemailer = require('nodemailer'),
sanitizeHtml = require('sanitize-html'), sanitizeHtml = require('sanitize-html'),
express = require('express'),
moment = require('moment'), moment = require('moment'),
mongodb = require('mongodb'), mongodb = require('mongodb'),
// debug = require('debug')('freecc:cntr:story'), // debug = require('debug')('freecc:cntr:story'),
Story = require('../../common/models/Story'),
Comment = require('../../common/models/Comment'),
User = require('../../common/models/User'),
resources = require('../resources/resources'), resources = require('../resources/resources'),
MongoClient = mongodb.MongoClient, MongoClient = mongodb.MongoClient,
secrets = require('../../config/secrets'), secrets = require('../../config/secrets');
router = express.Router();
router.get('/stories/hotStories', hotJSON); module.exports = function(app) {
router.get('/stories/recentStories', recentJSON); var router = app.Router();
router.get('/stories/comments/:id', comments); var User = app.models.User;
router.post('/stories/comment/', commentSubmit); var Story = app.models.Story;
router.post('/stories/comment/:id/comment', commentOnCommentSubmit);
router.put('/stories/comment/:id/edit', commentEdit);
router.get('/stories/submit', submitNew);
router.get('/stories/submit/new-story', preSubmit);
router.post('/stories/preliminary', newStory);
router.post('/stories/', storySubmission);
router.get('/news/', hot);
router.post('/stories/search', getStories);
router.get('/news/:storyName', returnIndividualStory);
router.post('/stories/upvote/', upvote);
function hotRank(timeValue, rank) { router.get('/stories/hotStories', hotJSON);
router.get('/stories/recentStories', recentJSON);
router.get('/stories/comments/:id', comments);
router.post('/stories/comment/', commentSubmit);
router.post('/stories/comment/:id/comment', commentOnCommentSubmit);
router.put('/stories/comment/:id/edit', commentEdit);
router.get('/stories/submit', submitNew);
router.get('/stories/submit/new-story', preSubmit);
router.post('/stories/preliminary', newStory);
router.post('/stories/', storySubmission);
router.get('/news/', hot);
router.post('/stories/search', getStories);
router.get('/news/:storyName', returnIndividualStory);
router.post('/stories/upvote/', upvote);
function hotRank(timeValue, rank) {
/* /*
* Hotness ranking algorithm: http://amix.dk/blog/post/19588 * Hotness ranking algorithm: http://amix.dk/blog/post/19588
* tMS = postedOnDate - foundationTime; * tMS = postedOnDate - foundationTime;
@ -39,10 +39,9 @@ function hotRank(timeValue, rank) {
var z = Math.log(rank) / Math.log(10); var z = Math.log(rank) / Math.log(10);
hotness = z + (timeValue / time48Hours); hotness = z + (timeValue / time48Hours);
return hotness; return hotness;
}
} function hotJSON(req, res, next) {
function hotJSON(req, res, next) {
var story = Story.find({}).sort({'timePosted': -1}).limit(1000); var story = Story.find({}).sort({'timePosted': -1}).limit(1000);
story.exec(function(err, stories) { story.exec(function(err, stories) {
if (err) { if (err) {
@ -60,9 +59,9 @@ function hotJSON(req, res, next) {
}).slice(0, sliceVal)); }).slice(0, sliceVal));
}); });
} }
function recentJSON(req, res, next) { function recentJSON(req, res, next) {
var story = Story.find({}).sort({'timePosted': -1}).limit(100); var story = Story.find({}).sort({'timePosted': -1}).limit(100);
story.exec(function(err, stories) { story.exec(function(err, stories) {
if (err) { if (err) {
@ -70,40 +69,40 @@ function recentJSON(req, res, next) {
} }
return res.json(stories); return res.json(stories);
}); });
} }
function hot(req, res) { function hot(req, res) {
return res.render('stories/index', { return res.render('stories/index', {
title: 'Hot stories currently trending on Camper News', title: 'Hot stories currently trending on Camper News',
page: 'hot' page: 'hot'
}); });
} }
function submitNew(req, res) { function submitNew(req, res) {
return res.render('stories/index', { return res.render('stories/index', {
title: 'Submit a new story to Camper News', title: 'Submit a new story to Camper News',
page: 'submit' page: 'submit'
}); });
} }
/* /*
* no used anywhere * no used anywhere
function search(req, res) { function search(req, res) {
return res.render('stories/index', { return res.render('stories/index', {
title: 'Search the archives of Camper News', title: 'Search the archives of Camper News',
page: 'search' page: 'search'
}); });
} }
function recent(req, res) { function recent(req, res) {
return res.render('stories/index', { return res.render('stories/index', {
title: 'Recently submitted stories on Camper News', title: 'Recently submitted stories on Camper News',
page: 'recent' page: 'recent'
}); });
} }
*/ */
function preSubmit(req, res) { function preSubmit(req, res) {
var data = req.query; var data = req.query;
var cleanData = sanitizeHtml(data.url, { var cleanData = sanitizeHtml(data.url, {
@ -131,10 +130,10 @@ function preSubmit(req, res) {
storyImage: image, storyImage: image,
storyMetaDescription: description storyMetaDescription: description
}); });
} }
function returnIndividualStory(req, res, next) { function returnIndividualStory(req, res, next) {
var dashedName = req.params.storyName; var dashedName = req.params.storyName;
var storyName = dashedName.replace(/\-/g, ' ').trim(); var storyName = dashedName.replace(/\-/g, ' ').trim();
@ -191,9 +190,9 @@ function returnIndividualStory(req, res, next) {
hasUserVoted: userVoted hasUserVoted: userVoted
}); });
}); });
} }
function getStories(req, res, next) { function getStories(req, res, next) {
MongoClient.connect(secrets.db, function(err, database) { MongoClient.connect(secrets.db, function(err, database) {
if (err) { if (err) {
return next(err); return next(err);
@ -233,9 +232,9 @@ function getStories(req, res, next) {
return res.sendStatus(404); return res.sendStatus(404);
}); });
}); });
} }
function upvote(req, res, next) { function upvote(req, res, next) {
var data = req.body.data; var data = req.body.data;
Story.find({'_id': data.id}, function(err, story) { Story.find({'_id': data.id}, function(err, story) {
if (err) { if (err) {
@ -252,9 +251,12 @@ function upvote(req, res, next) {
story.markModified('rank'); story.markModified('rank');
story.save(); story.save();
// NOTE(Berks): This logic is full of wholes and race conditions // NOTE(Berks): This logic is full of wholes and race conditions
// this could be the source of many 'can't set headers after they are sent' // this could be the source of many 'can't set headers after
// they are sent'
// errors. This needs cleaning // errors. This needs cleaning
User.findOne({'_id': story.author.userId}, function(err, user) { User.findOne(
{ where: { id: story.author.userId } },
function(err, user) {
if (err) { return next(err); } if (err) { return next(err); }
user.progressTimestamps.push(Date.now() || 0); user.progressTimestamps.push(Date.now() || 0);
@ -267,23 +269,26 @@ function upvote(req, res, next) {
return next(err); return next(err);
} }
}); });
}); }
);
return res.send(story); return res.send(story);
}); });
} }
function comments(req, res, next) { function comments(req, res, next) {
var data = req.params.id; var data = req.params.id;
Comment.find({'_id': data}, function(err, comment) { Comment.find(
{ where: {'_id': data } },
function(err, comment) {
if (err) { if (err) {
return next(err); return next(err);
} }
comment = comment.pop(); comment = comment.pop();
return res.send(comment); return res.send(comment);
}); });
} }
function newStory(req, res, next) { function newStory(req, res, next) {
if (!req.user) { if (!req.user) {
return next(new Error('Must be logged in')); return next(new Error('Must be logged in'));
} }
@ -305,7 +310,9 @@ function newStory(req, res, next) {
if (url.search(/^https?:\/\//g) === -1) { if (url.search(/^https?:\/\//g) === -1) {
url = 'http://' + url; url = 'http://' + url;
} }
Story.find({'link': url}, function(err, story) { Story.find(
{ where: {'link': url} },
function(err, story) {
if (err) { if (err) {
return next(err); return next(err);
} }
@ -319,7 +326,8 @@ function newStory(req, res, next) {
}); });
} }
resources.getURLTitle(url, processResponse); resources.getURLTitle(url, processResponse);
}); }
);
function processResponse(err, story) { function processResponse(err, story) {
if (err) { if (err) {
@ -340,9 +348,9 @@ function newStory(req, res, next) {
}); });
} }
} }
} }
function storySubmission(req, res, next) { function storySubmission(req, res, next) {
var data = req.body.data; var data = req.body.data;
if (!req.user) { if (!req.user) {
return next(new Error('Not authorized')); return next(new Error('Not authorized'));
@ -360,7 +368,7 @@ function storySubmission(req, res, next) {
} }
Story.count({ Story.count({
storyLink: new RegExp('^' + storyLink + '(?: [0-9]+)?$', 'i') storyLink: { like: new RegExp('^' + storyLink + '(?: [0-9]+)?$', 'i') }
}, function (err, storyCount) { }, function (err, storyCount) {
if (err) { if (err) {
return next(err); return next(err);
@ -416,9 +424,9 @@ function storySubmission(req, res, next) {
}); });
}); });
}); });
} }
function commentSubmit(req, res, next) { function commentSubmit(req, res, next) {
var data = req.body.data; var data = req.body.data;
if (!req.user) { if (!req.user) {
return next(new Error('Not authorized')); return next(new Error('Not authorized'));
@ -453,25 +461,29 @@ function commentSubmit(req, res, next) {
}); });
commentSave(comment, Story, res, next); commentSave(comment, Story, res, next);
} }
function commentOnCommentSubmit(req, res, next) { function commentOnCommentSubmit(req, res, next) {
var data = req.body.data; var data = req.body.data;
if (!req.user) { if (!req.user) {
return next(new Error('Not authorized')); return next(new Error('Not authorized'));
} }
var sanitizedBody = sanitizeHtml(data.body, var sanitizedBody = sanitizeHtml(
data.body,
{ {
allowedTags: [], allowedTags: [],
allowedAttributes: [] allowedAttributes: []
}).replace(/"/g, '"'); }
).replace(/"/g, '"');
if (data.body !== sanitizedBody) { if (data.body !== sanitizedBody) {
req.flash('errors', { req.flash('errors', {
msg: 'HTML is not allowed' msg: 'HTML is not allowed'
}); });
return res.send(true); return res.send(true);
} }
var comment = new Comment({ var comment = new Comment({
associatedPost: data.associatedPost, associatedPost: data.associatedPost,
body: sanitizedBody, body: sanitizedBody,
@ -490,11 +502,11 @@ function commentOnCommentSubmit(req, res, next) {
commentOn: Date.now() commentOn: Date.now()
}); });
commentSave(comment, Comment, res, next); commentSave(comment, Comment, res, next);
} }
function commentEdit(req, res, next) { function commentEdit(req, res, next) {
Comment.find({'_id': req.params.id}, function(err, cmt) { Comment.find({ id: req.params.id }, function(err, cmt) {
if (err) { if (err) {
return next(err); return next(err);
} }
@ -504,7 +516,6 @@ function commentEdit(req, res, next) {
return next(new Error('Not authorized')); return next(new Error('Not authorized'));
} }
var sanitizedBody = sanitizeHtml(req.body.body, { var sanitizedBody = sanitizeHtml(req.body.body, {
allowedTags: [], allowedTags: [],
allowedAttributes: [] allowedAttributes: []
@ -518,7 +529,7 @@ function commentEdit(req, res, next) {
cmt.body = sanitizedBody; cmt.body = sanitizedBody;
cmt.commentOn = Date.now(); cmt.commentOn = Date.now();
cmt.save(function (err) { cmt.save(function(err) {
if (err) { if (err) {
return next(err); return next(err);
} }
@ -527,9 +538,9 @@ function commentEdit(req, res, next) {
}); });
} }
function commentSave(comment, Context, res, next) { function commentSave(comment, Context, res, next) {
comment.save(function(err, data) { comment.save(function(err, data) {
if (err) { if (err) {
return next(err); return next(err);
@ -538,7 +549,7 @@ function commentSave(comment, Context, res, next) {
// Based on the context retrieve the parent // Based on the context retrieve the parent
// object of the comment (Story/Comment) // object of the comment (Story/Comment)
Context.find({ Context.find({
'_id': data.associatedPost id: data.associatedPost
}, function (err, associatedContext) { }, function (err, associatedContext) {
if (err) { if (err) {
return next(err); return next(err);
@ -604,6 +615,5 @@ function commentSave(comment, Context, res, next) {
return next(err); return next(err);
} }
}); });
} }
};
module.exports = router;

View File

@ -5,63 +5,64 @@ var _ = require('lodash'),
nodemailer = require('nodemailer'), nodemailer = require('nodemailer'),
passport = require('passport'), passport = require('passport'),
moment = require('moment'), moment = require('moment'),
express = require('express'),
debug = require('debug')('freecc:cntr:userController'), debug = require('debug')('freecc:cntr:userController'),
User = require('../../common/models/User'),
secrets = require('../../config/secrets'), secrets = require('../../config/secrets'),
resources = require('./../resources/resources'); resources = require('./../resources/resources');
var router = express.Router(); module.exports = function(app) {
router.get('/login', function(req, res) { var router = app.Router();
res.redirect(301, '/signin'); var User = app.models.User;
});
router.get('/logout', function(req, res) {
res.redirect(301, '/signout');
});
router.get('/signin', getSignin);
router.post('/signin', postSignin);
router.get('/signout', signout);
router.get('/forgot', getForgot);
router.post('/forgot', postForgot);
router.get('/reset/:token', getReset);
router.post('/reset/:token', postReset);
router.get('/email-signup', getEmailSignup);
router.get('/email-signin', getEmailSignin);
router.post('/email-signup', postEmailSignup);
router.post('/email-signin', postSignin);
router.get('/account/api', getAccountAngular);
router.get('/api/checkUniqueUsername/:username', checkUniqueUsername);
router.get('/api/checkExistingUsername/:username', checkExistingUsername);
router.get('/api/checkUniqueEmail/:email', checkUniqueEmail);
router.post('/account/profile', postUpdateProfile);
router.post('/account/password', postUpdatePassword);
router.post('/account/delete', postDeleteAccount);
router.get('/account/unlink/:provider', getOauthUnlink);
router.get('/account', getAccount);
// Ensure this is the last route!
router.get('/:username', returnUser);
/** router.get('/login', function(req, res) {
res.redirect(301, '/signin');
});
router.get('/logout', function(req, res) {
res.redirect(301, '/signout');
});
router.get('/signin', getSignin);
router.post('/signin', postSignin);
router.get('/signout', signout);
router.get('/forgot', getForgot);
router.post('/forgot', postForgot);
router.get('/reset/:token', getReset);
router.post('/reset/:token', postReset);
router.get('/email-signup', getEmailSignup);
router.get('/email-signin', getEmailSignin);
router.post('/email-signup', postEmailSignup);
router.post('/email-signin', postSignin);
router.get('/account/api', getAccountAngular);
router.get('/api/checkUniqueUsername/:username', checkUniqueUsername);
router.get('/api/checkExistingUsername/:username', checkExistingUsername);
router.get('/api/checkUniqueEmail/:email', checkUniqueEmail);
router.post('/account/profile', postUpdateProfile);
router.post('/account/password', postUpdatePassword);
router.post('/account/delete', postDeleteAccount);
router.get('/account/unlink/:provider', getOauthUnlink);
router.get('/account', getAccount);
// Ensure this is the last route!
router.get('/:username', returnUser);
/**
* GET /signin * GET /signin
* Siginin page. * Siginin page.
*/ */
function getSignin (req, res) { function getSignin (req, res) {
if (req.user) { if (req.user) {
return res.redirect('/'); return res.redirect('/');
} }
res.render('account/signin', { res.render('account/signin', {
title: 'Free Code Camp Login' title: 'Free Code Camp Login'
}); });
} }
/** /**
* POST /signin * POST /signin
* Sign in using email and password. * Sign in using email and password.
*/ */
function postSignin (req, res, next) { function postSignin (req, res, next) {
req.assert('email', 'Email is not valid').isEmail(); req.assert('email', 'Email is not valid').isEmail();
req.assert('password', 'Password cannot be blank').notEmpty(); req.assert('password', 'Password cannot be blank').notEmpty();
@ -94,52 +95,52 @@ function postSignin (req, res, next) {
return res.redirect(req.session.returnTo || '/'); return res.redirect(req.session.returnTo || '/');
}); });
})(req, res, next); })(req, res, next);
} }
/** /**
* GET /signout * GET /signout
* Log out. * Log out.
*/ */
function signout (req, res) { function signout (req, res) {
req.logout(); req.logout();
res.redirect('/'); res.redirect('/');
} }
/** /**
* GET /email-signup * GET /email-signup
* Signup page. * Signup page.
*/ */
function getEmailSignin (req, res) { function getEmailSignin (req, res) {
if (req.user) { if (req.user) {
return res.redirect('/'); return res.redirect('/');
} }
res.render('account/email-signin', { res.render('account/email-signin', {
title: 'Sign in to your Free Code Camp Account' title: 'Sign in to your Free Code Camp Account'
}); });
} }
/** /**
* GET /signin * GET /signin
* Signup page. * Signup page.
*/ */
function getEmailSignup (req, res) { function getEmailSignup (req, res) {
if (req.user) { if (req.user) {
return res.redirect('/'); return res.redirect('/');
} }
res.render('account/email-signup', { res.render('account/email-signup', {
title: 'Create Your Free Code Camp Account' title: 'Create Your Free Code Camp Account'
}); });
} }
/** /**
* POST /email-signup * POST /email-signup
* Create a new local account. * Create a new local account.
*/ */
function postEmailSignup (req, res, next) { function postEmailSignup (req, res, next) {
req.assert('email', 'valid email required').isEmail(); req.assert('email', 'valid email required').isEmail();
var errors = req.validationErrors(); var errors = req.validationErrors();
@ -233,34 +234,34 @@ function postEmailSignup (req, res, next) {
}); });
}); });
}); });
} }
/** /**
* GET /account * GET /account
* Profile page. * Profile page.
*/ */
function getAccount (req, res) { function getAccount (req, res) {
res.render('account/account', { res.render('account/account', {
title: 'Manage your Free Code Camp Account' title: 'Manage your Free Code Camp Account'
}); });
} }
/** /**
* Angular API Call * Angular API Call
*/ */
function getAccountAngular (req, res) { function getAccountAngular (req, res) {
res.json({ res.json({
user: req.user user: req.user
}); });
} }
/** /**
* Unique username check API Call * Unique username check API Call
*/ */
function checkUniqueUsername (req, res, next) { function checkUniqueUsername (req, res, next) {
User.count( User.count(
{ 'profile.username': req.params.username.toLowerCase() }, { 'profile.username': req.params.username.toLowerCase() },
function (err, data) { function (err, data) {
@ -271,13 +272,13 @@ function checkUniqueUsername (req, res, next) {
return res.send(false); return res.send(false);
} }
}); });
} }
/** /**
* Existing username check * Existing username check
*/ */
function checkExistingUsername (req, res, next) { function checkExistingUsername (req, res, next) {
User.count( User.count(
{ 'profile.username': req.params.username.toLowerCase() }, { 'profile.username': req.params.username.toLowerCase() },
function (err, data) { function (err, data) {
@ -289,13 +290,13 @@ function checkExistingUsername (req, res, next) {
} }
} }
); );
} }
/** /**
* Unique email check API Call * Unique email check API Call
*/ */
function checkUniqueEmail (req, res, next) { function checkUniqueEmail (req, res, next) {
User.count( User.count(
{ email: decodeURIComponent(req.params.email).toLowerCase() }, { email: decodeURIComponent(req.params.email).toLowerCase() },
function (err, data) { function (err, data) {
@ -307,15 +308,15 @@ function checkUniqueEmail (req, res, next) {
} }
} }
); );
} }
/** /**
* GET /campers/:username * GET /campers/:username
* Public Profile page. * Public Profile page.
*/ */
function returnUser (req, res, next) { function returnUser (req, res, next) {
User.find( User.find(
{ 'profile.username': req.params.username.toLowerCase() }, { 'profile.username': req.params.username.toLowerCase() },
function(err, user) { function(err, user) {
@ -325,8 +326,8 @@ function returnUser (req, res, next) {
} }
if (user[0]) { if (user[0]) {
user = user[0]; user = user[0];
user.progressTimestamps =
user.progressTimestamps = user.progressTimestamps.sort(function(a, b) { user.progressTimestamps.sort(function(a, b) {
return a - b; return a - b;
}); });
@ -442,14 +443,14 @@ function returnUser (req, res, next) {
} }
} }
); );
} }
/** /**
* POST /account/profile * POST /account/profile
* Update profile information. * Update profile information.
*/ */
function postUpdateProfile (req, res, next) { function postUpdateProfile (req, res, next) {
User.findById(req.user.id, function(err) { User.findById(req.user.id, function(err) {
if (err) { return next(err); } if (err) { return next(err); }
@ -486,29 +487,34 @@ function postUpdateProfile (req, res, next) {
}); });
return res.redirect('/account'); return res.redirect('/account');
} }
user.email = req.body.email.trim() || ''; var body = req.body || {};
user.profile.name = req.body.name.trim() || ''; user.email = body.email.trim() || '';
user.profile.username = req.body.username.trim() || ''; user.profile.name = body.name.trim() || '';
user.profile.location = req.body.location.trim() || ''; user.profile.username = body.username.trim() || '';
user.profile.githubProfile = req.body.githubProfile.trim() || ''; user.profile.location = body.location.trim() || '';
user.profile.facebookProfile = req.body.facebookProfile.trim() || '';
user.profile.linkedinProfile = req.body.linkedinProfile.trim() || '';
user.profile.codepenProfile = req.body.codepenProfile.trim() || '';
user.profile.twitterHandle = req.body.twitterHandle.trim() || '';
user.profile.bio = req.body.bio.trim() || '';
user.profile.picture = req.body.picture.trim() || user.profile.githubProfile = body.githubProfile.trim() || '';
user.profile.facebookProfile = body.facebookProfile.trim() || '';
user.profile.linkedinProfile = body.linkedinProfile.trim() || '';
user.profile.codepenProfile = body.codepenProfile.trim() || '';
user.profile.twitterHandle = body.twitterHandle.trim() || '';
user.profile.bio = body.bio.trim() || '';
user.profile.picture = body.picture.trim() ||
'https://s3.amazonaws.com/freecodecamp/' + 'https://s3.amazonaws.com/freecodecamp/' +
'camper-image-placeholder.png'; 'camper-image-placeholder.png';
user.portfolio.website1Title = req.body.website1Title.trim() || ''; user.portfolio.website1Title = body.website1Title.trim() || '';
user.portfolio.website1Link = req.body.website1Link.trim() || ''; user.portfolio.website1Link = body.website1Link.trim() || '';
user.portfolio.website1Image = req.body.website1Image.trim() || ''; user.portfolio.website1Image = body.website1Image.trim() || '';
user.portfolio.website2Title = req.body.website2Title.trim() || '';
user.portfolio.website2Link = req.body.website2Link.trim() || ''; user.portfolio.website2Title = body.website2Title.trim() || '';
user.portfolio.website2Image = req.body.website2Image.trim() || ''; user.portfolio.website2Link = body.website2Link.trim() || '';
user.portfolio.website3Title = req.body.website3Title.trim() || ''; user.portfolio.website2Image = body.website2Image.trim() || '';
user.portfolio.website3Link = req.body.website3Link.trim() || '';
user.portfolio.website3Image = req.body.website3Image.trim() || ''; user.portfolio.website3Title = body.website3Title.trim() || '';
user.portfolio.website3Link = body.website3Link.trim() || '';
user.portfolio.website3Image = body.website3Image.trim() || '';
user.save(function (err) { user.save(function (err) {
@ -532,15 +538,17 @@ function postUpdateProfile (req, res, next) {
); );
}); });
}); });
} }
/** /**
* POST /account/password * POST /account/password
* Update current password. * Update current password.
*/ */
function postUpdatePassword (req, res, next) { function postUpdatePassword (req, res, next) {
req.assert('password', 'Password must be at least 4 characters long').len(4); req.assert('password', 'Password must be at least 4 characters long')
.len(4);
req.assert('confirmPassword', 'Passwords do not match') req.assert('confirmPassword', 'Passwords do not match')
.equals(req.body.password); .equals(req.body.password);
@ -563,28 +571,28 @@ function postUpdatePassword (req, res, next) {
res.redirect('/account'); res.redirect('/account');
}); });
}); });
} }
/** /**
* POST /account/delete * POST /account/delete
* Delete user account. * Delete user account.
*/ */
function postDeleteAccount (req, res, next) { function postDeleteAccount (req, res, next) {
User.remove({ _id: req.user.id }, function(err) { User.destroyById(req.user.id, function(err) {
if (err) { return next(err); } if (err) { return next(err); }
req.logout(); req.logout();
req.flash('info', { msg: 'Your account has been deleted.' }); req.flash('info', { msg: 'Your account has been deleted.' });
res.redirect('/'); res.redirect('/');
}); });
} }
/** /**
* GET /account/unlink/:provider * GET /account/unlink/:provider
* Unlink OAuth provider. * Unlink OAuth provider.
*/ */
function getOauthUnlink (req, res, next) { function getOauthUnlink (req, res, next) {
var provider = req.params.provider; var provider = req.params.provider;
User.findById(req.user.id, function(err, user) { User.findById(req.user.id, function(err, user) {
if (err) { return next(err); } if (err) { return next(err); }
@ -601,21 +609,25 @@ function getOauthUnlink (req, res, next) {
res.redirect('/account'); res.redirect('/account');
}); });
}); });
} }
/** /**
* GET /reset/:token * GET /reset/:token
* Reset Password page. * Reset Password page.
*/ */
function getReset (req, res, next) { function getReset (req, res, next) {
if (req.isAuthenticated()) { if (req.isAuthenticated()) {
return res.redirect('/'); return res.redirect('/');
} }
User User.findOne(
.findOne({ resetPasswordToken: req.params.token }) {
.where('resetPasswordExpires').gt(Date.now()) where: {
.exec(function(err, user) { resetPasswordToken: req.params.token,
resetPasswordExpires: Date.now()
}
},
function(err, user) {
if (err) { return next(err); } if (err) { return next(err); }
if (!user) { if (!user) {
req.flash('errors', { req.flash('errors', {
@ -628,14 +640,14 @@ function getReset (req, res, next) {
token: req.params.token token: req.params.token
}); });
}); });
} }
/** /**
* POST /reset/:token * POST /reset/:token
* Process the reset password request. * Process the reset password request.
*/ */
function postReset (req, res, next) { function postReset (req, res, next) {
var errors = req.validationErrors(); var errors = req.validationErrors();
if (errors) { if (errors) {
@ -645,10 +657,14 @@ function postReset (req, res, next) {
async.waterfall([ async.waterfall([
function(done) { function(done) {
User User.findOne(
.findOne({ resetPasswordToken: req.params.token }) {
.where('resetPasswordExpires').gt(Date.now()) where: {
.exec(function(err, user) { resetPasswordToken: req.params.token,
resetPasswordExpires: Date.now()
}
},
function(err, user) {
if (err) { return next(err); } if (err) { return next(err); }
if (!user) { if (!user) {
req.flash('errors', { req.flash('errors', {
@ -702,28 +718,28 @@ function postReset (req, res, next) {
if (err) { return next(err); } if (err) { return next(err); }
res.redirect('/'); res.redirect('/');
}); });
} }
/** /**
* GET /forgot * GET /forgot
* Forgot Password page. * Forgot Password page.
*/ */
function getForgot (req, res) { function getForgot (req, res) {
if (req.isAuthenticated()) { if (req.isAuthenticated()) {
return res.redirect('/'); return res.redirect('/');
} }
res.render('account/forgot', { res.render('account/forgot', {
title: 'Forgot Password' title: 'Forgot Password'
}); });
} }
/** /**
* POST /forgot * POST /forgot
* Create a random token, then the send user an email with a reset link. * Create a random token, then the send user an email with a reset link.
*/ */
function postForgot (req, res, next) { function postForgot (req, res, next) {
var errors = req.validationErrors(); var errors = req.validationErrors();
if (errors) { if (errors) {
@ -801,6 +817,5 @@ function postForgot (req, res, next) {
if (err) { return next(err); } if (err) { return next(err); }
res.redirect('/forgot'); res.redirect('/forgot');
}); });
} }
};
module.exports = router;

View File

@ -1,44 +1,45 @@
var express = require('express'), var Rx = require('rx'),
Twit = require('twit'),
async = require('async'), async = require('async'),
moment = require('moment'), moment = require('moment'),
Twit = require('twit'),
Slack = require('node-slack'), Slack = require('node-slack'),
request = require('request'), request = require('request'),
debug = require('debug')('freecc:cntr:resources'), debug = require('debug')('freecc:cntr:resources'),
constantStrings = require('../resources/constantStrings.json'),
User = require('../../common/models/User'), constantStrings = require('../resources/constantStrings.json'),
Challenge = require('../../common/models/Challenge'),
Story = require('../../common/models/Story'),
FieldGuide = require('../../common/models/FieldGuide'),
Nonprofit = require('../../common/models/Nonprofit'),
secrets = require('../../config/secrets'); secrets = require('../../config/secrets');
var slack = new Slack(secrets.slackHook); var slack = new Slack(secrets.slackHook);
var router = express.Router(); module.exports = function(app) {
var router = app.Router();
var User = app.models.User;
var Challenge = app.models.Challenge;
var Story = app.models.Store;
var FieldGuide = app.models.FieldGuide;
var Nonprofit = app.models.Nonprofit;
router.get('/api/github', githubCalls); router.get('/api/github', githubCalls);
router.get('/api/blogger', bloggerCalls); router.get('/api/blogger', bloggerCalls);
router.get('/api/trello', trelloCalls); router.get('/api/trello', trelloCalls);
router.get('/api/codepen/twitter/:screenName', twitter); router.get('/api/codepen/twitter/:screenName', twitter);
router.get('/sitemap.xml', sitemap); router.get('/sitemap.xml', sitemap);
router.post('/get-help', getHelp); router.post('/get-help', getHelp);
router.post('/get-pair', getPair); router.post('/get-pair', getPair);
router.get('/chat', chat); router.get('/chat', chat);
router.get('/twitch', twitch); router.get('/twitch', twitch);
router.get('/pmi-acp-agile-project-managers', agileProjectManagers); router.get('/pmi-acp-agile-project-managers', agileProjectManagers);
router.get('/pmi-acp-agile-project-managers-form', agileProjectManagersForm); router.get('/pmi-acp-agile-project-managers-form', agileProjectManagersForm);
router.get('/nonprofits', nonprofits); router.get('/nonprofits', nonprofits);
router.get('/nonprofits-form', nonprofitsForm); router.get('/nonprofits-form', nonprofitsForm);
router.get('/jobs-form', jobsForm); router.get('/jobs-form', jobsForm);
router.get('/submit-cat-photo', catPhotoSubmit); router.get('/submit-cat-photo', catPhotoSubmit);
router.get('/unsubscribe/:email', unsubscribe); router.get('/unsubscribe/:email', unsubscribe);
router.get('/unsubscribed', unsubscribed); router.get('/unsubscribed', unsubscribed);
router.get('/cats.json', getCats); router.get('/cats.json', getCats);
router.get('/api/slack', slackInvite); router.get('/api/slack', slackInvite);
function slackInvite(req, res, next) { function slackInvite(req, res, next) {
if (req.user) { if (req.user) {
if (req.user.email) { if (req.user.email) {
var invite = { var invite = {
@ -63,7 +64,8 @@ function slackInvite(req, res, next) {
if (!error && response.statusCode === 200) { if (!error && response.statusCode === 200) {
req.flash('success', { req.flash('success', {
msg: 'We\'ve successfully requested an invite for you.' + msg: 'We\'ve successfully requested an invite for you.' +
' Please check your email and follow the instructions from Slack.' ' Please check your email and follow the ' +
'instructions from Slack.'
}); });
req.user.sentSlackInvite = true; req.user.sentSlackInvite = true;
req.user.save(function(err) { req.user.save(function(err) {
@ -97,9 +99,9 @@ function slackInvite(req, res, next) {
}); });
return res.redirect('/account'); return res.redirect('/account');
} }
} }
function twitter(req, res, next) { function twitter(req, res, next) {
// sends out random tweets about javascript // sends out random tweets about javascript
var T = new Twit({ var T = new Twit({
'consumer_key': secrets.twitter.consumerKey, 'consumer_key': secrets.twitter.consumerKey,
@ -126,10 +128,10 @@ function twitter(req, res, next) {
return res.json(data); return res.json(data);
} }
); );
} }
function getHelp(req, res) { function getHelp(req, res) {
var userName = req.user.profile.username; var userName = req.user.profile.username;
var code = req.body.payload.code ? '\n```\n' + var code = req.body.payload.code ? '\n```\n' +
req.body.payload.code + '\n```\n' req.body.payload.code + '\n```\n'
@ -147,9 +149,9 @@ function getHelp(req, res) {
'3609875545/569237541c920fa78d78902069615caf.jpeg' '3609875545/569237541c920fa78d78902069615caf.jpeg'
}); });
return res.sendStatus(200); return res.sendStatus(200);
} }
function getPair(req, res) { function getPair(req, res) {
var userName = req.user.profile.username; var userName = req.user.profile.username;
var challenge = req.body.payload.challenge; var challenge = req.body.payload.challenge;
slack.send({ slack.send({
@ -171,84 +173,130 @@ function getPair(req, res) {
].join(''), ].join(''),
channel: '#letspair', channel: '#letspair',
username: 'Companion Cube', username: 'Companion Cube',
'icon_url': 'https://lh3.googleusercontent.com/-f6xDPDV2rPE/AAAAAAAAAAI/' + 'icon_url':
'https://lh3.googleusercontent.com/-f6xDPDV2rPE/AAAAAAAAAAI/' +
'AAAAAAAAAAA/mdlESXQu11Q/photo.jpg' 'AAAAAAAAAAA/mdlESXQu11Q/photo.jpg'
}); });
return res.sendStatus(200); return res.sendStatus(200);
} }
function sitemap(req, res, next) { function sitemap(req, res, next) {
var appUrl = 'http://www.freecodecamp.com'; var appUrl = 'http://www.freecodecamp.com';
var now = moment(new Date()).format('YYYY-MM-DD'); var now = moment(new Date()).format('YYYY-MM-DD');
// TODO(berks): refactor async to rx
async.parallel({ async.parallel({
users: function(callback) { users: function(callback) {
User.aggregate() User.find(
.group({_id: 1, usernames: { $addToSet: '$profile.username'}}) {
.match({'profile.username': { $ne: ''}}) where: { 'profile.username': { nlike: '' } },
.exec(function(err, users) { fields: { 'profile.username': true }
},
function(err, users) {
if (err) { if (err) {
debug('User err: ', err); debug('User err: ', err);
callback(err); callback(err);
} else { } else {
callback(null, users[0].usernames); Rx.Observable.from(users)
.map(function(user) {
return user.profile.username;
})
.toArray()
.subscribe(
function(usernames) {
callback(null, usernames);
},
callback
);
} }
}); });
}, },
challenges: function (callback) { challenges: function (callback) {
Challenge.aggregate() Challenge.find(
.group({_id: 1, names: { $addToSet: '$name'}}) { fields: { name: true } },
.exec(function (err, challenges) { function (err, challenges) {
if (err) { if (err) {
debug('Challenge err: ', err); debug('Challenge err: ', err);
callback(err); callback(err);
} else { } else {
callback(null, challenges[0].names); Rx.Observable.from(challenges)
.map(function(challenge) {
return challenge.name;
})
.toArray()
.subscribe(
callback.bind(callback, null),
callback
);
} }
}); });
}, },
stories: function (callback) { stories: function (callback) {
Story.aggregate() Story.find(
.group({_id: 1, links: {$addToSet: '$link'}}) { field: { link: true } },
.exec(function (err, stories) { function (err, stories) {
if (err) { if (err) {
debug('Story err: ', err); debug('Story err: ', err);
callback(err); callback(err);
} else { } else {
callback(null, stories[0].links); Rx.Observable.from(stories)
.map(function(story) {
return story.link;
})
.toArray()
.subscribe(
callback.bind(callback, null),
callback
);
} }
}); }
);
}, },
nonprofits: function (callback) { nonprofits: function (callback) {
Nonprofit.aggregate() Nonprofit.find(
.group({_id: 1, names: { $addToSet: '$name'}}) { field: { name: true } },
.exec(function (err, nonprofits) { function(err, nonprofits) {
if (err) { if (err) {
debug('User err: ', err); debug('User err: ', err);
callback(err); callback(err);
} else { } else {
callback(null, nonprofits[0].names); Rx.Observable.from(nonprofits)
.map(function(nonprofit) {
return nonprofit.name;
})
.toArray()
.subscribe(
callback.bind(callback, null),
callback
);
} }
}); });
}, },
fieldGuides: function (callback) { fieldGuides: function(callback) {
FieldGuide.aggregate() FieldGuide.find(
.group({_id: 1, names: { $addToSet: '$name'}}) { field: { name: true } },
.exec(function (err, fieldGuides) { function(err, fieldGuides) {
if (err) { if (err) {
debug('User err: ', err); debug('User err: ', err);
callback(err); callback(err);
} else { } else {
callback(null, fieldGuides[0].names); Rx.Observable.from(fieldGuides)
.map(function(fieldGuide) {
return fieldGuide.name;
})
.toArray()
.subscribe(
callback.bind(callback, null),
callback
);
} }
}); });
} }
}, function (err, results) { }, function(err, results) {
if (err) { if (err) {
return next(err); return next(err);
} else { }
setTimeout(function() { setTimeout(function() {
res.header('Content-Type', 'application/xml'); res.header('Content-Type', 'application/xml');
res.render('resources/sitemap', { res.render('resources/sitemap', {
@ -262,11 +310,10 @@ function sitemap(req, res, next) {
}); });
}, 0); }, 0);
} }
}
); );
} }
function chat(req, res) { function chat(req, res) {
if (req.user && req.user.progressTimestamps.length > 5) { if (req.user && req.user.progressTimestamps.length > 5) {
res.redirect('http://freecodecamp.slack.com'); res.redirect('http://freecodecamp.slack.com');
} else { } else {
@ -274,53 +321,53 @@ function chat(req, res) {
title: 'Watch us code live on Twitch.tv' title: 'Watch us code live on Twitch.tv'
}); });
} }
} }
function jobsForm(req, res) { function jobsForm(req, res) {
res.render('resources/jobs-form', { res.render('resources/jobs-form', {
title: 'Employer Partnership Form for Job Postings,' + title: 'Employer Partnership Form for Job Postings,' +
' Recruitment and Corporate Sponsorships' ' Recruitment and Corporate Sponsorships'
}); });
} }
function catPhotoSubmit(req, res) { function catPhotoSubmit(req, res) {
res.send( res.send(
'Success! You have submitted your cat photo. Return to your website ' + 'Success! You have submitted your cat photo. Return to your website ' +
'by typing any letter into your code editor.' 'by typing any letter into your code editor.'
); );
} }
function nonprofits(req, res) { function nonprofits(req, res) {
res.render('resources/nonprofits', { res.render('resources/nonprofits', {
title: 'A guide to our Nonprofit Projects' title: 'A guide to our Nonprofit Projects'
}); });
} }
function nonprofitsForm(req, res) { function nonprofitsForm(req, res) {
res.render('resources/nonprofits-form', { res.render('resources/nonprofits-form', {
title: 'Nonprofit Projects Proposal Form' title: 'Nonprofit Projects Proposal Form'
}); });
} }
function agileProjectManagers(req, res) { function agileProjectManagers(req, res) {
res.render('resources/pmi-acp-agile-project-managers', { res.render('resources/pmi-acp-agile-project-managers', {
title: 'Get Agile Project Management Experience for the PMI-ACP' title: 'Get Agile Project Management Experience for the PMI-ACP'
}); });
} }
function agileProjectManagersForm(req, res) { function agileProjectManagersForm(req, res) {
res.render('resources/pmi-acp-agile-project-managers-form', { res.render('resources/pmi-acp-agile-project-managers-form', {
title: 'Agile Project Management Program Application Form' title: 'Agile Project Management Program Application Form'
}); });
} }
function twitch(req, res) { function twitch(req, res) {
res.render('resources/twitch', { res.render('resources/twitch', {
title: 'Enter Free Code Camp\'s Chat Rooms' title: 'Enter Free Code Camp\'s Chat Rooms'
}); });
} }
function unsubscribe(req, res, next) { function unsubscribe(req, res, next) {
User.findOne({ email: req.params.email }, function(err, user) { User.findOne({ email: req.params.email }, function(err, user) {
if (user) { if (user) {
if (err) { if (err) {
@ -337,15 +384,15 @@ function unsubscribe(req, res, next) {
res.redirect('/unsubscribed'); res.redirect('/unsubscribed');
} }
}); });
} }
function unsubscribed(req, res) { function unsubscribed(req, res) {
res.render('resources/unsubscribed', { res.render('resources/unsubscribed', {
title: 'You have been unsubscribed' title: 'You have been unsubscribed'
}); });
} }
function githubCalls(req, res, next) { function githubCalls(req, res, next) {
var githubHeaders = { var githubHeaders = {
headers: { headers: {
'User-Agent': constantStrings.gitHubUserAgent 'User-Agent': constantStrings.gitHubUserAgent
@ -389,9 +436,9 @@ function githubCalls(req, res, next) {
); );
} }
); );
} }
function trelloCalls(req, res, next) { function trelloCalls(req, res, next) {
request( request(
'https://trello.com/1/boards/BA3xVpz9/cards?key=' + 'https://trello.com/1/boards/BA3xVpz9/cards?key=' +
secrets.trello.key, secrets.trello.key,
@ -403,9 +450,9 @@ function trelloCalls(req, res, next) {
res.end(JSON.stringify(trello)); res.end(JSON.stringify(trello));
}); });
} }
function bloggerCalls(req, res, next) { function bloggerCalls(req, res, next) {
request( request(
'https://www.googleapis.com/blogger/v3/blogs/2421288658305323950/' + 'https://www.googleapis.com/blogger/v3/blogs/2421288658305323950/' +
'posts?key=' + 'posts?key=' +
@ -419,9 +466,9 @@ function bloggerCalls(req, res, next) {
res.end(JSON.stringify(blog)); res.end(JSON.stringify(blog));
} }
); );
} }
function getCats(req, res) { function getCats(req, res) {
res.send( res.send(
[ [
{ {
@ -441,6 +488,5 @@ function getCats(req, res) {
} }
] ]
); );
} }
};
module.exports = router;