Begin shaping codebase for loopback migration.
This commit is contained in:
		| @@ -15,7 +15,8 @@ | ||||
|     "window": true, | ||||
|     "$": true, | ||||
|     "ga": true, | ||||
|     "jQuery": true | ||||
|     "jQuery": true, | ||||
|     "router": true | ||||
|   }, | ||||
|   "rules": { | ||||
|     "no-comma-dangle": 2, | ||||
|   | ||||
							
								
								
									
										2
									
								
								Procfile
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								Procfile
									
									
									
									
									
								
							| @@ -1 +1 @@ | ||||
| web: ./node_modules/.bin/forever -m 5 app.js | ||||
| web: ./node_modules/.bin/forever -m 5 server.js | ||||
| @@ -126,7 +126,7 @@ Project Structure | ||||
| | **views/partials**/footer.jade     | Footer partial template.                                    | | ||||
| | **views**/layout.jade              | Base template.                                              | | ||||
| | **views**/home.jade                | Home page template.                                         | | ||||
| | app.js                             | Main application file.                                      | | ||||
| | server.js                             | Main application file.                                      | | ||||
|  | ||||
|  | ||||
| List of Packages | ||||
| @@ -155,7 +155,7 @@ List of Packages | ||||
| | github-api                      | GitHub API library.                                                  | | ||||
| | jade                            | Template engine for Express.                                         | | ||||
| | less                            | LESS compiler. Used implicitly by connect-assets.                    | | ||||
| | helmet                          | Restricts Cross site requests. You can modify its settings in app.js | | ||||
| | helmet                          | Restricts Cross site requests. You can modify its settings in server.js | | ||||
| | mongoose                        | MongoDB ODM.                                                         | | ||||
| | nodemailer                      | Node.js library for sending emails.                                  | | ||||
| | passport                        | Simple and elegant authentication library for node.js                | | ||||
|   | ||||
| @@ -1,53 +0,0 @@ | ||||
| var R = require('ramda'), | ||||
|     debug = require('debug')('freecc:cntr:challengeMap'), | ||||
|     User = require('../models/User'), | ||||
|     resources = require('./resources'); | ||||
|  | ||||
| var challengeTypes = { | ||||
|   'HTML_CSS_JQ': 0, | ||||
|   'JAVASCRIPT': 1, | ||||
|   'VIDEO': 2, | ||||
|   'ZIPLINE': 3, | ||||
|   'BASEJUMP': 4, | ||||
|   'BONFIRE': 5 | ||||
| }; | ||||
|  | ||||
| module.exports = { | ||||
|   challengeMap: function challengeMap(req, res, next) { | ||||
|     var completedList = []; | ||||
|  | ||||
|     if (req.user) { | ||||
|       completedList = req.user.completedChallenges; | ||||
|     } | ||||
|  | ||||
|     var noDuplicatedChallenges = R.uniq(completedList); | ||||
|  | ||||
|     var completedChallengeList = noDuplicatedChallenges | ||||
|       .map(function(challenge) { | ||||
|         return challenge._id; | ||||
|       }); | ||||
|     var challengeList = resources.getChallengeMapForDisplay(completedChallengeList); | ||||
|  | ||||
|     function numberWithCommas(x) { | ||||
|       return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ','); | ||||
|     } | ||||
|  | ||||
|     var date1 = new Date('10/15/2014'); | ||||
|     var date2 = new Date(); | ||||
|     var timeDiff = Math.abs(date2.getTime() - date1.getTime()); | ||||
|     var daysRunning = Math.ceil(timeDiff / (1000 * 3600 * 24)); | ||||
|  | ||||
|     User.count({}, function (err, camperCount) { | ||||
|       if (err) { | ||||
|         return next(err); | ||||
|       } | ||||
|       res.render('challengeMap/show', { | ||||
|         daysRunning: daysRunning, | ||||
|         camperCount: numberWithCommas(camperCount), | ||||
|         title: "A map of all Free Code Camp's Challenges", | ||||
|         challengeList: challengeList, | ||||
|         completedChallengeList: completedChallengeList | ||||
|       }); | ||||
|     }); | ||||
|   } | ||||
| }; | ||||
| @@ -1,641 +0,0 @@ | ||||
| var async = require('async'), | ||||
|   path = require('path'), | ||||
|   moment = require('moment'), | ||||
|   Twit = require('twit'), | ||||
|   debug = require('debug')('freecc:cntr:resources'), | ||||
|   cheerio = require('cheerio'), | ||||
|   request = require('request'), | ||||
|   R = require('ramda'), | ||||
|   _ = require('lodash'), | ||||
|   fs = require('fs'), | ||||
|  | ||||
|  | ||||
|   constantStrings = require('./constantStrings.json'), | ||||
|   User = require('../models/User'), | ||||
|   Challenge = require('./../models/Challenge'), | ||||
|   Story = require('./../models/Story'), | ||||
|   FieldGuide = require('./../models/FieldGuide'), | ||||
|   Nonprofit = require('./../models/Nonprofit'), | ||||
|   Comment = require('./../models/Comment'), | ||||
|   resources = require('./resources.json'), | ||||
|   secrets = require('./../config/secrets'), | ||||
|   nonprofits = require('../seed_data/nonprofits.json'), | ||||
|   fieldGuides = require('../seed_data/field-guides.json'), | ||||
|   Slack = require('node-slack'), | ||||
|   slack = new Slack(secrets.slackHook); | ||||
|  | ||||
| /** | ||||
|  * Cached values | ||||
|  */ | ||||
| var allFieldGuideIds, allFieldGuideNames, allNonprofitNames, | ||||
|   challengeMap, challengeMapForDisplay, challengeMapWithIds, | ||||
|   challengeMapWithNames, allChallengeIds, allChallenges; | ||||
|  | ||||
| /** | ||||
|  * GET / | ||||
|  * Resources. | ||||
|  */ | ||||
|  | ||||
| Array.zip = function(left, right, combinerFunction) { | ||||
|   var counter, | ||||
|     results = []; | ||||
|  | ||||
|   for (counter = 0; counter < Math.min(left.length, right.length); counter++) { | ||||
|     results.push(combinerFunction(left[counter], right[counter])); | ||||
|   } | ||||
|  | ||||
|   return results; | ||||
| }; | ||||
|  | ||||
| (function() { | ||||
|   if (!challengeMap) { | ||||
|     var localChallengeMap = {}; | ||||
|     var files = fs.readdirSync( | ||||
|       path.join(__dirname, '/../seed_data/challenges') | ||||
|     ); | ||||
|     var keyCounter = 0; | ||||
|     files = files.map(function (file) { | ||||
|       return require( | ||||
|         path.join(__dirname, '/../seed_data/challenges/' + file) | ||||
|       ); | ||||
|     }); | ||||
|     files = files.sort(function (a, b) { | ||||
|       return a.order - b.order; | ||||
|     }); | ||||
|     files.forEach(function (file) { | ||||
|       localChallengeMap[keyCounter++] = file; | ||||
|     }); | ||||
|     challengeMap = _.cloneDeep(localChallengeMap); | ||||
|   } | ||||
| })(); | ||||
|  | ||||
|  | ||||
| module.exports = { | ||||
|  | ||||
|   getChallengeMapForDisplay: function(completedChallengeList) { | ||||
|     if (!challengeMapForDisplay) { | ||||
|       challengeMapForDisplay = {}; | ||||
|       Object.keys(challengeMap).forEach(function(key) { | ||||
|         //TODO get ratio of completed to uncompleted for each section | ||||
|         //challengeMap[key].challenges.forEach(function(challenge){ | ||||
|         // | ||||
|         //} | ||||
|         challengeMapForDisplay[key] = { | ||||
|           name: challengeMap[key].name, | ||||
|           dashedName: challengeMap[key].name.replace(/\s/g, '-'), | ||||
|           challenges: challengeMap[key].challenges, | ||||
|           completedCount: challengeMap[key].challenges //ToDo count number of uncompleted challenges | ||||
|         } | ||||
|       }); | ||||
|     } | ||||
|     return challengeMapForDisplay; | ||||
|   }, | ||||
|  | ||||
|   getChallengeMapWithIds: function() { | ||||
|     if (!challengeMapWithIds) { | ||||
|       challengeMapWithIds = {}; | ||||
|       Object.keys(challengeMap).forEach(function (key) { | ||||
|         var onlyIds = challengeMap[key].challenges.map(function (elem) { | ||||
|           return elem._id; | ||||
|         }); | ||||
|         challengeMapWithIds[key] = onlyIds; | ||||
|       }); | ||||
|     } | ||||
|     return challengeMapWithIds; | ||||
|   }, | ||||
|  | ||||
|   allChallengeIds: function() { | ||||
|  | ||||
|     if (!allChallengeIds) { | ||||
|       allChallengeIds = []; | ||||
|       Object.keys(this.getChallengeMapWithIds()).forEach(function(key) { | ||||
|         allChallengeIds.push(challengeMapWithIds[key]); | ||||
|       }); | ||||
|       allChallengeIds = R.flatten(allChallengeIds); | ||||
|     } | ||||
|     return allChallengeIds; | ||||
|   }, | ||||
|  | ||||
|   allChallenges: function() { | ||||
|     if (!allChallenges) { | ||||
|       allChallenges = []; | ||||
|       Object.keys(this.getChallengeMapWithNames()).forEach(function(key) { | ||||
|         allChallenges.push(challengeMap[key].challenges); | ||||
|       }); | ||||
|       allChallenges = R.flatten(allChallenges); | ||||
|     } | ||||
|     return allChallenges; | ||||
|   }, | ||||
|  | ||||
|   getChallengeMapWithNames: function() { | ||||
|     if (!challengeMapWithNames) { | ||||
|       challengeMapWithNames = {}; | ||||
|       Object.keys(challengeMap). | ||||
|         forEach(function (key) { | ||||
|           var onlyNames = challengeMap[key].challenges.map(function (elem) { | ||||
|             return elem.name; | ||||
|           }); | ||||
|           challengeMapWithNames[key] = onlyNames; | ||||
|         }); | ||||
|     } | ||||
|     return challengeMapWithNames; | ||||
|   }, | ||||
|  | ||||
|   sitemap: function sitemap(req, res, next) { | ||||
|     var appUrl = 'http://www.freecodecamp.com'; | ||||
|     var now = moment(new Date()).format('YYYY-MM-DD'); | ||||
|  | ||||
|  | ||||
|     async.parallel({ | ||||
|         users: function(callback) { | ||||
|           User.aggregate() | ||||
|             .group({_id: 1, usernames: { $addToSet: '$profile.username'}}) | ||||
|             .match({'profile.username': { $ne: ''}}) | ||||
|             .exec(function(err, users) { | ||||
|               if (err) { | ||||
|                 debug('User err: ', err); | ||||
|                 callback(err); | ||||
|               } else { | ||||
|                 callback(null, users[0].usernames); | ||||
|               } | ||||
|             }); | ||||
|         }, | ||||
|  | ||||
|         challenges: function (callback) { | ||||
|           Challenge.aggregate() | ||||
|             .group({_id: 1, names: { $addToSet: '$name'}}) | ||||
|             .exec(function (err, challenges) { | ||||
|               if (err) { | ||||
|                 debug('Challenge err: ', err); | ||||
|                 callback(err); | ||||
|               } else { | ||||
|                 callback(null, challenges[0].names); | ||||
|               } | ||||
|             }); | ||||
|         }, | ||||
|         stories: function (callback) { | ||||
|           Story.aggregate() | ||||
|             .group({_id: 1, links: {$addToSet: '$link'}}) | ||||
|           .exec(function (err, stories) { | ||||
|             if (err) { | ||||
|               debug('Story err: ', err); | ||||
|               callback(err); | ||||
|             } else { | ||||
|               callback(null, stories[0].links); | ||||
|             } | ||||
|           }); | ||||
|         }, | ||||
|         nonprofits: function (callback) { | ||||
|           Nonprofit.aggregate() | ||||
|             .group({_id: 1, names: { $addToSet: '$name'}}) | ||||
|             .exec(function (err, nonprofits) { | ||||
|             if (err) { | ||||
|               debug('User err: ', err); | ||||
|               callback(err); | ||||
|             } else { | ||||
|               callback(null, nonprofits[0].names); | ||||
|             } | ||||
|           }); | ||||
|         }, | ||||
|         fieldGuides: function (callback) { | ||||
|           FieldGuide.aggregate() | ||||
|             .group({_id: 1, names: { $addToSet: '$name'}}) | ||||
|             .exec(function (err, fieldGuides) { | ||||
|             if (err) { | ||||
|               debug('User err: ', err); | ||||
|               callback(err); | ||||
|             } else { | ||||
|               callback(null, fieldGuides[0].names); | ||||
|             } | ||||
|           }); | ||||
|         } | ||||
|       }, function (err, results) { | ||||
|         if (err) { | ||||
|           return next(err); | ||||
|         } else { | ||||
|           setTimeout(function() { | ||||
|             res.header('Content-Type', 'application/xml'); | ||||
|             res.render('resources/sitemap', { | ||||
|               appUrl: appUrl, | ||||
|               now: now, | ||||
|               users: results.users, | ||||
|               challenges: results.challenges, | ||||
|               stories: results.stories, | ||||
|               nonprofits: results.nonprofits, | ||||
|               fieldGuides: results.fieldGuides | ||||
|             }); | ||||
|           }, 0); | ||||
|         } | ||||
|       } | ||||
|     ); | ||||
|   }, | ||||
|  | ||||
|   chat: function chat(req, res) { | ||||
|     if (req.user && req.user.progressTimestamps.length > 5) { | ||||
|       res.redirect('http://freecode.slack.com'); | ||||
|     } else { | ||||
|       res.render('resources/chat', { | ||||
|         title: 'Watch us code live on Twitch.tv' | ||||
|       }); | ||||
|     } | ||||
|   }, | ||||
|  | ||||
|   jobsForm: function jobsForm(req, res) { | ||||
|     res.render('resources/jobs-form', { | ||||
|       title: 'Employer Partnership Form for Job Postings, Recruitment and Corporate Sponsorships' | ||||
|     }); | ||||
|   }, | ||||
|  | ||||
|   catPhotoSubmit: function catPhotoSubmit(req, res) { | ||||
|     res.send( | ||||
|       'Success! You have submitted your cat photo. Return to your website ' + | ||||
|       'by typing any letter into your code editor.' | ||||
|     ); | ||||
|   }, | ||||
|  | ||||
|   nonprofits: function nonprofits(req, res) { | ||||
|     res.render('resources/nonprofits', { | ||||
|       title: 'A guide to our Nonprofit Projects' | ||||
|     }); | ||||
|   }, | ||||
|  | ||||
|   nonprofitsForm: function nonprofitsForm(req, res) { | ||||
|     res.render('resources/nonprofits-form', { | ||||
|       title: 'Nonprofit Projects Proposal Form' | ||||
|     }); | ||||
|   }, | ||||
|  | ||||
|   agileProjectManagers: function agileProjectManagers(req, res) { | ||||
|     res.render('resources/pmi-acp-agile-project-managers', { | ||||
|       title: 'Get Agile Project Management Experience for the PMI-ACP' | ||||
|     }); | ||||
|   }, | ||||
|  | ||||
|   agileProjectManagersForm: function agileProjectManagersForm(req, res) { | ||||
|     res.render('resources/pmi-acp-agile-project-managers-form', { | ||||
|       title: 'Agile Project Management Program Application Form' | ||||
|     }); | ||||
|   }, | ||||
|  | ||||
|   twitch: function twitch(req, res) { | ||||
|     res.render('resources/twitch', { | ||||
|       title: "Enter Free Code Camp's Chat Rooms" | ||||
|     }); | ||||
|   }, | ||||
|  | ||||
|   unsubscribe: function unsubscribe(req, res, next) { | ||||
|     User.findOne({ email: req.params.email }, function(err, user) { | ||||
|       if (user) { | ||||
|         if (err) { | ||||
|           return next(err); | ||||
|         } | ||||
|         user.sendMonthlyEmail = false; | ||||
|         user.save(function () { | ||||
|           if (err) { | ||||
|             return next(err); | ||||
|           } | ||||
|           res.redirect('/unsubscribed'); | ||||
|         }); | ||||
|       } else { | ||||
|         res.redirect('/unsubscribed'); | ||||
|       } | ||||
|     }); | ||||
|   }, | ||||
|  | ||||
|   unsubscribed: function unsubscribed(req, res) { | ||||
|     res.render('resources/unsubscribed', { | ||||
|       title: 'You have been unsubscribed' | ||||
|     }); | ||||
|   }, | ||||
|  | ||||
|   githubCalls: function(req, res, next) { | ||||
|     var githubHeaders = { | ||||
|       headers: { | ||||
|         'User-Agent': constantStrings.gitHubUserAgent | ||||
|       }, | ||||
|       port: 80 | ||||
|     }; | ||||
|     request( | ||||
|       [ | ||||
|         'https://api.github.com/repos/freecodecamp/', | ||||
|         'freecodecamp/pulls?client_id=', | ||||
|         secrets.github.clientID, | ||||
|         '&client_secret=', | ||||
|         secrets.github.clientSecret | ||||
|       ].join(''), | ||||
|       githubHeaders, | ||||
|       function(err, status1, pulls) { | ||||
|         if (err) { return next(err); } | ||||
|         pulls = pulls ? | ||||
|           Object.keys(JSON.parse(pulls)).length : | ||||
|           "Can't connect to github"; | ||||
|  | ||||
|         request( | ||||
|           [ | ||||
|             'https://api.github.com/repos/freecodecamp/', | ||||
|             'freecodecamp/issues?client_id=', | ||||
|             secrets.github.clientID, | ||||
|             '&client_secret=', | ||||
|             secrets.github.clientSecret | ||||
|           ].join(''), | ||||
|           githubHeaders, | ||||
|           function (err, status2, issues) { | ||||
|             if (err) { return next(err); } | ||||
|             issues = ((pulls === parseInt(pulls, 10)) && issues) ? | ||||
|               Object.keys(JSON.parse(issues)).length - pulls : | ||||
|               "Can't connect to GitHub"; | ||||
|             res.send({ | ||||
|               issues: issues, | ||||
|               pulls: pulls | ||||
|             }); | ||||
|           } | ||||
|         ); | ||||
|       } | ||||
|     ); | ||||
|   }, | ||||
|  | ||||
|   trelloCalls: function(req, res, next) { | ||||
|     request( | ||||
|       'https://trello.com/1/boards/BA3xVpz9/cards?key=' + | ||||
|       secrets.trello.key, | ||||
|       function(err, status, trello) { | ||||
|         if (err) { return next(err); } | ||||
|         trello = (status && status.statusCode === 200) ? | ||||
|           (JSON.parse(trello)) : | ||||
|           "Can't connect to to Trello"; | ||||
|  | ||||
|         res.end(JSON.stringify(trello)); | ||||
|       }); | ||||
|   }, | ||||
|  | ||||
|   bloggerCalls: function(req, res, next) { | ||||
|     request( | ||||
|       'https://www.googleapis.com/blogger/v3/blogs/2421288658305323950/' + | ||||
|       'posts?key=' + | ||||
|         secrets.blogger.key, | ||||
|       function (err, status, blog) { | ||||
|         if (err) { return next(err); } | ||||
|  | ||||
|         blog = (status && status.statusCode === 200) ? | ||||
|           JSON.parse(blog) : | ||||
|           "Can't connect to Blogger"; | ||||
|         res.end(JSON.stringify(blog)); | ||||
|       } | ||||
|     ); | ||||
|   }, | ||||
|  | ||||
|   about: function(req, res, next) { | ||||
|     if (req.user) { | ||||
|       if ( | ||||
|         !req.user.profile.picture || | ||||
|         req.user.profile.picture.indexOf('apple-touch-icon-180x180.png') !== -1 | ||||
|       ) { | ||||
|         req.user.profile.picture = | ||||
|           'https://s3.amazonaws.com/freecodecamp/camper-image-placeholder.png'; | ||||
|         // TODO(berks): unhandled callback | ||||
|         req.user.save(); | ||||
|       } | ||||
|     } | ||||
|     var date1 = new Date('10/15/2014'); | ||||
|     var date2 = new Date(); | ||||
|  | ||||
|     var timeDiff = Math.abs(date2.getTime() - date1.getTime()); | ||||
|     var daysRunning = Math.ceil(timeDiff / (1000 * 3600 * 24)); | ||||
|     var announcements = resources.announcements; | ||||
|     function numberWithCommas(x) { | ||||
|       return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ','); | ||||
|     } | ||||
|     User.count({}, function (err, c3) { | ||||
|       if (err) { | ||||
|         debug('User err: ', err); | ||||
|         return next(err); | ||||
|       } | ||||
|  | ||||
|       res.render('resources/learn-to-code', { | ||||
|         title: 'About Free Code Camp', | ||||
|         daysRunning: daysRunning, | ||||
|         c3: numberWithCommas(c3), | ||||
|         announcements: announcements | ||||
|       }); | ||||
|     }); | ||||
|   }, | ||||
|  | ||||
|   randomPhrase: function() { | ||||
|     return resources.phrases[ | ||||
|       Math.floor(Math.random() * resources.phrases.length) | ||||
|     ]; | ||||
|   }, | ||||
|  | ||||
|   randomVerb: function() { | ||||
|     return resources.verbs[ | ||||
|       Math.floor(Math.random() * resources.verbs.length) | ||||
|     ]; | ||||
|   }, | ||||
|  | ||||
|   randomCompliment: function() { | ||||
|     return resources.compliments[ | ||||
|       Math.floor(Math.random() * resources.compliments.length) | ||||
|     ]; | ||||
|   }, | ||||
|  | ||||
|   allFieldGuideIds: function() { | ||||
|     if (allFieldGuideIds) { | ||||
|       return allFieldGuideIds; | ||||
|     } else { | ||||
|       allFieldGuideIds = fieldGuides.map(function (elem) { | ||||
|         return elem._id; | ||||
|       }); | ||||
|       return allFieldGuideIds; | ||||
|     } | ||||
|   }, | ||||
|  | ||||
|   allFieldGuideNamesAndIds: function() { | ||||
|     if (allFieldGuideNames) { | ||||
|       return allFieldGuideNames; | ||||
|     } else { | ||||
|       allFieldGuideNames = fieldGuides.map(function (elem) { | ||||
|         return { | ||||
|           name: elem.name, | ||||
|           dashedName: elem.dashedName, | ||||
|           id: elem._id }; | ||||
|       }); | ||||
|       return allFieldGuideNames; | ||||
|     } | ||||
|   }, | ||||
|  | ||||
|   allNonprofitNames: function() { | ||||
|     if (allNonprofitNames) { | ||||
|       return allNonprofitNames; | ||||
|     } else { | ||||
|       allNonprofitNames = nonprofits.map(function (elem) { | ||||
|         return { name: elem.name }; | ||||
|       }); | ||||
|       return allNonprofitNames; | ||||
|     } | ||||
|   }, | ||||
|  | ||||
|   whichEnvironment: function() { | ||||
|     return process.env.NODE_ENV; | ||||
|   }, | ||||
|  | ||||
|   getURLTitle: function(url, callback) { | ||||
|     (function () { | ||||
|       var result = {title: '', image: '', url: '', description: ''}; | ||||
|       request(url, function (error, response, body) { | ||||
|         if (!error && response.statusCode === 200) { | ||||
|           var $ = cheerio.load(body); | ||||
|           var metaDescription = $("meta[name='description']"); | ||||
|           var metaImage = $("meta[property='og:image']"); | ||||
|           var urlImage = metaImage.attr('content') ? | ||||
|             metaImage.attr('content') : | ||||
|             ''; | ||||
|  | ||||
|           var metaTitle = $('title'); | ||||
|           var description = metaDescription.attr('content') ? | ||||
|             metaDescription.attr('content') : | ||||
|             ''; | ||||
|  | ||||
|           result.title = metaTitle.text().length < 90 ? | ||||
|             metaTitle.text() : | ||||
|             metaTitle.text().slice(0, 87) + '...'; | ||||
|  | ||||
|           result.image = urlImage; | ||||
|           result.description = description; | ||||
|           callback(null, result); | ||||
|         } else { | ||||
|           callback(new Error('failed')); | ||||
|         } | ||||
|       }); | ||||
|     })(); | ||||
|   }, | ||||
|  | ||||
|   updateUserStoryPictures: function(userId, picture, username, cb) { | ||||
|  | ||||
|     var counter = 0, | ||||
|       foundStories, | ||||
|       foundComments; | ||||
|  | ||||
|     Story.find({'author.userId': userId}, function(err, stories) { | ||||
|       if (err) { | ||||
|         return cb(err); | ||||
|       } | ||||
|       foundStories = stories; | ||||
|       counter++; | ||||
|       saveStoriesAndComments(); | ||||
|     }); | ||||
|     Comment.find({'author.userId': userId}, function(err, comments) { | ||||
|       if (err) { | ||||
|         return cb(err); | ||||
|       } | ||||
|       foundComments = comments; | ||||
|       counter++; | ||||
|       saveStoriesAndComments(); | ||||
|     }); | ||||
|  | ||||
|     function saveStoriesAndComments() { | ||||
|       if (counter !== 2) { | ||||
|         return; | ||||
|       } | ||||
|       var tasks = []; | ||||
|       R.forEach(function(comment) { | ||||
|         comment.author.picture = picture; | ||||
|         comment.author.username = username; | ||||
|         comment.markModified('author'); | ||||
|         tasks.push(function(cb) { | ||||
|           comment.save(cb); | ||||
|         }); | ||||
|       }, foundComments); | ||||
|  | ||||
|       R.forEach(function(story) { | ||||
|         story.author.picture = picture; | ||||
|         story.author.username = username; | ||||
|         story.markModified('author'); | ||||
|         tasks.push(function(cb) { | ||||
|           story.save(cb); | ||||
|         }); | ||||
|       }, foundStories); | ||||
|       async.parallel(tasks, function(err) { | ||||
|         if (err) { | ||||
|           return cb(err); | ||||
|         } | ||||
|         cb(); | ||||
|       }); | ||||
|     } | ||||
|   }, | ||||
|   codepenResources: { | ||||
|     twitter: function(req, res, next) { | ||||
|       // sends out random tweets about javascript | ||||
|       var T = new Twit({ | ||||
|         'consumer_key': secrets.twitter.consumerKey, | ||||
|         'consumer_secret': secrets.twitter.consumerSecret, | ||||
|         'access_token': secrets.twitter.token, | ||||
|         'access_token_secret': secrets.twitter.tokenSecret | ||||
|       }); | ||||
|  | ||||
|       var screenName; | ||||
|       if (req.params.screenName) { | ||||
|         screenName = req.params.screenName; | ||||
|       } else { | ||||
|         screenName = 'freecodecamp'; | ||||
|       } | ||||
|  | ||||
|       T.get( | ||||
|         'statuses/user_timeline', | ||||
|         { | ||||
|           'screen_name': screenName, | ||||
|           count: 10 | ||||
|         }, | ||||
|         function(err, data) { | ||||
|           if (err) { return next(err); } | ||||
|           return res.json(data); | ||||
|         } | ||||
|       ); | ||||
|     }, | ||||
|     twitterFCCStream: function() { | ||||
|       // sends out a tweet stream from FCC's account | ||||
|     }, | ||||
|     twitch: function() { | ||||
|       // exports information from the twitch account | ||||
|     }, | ||||
|     slack: function() { | ||||
|  | ||||
|     } | ||||
|   }, | ||||
|  | ||||
|   getHelp: function(req, res, next) { | ||||
|     var userName = req.user.profile.username; | ||||
|     var code = req.body.payload.code ? '\n```\n' + | ||||
|       req.body.payload.code + '\n```\n' | ||||
|       : ''; | ||||
|     var challenge = req.body.payload.challenge; | ||||
|  | ||||
|     slack.send({ | ||||
|       text: "*@" + userName + "* wants help with " + challenge + ". " + | ||||
|         code +  "Hey, *@" + userName + "*, if no one helps you right " + | ||||
|         "away, try typing out your problem in detail to me. Like this: " + | ||||
|         "http://en.wikipedia.org/wiki/Rubber_duck_debugging", | ||||
|       channel: '#help', | ||||
|       username: "Debuggy the Rubber Duck", | ||||
|       icon_url: "https://pbs.twimg.com/profile_images/3609875545/569237541c920fa78d78902069615caf.jpeg" | ||||
|     }); | ||||
|     return res.sendStatus(200); | ||||
|   }, | ||||
|  | ||||
|   getPair: function(req, res, next) { | ||||
|     var userName = req.user.profile.username; | ||||
|     var challenge = req.body.payload.challenge; | ||||
|     slack.send({ | ||||
|       text: "Anyone want to pair with *@" + userName + "* on " + challenge + | ||||
|       "?\nMake sure you install Screen Hero here: " + | ||||
|       "http://freecodecamp.com/field-guide/how-do-i-install-screenhero\n" + | ||||
|       "Then start your pair program session with *@" + userName + | ||||
|       "* by typing \"/hero @" + userName + "\" into Slack.\n And *@"+ userName + | ||||
|       "*, be sure to launch Screen Hero, then keep coding. " + | ||||
|       "Another camper may pair with you soon.", | ||||
|       channel: '#letspair', | ||||
|       username: "Companion Cube", | ||||
|       icon_url: "https://lh3.googleusercontent.com/-f6xDPDV2rPE/AAAAAAAAAAI/AAAAAAAAAAA/mdlESXQu11Q/photo.jpg" | ||||
|     }); | ||||
|     return res.sendStatus(200); | ||||
|   } | ||||
| }; | ||||
| @@ -9,7 +9,7 @@ var gulp = require('gulp'), | ||||
|     eslint = require('gulp-eslint'); | ||||
|  | ||||
| var paths = { | ||||
|     server: './app.js', | ||||
|     server: './server.js', | ||||
|     serverIgnore: [] | ||||
| }; | ||||
|  | ||||
|   | ||||
| @@ -31,10 +31,10 @@ | ||||
|  */ | ||||
| 
 | ||||
| var R = require('ramda'), | ||||
|     Challenge = require('./../models/Challenge'), | ||||
|     User = require('./../models/User'), | ||||
|     resources = require('./resources'), | ||||
|     MDNlinks = require('./../seed_data/bonfireMDNlinks'); | ||||
|     Challenge = require('./../../models/Challenge'), | ||||
|     User = require('./../../models/User'), | ||||
|     resources = require('./../resources/resources'), | ||||
|     MDNlinks = require('./../../seed_data/bonfireMDNlinks'); | ||||
| 
 | ||||
| var challengeMapWithNames = resources.getChallengeMapWithNames(); | ||||
| var challengeMapWithIds = resources.getChallengeMapWithIds(); | ||||
							
								
								
									
										63
									
								
								server/boot/challengeMap.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								server/boot/challengeMap.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,63 @@ | ||||
| var R = require('ramda'), | ||||
|   debug = require('debug')('freecc:cntr:challengeMap'), //eslint-disable-line | ||||
|   User = require('../../models/User'), | ||||
|   resources = require('./../resources/resources'), | ||||
|   middleware = require('../resources/middleware'), | ||||
|   express = require('express'), | ||||
|   router = express.Router(); | ||||
|  | ||||
| router.get('/map', | ||||
|   middleware.userMigration, | ||||
|   challengeMap | ||||
| ); | ||||
|  | ||||
| router.get('/learn-to-code', function(req, res) { | ||||
|   res.redirect(301, '/map'); | ||||
| }); | ||||
|  | ||||
| router.get('/about', function(req, res) { | ||||
|   res.redirect(301, '/map'); | ||||
| }); | ||||
|  | ||||
|  | ||||
|  | ||||
| function challengeMap(req, res, next) { | ||||
|   var completedList = []; | ||||
|  | ||||
|   if (req.user) { | ||||
|     completedList = req.user.completedChallenges; | ||||
|   } | ||||
|  | ||||
|   var noDuplicatedChallenges = R.uniq(completedList); | ||||
|  | ||||
|   var completedChallengeList = noDuplicatedChallenges | ||||
|     .map(function(challenge) { | ||||
|       return challenge._id; | ||||
|     }); | ||||
|   var challengeList = resources. | ||||
|     getChallengeMapForDisplay(completedChallengeList); | ||||
|  | ||||
|   function numberWithCommas(x) { | ||||
|     return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ','); | ||||
|   } | ||||
|  | ||||
|   var date1 = new Date('10/15/2014'); | ||||
|   var date2 = new Date(); | ||||
|   var timeDiff = Math.abs(date2.getTime() - date1.getTime()); | ||||
|   var daysRunning = Math.ceil(timeDiff / (1000 * 3600 * 24)); | ||||
|  | ||||
|   User.count({}, function (err, camperCount) { | ||||
|     if (err) { | ||||
|       return next(err); | ||||
|     } | ||||
|     res.render('challengeMap/show', { | ||||
|       daysRunning: daysRunning, | ||||
|       camperCount: numberWithCommas(camperCount), | ||||
|       title: "A map of all Free Code Camp's Challenges", | ||||
|       challengeList: challengeList, | ||||
|       completedChallengeList: completedChallengeList | ||||
|     }); | ||||
|   }); | ||||
| } | ||||
|  | ||||
| module.exports = router; | ||||
| @@ -1,6 +1,6 @@ | ||||
| var R = require('ramda'), | ||||
|     FieldGuide = require('./../models/FieldGuide'), | ||||
|     resources = require('./resources'), | ||||
|     FieldGuide = require('./../../models/FieldGuide'), | ||||
|     resources = require('./../resources/resources'), | ||||
|     debug = require('debug')('freecc:fieldguides'); | ||||
| 
 | ||||
| exports.returnIndividualFieldGuide = function(req, res, next) { | ||||
| @@ -1,7 +1,13 @@ | ||||
| var message = | ||||
|   'Learn to Code JavaScript and get a Coding Job by Helping Nonprofits'; | ||||
| var express = require('express'); | ||||
| var router = express.Router(); | ||||
| 
 | ||||
| exports.index = function(req, res, next) { | ||||
| router.get('/', index); | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| function index(req, res, next) { | ||||
|   if (req.user && !req.user.profile.picture) { | ||||
|     req.user.profile.picture = | ||||
|       'https://s3.amazonaws.com/freecodecamp/camper-image-placeholder.png'; | ||||
| @@ -13,4 +19,6 @@ exports.index = function(req, res, next) { | ||||
|   } else { | ||||
|     res.render('home', { title: message }); | ||||
|   } | ||||
| }; | ||||
| } | ||||
| 
 | ||||
| module.exports = router; | ||||
| @@ -1,6 +1,6 @@ | ||||
| var moment = require('moment'), | ||||
|   Job = require('./../models/Job'), | ||||
|   resources = require('./resources'); | ||||
|   Job = require('./../../models/Job'), | ||||
|   resources = require('./../resources/resources'); | ||||
| 
 | ||||
| exports.jobsDirectory = function(req, res, next) { | ||||
|   Job.find({}, function(err, jobs) { | ||||
| @@ -1,6 +1,6 @@ | ||||
| var moment = require('moment'), | ||||
|     Nonprofit = require('./../models/Nonprofit'), | ||||
|     resources = require('./resources'); | ||||
|     Nonprofit = require('./../../models/Nonprofit'), | ||||
|     resources = require('./../resources/resources'); | ||||
| 
 | ||||
| exports.nonprofitsDirectory = function(req, res, next) { | ||||
|   Nonprofit.find({estimatedHours: { $gt: 0 } }, function(err, nonprofits) { | ||||
							
								
								
									
										45
									
								
								server/boot/redirects.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								server/boot/redirects.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,45 @@ | ||||
| var express = require('express'); | ||||
| var router = express.Router(); | ||||
|  | ||||
|  | ||||
| router.get('/nonprofit-project-instructions', function(req, res) { | ||||
|   res.redirect(301, '/field-guide/how-do-free-code-camp\'s-nonprofit-projects-work'); | ||||
| }); | ||||
|  | ||||
| router.get('/agile', function(req, res) { | ||||
|   res.redirect(301, '/pmi-acp-agile-project-managers'); | ||||
| }); | ||||
|  | ||||
| router.get('/live-pair-programming', function(req, res) { | ||||
|   res.redirect(301, '/field-guide/live-stream-pair-programming-on-twitch.tv'); | ||||
| }); | ||||
|  | ||||
| router.get('/install-screenhero', function(req, res) { | ||||
|   res.redirect(301, '/field-guide/install-screenhero'); | ||||
| }); | ||||
|  | ||||
| router.get('/guide-to-our-nonprofit-projects', function(req, res) { | ||||
|   res.redirect(301, '/field-guide/a-guide-to-our-nonprofit-projects'); | ||||
| }); | ||||
|  | ||||
| router.get('/chromebook', function(req, res) { | ||||
|   res.redirect(301, '/field-guide/chromebook'); | ||||
| }); | ||||
|  | ||||
| router.get('/deploy-a-website', function(req, res) { | ||||
|   res.redirect(301, '/field-guide/deploy-a-website'); | ||||
| }); | ||||
|  | ||||
| router.get('/gmail-shortcuts', function(req, res) { | ||||
|   res.redirect(301, '/field-guide/gmail-shortcuts'); | ||||
| }); | ||||
|  | ||||
| router.get('/nodeschool-challenges', function(req, res) { | ||||
|   res.redirect(301, '/field-guide/nodeschool-challenges'); | ||||
| }); | ||||
|  | ||||
| router.get('/privacy', function(req, res) { | ||||
|   res.redirect(301, '/field-guide/what-is-the-free-code-camp-privacy-policy?'); | ||||
| }); | ||||
|  | ||||
| module.exports = router; | ||||
| @@ -1,16 +1,33 @@ | ||||
| /* eslint-disable no-catch-shadow, no-unused-vars */ | ||||
| var R = require('ramda'), | ||||
|   debug = require('debug')('freecc:cntr:story'), | ||||
|   Story = require('./../models/Story'), | ||||
|   Comment = require('./../models/Comment'), | ||||
|   User = require('./../models/User'), | ||||
|   Story = require('./../../models/Story'), | ||||
|   Comment = require('./../../models/Comment'), | ||||
|   User = require('./../../models/User'), | ||||
|   moment = require('moment'), | ||||
|   resources = require('./resources'), | ||||
|   resources = require('./../resources/resources'), | ||||
|   mongodb = require('mongodb'), | ||||
|   MongoClient = mongodb.MongoClient, | ||||
|   secrets = require('../config/secrets'), | ||||
|   secrets = require('../../config/secrets'), | ||||
|   nodemailer = require('nodemailer'), | ||||
|   sanitizeHtml = require('sanitize-html'); | ||||
|   sanitizeHtml = require('sanitize-html'), | ||||
|   express = require('express'), | ||||
|   router = express.Router(); | ||||
| 
 | ||||
| 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) { | ||||
|   /* | ||||
| @@ -27,7 +44,7 @@ function hotRank(timeValue, rank) { | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| exports.hotJSON = function(req, res, next) { | ||||
| function hotJSON(req, res, next) { | ||||
|   var story = Story.find({}).sort({'timePosted': -1}).limit(1000); | ||||
|   story.exec(function(err, stories) { | ||||
|     if (err) { | ||||
| @@ -45,9 +62,9 @@ exports.hotJSON = function(req, res, next) { | ||||
|     }).slice(0, sliceVal)); | ||||
| 
 | ||||
|   }); | ||||
| }; | ||||
| } | ||||
| 
 | ||||
| exports.recentJSON = function(req, res, next) { | ||||
| function recentJSON(req, res, next) { | ||||
|   var story = Story.find({}).sort({'timePosted': -1}).limit(100); | ||||
|   story.exec(function(err, stories) { | ||||
|     if (err) { | ||||
| @@ -55,37 +72,37 @@ exports.recentJSON = function(req, res, next) { | ||||
|     } | ||||
|     return res.json(stories); | ||||
|   }); | ||||
| }; | ||||
| } | ||||
| 
 | ||||
| exports.hot = function(req, res) { | ||||
| function hot(req, res) { | ||||
|   return res.render('stories/index', { | ||||
|     title: 'Hot stories currently trending on Camper News', | ||||
|     page: 'hot' | ||||
|   }); | ||||
| }; | ||||
| } | ||||
| 
 | ||||
| exports.submitNew = function(req, res) { | ||||
| function submitNew(req, res) { | ||||
|   return res.render('stories/index', { | ||||
|     title: 'Submit a new story to Camper News', | ||||
|     page: 'submit' | ||||
|   }); | ||||
| }; | ||||
| } | ||||
| 
 | ||||
| exports.search = function(req, res) { | ||||
| function search(req, res) { | ||||
|   return res.render('stories/index', { | ||||
|     title: 'Search the archives of Camper News', | ||||
|     page: 'search' | ||||
|   }); | ||||
| }; | ||||
| } | ||||
| 
 | ||||
| exports.recent = function(req, res) { | ||||
| function recent(req, res) { | ||||
|   return res.render('stories/index', { | ||||
|     title: 'Recently submitted stories on Camper News', | ||||
|     page: 'recent' | ||||
|   }); | ||||
| }; | ||||
| } | ||||
| 
 | ||||
| exports.preSubmit = function(req, res) { | ||||
| function preSubmit(req, res) { | ||||
| 
 | ||||
|   var data = req.query; | ||||
|   var cleanData = sanitizeHtml(data.url, { | ||||
| @@ -113,10 +130,10 @@ exports.preSubmit = function(req, res) { | ||||
|     storyImage: image, | ||||
|     storyMetaDescription: description | ||||
|   }); | ||||
| }; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| exports.returnIndividualStory = function(req, res, next) { | ||||
| function returnIndividualStory(req, res, next) { | ||||
|   var dashedName = req.params.storyName; | ||||
| 
 | ||||
|   var storyName = dashedName.replace(/\-/g, ' ').trim(); | ||||
| @@ -173,9 +190,9 @@ exports.returnIndividualStory = function(req, res, next) { | ||||
|       hasUserVoted: userVoted | ||||
|     }); | ||||
|   }); | ||||
| }; | ||||
| } | ||||
| 
 | ||||
| exports.getStories = function(req, res, next) { | ||||
| function getStories(req, res, next) { | ||||
|   MongoClient.connect(secrets.db, function(err, database) { | ||||
|     if (err) { | ||||
|       return next(err); | ||||
| @@ -215,9 +232,9 @@ exports.getStories = function(req, res, next) { | ||||
|       return res.sendStatus(404); | ||||
|     }); | ||||
|   }); | ||||
| }; | ||||
| } | ||||
| 
 | ||||
| exports.upvote = function(req, res, next) { | ||||
| function upvote(req, res, next) { | ||||
|   var data = req.body.data; | ||||
|   Story.find({'_id': data.id}, function(err, story) { | ||||
|     if (err) { | ||||
| @@ -252,9 +269,9 @@ exports.upvote = function(req, res, next) { | ||||
|     }); | ||||
|     return res.send(story); | ||||
|   }); | ||||
| }; | ||||
| } | ||||
| 
 | ||||
| exports.comments = function(req, res, next) { | ||||
| function comments(req, res, next) { | ||||
|   var data = req.params.id; | ||||
|   Comment.find({'_id': data}, function(err, comment) { | ||||
|     if (err) { | ||||
| @@ -263,9 +280,9 @@ exports.comments = function(req, res, next) { | ||||
|     comment = comment.pop(); | ||||
|     return res.send(comment); | ||||
|   }); | ||||
| }; | ||||
| } | ||||
| 
 | ||||
| exports.newStory = function(req, res, next) { | ||||
| function newStory(req, res, next) { | ||||
|   if (!req.user) { | ||||
|     return next(new Error('Must be logged in')); | ||||
|   } | ||||
| @@ -322,9 +339,9 @@ exports.newStory = function(req, res, next) { | ||||
|       }); | ||||
|     } | ||||
|   } | ||||
| }; | ||||
| } | ||||
| 
 | ||||
| exports.storySubmission = function(req, res, next) { | ||||
| function storySubmission(req, res, next) { | ||||
|   var data = req.body.data; | ||||
|   if (!req.user) { | ||||
|     return next(new Error('Not authorized')); | ||||
| @@ -393,9 +410,9 @@ exports.storySubmission = function(req, res, next) { | ||||
|       })); | ||||
|     }); | ||||
|   }); | ||||
| }; | ||||
| } | ||||
| 
 | ||||
|   exports.commentSubmit = function(req, res, next) { | ||||
| function commentSubmit(req, res, next) { | ||||
|   var data = req.body.data; | ||||
|   if (!req.user) { | ||||
|     return next(new Error('Not authorized')); | ||||
| @@ -430,9 +447,9 @@ exports.storySubmission = function(req, res, next) { | ||||
|   }); | ||||
| 
 | ||||
|   commentSave(comment, Story, res, next); | ||||
|   }; | ||||
| } | ||||
| 
 | ||||
|   exports.commentOnCommentSubmit = function(req, res, next) { | ||||
| function commentOnCommentSubmit(req, res, next) { | ||||
|   var data = req.body.data; | ||||
|   if (!req.user) { | ||||
|     return next(new Error('Not authorized')); | ||||
| @@ -467,9 +484,9 @@ exports.storySubmission = function(req, res, next) { | ||||
|     commentOn: Date.now() | ||||
|   }); | ||||
|   commentSave(comment, Comment, res, next); | ||||
|   }; | ||||
| } | ||||
| 
 | ||||
|   exports.commentEdit = function(req, res, next) { | ||||
| function commentEdit(req, res, next) { | ||||
| 
 | ||||
|   Comment.find({'_id': req.params.id}, function(err, cmt) { | ||||
|     if (err) { | ||||
| @@ -504,9 +521,9 @@ exports.storySubmission = function(req, res, next) { | ||||
| 
 | ||||
|   }); | ||||
| 
 | ||||
|   }; | ||||
| } | ||||
| 
 | ||||
|   function commentSave(comment, Context, res, next) { | ||||
| function commentSave(comment, Context, res, next) { | ||||
|   comment.save(function(err, data) { | ||||
|     if (err) { | ||||
|       return next(err); | ||||
| @@ -574,8 +591,9 @@ exports.storySubmission = function(req, res, next) { | ||||
|         }); | ||||
|       }); | ||||
|     } catch (e) { | ||||
|         // delete comment
 | ||||
|       return next(err); | ||||
|     } | ||||
|   }); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| module.exports = router; | ||||
| @@ -3,68 +3,62 @@ var _ = require('lodash'), | ||||
|   crypto = require('crypto'), | ||||
|   nodemailer = require('nodemailer'), | ||||
|   passport = require('passport'), | ||||
|   User = require('../models/User'), | ||||
|   secrets = require('../config/secrets'), | ||||
|   User = require('../../models/User'), | ||||
|   secrets = require('../../config/secrets'), | ||||
|   moment = require('moment'), | ||||
|   debug = require('debug')('freecc:cntr:userController'), | ||||
|   resources = require('./resources'), | ||||
|   resources = require('./../resources/resources'), | ||||
|   R = require('ramda'); | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| /** | ||||
|  * | ||||
|  * @param req | ||||
|  * @param res | ||||
|  * @returns null | ||||
|  * Middleware to migrate users from fragmented challenge structure to unified | ||||
|  * challenge structure | ||||
|  */ | ||||
| exports.userMigration = function(req, res, next) { | ||||
|   if (req.user && req.user.completedChallenges.length === 0) { | ||||
|     req.user.completedChallenges = R.filter(function (elem) { | ||||
|       return elem; // getting rid of undefined
 | ||||
|     }, R.concat( | ||||
|       req.user.completedCoursewares, | ||||
|       req.user.completedBonfires.map(function (bonfire) { | ||||
|         return ({ | ||||
|           completedDate: bonfire.completedDate, | ||||
|           _id: bonfire._id, | ||||
|           name: bonfire.name, | ||||
|           completedWith: bonfire.completedWith, | ||||
|           solution: bonfire.solution, | ||||
|           githubLink: '', | ||||
|           verified: false, | ||||
|           challengeType: 5 | ||||
|         }); | ||||
|       }) | ||||
|     )); | ||||
|     next(); | ||||
|   } else { | ||||
|     next(); | ||||
|   } | ||||
| }; | ||||
| 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); | ||||
| router.get('/:username', returnUser); // Ensure this is the last route!
 | ||||
| 
 | ||||
| /** | ||||
|  * GET /signin | ||||
|  * Siginin page. | ||||
|  */ | ||||
| 
 | ||||
| exports.getSignin = function(req, res) { | ||||
| function getSignin (req, res) { | ||||
|   if (req.user) { | ||||
|     return res.redirect('/'); | ||||
|   } | ||||
|   res.render('account/signin', { | ||||
|     title: 'Free Code Camp Login' | ||||
|   }); | ||||
| }; | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * POST /signin | ||||
|  * Sign in using email and password. | ||||
|  */ | ||||
| 
 | ||||
| exports.postSignin = function(req, res, next) { | ||||
| function postSignin (req, res, next) { | ||||
|   req.assert('email', 'Email is not valid').isEmail(); | ||||
|   req.assert('password', 'Password cannot be blank').notEmpty(); | ||||
| 
 | ||||
| @@ -97,53 +91,52 @@ exports.postSignin = function(req, res, next) { | ||||
|       return res.redirect(req.session.returnTo || '/'); | ||||
|     }); | ||||
|   })(req, res, next); | ||||
| }; | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * GET /signout | ||||
|  * Log out. | ||||
|  */ | ||||
| 
 | ||||
| exports.signout = function(req, res) { | ||||
| function signout (req, res) { | ||||
|   req.logout(); | ||||
|   res.redirect('/'); | ||||
| }; | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * GET /email-signup | ||||
|  * Signup page. | ||||
|  */ | ||||
| 
 | ||||
| exports.getEmailSignin = function(req, res) //noinspection Eslint
 | ||||
| { | ||||
| function getEmailSignin (req, res) { | ||||
|   if (req.user) { | ||||
|     return res.redirect('/'); | ||||
|   } | ||||
|   res.render('account/email-signin', { | ||||
|     title: 'Sign in to your Free Code Camp Account' | ||||
|   }); | ||||
| }; | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * GET /signin | ||||
|  * Signup page. | ||||
|  */ | ||||
| 
 | ||||
| exports.getEmailSignup = function(req, res) { | ||||
| function getEmailSignup (req, res) { | ||||
|   if (req.user) { | ||||
|     return res.redirect('/'); | ||||
|   } | ||||
|   res.render('account/email-signup', { | ||||
|     title: 'Create Your Free Code Camp Account' | ||||
|   }); | ||||
| }; | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * POST /email-signup | ||||
|  * Create a new local account. | ||||
|  */ | ||||
| 
 | ||||
| exports.postEmailSignup = function(req, res, next) { | ||||
| function postEmailSignup (req, res, next) { | ||||
|   req.assert('email', 'valid email required').isEmail(); | ||||
|   var errors = req.validationErrors(); | ||||
| 
 | ||||
| @@ -237,34 +230,34 @@ exports.postEmailSignup = function(req, res, next) { | ||||
|       }); | ||||
|     }); | ||||
|   }); | ||||
| }; | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * GET /account | ||||
|  * Profile page. | ||||
|  */ | ||||
| 
 | ||||
| exports.getAccount = function(req, res) { | ||||
| function getAccount (req, res) { | ||||
|   res.render('account/account', { | ||||
|     title: 'Manage your Free Code Camp Account' | ||||
|   }); | ||||
| }; | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * Angular API Call | ||||
|  */ | ||||
| 
 | ||||
| exports.getAccountAngular = function(req, res) { | ||||
| function getAccountAngular (req, res) { | ||||
|   res.json({ | ||||
|     user: req.user | ||||
|   }); | ||||
| }; | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * Unique username check API Call | ||||
|  */ | ||||
| 
 | ||||
| exports.checkUniqueUsername = function(req, res, next) { | ||||
| function checkUniqueUsername (req, res, next) { | ||||
|   User.count( | ||||
|     { 'profile.username': req.params.username.toLowerCase() }, | ||||
|     function (err, data) { | ||||
| @@ -275,12 +268,12 @@ exports.checkUniqueUsername = function(req, res, next) { | ||||
|       return res.send(false); | ||||
|     } | ||||
|   }); | ||||
| }; | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * Existing username check | ||||
|  */ | ||||
| exports.checkExistingUsername = function(req, res, next) { | ||||
| function checkExistingUsername (req, res, next) { | ||||
|   User.count( | ||||
|     { 'profile.username': req.params.username.toLowerCase() }, | ||||
|     function (err, data) { | ||||
| @@ -292,13 +285,13 @@ exports.checkExistingUsername = function(req, res, next) { | ||||
|       } | ||||
|     } | ||||
|   ); | ||||
| }; | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * Unique email check API Call | ||||
|  */ | ||||
| 
 | ||||
| exports.checkUniqueEmail = function(req, res, next) { | ||||
| function checkUniqueEmail (req, res, next) { | ||||
|   User.count( | ||||
|     { email: decodeURIComponent(req.params.email).toLowerCase() }, | ||||
|     function (err, data) { | ||||
| @@ -310,7 +303,7 @@ exports.checkUniqueEmail = function(req, res, next) { | ||||
|       } | ||||
|     } | ||||
|   ); | ||||
| }; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /** | ||||
| @@ -318,7 +311,7 @@ exports.checkUniqueEmail = function(req, res, next) { | ||||
|  * Public Profile page. | ||||
|  */ | ||||
| 
 | ||||
| exports.returnUser = function(req, res, next) { | ||||
| function returnUser (req, res, next) { | ||||
|   User.find( | ||||
|     { 'profile.username': req.params.username.toLowerCase() }, | ||||
|     function(err, user) { | ||||
| @@ -445,37 +438,14 @@ exports.returnUser = function(req, res, next) { | ||||
|       } | ||||
|     } | ||||
|   ); | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| /** | ||||
|  * POST /update-progress | ||||
|  * Update profile information. | ||||
|  */ | ||||
| 
 | ||||
| exports.updateProgress = function(req, res, next) { | ||||
|   User.findById(req.user.id, function(err, user) { | ||||
|     if (err) { return next(err); } | ||||
|     user.email = req.body.email || ''; | ||||
|     user.profile.name = req.body.name || ''; | ||||
|     user.profile.gender = req.body.gender || ''; | ||||
|     user.profile.location = req.body.location || ''; | ||||
|     user.profile.website = req.body.website || ''; | ||||
| 
 | ||||
|     user.save(function(err) { | ||||
|       if (err) { return next(err); } | ||||
|       req.flash('success', { msg: 'Profile information updated.' }); | ||||
|       res.redirect('/account'); | ||||
|     }); | ||||
|   }); | ||||
| }; | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * POST /account/profile | ||||
|  * Update profile information. | ||||
|  */ | ||||
| 
 | ||||
| exports.postUpdateProfile = function(req, res, next) { | ||||
| function postUpdateProfile (req, res, next) { | ||||
| 
 | ||||
|   User.findById(req.user.id, function(err) { | ||||
|     if (err) { return next(err); } | ||||
| @@ -558,14 +528,14 @@ exports.postUpdateProfile = function(req, res, next) { | ||||
|       ); | ||||
|     }); | ||||
|   }); | ||||
| }; | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * POST /account/password | ||||
|  * Update current password. | ||||
|  */ | ||||
| 
 | ||||
| exports.postUpdatePassword = function(req, res, next) { | ||||
| function postUpdatePassword (req, res, next) { | ||||
|   req.assert('password', 'Password must be at least 4 characters long').len(4); | ||||
|   req.assert('confirmPassword', 'Passwords do not match') | ||||
|     .equals(req.body.password); | ||||
| @@ -589,28 +559,28 @@ exports.postUpdatePassword = function(req, res, next) { | ||||
|       res.redirect('/account'); | ||||
|     }); | ||||
|   }); | ||||
| }; | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * POST /account/delete | ||||
|  * Delete user account. | ||||
|  */ | ||||
| 
 | ||||
| exports.postDeleteAccount = function(req, res, next) { | ||||
| function postDeleteAccount (req, res, next) { | ||||
|   User.remove({ _id: req.user.id }, function(err) { | ||||
|     if (err) { return next(err); } | ||||
|     req.logout(); | ||||
|     req.flash('info', { msg: 'Your account has been deleted.' }); | ||||
|     res.redirect('/'); | ||||
|   }); | ||||
| }; | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * GET /account/unlink/:provider | ||||
|  * Unlink OAuth provider. | ||||
|  */ | ||||
| 
 | ||||
| exports.getOauthUnlink = function(req, res, next) { | ||||
| function getOauthUnlink (req, res, next) { | ||||
|   var provider = req.params.provider; | ||||
|   User.findById(req.user.id, function(err, user) { | ||||
|     if (err) { return next(err); } | ||||
| @@ -627,14 +597,14 @@ exports.getOauthUnlink = function(req, res, next) { | ||||
|       res.redirect('/account'); | ||||
|     }); | ||||
|   }); | ||||
| }; | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * GET /reset/:token | ||||
|  * Reset Password page. | ||||
|  */ | ||||
| 
 | ||||
| exports.getReset = function(req, res, next) { | ||||
| function getReset (req, res, next) { | ||||
|   if (req.isAuthenticated()) { | ||||
|     return res.redirect('/'); | ||||
|   } | ||||
| @@ -654,14 +624,14 @@ exports.getReset = function(req, res, next) { | ||||
|         token: req.params.token | ||||
|       }); | ||||
|     }); | ||||
| }; | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * POST /reset/:token | ||||
|  * Process the reset password request. | ||||
|  */ | ||||
| 
 | ||||
| exports.postReset = function(req, res, next) { | ||||
| function postReset (req, res, next) { | ||||
|   var errors = req.validationErrors(); | ||||
| 
 | ||||
|   if (errors) { | ||||
| @@ -728,28 +698,28 @@ exports.postReset = function(req, res, next) { | ||||
|     if (err) { return next(err); } | ||||
|     res.redirect('/'); | ||||
|   }); | ||||
| }; | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * GET /forgot | ||||
|  * Forgot Password page. | ||||
|  */ | ||||
| 
 | ||||
| exports.getForgot = function(req, res) { | ||||
| function getForgot (req, res) { | ||||
|   if (req.isAuthenticated()) { | ||||
|     return res.redirect('/'); | ||||
|   } | ||||
|   res.render('account/forgot', { | ||||
|     title: 'Forgot Password' | ||||
|   }); | ||||
| }; | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * POST /forgot | ||||
|  * Create a random token, then the send user an email with a reset link. | ||||
|  */ | ||||
| 
 | ||||
| exports.postForgot = function(req, res, next) { | ||||
| function postForgot (req, res, next) { | ||||
|   var errors = req.validationErrors(); | ||||
| 
 | ||||
|   if (errors) { | ||||
| @@ -826,4 +796,6 @@ exports.postForgot = function(req, res, next) { | ||||
|     if (err) { return next(err); } | ||||
|     res.redirect('/forgot'); | ||||
|   }); | ||||
| }; | ||||
| } | ||||
| 
 | ||||
| module.exports = router; | ||||
							
								
								
									
										435
									
								
								server/boot/utility.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										435
									
								
								server/boot/utility.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,435 @@ | ||||
| var express = require('express'), | ||||
|   async = require('async'), | ||||
|   moment = require('moment'), | ||||
|   Twit = require('twit'), | ||||
|   debug = require('debug')('freecc:cntr:resources'), | ||||
|   request = require('request'), | ||||
|   constantStrings = require('./constantStrings.json'), | ||||
|   User = require('../../models/User'), | ||||
|   Challenge = require('./../../models/Challenge'), | ||||
|   Story = require('./../../models/Story'), | ||||
|   FieldGuide = require('./../../models/FieldGuide'), | ||||
|   Nonprofit = require('./../../models/Nonprofit'), | ||||
|   secrets = require('./../../config/secrets'), | ||||
|   Slack = require('node-slack'), | ||||
|   slack = new Slack(secrets.slackHook); | ||||
| router = express.Router(); | ||||
|  | ||||
| router.get('/api/github', githubCalls); | ||||
| router.get('/api/blogger', bloggerCalls); | ||||
| router.get('/api/trello', trelloCalls); | ||||
| router.get('/api/codepen/twitter/:screenName', twitter); | ||||
| router.get('/sitemap.xml', sitemap); | ||||
| router.post('/get-help', getHelp); | ||||
| router.post('/get-pair', getPair); | ||||
| router.get('/chat', chat); | ||||
| router.get('/twitch', twitch); | ||||
| router.get('/pmi-acp-agile-project-managers', agileProjectManagers); | ||||
| router.get('/pmi-acp-agile-project-managers-form', agileProjectManagersForm); | ||||
| router.get('/nonprofits', nonprofits); | ||||
| router.get('/nonprofits-form', nonprofitsForm); | ||||
| router.get('/jobs-form', jobsForm); | ||||
| router.get('/submit-cat-photo', catPhotoSubmit); | ||||
| router.get('/unsubscribe/:email', unsubscribe); | ||||
| router.get('/unsubscribed', unsubscribed); | ||||
| router.get('/cats.json', getCats); | ||||
|  | ||||
| router.get('/api/slack', slackInvite); | ||||
|  | ||||
| function slackInvite(req, res, next) { | ||||
|   if (req.user) { | ||||
|     if (req.user.email) { | ||||
|       var invite = { | ||||
|         'email': req.user.email, | ||||
|         'token': process.env.SLACK_KEY, | ||||
|         'set_active': true | ||||
|       }; | ||||
|  | ||||
|       var headers = { | ||||
|         'User-Agent': 'Node Browser/0.0.1', | ||||
|         'Content-Type': 'application/x-www-form-urlencoded' | ||||
|       }; | ||||
|  | ||||
|       var options = { | ||||
|         url: 'https://freecode.slack.com/api/users.admin.invite', | ||||
|         method: 'POST', | ||||
|         headers: headers, | ||||
|         form: invite | ||||
|       }; | ||||
|  | ||||
|       request(options, function (error, response) { | ||||
|         if (!error && response.statusCode === 200) { | ||||
|           req.flash('success', { | ||||
|             msg: 'We\'ve successfully requested an invite for you.' + | ||||
|               ' Please check your email and follow the instructions from Slack.' | ||||
|           }); | ||||
|           req.user.sentSlackInvite = true; | ||||
|           req.user.save(function(err) { | ||||
|             if (err) { | ||||
|               return next(err); | ||||
|             } | ||||
|             return res.redirect('back'); | ||||
|           }); | ||||
|         } else { | ||||
|           req.flash('errors', { | ||||
|             msg: 'The invitation email did not go through for some reason.' + | ||||
|               ' Please try again or <a href=\'mailto:team@' + | ||||
|               'freecodecamp.com?subject=' + | ||||
|               'slack%20invite%20failed%20to%20send\'>' + | ||||
|               'email us</a>.' | ||||
|           }); | ||||
|           return res.redirect('back'); | ||||
|         } | ||||
|       }); | ||||
|     } else { | ||||
|       req.flash('notice', { | ||||
|         msg: 'Before we can send your Slack invite, we need your email ' + | ||||
|           'address. Please update your profile information here.' | ||||
|       }); | ||||
|       return res.redirect('/account'); | ||||
|     } | ||||
|   } else { | ||||
|     req.flash('notice', { | ||||
|       msg: 'You need to sign in to Free Code Camp before ' + | ||||
|         'we can send you a Slack invite.' | ||||
|     }); | ||||
|     return res.redirect('/account'); | ||||
|   } | ||||
| } | ||||
|  | ||||
| function twitter(req, res, next) { | ||||
|   // sends out random tweets about javascript | ||||
|   var T = new Twit({ | ||||
|     'consumer_key': secrets.twitter.consumerKey, | ||||
|     'consumer_secret': secrets.twitter.consumerSecret, | ||||
|     'access_token': secrets.twitter.token, | ||||
|     'access_token_secret': secrets.twitter.tokenSecret | ||||
|   }); | ||||
|  | ||||
|   var screenName; | ||||
|   if (req.params.screenName) { | ||||
|     screenName = req.params.screenName; | ||||
|   } else { | ||||
|     screenName = 'freecodecamp'; | ||||
|   } | ||||
|  | ||||
|   T.get( | ||||
|     'statuses/user_timeline', | ||||
|     { | ||||
|       'screen_name': screenName, | ||||
|       count: 10 | ||||
|     }, | ||||
|     function(err, data) { | ||||
|       if (err) { return next(err); } | ||||
|       return res.json(data); | ||||
|     } | ||||
|   ); | ||||
| } | ||||
|  | ||||
|  | ||||
| function getHelp(req, res) { | ||||
|   var userName = req.user.profile.username; | ||||
|   var code = req.body.payload.code ? '\n```\n' + | ||||
|   req.body.payload.code + '\n```\n' | ||||
|     : ''; | ||||
|   var challenge = req.body.payload.challenge; | ||||
|  | ||||
|   slack.send({ | ||||
|     text: '*@' + userName + '* wants help with ' + challenge + '. ' + | ||||
|       code + 'Hey, *@' + userName + '*, if no one helps you right ' + | ||||
|       'away, try typing out your problem in detail to me. Like this: ' + | ||||
|       'http://en.wikipedia.org/wiki/Rubber_duck_debugging', | ||||
|     channel: '#help', | ||||
|     username: 'Debuggy the Rubber Duck', | ||||
|     'icon_url': 'https://pbs.twimg.com/profile_images/' + | ||||
|     '3609875545/569237541c920fa78d78902069615caf.jpeg' | ||||
|   }); | ||||
|   return res.sendStatus(200); | ||||
| } | ||||
|  | ||||
| function getPair(req, res) { | ||||
|   var userName = req.user.profile.username; | ||||
|   var challenge = req.body.payload.challenge; | ||||
|   slack.send({ | ||||
|     text: 'Anyone want to pair with *@' + userName + '* on ' + challenge + | ||||
|       '?\nMake sure you install Screen Hero here: ' + | ||||
|       'http://freecodecamp.com/field-guide/how-do-i-install-screenhero\n' + | ||||
|       'Then start your pair program session with *@' + userName + | ||||
|       '* by typing \"/hero @' + userName + '\" into Slack.\n And *@'+ userName + | ||||
|       '*, be sure to launch Screen Hero, then keep coding. ' + | ||||
|       'Another camper may pair with you soon.', | ||||
|     channel: '#letspair', | ||||
|     username: 'Companion Cube', | ||||
|     'icon_url': 'https://lh3.googleusercontent.com/-f6xDPDV2rPE/AAAAAAAAAAI/' + | ||||
|       'AAAAAAAAAAA/mdlESXQu11Q/photo.jpg' | ||||
|   }); | ||||
|   return res.sendStatus(200); | ||||
| } | ||||
|  | ||||
| function sitemap(req, res, next) { | ||||
|   var appUrl = 'http://www.freecodecamp.com'; | ||||
|   var now = moment(new Date()).format('YYYY-MM-DD'); | ||||
|  | ||||
|  | ||||
|   async.parallel({ | ||||
|       users: function(callback) { | ||||
|         User.aggregate() | ||||
|           .group({_id: 1, usernames: { $addToSet: '$profile.username'}}) | ||||
|           .match({'profile.username': { $ne: ''}}) | ||||
|           .exec(function(err, users) { | ||||
|             if (err) { | ||||
|               debug('User err: ', err); | ||||
|               callback(err); | ||||
|             } else { | ||||
|               callback(null, users[0].usernames); | ||||
|             } | ||||
|           }); | ||||
|       }, | ||||
|  | ||||
|       challenges: function (callback) { | ||||
|         Challenge.aggregate() | ||||
|           .group({_id: 1, names: { $addToSet: '$name'}}) | ||||
|           .exec(function (err, challenges) { | ||||
|             if (err) { | ||||
|               debug('Challenge err: ', err); | ||||
|               callback(err); | ||||
|             } else { | ||||
|               callback(null, challenges[0].names); | ||||
|             } | ||||
|           }); | ||||
|       }, | ||||
|       stories: function (callback) { | ||||
|         Story.aggregate() | ||||
|           .group({_id: 1, links: {$addToSet: '$link'}}) | ||||
|           .exec(function (err, stories) { | ||||
|             if (err) { | ||||
|               debug('Story err: ', err); | ||||
|               callback(err); | ||||
|             } else { | ||||
|               callback(null, stories[0].links); | ||||
|             } | ||||
|           }); | ||||
|       }, | ||||
|       nonprofits: function (callback) { | ||||
|         Nonprofit.aggregate() | ||||
|           .group({_id: 1, names: { $addToSet: '$name'}}) | ||||
|           .exec(function (err, nonprofits) { | ||||
|             if (err) { | ||||
|               debug('User err: ', err); | ||||
|               callback(err); | ||||
|             } else { | ||||
|               callback(null, nonprofits[0].names); | ||||
|             } | ||||
|           }); | ||||
|       }, | ||||
|       fieldGuides: function (callback) { | ||||
|         FieldGuide.aggregate() | ||||
|           .group({_id: 1, names: { $addToSet: '$name'}}) | ||||
|           .exec(function (err, fieldGuides) { | ||||
|             if (err) { | ||||
|               debug('User err: ', err); | ||||
|               callback(err); | ||||
|             } else { | ||||
|               callback(null, fieldGuides[0].names); | ||||
|             } | ||||
|           }); | ||||
|       } | ||||
|     }, function (err, results) { | ||||
|       if (err) { | ||||
|         return next(err); | ||||
|       } else { | ||||
|         setTimeout(function() { | ||||
|           res.header('Content-Type', 'application/xml'); | ||||
|           res.render('resources/sitemap', { | ||||
|             appUrl: appUrl, | ||||
|             now: now, | ||||
|             users: results.users, | ||||
|             challenges: results.challenges, | ||||
|             stories: results.stories, | ||||
|             nonprofits: results.nonprofits, | ||||
|             fieldGuides: results.fieldGuides | ||||
|           }); | ||||
|         }, 0); | ||||
|       } | ||||
|     } | ||||
|   ); | ||||
| } | ||||
|  | ||||
| function chat(req, res) { | ||||
|   if (req.user && req.user.progressTimestamps.length > 5) { | ||||
|     res.redirect('http://freecode.slack.com'); | ||||
|   } else { | ||||
|     res.render('resources/chat', { | ||||
|       title: 'Watch us code live on Twitch.tv' | ||||
|     }); | ||||
|   } | ||||
| } | ||||
|  | ||||
| function jobsForm(req, res) { | ||||
|   res.render('resources/jobs-form', { | ||||
|     title: 'Employer Partnership Form for Job Postings,' + | ||||
|       ' Recruitment and Corporate Sponsorships' | ||||
|   }); | ||||
| } | ||||
|  | ||||
| function catPhotoSubmit(req, res) { | ||||
|   res.send( | ||||
|     'Success! You have submitted your cat photo. Return to your website ' + | ||||
|     'by typing any letter into your code editor.' | ||||
|   ); | ||||
| } | ||||
|  | ||||
| function nonprofits(req, res) { | ||||
|   res.render('resources/nonprofits', { | ||||
|     title: 'A guide to our Nonprofit Projects' | ||||
|   }); | ||||
| } | ||||
|  | ||||
| function nonprofitsForm(req, res) { | ||||
|   res.render('resources/nonprofits-form', { | ||||
|     title: 'Nonprofit Projects Proposal Form' | ||||
|   }); | ||||
| } | ||||
|  | ||||
| function agileProjectManagers(req, res) { | ||||
|   res.render('resources/pmi-acp-agile-project-managers', { | ||||
|     title: 'Get Agile Project Management Experience for the PMI-ACP' | ||||
|   }); | ||||
| } | ||||
|  | ||||
| function agileProjectManagersForm(req, res) { | ||||
|   res.render('resources/pmi-acp-agile-project-managers-form', { | ||||
|     title: 'Agile Project Management Program Application Form' | ||||
|   }); | ||||
| } | ||||
|  | ||||
| function twitch(req, res) { | ||||
|   res.render('resources/twitch', { | ||||
|     title: 'Enter Free Code Camp\'s Chat Rooms' | ||||
|   }); | ||||
| } | ||||
|  | ||||
| function unsubscribe(req, res, next) { | ||||
|   User.findOne({ email: req.params.email }, function(err, user) { | ||||
|     if (user) { | ||||
|       if (err) { | ||||
|         return next(err); | ||||
|       } | ||||
|       user.sendMonthlyEmail = false; | ||||
|       user.save(function () { | ||||
|         if (err) { | ||||
|           return next(err); | ||||
|         } | ||||
|         res.redirect('/unsubscribed'); | ||||
|       }); | ||||
|     } else { | ||||
|       res.redirect('/unsubscribed'); | ||||
|     } | ||||
|   }); | ||||
| } | ||||
|  | ||||
| function unsubscribed(req, res) { | ||||
|   res.render('resources/unsubscribed', { | ||||
|     title: 'You have been unsubscribed' | ||||
|   }); | ||||
| } | ||||
|  | ||||
| function githubCalls(req, res, next) { | ||||
|   var githubHeaders = { | ||||
|     headers: { | ||||
|       'User-Agent': constantStrings.gitHubUserAgent | ||||
|     }, | ||||
|     port: 80 | ||||
|   }; | ||||
|   request( | ||||
|     [ | ||||
|       'https://api.github.com/repos/freecodecamp/', | ||||
|       'freecodecamp/pulls?client_id=', | ||||
|       secrets.github.clientID, | ||||
|       '&client_secret=', | ||||
|       secrets.github.clientSecret | ||||
|     ].join(''), | ||||
|     githubHeaders, | ||||
|     function(err, status1, pulls) { | ||||
|       if (err) { return next(err); } | ||||
|       pulls = pulls ? | ||||
|         Object.keys(JSON.parse(pulls)).length : | ||||
|         'Can\'t connect to github'; | ||||
|  | ||||
|       request( | ||||
|         [ | ||||
|           'https://api.github.com/repos/freecodecamp/', | ||||
|           'freecodecamp/issues?client_id=', | ||||
|           secrets.github.clientID, | ||||
|           '&client_secret=', | ||||
|           secrets.github.clientSecret | ||||
|         ].join(''), | ||||
|         githubHeaders, | ||||
|         function (err, status2, issues) { | ||||
|           if (err) { return next(err); } | ||||
|           issues = ((pulls === parseInt(pulls, 10)) && issues) ? | ||||
|           Object.keys(JSON.parse(issues)).length - pulls : | ||||
|             "Can't connect to GitHub"; | ||||
|           res.send({ | ||||
|             issues: issues, | ||||
|             pulls: pulls | ||||
|           }); | ||||
|         } | ||||
|       ); | ||||
|     } | ||||
|   ); | ||||
| } | ||||
|  | ||||
| function trelloCalls(req, res, next) { //eslint-disable-line | ||||
|   request( | ||||
|     'https://trello.com/1/boards/BA3xVpz9/cards?key=' + | ||||
|     secrets.trello.key, | ||||
|     function(err, status, trello) { | ||||
|       if (err) { return next(err); } | ||||
|       trello = (status && status.statusCode === 200) ? | ||||
|         (JSON.parse(trello)) : | ||||
|         'Can\'t connect to to Trello'; | ||||
|  | ||||
|       res.end(JSON.stringify(trello)); | ||||
|     }); | ||||
| } | ||||
|  | ||||
| function bloggerCalls(req, res, next) { //eslint-disable-line | ||||
|   request( | ||||
|     'https://www.googleapis.com/blogger/v3/blogs/2421288658305323950/' + | ||||
|       'posts?key=' + | ||||
|     secrets.blogger.key, | ||||
|     function (err, status, blog) { | ||||
|       if (err) { return next(err); } | ||||
|  | ||||
|       blog = (status && status.statusCode === 200) ? | ||||
|         JSON.parse(blog) : | ||||
|         'Can\'t connect to Blogger'; | ||||
|       res.end(JSON.stringify(blog)); | ||||
|     } | ||||
|   ); | ||||
| } | ||||
|  | ||||
| function getCats(req, res) { //eslint-disable-line | ||||
|   res.send( | ||||
|     [ | ||||
|       { | ||||
|         'name': 'cute', | ||||
|         'imageLink': 'https://encrypted-tbn3.gstatic.com/images' + | ||||
|           '?q=tbn:ANd9GcRaP1ecF2jerISkdhjr4R9yM9-8ClUy-TA36MnDiFBukd5IvEME0g' | ||||
|       }, | ||||
|       { | ||||
|         'name': 'grumpy', | ||||
|         'imageLink': 'http://cdn.grumpycats.com/wp-content/uploads/' + | ||||
|           '2012/09/GC-Gravatar-copy.png' | ||||
|       }, | ||||
|       { | ||||
|         'name': 'mischievous', | ||||
|         'imageLink': 'http://www.kittenspet.com/wp-content' + | ||||
|           '/uploads/2012/08/cat_with_funny_face_3-200x200.jpg' | ||||
|       } | ||||
|     ] | ||||
|   ); | ||||
| } | ||||
|  | ||||
| module.exports = router; | ||||
							
								
								
									
										34
									
								
								server/resources/middleware.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								server/resources/middleware.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,34 @@ | ||||
| var R = require('ramda'); | ||||
|  | ||||
| /** | ||||
|  * | ||||
|  * @param req | ||||
|  * @param res | ||||
|  * @returns null | ||||
|  * Middleware to migrate users from fragmented challenge structure to unified | ||||
|  * challenge structure | ||||
|  */ | ||||
| exports.userMigration = function(req, res, next) { | ||||
|   if (!req.user || req.user.completedChallenges.length !== 0) { | ||||
|     return next(); | ||||
|   } | ||||
|   req.user.completedChallenges = R.filter(function (elem) { | ||||
|     return elem; // getting rid of undefined | ||||
|   }, R.concat( | ||||
|       req.user.completedCoursewares, | ||||
|       req.user.completedBonfires.map(function (bonfire) { | ||||
|         return ({ | ||||
|           completedDate: bonfire.completedDate, | ||||
|           _id: bonfire._id, | ||||
|           name: bonfire.name, | ||||
|           completedWith: bonfire.completedWith, | ||||
|           solution: bonfire.solution, | ||||
|           githubLink: '', | ||||
|           verified: false, | ||||
|           challengeType: 5 | ||||
|         }); | ||||
|       }) | ||||
|     ) | ||||
|   ); | ||||
|   return next(); | ||||
| }; | ||||
							
								
								
									
										273
									
								
								server/resources/resources.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										273
									
								
								server/resources/resources.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,273 @@ | ||||
| var async = require('async'), | ||||
|   path = require('path'), | ||||
|   debug = require('debug')('freecc:cntr:resources'), // eslint-disable-line | ||||
|   cheerio = require('cheerio'), | ||||
|   request = require('request'), | ||||
|   R = require('ramda'), | ||||
|   _ = require('lodash'), | ||||
|   fs = require('fs'), | ||||
|  | ||||
|  | ||||
|   Story = require('./../../models/Story'), | ||||
|   Comment = require('./../../models/Comment'), | ||||
|   resources = require('./resources.json'), | ||||
|   nonprofits = require('../../seed_data/nonprofits.json'), | ||||
|   fieldGuides = require('../../seed_data/field-guides.json'); | ||||
|  | ||||
| /** | ||||
|  * Cached values | ||||
|  */ | ||||
| var allFieldGuideIds, allFieldGuideNames, allNonprofitNames, | ||||
|   challengeMap, challengeMapForDisplay, challengeMapWithIds, | ||||
|   challengeMapWithNames, allChallengeIds, allChallenges; | ||||
|  | ||||
| /** | ||||
|  * GET / | ||||
|  * Resources. | ||||
|  */ | ||||
|  | ||||
| Array.zip = function(left, right, combinerFunction) { | ||||
|   var counter, | ||||
|     results = []; | ||||
|  | ||||
|   for (counter = 0; counter < Math.min(left.length, right.length); counter++) { | ||||
|     results.push(combinerFunction(left[counter], right[counter])); | ||||
|   } | ||||
|  | ||||
|   return results; | ||||
| }; | ||||
|  | ||||
| (function() { | ||||
|   if (!challengeMap) { | ||||
|     var localChallengeMap = {}; | ||||
|     var files = fs.readdirSync( | ||||
|       path.join(__dirname, '/../seed_data/challenges') | ||||
|     ); | ||||
|     var keyCounter = 0; | ||||
|     files = files.map(function (file) { | ||||
|       return require( | ||||
|         path.join(__dirname, '/../seed_data/challenges/' + file) | ||||
|       ); | ||||
|     }); | ||||
|     files = files.sort(function (a, b) { | ||||
|       return a.order - b.order; | ||||
|     }); | ||||
|     files.forEach(function (file) { | ||||
|       localChallengeMap[keyCounter++] = file; | ||||
|     }); | ||||
|     challengeMap = _.cloneDeep(localChallengeMap); | ||||
|   } | ||||
| })(); | ||||
|  | ||||
|  | ||||
| module.exports = { | ||||
|   getChallengeMapForDisplay: function () { | ||||
|     if (!challengeMapForDisplay) { | ||||
|       challengeMapForDisplay = {}; | ||||
|       Object.keys(challengeMap).forEach(function (key) { | ||||
|         challengeMapForDisplay[key] = { | ||||
|           name: challengeMap[key].name, | ||||
|           dashedName: challengeMap[key].name.replace(/\s/g, '-'), | ||||
|           challenges: challengeMap[key].challenges, | ||||
|           completedCount: challengeMap[key].challenges | ||||
|         }; | ||||
|       }); | ||||
|     } | ||||
|     return challengeMapForDisplay; | ||||
|   }, | ||||
|  | ||||
|   getChallengeMapWithIds: function () { | ||||
|     if (!challengeMapWithIds) { | ||||
|       challengeMapWithIds = {}; | ||||
|       Object.keys(challengeMap).forEach(function (key) { | ||||
|         var onlyIds = challengeMap[key].challenges.map(function (elem) { | ||||
|           return elem._id; | ||||
|         }); | ||||
|         challengeMapWithIds[key] = onlyIds; | ||||
|       }); | ||||
|     } | ||||
|     return challengeMapWithIds; | ||||
|   }, | ||||
|  | ||||
|   allChallengeIds: function () { | ||||
|  | ||||
|     if (!allChallengeIds) { | ||||
|       allChallengeIds = []; | ||||
|       Object.keys(this.getChallengeMapWithIds()).forEach(function (key) { | ||||
|         allChallengeIds.push(challengeMapWithIds[key]); | ||||
|       }); | ||||
|       allChallengeIds = R.flatten(allChallengeIds); | ||||
|     } | ||||
|     return allChallengeIds; | ||||
|   }, | ||||
|  | ||||
|   allChallenges: function () { | ||||
|     if (!allChallenges) { | ||||
|       allChallenges = []; | ||||
|       Object.keys(this.getChallengeMapWithNames()).forEach(function (key) { | ||||
|         allChallenges.push(challengeMap[key].challenges); | ||||
|       }); | ||||
|       allChallenges = R.flatten(allChallenges); | ||||
|     } | ||||
|     return allChallenges; | ||||
|   }, | ||||
|  | ||||
|   getChallengeMapWithNames: function () { | ||||
|     if (!challengeMapWithNames) { | ||||
|       challengeMapWithNames = {}; | ||||
|       Object.keys(challengeMap). | ||||
|         forEach(function (key) { | ||||
|           var onlyNames = challengeMap[key].challenges.map(function (elem) { | ||||
|             return elem.name; | ||||
|           }); | ||||
|           challengeMapWithNames[key] = onlyNames; | ||||
|         }); | ||||
|     } | ||||
|     return challengeMapWithNames; | ||||
|   }, | ||||
|  | ||||
|  | ||||
|   randomPhrase: function () { | ||||
|     return resources.phrases[ | ||||
|       Math.floor(Math.random() * resources.phrases.length) | ||||
|       ]; | ||||
|   }, | ||||
|  | ||||
|   randomVerb: function () { | ||||
|     return resources.verbs[ | ||||
|       Math.floor(Math.random() * resources.verbs.length) | ||||
|       ]; | ||||
|   }, | ||||
|  | ||||
|   randomCompliment: function () { | ||||
|     return resources.compliments[ | ||||
|       Math.floor(Math.random() * resources.compliments.length) | ||||
|       ]; | ||||
|   }, | ||||
|  | ||||
|   allFieldGuideIds: function () { | ||||
|     if (allFieldGuideIds) { | ||||
|       return allFieldGuideIds; | ||||
|     } else { | ||||
|       allFieldGuideIds = fieldGuides.map(function (elem) { | ||||
|         return elem._id; | ||||
|       }); | ||||
|       return allFieldGuideIds; | ||||
|     } | ||||
|   }, | ||||
|  | ||||
|   allFieldGuideNamesAndIds: function () { | ||||
|     if (allFieldGuideNames) { | ||||
|       return allFieldGuideNames; | ||||
|     } else { | ||||
|       allFieldGuideNames = fieldGuides.map(function (elem) { | ||||
|         return { | ||||
|           name: elem.name, | ||||
|           dashedName: elem.dashedName, | ||||
|           id: elem._id | ||||
|         }; | ||||
|       }); | ||||
|       return allFieldGuideNames; | ||||
|     } | ||||
|   }, | ||||
|  | ||||
|   allNonprofitNames: function () { | ||||
|     if (allNonprofitNames) { | ||||
|       return allNonprofitNames; | ||||
|     } else { | ||||
|       allNonprofitNames = nonprofits.map(function (elem) { | ||||
|         return {name: elem.name}; | ||||
|       }); | ||||
|       return allNonprofitNames; | ||||
|     } | ||||
|   }, | ||||
|  | ||||
|   whichEnvironment: function () { | ||||
|     return process.env.NODE_ENV; | ||||
|   }, | ||||
|  | ||||
|   getURLTitle: function (url, callback) { | ||||
|     (function () { | ||||
|       var result = {title: '', image: '', url: '', description: ''}; | ||||
|       request(url, function (error, response, body) { | ||||
|         if (!error && response.statusCode === 200) { | ||||
|           var $ = cheerio.load(body); | ||||
|           var metaDescription = $("meta[name='description']"); | ||||
|           var metaImage = $("meta[property='og:image']"); | ||||
|           var urlImage = metaImage.attr('content') ? | ||||
|             metaImage.attr('content') : | ||||
|             ''; | ||||
|  | ||||
|           var metaTitle = $('title'); | ||||
|           var description = metaDescription.attr('content') ? | ||||
|             metaDescription.attr('content') : | ||||
|             ''; | ||||
|  | ||||
|           result.title = metaTitle.text().length < 90 ? | ||||
|             metaTitle.text() : | ||||
|           metaTitle.text().slice(0, 87) + '...'; | ||||
|  | ||||
|           result.image = urlImage; | ||||
|           result.description = description; | ||||
|           callback(null, result); | ||||
|         } else { | ||||
|           callback(new Error('failed')); | ||||
|         } | ||||
|       }); | ||||
|     })(); | ||||
|   }, | ||||
|  | ||||
|   updateUserStoryPictures: function (userId, picture, username, cb) { | ||||
|  | ||||
|     var counter = 0, | ||||
|       foundStories, | ||||
|       foundComments; | ||||
|  | ||||
|     Story.find({'author.userId': userId}, function (err, stories) { | ||||
|       if (err) { | ||||
|         return cb(err); | ||||
|       } | ||||
|       foundStories = stories; | ||||
|       counter++; | ||||
|       saveStoriesAndComments(); | ||||
|     }); | ||||
|     Comment.find({'author.userId': userId}, function (err, comments) { | ||||
|       if (err) { | ||||
|         return cb(err); | ||||
|       } | ||||
|       foundComments = comments; | ||||
|       counter++; | ||||
|       saveStoriesAndComments(); | ||||
|     }); | ||||
|  | ||||
|     function saveStoriesAndComments() { | ||||
|       if (counter !== 2) { | ||||
|         return; | ||||
|       } | ||||
|       var tasks = []; | ||||
|       R.forEach(function (comment) { | ||||
|         comment.author.picture = picture; | ||||
|         comment.author.username = username; | ||||
|         comment.markModified('author'); | ||||
|         tasks.push(function (cb) { | ||||
|           comment.save(cb); | ||||
|         }); | ||||
|       }, foundComments); | ||||
|  | ||||
|       R.forEach(function (story) { | ||||
|         story.author.picture = picture; | ||||
|         story.author.username = username; | ||||
|         story.markModified('author'); | ||||
|         tasks.push(function (cb) { | ||||
|           story.save(cb); | ||||
|         }); | ||||
|       }, foundStories); | ||||
|       async.parallel(tasks, function (err) { | ||||
|         if (err) { | ||||
|           return cb(err); | ||||
|         } | ||||
|         cb(); | ||||
|       }); | ||||
|     } | ||||
|   } | ||||
| }; | ||||
| @@ -21,8 +21,8 @@ var express = require('express'), | ||||
|   methodOverride = require('method-override'), | ||||
|   bodyParser = require('body-parser'), | ||||
|   helmet = require('helmet'), | ||||
|   frameguard = require('frameguard'), | ||||
|   csp = require('helmet-csp'), | ||||
|   //frameguard = require('frameguard'),
 | ||||
|   //csp = require('helmet-csp'),
 | ||||
|   MongoStore = require('connect-mongo')(session), | ||||
|   flash = require('express-flash'), | ||||
|   path = require('path'), | ||||
| @@ -36,25 +36,23 @@ var express = require('express'), | ||||
|   /** | ||||
|    * Controllers (route handlers). | ||||
|    */ | ||||
|   homeController = require('./controllers/home'), | ||||
|   resourcesController = require('./controllers/resources'), | ||||
|   userController = require('./controllers/user'), | ||||
|   nonprofitController = require('./controllers/nonprofits'), | ||||
|   fieldGuideController = require('./controllers/fieldGuide'), | ||||
|   challengeMapController = require('./controllers/challengeMap'), | ||||
|   challengeController = require('./controllers/challenge'), | ||||
|   jobsController = require('./controllers/jobs'), | ||||
| 
 | ||||
|   /** | ||||
|    *  Stories | ||||
|    */ | ||||
|   storyController = require('./controllers/story'), | ||||
|   homeController = require('./boot/home'), | ||||
|   resourcesController = require('./resources/resources'), | ||||
|   userController = require('./boot/user'), | ||||
|   nonprofitController = require('./boot/nonprofits'), | ||||
|   fieldGuideController = require('./boot/fieldGuide'), | ||||
|   challengeMapController = require('./boot/challengeMap'), | ||||
|   challengeController = require('./boot/challenge'), | ||||
|   jobsController = require('./boot/jobs'), | ||||
|   redirects = require('./boot/redirects'), | ||||
|   utility = require('./boot/utility'), | ||||
|   storyController = require('./boot/story'), | ||||
| 
 | ||||
|   /** | ||||
|    * API keys and Passport configuration. | ||||
|    */ | ||||
|   secrets = require('./config/secrets'), | ||||
|   passportConf = require('./config/passport'); | ||||
|   secrets = require('./../config/secrets'), | ||||
|   passportConf = require('./../config/passport'); | ||||
| 
 | ||||
| /** | ||||
|  * Create Express server. | ||||
| @@ -216,128 +214,9 @@ app.use(function (req, res, next) { | ||||
|   next(); | ||||
| }); | ||||
| 
 | ||||
| /** | ||||
|  * Main routes. | ||||
|  */ | ||||
| 
 | ||||
| app.get('/', homeController.index); | ||||
| 
 | ||||
| app.get('/nonprofit-project-instructions', function(req, res) { | ||||
|   res.redirect(301, '/field-guide/how-do-free-code-camp\'s-nonprofit-projects-work'); | ||||
| }); | ||||
| 
 | ||||
| app.post('/get-help', resourcesController.getHelp); | ||||
| 
 | ||||
| app.post('/get-pair', resourcesController.getPair); | ||||
| 
 | ||||
| app.get('/chat', resourcesController.chat); | ||||
| 
 | ||||
| app.get('/twitch', resourcesController.twitch); | ||||
| 
 | ||||
| app.get('/cats.json', function(req, res) { | ||||
|   res.send( | ||||
|     [ | ||||
|       { | ||||
|         "name": "cute", | ||||
|         "imageLink": "https://encrypted-tbn3.gstatic.com/images?q=tbn:ANd9GcRaP1ecF2jerISkdhjr4R9yM9-8ClUy-TA36MnDiFBukd5IvEME0g" | ||||
|       }, | ||||
|       { | ||||
|         "name": "grumpy", | ||||
|         "imageLink": "http://cdn.grumpycats.com/wp-content/uploads/2012/09/GC-Gravatar-copy.png" | ||||
|       }, | ||||
|       { | ||||
|         "name": "mischievous", | ||||
|         "imageLink": "http://www.kittenspet.com/wp-content/uploads/2012/08/cat_with_funny_face_3-200x200.jpg" | ||||
|       } | ||||
|     ] | ||||
|   ) | ||||
| }); | ||||
| 
 | ||||
| // Agile Project Manager Onboarding
 | ||||
| 
 | ||||
| app.get('/pmi-acp-agile-project-managers', | ||||
|   resourcesController.agileProjectManagers); | ||||
| 
 | ||||
| app.get('/agile', function(req, res) { | ||||
|   res.redirect(301, '/pmi-acp-agile-project-managers'); | ||||
| }); | ||||
| 
 | ||||
| app.get('/pmi-acp-agile-project-managers-form', | ||||
|   resourcesController.agileProjectManagersForm); | ||||
| 
 | ||||
| // Nonprofit Onboarding
 | ||||
| 
 | ||||
| app.get('/nonprofits', resourcesController.nonprofits); | ||||
| 
 | ||||
| app.get('/nonprofits-form', resourcesController.nonprofitsForm); | ||||
| 
 | ||||
| app.get('/map', | ||||
|   userController.userMigration, | ||||
|   challengeMapController.challengeMap | ||||
| ); | ||||
| 
 | ||||
| app.get('/live-pair-programming', function(req, res) { | ||||
|   res.redirect(301, '/field-guide/live-stream-pair-programming-on-twitch.tv'); | ||||
| }); | ||||
| 
 | ||||
| app.get('/install-screenhero', function(req, res) { | ||||
|   res.redirect(301, '/field-guide/install-screenhero'); | ||||
| }); | ||||
| 
 | ||||
| app.get('/guide-to-our-nonprofit-projects', function(req, res) { | ||||
|   res.redirect(301, '/field-guide/a-guide-to-our-nonprofit-projects'); | ||||
| }); | ||||
| 
 | ||||
| app.get('/chromebook', function(req, res) { | ||||
|   res.redirect(301, '/field-guide/chromebook'); | ||||
| }); | ||||
| 
 | ||||
| app.get('/deploy-a-website', function(req, res) { | ||||
|   res.redirect(301, '/field-guide/deploy-a-website'); | ||||
| }); | ||||
| 
 | ||||
| app.get('/gmail-shortcuts', function(req, res) { | ||||
|   res.redirect(301, '/field-guide/gmail-shortcuts'); | ||||
| }); | ||||
| 
 | ||||
| app.get('/nodeschool-challenges', function(req, res) { | ||||
|   res.redirect(301, '/field-guide/nodeschool-challenges'); | ||||
| }); | ||||
| 
 | ||||
| 
 | ||||
| app.get('/learn-to-code', challengeMapController.challengeMap); | ||||
| app.get('/about', function(req, res) { | ||||
|   res.redirect(301, '/map'); | ||||
| }); | ||||
| app.get('/signin', userController.getSignin); | ||||
| 
 | ||||
| app.get('/login', function(req, res) { | ||||
|   res.redirect(301, '/signin'); | ||||
| }); | ||||
| 
 | ||||
| app.post('/signin', userController.postSignin); | ||||
| 
 | ||||
| app.get('/signout', userController.signout); | ||||
| 
 | ||||
| app.get('/logout', function(req, res) { | ||||
|   res.redirect(301, '/signout'); | ||||
| }); | ||||
| 
 | ||||
| app.get('/forgot', userController.getForgot); | ||||
| 
 | ||||
| app.post('/forgot', userController.postForgot); | ||||
| 
 | ||||
| app.get('/reset/:token', userController.getReset); | ||||
| 
 | ||||
| app.post('/reset/:token', userController.postReset); | ||||
| 
 | ||||
| app.get('/email-signup', userController.getEmailSignup); | ||||
| 
 | ||||
| app.get('/email-signin', userController.getEmailSignin); | ||||
| 
 | ||||
| app.post('/email-signup', userController.postEmailSignup); | ||||
| 
 | ||||
| app.post('/email-signin', userController.postSignin); | ||||
| 
 | ||||
| /** | ||||
|  * Nonprofit Project routes. | ||||
| @@ -355,169 +234,25 @@ app.get( | ||||
|   jobsController.jobsDirectory | ||||
| ); | ||||
| 
 | ||||
| app.get( | ||||
|   '/jobs-form', | ||||
|   resourcesController.jobsForm | ||||
| ); | ||||
| 
 | ||||
| app.get('/privacy', function(req, res) { | ||||
|   res.redirect(301, '/field-guide/what-is-the-free-code-camp-privacy-policy?'); | ||||
| }); | ||||
| 
 | ||||
| app.get('/submit-cat-photo', resourcesController.catPhotoSubmit); | ||||
| 
 | ||||
| app.get('/api/slack', function(req, res) { | ||||
|   if (req.user) { | ||||
|     if (req.user.email) { | ||||
|       var invite = { | ||||
|         'email': req.user.email, | ||||
|         'token': process.env.SLACK_KEY, | ||||
|         'set_active': true | ||||
|       }; | ||||
| 
 | ||||
|       var headers = { | ||||
|         'User-Agent': 'Node Browser/0.0.1', | ||||
|         'Content-Type': 'application/x-www-form-urlencoded' | ||||
|       }; | ||||
| 
 | ||||
|       var options = { | ||||
|         url: 'https://freecode.slack.com/api/users.admin.invite', | ||||
|         method: 'POST', | ||||
|         headers: headers, | ||||
|         form: invite | ||||
|       }; | ||||
| 
 | ||||
|       request(options, function (error, response, body) { | ||||
|         if (!error && response.statusCode === 200) { | ||||
|           req.flash('success', { | ||||
|             msg: "We've successfully requested an invite for you. Please check your email and follow the instructions from Slack." | ||||
|           }); | ||||
|           req.user.sentSlackInvite = true; | ||||
|           req.user.save(function(err, user) { | ||||
|             if (err) { | ||||
|               next(err); | ||||
|             } | ||||
|             return res.redirect('back'); | ||||
|           }); | ||||
|         } else { | ||||
|           req.flash('errors', { | ||||
|             msg: "The invitation email did not go through for some reason. Please try again or <a href='mailto:team@freecodecamp.com?subject=slack%20invite%20failed%20to%20send>email us</a>." | ||||
|           }); | ||||
|           return res.redirect('back'); | ||||
|         } | ||||
|       }); | ||||
|     } else { | ||||
|       req.flash('notice', { | ||||
|         msg: "Before we can send your Slack invite, we need your email address. Please update your profile information here." | ||||
|       }); | ||||
|       return res.redirect('/account'); | ||||
|     } | ||||
|   } else { | ||||
|     req.flash('notice', { | ||||
|       msg: "You need to sign in to Free Code Camp before we can send you a Slack invite." | ||||
|     }); | ||||
|     return res.redirect('/account'); | ||||
|   } | ||||
| }); | ||||
| 
 | ||||
| /** | ||||
|  * Camper News routes. | ||||
|  */ | ||||
| app.get( | ||||
|   '/stories/hotStories', | ||||
|   storyController.hotJSON | ||||
| ); | ||||
| 
 | ||||
| app.get( | ||||
|   '/stories/recentStories', | ||||
|   storyController.recentJSON | ||||
| ); | ||||
| 
 | ||||
| app.get( | ||||
|   '/stories/comments/:id', | ||||
|   storyController.comments | ||||
| ); | ||||
| 
 | ||||
| app.post( | ||||
|   '/stories/comment/', | ||||
|   storyController.commentSubmit | ||||
| ); | ||||
| 
 | ||||
| app.post( | ||||
|   '/stories/comment/:id/comment', | ||||
|   storyController.commentOnCommentSubmit | ||||
| ); | ||||
| 
 | ||||
| app.put( | ||||
|   '/stories/comment/:id/edit', | ||||
|   storyController.commentEdit | ||||
| ); | ||||
| 
 | ||||
| app.get( | ||||
|   '/stories/submit', | ||||
|   storyController.submitNew | ||||
| ); | ||||
| 
 | ||||
| app.get( | ||||
|   '/stories/submit/new-story', | ||||
|   storyController.preSubmit | ||||
| ); | ||||
| 
 | ||||
| app.post( | ||||
|   '/stories/preliminary', | ||||
|   storyController.newStory | ||||
| ); | ||||
| 
 | ||||
| app.post( | ||||
|   '/stories/', | ||||
|   storyController.storySubmission | ||||
| ); | ||||
| 
 | ||||
| app.get( | ||||
|   '/news/', | ||||
|   storyController.hot | ||||
| ); | ||||
| 
 | ||||
| app.post( | ||||
|   '/stories/search', | ||||
|   storyController.getStories | ||||
| ); | ||||
| 
 | ||||
| app.get( | ||||
|   '/news/:storyName', | ||||
|   storyController.returnIndividualStory | ||||
| ); | ||||
| 
 | ||||
| app.post( | ||||
|   '/stories/upvote/', | ||||
|   storyController.upvote | ||||
| ); | ||||
| 
 | ||||
| app.get( | ||||
|   '/unsubscribe/:email', | ||||
|   resourcesController.unsubscribe | ||||
| ); | ||||
| 
 | ||||
| app.get( | ||||
|   '/unsubscribed', | ||||
|   resourcesController.unsubscribed | ||||
| ); | ||||
| 
 | ||||
| app.all('/account', passportConf.isAuthenticated); | ||||
| 
 | ||||
| app.get('/account/api', userController.getAccountAngular); | ||||
| 
 | ||||
| /** | ||||
|  * API routes | ||||
|  */ | ||||
| 
 | ||||
| app.get('/api/github', resourcesController.githubCalls); | ||||
| 
 | ||||
| app.get('/api/blogger', resourcesController.bloggerCalls); | ||||
| 
 | ||||
| app.get('/api/trello', resourcesController.trelloCalls); | ||||
| 
 | ||||
| app.get('/api/codepen/twitter/:screenName', resourcesController.codepenResources.twitter); | ||||
| 
 | ||||
| /** | ||||
|  * Field Guide related routes | ||||
| @@ -560,27 +295,8 @@ app.post('/completed-zipline-or-basejump', | ||||
| app.post('/completed-bonfire', challengeController.completedBonfire); | ||||
| 
 | ||||
| // Unique Check API route
 | ||||
| app.get('/api/checkUniqueUsername/:username', | ||||
|   userController.checkUniqueUsername | ||||
| ); | ||||
| 
 | ||||
| app.get('/api/checkExistingUsername/:username', | ||||
|   userController.checkExistingUsername | ||||
| ); | ||||
| 
 | ||||
| app.get('/api/checkUniqueEmail/:email', userController.checkUniqueEmail); | ||||
| 
 | ||||
| app.get('/account', userController.getAccount); | ||||
| 
 | ||||
| app.post('/account/profile', userController.postUpdateProfile); | ||||
| 
 | ||||
| app.post('/account/password', userController.postUpdatePassword); | ||||
| 
 | ||||
| app.post('/account/delete', userController.postDeleteAccount); | ||||
| 
 | ||||
| app.get('/account/unlink/:provider', userController.getOauthUnlink); | ||||
| 
 | ||||
| app.get('/sitemap.xml', resourcesController.sitemap); | ||||
| 
 | ||||
| /** | ||||
|  * OAuth sign-in routes. | ||||
| @@ -646,11 +362,6 @@ app.get( | ||||
|   } | ||||
| ); | ||||
| 
 | ||||
| // put this route last
 | ||||
| app.get( | ||||
|   '/:username', | ||||
|   userController.returnUser | ||||
| ); | ||||
| 
 | ||||
| /** | ||||
|  * 500 Error Handler. | ||||
| @@ -14,19 +14,19 @@ block content | ||||
|     .panel.panel-info | ||||
|         .panel-heading.text-center Camper News | ||||
|         .panel-body | ||||
|             include ./news-nav | ||||
|             include news-nav | ||||
|             .spacer | ||||
|             if (page === 'hot') | ||||
|                 include ./hot-stories | ||||
|                 include hot-stories | ||||
|             if (page === 'submit') | ||||
|                 if (user) | ||||
|                     include ./preliminary-submit | ||||
|                     include preliminary-submit | ||||
|                 else | ||||
|                     .spacer | ||||
|                     .text-center | ||||
|                         a.btn.btn-cta.signup-btn.btn-primary(href="/login") Sign in to post your story (it's free) | ||||
|                     .spacer | ||||
|             if (page === 'storySubmission') | ||||
|                 include ./submit-story | ||||
|                 include submit-story | ||||
|             if (page === 'show') | ||||
|                 include ./show | ||||
|                 include show | ||||
| @@ -74,4 +74,4 @@ script. | ||||
|         var text_remaining = text_max - text_length; | ||||
|         $('#textarea_feedback').html(text_remaining + ' characters remaining'); | ||||
|     }); | ||||
| include ./comments | ||||
| include comments | ||||
							
								
								
									
										6
									
								
								setup.js
									
									
									
									
									
								
							
							
						
						
									
										6
									
								
								setup.js
									
									
									
									
									
								
							| @@ -410,7 +410,7 @@ authForm.on('submit', function() { | ||||
|   home.append(success); | ||||
|   success.setContent( | ||||
|     'Selected authentication providers have been removed' + | ||||
|     'from passportConfig.js, User.js, app.js, login.jade and profile.jade!' | ||||
|     'from passportConfig.js, User.js, server.js, login.jade and profile.jade!' | ||||
|   ); | ||||
|   success.focus(); | ||||
|   screen.render(); | ||||
| @@ -710,7 +710,7 @@ home.on('select', function(child, index) { | ||||
|         'New file {underline}cluster_app.js{/underline} has been created.', | ||||
|         'Your app is now able to use more than 1 CPU by running', | ||||
|         '{underline}node cluster_app.js{/underline}, which in turn', | ||||
|         'spawns multiple instances of {underline}app.js{/underline}' | ||||
|         'spawns multiple instances of {underline}server.js{/underline}' | ||||
|       ].join(' ')); | ||||
|       success.focus(); | ||||
|       screen.render(); | ||||
| @@ -731,7 +731,7 @@ var os = require('os'); | ||||
| var cluster = require('cluster'); | ||||
|  | ||||
| cluster.setupMaster({ | ||||
|   exec: 'app.js' | ||||
|   exec: 'server.js' | ||||
| }); | ||||
|  | ||||
| cluster.on('exit', function(worker) { | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| var request = require('supertest'); | ||||
| var app = require('../app.js'); | ||||
| var app = require('../server/server.js'); | ||||
|  | ||||
| describe('GET /', function() { | ||||
|   it('should return 200 OK', function(done) { | ||||
|   | ||||
		Reference in New Issue
	
	Block a user