From 51257be6a44fe951db9ff09a5633e37d44d767bc Mon Sep 17 00:00:00 2001 From: Sage Elliott Date: Mon, 18 May 2015 21:25:22 -0700 Subject: [PATCH 1/5] fix typo on line 97 of coursewwares.json --- seed_data/coursewares.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/seed_data/coursewares.json b/seed_data/coursewares.json index fffdab5fbb..fa0c2ecea1 100644 --- a/seed_data/coursewares.json +++ b/seed_data/coursewares.json @@ -94,7 +94,7 @@ "Click \"News\" in the upper right hand corner.", "You'll see a variety of links that have been submitted. Click on the \"Discuss\" button under one of them.", "You can upvote links. This will push the link up the rankings of hot links.", - "You an also comment on a link. If someone responds to your comment, you'll get an email notification so you can come back and respond to them.", + "You can also comment on a link. If someone responds to your comment, you'll get an email notification so you can come back and respond to them.", "You can also submit links. You can modify the link's headline and also leave an initial comment about the link.", "You can view the portfolio pages of any camper who has posted links or comments on Camper News. Just click on their photo.", "When you submit a link, you'll get a point. You will also get a point each time someone upvotes your link.", From b848fcb719f394c020f6773cf9942934e475ff25 Mon Sep 17 00:00:00 2001 From: Berkeley Martinez Date: Thu, 21 May 2015 09:52:18 -0700 Subject: [PATCH 2/5] Add eslint/babel-eslint/eslint-plugin-react --- .eslintrc | 25 ++++++++++++++++++++++--- package.json | 8 ++++++-- 2 files changed, 28 insertions(+), 5 deletions(-) diff --git a/.eslintrc b/.eslintrc index a167df14d6..418fe63976 100644 --- a/.eslintrc +++ b/.eslintrc @@ -7,6 +7,10 @@ "mocha": true, "node": true }, + "parser": "babel-eslint", + "plugins": [ + "react" + ], "globals": { "window": true, "$": true, @@ -41,7 +45,7 @@ "valid-jsdoc": 2, "valid-typeof": 2, - "block-scoped-var": 2, + "block-scoped-var": 0, "complexity": 0, "consistent-return": 2, "curly": 2, @@ -215,6 +219,21 @@ "max-params": 0, "max-statements": 0, "no-bitwise": 1, - "no-plusplus": 0 + "no-plusplus": 0, + + "react/display-name": 1, + "react/jsx-boolean-value": 1, + "react/jsx-quotes": [1, "single", "avoid-escape"], + "react/jsx-no-undef": 1, + "react/jsx-sort-props": 1, + "react/jsx-uses-react": 1, + "react/jsx-uses-vars": 1, + "react/no-did-mount-set-state": 2, + "react/no-did-update-set-state": 2, + "react/no-multi-comp": 2, + "react/prop-types": 2, + "react/react-in-jsx-scope": 1, + "react/self-closing-comp": 1, + "react/wrap-multilines": 1 } -} \ No newline at end of file +} diff --git a/package.json b/package.json index a73ad3fc48..72dae9262c 100644 --- a/package.json +++ b/package.json @@ -11,13 +11,14 @@ }, "scripts": { "start": "node app.js", + "lint": "eslint --ext=.js,.jsx .", "test": "mocha" }, "license": "BSD-3-Clause", - "contributors" : [ + "contributors": [ { "name": "Quincy Larson", - "url" : "https://github.com/QuincyLarson" + "url": "https://github.com/QuincyLarson" }, { "name": "Nathan Leniz", @@ -82,10 +83,13 @@ "yui": "~3.18.1" }, "devDependencies": { + "babel-eslint": "^3.1.7", "blessed": "~0.0.37", "bower-main-files": "~0.0.4", "browser-sync": "~1.8.1", "chai": "~1.10.0", + "eslint": "^0.21.2", + "eslint-plugin-react": "^2.3.0", "gulp": "~3.8.8", "gulp-eslint": "~0.9.0", "gulp-inject": "~1.0.2", From b58b725f9d42ef494ff5d68b1c81f97c6186fcc1 Mon Sep 17 00:00:00 2001 From: Berkeley Martinez Date: Thu, 21 May 2015 11:07:40 -0700 Subject: [PATCH 3/5] Fix Lint all the controllers Fix many undefined variables Fix many unhandled error calls --- controllers/challenge.js | 37 ++- controllers/challengeMap.js | 12 +- controllers/constantStrings.json | 3 + controllers/fieldGuide.js | 115 +++++---- controllers/home.js | 16 +- controllers/nonprofits.js | 269 +++++++++++--------- controllers/resources.js | 228 +++++++++++------ controllers/story.js | 242 +++++++++--------- controllers/user.js | 410 +++++++++++++++++-------------- 9 files changed, 759 insertions(+), 573 deletions(-) create mode 100644 controllers/constantStrings.json diff --git a/controllers/challenge.js b/controllers/challenge.js index 2c31c561ab..bbda541e63 100644 --- a/controllers/challenge.js +++ b/controllers/challenge.js @@ -1,27 +1,39 @@ -/*eslint-disable no-unused-vars */ - /** * Created by nathanleniz on 5/15/15. * Copyright (c) 2015, Free Code Camp All rights reserved. - Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: - 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. - 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. - 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS + BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -var debug = require('debug')('freecc:cntr:challenges'), +var R = require('ramda'), Challenge = require('./../models/Challenge'), User = require('./../models/User'), resources = require('./resources'), - R = require('ramda'), - moment = require('moment'), MDNlinks = require('./../seed_data/bonfireMDNlinks'); var challengeMapWithNames = resources.getChallengeMapWithNames(); @@ -31,9 +43,10 @@ function getMDNlinks(links) { // takes in an array of links, which are strings var populatedLinks = []; - // for each key value, push the corresponding link from the MDNlinks object into a new array + // for each key value, push the corresponding link + // from the MDNlinks object into a new array if (links) { - links.forEach(function (value, index) { + links.forEach(function (value) { populatedLinks.push(MDNlinks[value]); }); } diff --git a/controllers/challengeMap.js b/controllers/challengeMap.js index 7cc40feaf3..afda188330 100644 --- a/controllers/challengeMap.js +++ b/controllers/challengeMap.js @@ -1,7 +1,7 @@ -var User = require('../models/User'), - resources = require('./resources'), +var R = require('ramda'), debug = require('debug')('freecc:cntr:challengeMap'), - R = require('ramda'); + User = require('../models/User'), + resources = require('./resources'); var challengeTypes = { 'HTML_CSS_JQ': 0, @@ -13,7 +13,7 @@ var challengeTypes = { }; module.exports = { - challengeMap: function challengeMap(req, res) { + challengeMap: function challengeMap(req, res, next) { var completedList = []; if (req.user) { @@ -76,10 +76,10 @@ module.exports = { }); function numberWithCommas(x) { - return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ","); + return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ','); } - var date1 = new Date("10/15/2014"); + 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)); diff --git a/controllers/constantStrings.json b/controllers/constantStrings.json new file mode 100644 index 0000000000..70f5d9766c --- /dev/null +++ b/controllers/constantStrings.json @@ -0,0 +1,3 @@ +{ + "gitHubUserAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1521.3 Safari/537.36" +} diff --git a/controllers/fieldGuide.js b/controllers/fieldGuide.js index f8e35a47de..c498368f92 100644 --- a/controllers/fieldGuide.js +++ b/controllers/fieldGuide.js @@ -1,62 +1,69 @@ -var _ = require('lodash'), - debug = require('debug')('freecc:cntr:fieldGuide'), +var R = require('ramda'), FieldGuide = require('./../models/FieldGuide'), - resources = require('./resources'), - R = require('ramda'); + resources = require('./resources'); exports.returnIndividualFieldGuide = function(req, res, next) { - var dashedName = req.params.fieldGuideName; + var dashedName = req.params.fieldGuideName; - var fieldGuideName = dashedName.replace(/\-/g, ' '); + var fieldGuideName = dashedName.replace(/\-/g, ' '); - if (req.user) { - var completed = req.user.completedFieldGuides; + if (req.user) { + var completed = req.user.completedFieldGuides; - var uncompletedFieldGuides = resources.allFieldGuideIds().filter(function (elem) { + var uncompletedFieldGuides = resources.allFieldGuideIds() + .filter(function (elem) { if (completed.indexOf(elem) === -1) { return elem; } }); - req.user.uncompletedFieldGuides = uncompletedFieldGuides; - req.user.save(); - } + req.user.uncompletedFieldGuides = uncompletedFieldGuides; + // TODO(berks): handle callback properly + req.user.save(); + } - FieldGuide.find({'name': new RegExp(fieldGuideName, 'i')}, function(err, fieldGuideFromMongo) { - if (err) { - next(err); - } + FieldGuide.find( + { name: new RegExp(fieldGuideName, 'i') }, + function(err, fieldGuideFromMongo) { + if (err) { + return next(err); + } - if (fieldGuideFromMongo.length < 1) { - req.flash('errors', { - msg: "404: We couldn't find a field guide entry with that name. Please double check the name." - }); - - return res.redirect('/field-guide'); - } - - var fieldGuide = R.head(fieldGuideFromMongo); - var dashedNameFull = fieldGuide.name.toLowerCase().replace(/\s/g, '-').replace(/\?/g, ''); - if (dashedNameFull !== dashedName) { - return res.redirect('../field-guide/' + dashedNameFull); - } - res.render('field-guide/show', { - title: fieldGuide.name, - fieldGuideId: fieldGuide._id, - description: fieldGuide.description.join('') + if (fieldGuideFromMongo.length < 1) { + req.flash('errors', { + msg: "404: We couldn't find a field guide entry with that name. " + + 'Please double check the name.' }); - }); + + return res.redirect('/field-guide'); + } + + var fieldGuide = R.head(fieldGuideFromMongo); + var dashedNameFull = + fieldGuide.name.toLowerCase().replace(/\s/g, '-').replace(/\?/g, ''); + + if (dashedNameFull !== dashedName) { + return res.redirect('../field-guide/' + dashedNameFull); + } + res.render('field-guide/show', { + title: fieldGuide.name, + fieldGuideId: fieldGuide._id, + description: fieldGuide.description.join('') + }); + } + ); }; exports.showAllFieldGuides = function(req, res) { - var data = {}; - data.fieldGuideList = resources.allFieldGuideNames(); - data.fieldGuideIds = resources.allFieldGuideIds(); - if (req.user && req.user.completedFieldGuides) { - data.completedFieldGuides = req.user.completedFieldGuides; - } else { - data.completedFieldGuides = []; - } - res.send(data); + var data = {}; + data.fieldGuideList = resources.allFieldGuideNames(); + data.fieldGuideIds = resources.allFieldGuideIds(); + + if (req.user && req.user.completedFieldGuides) { + data.completedFieldGuides = req.user.completedFieldGuides; + } else { + data.completedFieldGuides = []; + } + res.send(data); }; exports.returnNextFieldGuide = function(req, res, next) { @@ -64,16 +71,22 @@ exports.returnNextFieldGuide = function(req, res, next) { return res.redirect('/field-guide/how-do-i-use-this-guide?'); } - var displayedFieldGuides = FieldGuide.find({'_id': req.user.uncompletedFieldGuides[0]}); + var displayedFieldGuides = + FieldGuide.find({'_id': req.user.uncompletedFieldGuides[0]}); + displayedFieldGuides.exec(function(err, fieldGuide) { - if (err) { - return next(err); - } + if (err) { return next(err); } fieldGuide = fieldGuide.pop(); + if (typeof fieldGuide === 'undefined') { if (req.user.completedFieldGuides.length > 0) { req.flash('success', { - msg: "You've read all our current Field Guide entries. You can contribute to our Field Guide here." + msg: [ + "You've read all our current Field Guide entries. You can ", + 'contribute to our Field Guide ', + "here." + ].join('') }); } return res.redirect('../field-guide/how-do-i-use-this-guide?'); @@ -94,12 +107,10 @@ exports.completedFieldGuide = function (req, res, next) { req.user.uncompletedFieldGuides.splice(index, 1); } - req.user.save(function (err, user) { + req.user.save(function (err) { if (err) { return next(err); } - if (user) { - res.send(true); - } + res.send(true); }); }; diff --git a/controllers/home.js b/controllers/home.js index 4c276db8f5..86b4a784c3 100644 --- a/controllers/home.js +++ b/controllers/home.js @@ -1,16 +1,16 @@ -/** - * GET / - * Home page. - */ +var message = + 'Learn to Code JavaScript and get a Coding Job by Helping Nonprofits'; exports.index = function(req, res, next) { if (req.user && !req.user.profile.picture) { - req.user.profile.picture = 'https://s3.amazonaws.com/freecodecamp/camper-image-placeholder.png'; + req.user.profile.picture = + 'https://s3.amazonaws.com/freecodecamp/camper-image-placeholder.png'; + req.user.save(function(err) { if (err) { return next(err); } + res.render('home', { title: message }); }); + } else { + res.render('home', { title: message }); } - res.render('home', { - title: 'Learn to Code JavaScript and get a Coding Job by Helping Nonprofits' - }); }; diff --git a/controllers/nonprofits.js b/controllers/nonprofits.js index 70a8c75366..77a2f04a8f 100644 --- a/controllers/nonprofits.js +++ b/controllers/nonprofits.js @@ -1,16 +1,11 @@ -var async = require('async'), +var moment = require('moment'), Nonprofit = require('./../models/Nonprofit'), - resources = require('./resources'), - secrets = require('./../config/secrets'), - moment = require('moment'), - debug = require('debug')('freecc:cntr:nonprofits'), - R = require('ramda'); + resources = require('./resources'); -exports.nonprofitsDirectory = function(req, res) { +exports.nonprofitsDirectory = function(req, res, next) { Nonprofit.find({estimatedHours: { $gt: 0 } }, function(err, nonprofits) { - if (err) { - next(err); - } + if (err) { return next(err); } + res.render('nonprofits/directory', { title: 'Nonprofits we help', nonprofits: nonprofits @@ -19,163 +14,197 @@ exports.nonprofitsDirectory = function(req, res) { }; exports.areYouWithARegisteredNonprofit = function(req, res) { - res.render('nonprofits/are-you-with-a-registered-nonprofit', { - title: 'Are you with a with a registered nonprofit', - step: 1 - }); + res.render('nonprofits/are-you-with-a-registered-nonprofit', { + title: 'Are you with a with a registered nonprofit', + step: 1 + }); }; -exports.areTherePeopleThatAreAlreadyBenefitingFromYourServices = function(req, res) { - res.render('nonprofits/are-there-people-that-are-already-benefiting-from-your-services', { +exports.areTherePeopleThatAreAlreadyBenefitingFromYourServices = + function(req, res) { + res.render( + 'nonprofits/' + + 'are-there-people-that-are-already-benefiting-from-your-services', + { title: 'Are there people already benefiting from your services', step: 2 - }); -}; + } + ); + }; exports.okWithJavaScript = function(req, res) { - res.render('nonprofits/ok-with-javascript', { - title: 'Are you OK with us using JavaScript', - step: 3 - }); + res.render('nonprofits/ok-with-javascript', { + title: 'Are you OK with us using JavaScript', + step: 3 + }); }; exports.inExchangeWeAsk = function(req, res) { - res.render('nonprofits/in-exchange-we-ask', { - title: 'In exchange we ask that you ...', - step: 4 - }); + res.render('nonprofits/in-exchange-we-ask', { + title: 'In exchange we ask that you ...', + step: 4 + }); }; exports.howCanFreeCodeCampHelpYou = function(req, res) { - res.render('nonprofits/how-can-free-code-camp-help-you', { - title: 'Are you with a with a registered nonprofit', - step: 5 - }); + res.render('nonprofits/how-can-free-code-camp-help-you', { + title: 'Are you with a with a registered nonprofit', + step: 5 + }); }; exports.whatDoesYourNonprofitDo = function(req, res) { - res.render('nonprofits/what-does-your-nonprofit-do', { - existingParams: req.params, - title: 'What does your nonprofit do?', - step: 6 - }); + res.render('nonprofits/what-does-your-nonprofit-do', { + existingParams: req.params, + title: 'What does your nonprofit do?', + step: 6 + }); }; exports.linkUsToYourWebsite = function(req, res) { - res.render('nonprofits/link-us-to-your-website', { - title: 'Link us to your website', - step: 7 - }); + res.render('nonprofits/link-us-to-your-website', { + title: 'Link us to your website', + step: 7 + }); }; exports.tellUsYourEmail = function(req, res) { - res.render('nonprofits/tell-us-your-email', { - title: 'Tell us your email', - step: 8 - }); + res.render('nonprofits/tell-us-your-email', { + title: 'Tell us your email', + step: 8 + }); }; exports.tellUsYourName = function(req, res) { - res.render('nonprofits/tell-us-your-name', { - title: 'Tell us your name', - step: 9 - }); + res.render('nonprofits/tell-us-your-name', { + title: 'Tell us your name', + step: 9 + }); }; exports.yourNonprofitProjectApplicationHasBeenSubmitted = function(req, res) { - res.render('nonprofits/your-nonprofit-project-application-has-been-submitted', { - title: 'Your Nonprofit Project application has been submitted!', - step: 10, - getBackDay: moment().weekday(5).format('dddd') - }); + res.render( + 'nonprofits/your-nonprofit-project-application-has-been-submitted', + { + title: 'Your Nonprofit Project application has been submitted!', + step: 10, + getBackDay: moment().weekday(5).format('dddd') + } + ); }; exports.otherSolutions = function(req, res) { - res.render('nonprofits/other-solutions', { - title: 'Here are some other possible solutions for you' - }); + res.render('nonprofits/other-solutions', { + title: 'Here are some other possible solutions for you' + }); }; exports.returnIndividualNonprofit = function(req, res, next) { - var dashedName = req.params.nonprofitName; + var dashedName = req.params.nonprofitName; + var nonprofitName = dashedName.replace(/\-/g, ' '); - var nonprofitName = dashedName.replace(/\-/g, ' '); + Nonprofit.find( + { name: new RegExp(nonprofitName, 'i') }, + function(err, nonprofit) { + if (err) { + return next(err); + } - Nonprofit.find({'name': new RegExp(nonprofitName, 'i')}, function(err, nonprofit) { - if (err) { - next(err); - } + if (nonprofit.length < 1) { + req.flash('errors', { + msg: "404: We couldn't find a nonprofit with that name. " + + 'Please double check the name.' + }); - if (nonprofit.length < 1) { - req.flash('errors', { - msg: "404: We couldn't find a nonprofit with that name. Please double check the name." - }); + return res.redirect('/nonprofits'); + } - return res.redirect('/nonprofits'); - } - - nonprofit = nonprofit.pop(); - var dashedNameFull = nonprofit.name.toLowerCase().replace(/\s/g, '-'); - if (dashedNameFull != dashedName) { - return res.redirect('../nonprofit/' + dashedNameFull); - } - var buttonActive = false; - if (req.user) { - if (req.user.uncompletedBonfires.length === 0) { - if (req.user.completedCoursewares.length > 63) { - var hasShownInterest = nonprofit.interestedCampers.filter(function ( obj ) { + nonprofit = nonprofit.pop(); + var dashedNameFull = nonprofit.name.toLowerCase().replace(/\s/g, '-'); + if (dashedNameFull !== dashedName) { + return res.redirect('../nonprofit/' + dashedNameFull); + } + var buttonActive = false; + if (req.user) { + if (req.user.uncompletedBonfires.length === 0) { + if (req.user.completedCoursewares.length > 63) { + var hasShownInterest = + nonprofit.interestedCampers.filter(function ( obj ) { return obj.username === req.user.profile.username; }); - if (hasShownInterest.length === 0) { - buttonActive = true; - } + + if (hasShownInterest.length === 0) { + buttonActive = true; } } } - res.render('nonprofits/show', { - dashedName: dashedNameFull, - title: nonprofit.name, - logoUrl: nonprofit.logoUrl, - estimatedHours: nonprofit.estimatedHours, - projectDescription: nonprofit.projectDescription, - approvedOther: nonprofit.approvedDeliverables.indexOf('other') > -1, - approvedWebsite: nonprofit.approvedDeliverables.indexOf('website') > -1, - approvedDonor: nonprofit.approvedDeliverables.indexOf('donor') > -1, - approvedInventory: nonprofit.approvedDeliverables.indexOf('inventory') > -1, - approvedVolunteer: nonprofit.approvedDeliverables.indexOf('volunteer') > -1, - approvedForm: nonprofit.approvedDeliverables.indexOf('form') > -1, - approvedCommunity: nonprofit.approvedDeliverables.indexOf('community') > -1, - approvedELearning: nonprofit.approvedDeliverables.indexOf('eLearning') > -1, - websiteLink: nonprofit.websiteLink, - imageUrl: nonprofit.imageUrl, - whatDoesNonprofitDo: nonprofit.whatDoesNonprofitDo, - interestedCampers: nonprofit.interestedCampers, - assignedCampers: nonprofit.assignedCampers, - buttonActive: buttonActive, - currentStatus: nonprofit.currentStatus - }); - }); + } + + res.render('nonprofits/show', { + dashedName: dashedNameFull, + title: nonprofit.name, + logoUrl: nonprofit.logoUrl, + estimatedHours: nonprofit.estimatedHours, + projectDescription: nonprofit.projectDescription, + + approvedOther: + nonprofit.approvedDeliverables.indexOf('other') > -1, + approvedWebsite: + nonprofit.approvedDeliverables.indexOf('website') > -1, + + approvedDonor: + nonprofit.approvedDeliverables.indexOf('donor') > -1, + approvedInventory: + nonprofit.approvedDeliverables.indexOf('inventory') > -1, + + approvedVolunteer: + nonprofit.approvedDeliverables.indexOf('volunteer') > -1, + approvedForm: + nonprofit.approvedDeliverables.indexOf('form') > -1, + + approvedCommunity: + nonprofit.approvedDeliverables.indexOf('community') > -1, + approvedELearning: + nonprofit.approvedDeliverables.indexOf('eLearning') > -1, + + websiteLink: nonprofit.websiteLink, + imageUrl: nonprofit.imageUrl, + whatDoesNonprofitDo: nonprofit.whatDoesNonprofitDo, + interestedCampers: nonprofit.interestedCampers, + assignedCampers: nonprofit.assignedCampers, + buttonActive: buttonActive, + currentStatus: nonprofit.currentStatus + }); + } + ); }; exports.showAllNonprofits = function(req, res) { - var data = {}; - data.nonprofitsList = resources.allNonprofitNames(); - res.send(data); + var data = {}; + data.nonprofitsList = resources.allNonprofitNames(); + res.send(data); }; -exports.interestedInNonprofit = function(req, res) { +exports.interestedInNonprofit = function(req, res, next) { if (req.user) { - Nonprofit.findOne({name: new RegExp(req.params.nonprofitName.replace(/-/, ' '), 'i')}, function(err, nonprofit) { - if (err) { return next(err); } - nonprofit.interestedCampers.push({"username": req.user.profile.username, - "picture": req.user.profile.picture, - "timeOfInterest": Date.now() - }); - nonprofit.save(function(err) { - if (err) { return done(err); } - req.flash('success', { msg: "Thanks for expressing interest in this nonprofit project! We've added you to this project as an interested camper!" }); - res.redirect('back'); - }); - }); + Nonprofit.findOne( + { name: new RegExp(req.params.nonprofitName.replace(/-/, ' '), 'i') }, + function(err, nonprofit) { + if (err) { return next(err); } + nonprofit.interestedCampers.push({ + username: req.user.profile.username, + picture: req.user.profile.picture, + timeOfInterest: Date.now() + }); + nonprofit.save(function(err) { + if (err) { return next(err); } + req.flash('success', { + msg: 'Thanks for expressing interest in this nonprofit project! ' + + "We've added you to this project as an interested camper!" + }); + res.redirect('back'); + }); + } + ); } }; diff --git a/controllers/resources.js b/controllers/resources.js index 5cc40bef64..9f80434b59 100644 --- a/controllers/resources.js +++ b/controllers/resources.js @@ -1,4 +1,15 @@ 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'), @@ -8,16 +19,7 @@ var async = require('async'), resources = require('./resources.json'), secrets = require('./../config/secrets'), nonprofits = require('../seed_data/nonprofits.json'), - fieldGuides = require('../seed_data/field-guides.json'), - moment = require('moment'), - Twit = require('twit'), - https = require('https'), - debug = require('debug')('freecc:cntr:resources'), - cheerio = require('cheerio'), - request = require('request'), - R = require('ramda'), - _ = require('lodash'), - fs = require('fs'); + fieldGuides = require('../seed_data/field-guides.json'); /** * Cached values @@ -45,11 +47,14 @@ Array.zip = function(left, right, combinerFunction) { (function() { if (!challengeMap) { var localChallengeMap = {}; - var files = fs.readdirSync(__dirname + '/../seed_data/challenges'); + var files = fs.readdirSync( + path.join(__dirname, '/../seed_data/challenges') + ); var keyCounter = 0; files = files.map(function (file) { - return require(__dirname + - '/../seed_data/challenges/' + file); + return require( + path.join(__dirname, '/../seed_data/challenges/' + file) + ); }); files = files.sort(function (a, b) { return a.order - b.order; @@ -208,13 +213,16 @@ module.exports = { res.redirect('http://freecode.slack.com'); } else { res.render('resources/chat', { - title: "Watch us code live on Twitch.tv" + title: 'Watch us code live on Twitch.tv' }); } }, 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.') + 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) { @@ -247,8 +255,8 @@ module.exports = { }); }, - unsubscribe: function unsubscribe(req, res) { - User.findOne({email: req.params.email}, function(err, user) { + unsubscribe: function unsubscribe(req, res, next) { + User.findOne({ email: req.params.email }, function(err, user) { if (user) { if (err) { return next(err); @@ -268,52 +276,106 @@ module.exports = { unsubscribed: function unsubscribed(req, res) { res.render('resources/unsubscribed', { - title: "You have been unsubscribed" + title: 'You have been unsubscribed' }); }, - githubCalls: function(req, res) { - var githubHeaders = {headers: {'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1521.3 Safari/537.36'}, port:80 }; - request('https://api.github.com/repos/freecodecamp/freecodecamp/pulls?client_id=' + secrets.github.clientID + '&client_secret=' + secrets.github.clientSecret, githubHeaders, function(err, status1, pulls) { - 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, githubHeaders, function (err, status2, issues) { - issues = ((pulls === parseInt(pulls)) && issues) ? Object.keys(JSON.parse(issues)).length - pulls : "Can't connect to GitHub"; - res.send({"issues": issues, "pulls" : pulls}); - }); - }); + 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)); - }); + 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)); - }); + 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 === "https://s3.amazonaws.com/freecodecamp/favicons/apple-touch-icon-180x180.png") { - req.user.profile.picture = "https://s3.amazonaws.com/freecodecamp/camper-image-placeholder.png"; + 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 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, ","); + return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ','); } User.count({}, function (err, c3) { if (err) { @@ -331,28 +393,30 @@ module.exports = { }, randomPhrase: function() { - return resources.phrases[Math.floor( - Math.random() * resources.phrases.length)]; + return resources.phrases[ + Math.floor(Math.random() * resources.phrases.length) + ]; }, randomVerb: function() { - return resources.verbs[Math.floor( - Math.random() * resources.verbs.length)]; + return resources.verbs[ + Math.floor(Math.random() * resources.verbs.length) + ]; }, randomCompliment: function() { - return resources.compliments[Math.floor( - Math.random() * resources.compliments.length)]; + 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; - }); + allFieldGuideIds = fieldGuides.map(function (elem) { + return elem._id; + }); return allFieldGuideIds; } }, @@ -361,12 +425,9 @@ module.exports = { if (allFieldGuideNames) { return allFieldGuideNames; } else { - allFieldGuideNames = fieldGuides. - map(function (elem) { - return { - name: elem.name - }; - }); + allFieldGuideNames = fieldGuides.map(function (elem) { + return { name: elem.name }; + }); return allFieldGuideNames; } }, @@ -375,12 +436,9 @@ module.exports = { if (allNonprofitNames) { return allNonprofitNames; } else { - allNonprofitNames = nonprofits. - map(function (elem) { - return { - name: elem.name - }; - }); + allNonprofitNames = nonprofits.map(function (elem) { + return { name: elem.name }; + }); return allNonprofitNames; } }, @@ -396,16 +454,25 @@ module.exports = { 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 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) + "..."; + 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('failed'); + callback(new Error('failed')); } }); })(); @@ -465,24 +532,33 @@ module.exports = { } }, codepenResources: { - twitter: function(req, res) { + 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 + '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, response) { - return res.json(data); - }); + 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 diff --git a/controllers/story.js b/controllers/story.js index cfde5345ef..8c01bedd2c 100755 --- a/controllers/story.js +++ b/controllers/story.js @@ -1,16 +1,13 @@ -/* eslint-disable no-catch-shadow, no-unused-vars */ -var R = require('ramda'), - debug = require('debug')('freecc:cntr:story'), +var moment = require('moment'), + mongodb = require('mongodb'), + nodemailer = require('nodemailer'), + sanitizeHtml = require('sanitize-html'), + MongoClient = mongodb.MongoClient, + resources = require('./resources'), + secrets = require('../config/secrets'), Story = require('./../models/Story'), Comment = require('./../models/Comment'), - User = require('./../models/User'), - moment = require('moment'), - resources = require('./resources'), - mongodb = require('mongodb'), - MongoClient = mongodb.MongoClient, - secrets = require('../config/secrets'), - nodemailer = require('nodemailer'), - sanitizeHtml = require('sanitize-html'); + User = require('./../models/User'); function hotRank(timeValue, rank) { /* @@ -128,7 +125,8 @@ exports.returnIndividualStory = function(req, res, next) { if (story.length < 1) { req.flash('errors', { - msg: "404: We couldn't find a story with that name. Please double check the name." + msg: "404: We couldn't find a story with that name. " + + 'Please double check the name.' }); return res.redirect('/news/'); @@ -148,7 +146,7 @@ exports.returnIndividualStory = function(req, res, next) { if (votedObj.length > 0) { userVoted = true; } - } catch(err) { + } catch(e) { userVoted = false; } res.render('stories/index', { @@ -229,15 +227,14 @@ exports.upvote = function(req, res, next) { ); story.markModified('rank'); story.save(); - User.find({'_id': story.author.userId}, function(err, user) { - 'use strict'; + User.find({ '_id': story.author.userId }, function(err, user) { if (err) { return next(err); } user = user.pop(); user.progressTimestamps.push(Date.now() || 0); - user.save(function (err, user) { - req.user.save(function (err, user) { + user.save(function (err) { + req.user.save(function (err) { if (err) { return next(err); } @@ -339,61 +336,64 @@ exports.storySubmission = function(req, res, next) { if (link.search(/^https?:\/\//g) === -1) { link = 'http://' + link; } - Story.count({'storyLink': new RegExp('^' + storyLink + '(?: [0-9]+)?$', 'i')}, function (err, storyCount) { - if (err) { - return res.status(500); - } - - // if duplicate storyLink add unique number - storyLink = (storyCount === 0) ? storyLink : storyLink + ' ' + storyCount; - - var link = data.link; - if (link.search(/^https?:\/\//g) === -1) { - link = 'http://' + link; - } - var story = new Story({ - headline: sanitizeHtml(data.headline, { - allowedTags: [], - allowedAttributes: [] - }).replace(/"/g, '"'), - timePosted: Date.now(), - link: link, - description: sanitizeHtml(data.description, { - allowedTags: [], - allowedAttributes: [] - }).replace(/"/g, '"'), - rank: 1, - upVotes: [({ - upVotedBy: req.user._id, - upVotedByUsername: req.user.profile.username - })], - author: { - picture: req.user.profile.picture, - userId: req.user._id, - username: req.user.profile.username, - email: req.user.email - }, - comments: [], - image: data.image, - storyLink: storyLink, - metaDescription: data.storyMetaDescription, - originalStoryAuthorEmail: req.user.email - }); - story.save(function (err) { + Story.count( + { storyLink: new RegExp('^' + storyLink + '(?: [0-9]+)?$', 'i') }, + function (err, storyCount) { if (err) { return res.status(500); } - req.user.progressTimestamps.push(Date.now() || 0); - req.user.save(function (err, user) { - if (err) { - return next(err); - } + + // if duplicate storyLink add unique number + storyLink = (storyCount === 0) ? storyLink : storyLink + ' ' + storyCount; + + var link = data.link; + if (link.search(/^https?:\/\//g) === -1) { + link = 'http://' + link; + } + var story = new Story({ + headline: sanitizeHtml(data.headline, { + allowedTags: [], + allowedAttributes: [] + }).replace(/"/g, '"'), + timePosted: Date.now(), + link: link, + description: sanitizeHtml(data.description, { + allowedTags: [], + allowedAttributes: [] + }).replace(/"/g, '"'), + rank: 1, + upVotes: [({ + upVotedBy: req.user._id, + upVotedByUsername: req.user.profile.username + })], + author: { + picture: req.user.profile.picture, + userId: req.user._id, + username: req.user.profile.username, + email: req.user.email + }, + comments: [], + image: data.image, + storyLink: storyLink, + metaDescription: data.storyMetaDescription, + originalStoryAuthorEmail: req.user.email }); - res.send(JSON.stringify({ - storyLink: story.storyLink.replace(/\s/g, '-').toLowerCase() - })); - }); - }); + story.save(function (err) { + if (err) { + return res.status(500); + } + req.user.progressTimestamps.push(Date.now() || 0); + req.user.save(function (err) { + if (err) { + return next(err); + } + }); + res.send(JSON.stringify({ + storyLink: story.storyLink.replace(/\s/g, '-').toLowerCase() + })); + }); + } + ); }; exports.commentSubmit = function(req, res, next) { @@ -513,58 +513,76 @@ exports.storySubmission = function(req, res, next) { return next(err); } try { - // Based on the context retrieve the parent object of the comment (Story/Comment) - Context.find({'_id': data.associatedPost}, function (err, associatedContext) { - if (err) { - return next(err); - } - associatedContext = associatedContext.pop(); - if (associatedContext) { - associatedContext.comments.push(data._id); - associatedContext.save(function (err) { - if (err) { - return next(err); - } - res.send(true); - }); - } - // Find the author of the parent object - User.findOne({'profile.username': associatedContext.author.username}, function(err, recipient) { + // Based on the context retrieve the parent + // object of the comment (Story/Comment) + Context.find( + { '_id': data.associatedPost }, + function (err, associatedContext) { if (err) { return next(err); } - // If the emails of both authors differ, only then proceed with email notification - if (typeof data.author !== 'undefined' && data.author.email && typeof recipient !== 'undefined' && recipient.email && (data.author.email !== recipient.email)) { - var transporter = nodemailer.createTransport({ - service: 'Mandrill', - auth: { - user: secrets.mandrill.user, - pass: secrets.mandrill.password - } - }); - - var mailOptions = { - to: recipient.email, - from: 'Team@freecodecamp.com', - subject: data.author.username + ' replied to your post on Camper News', - text: [ - 'Just a quick heads-up: ' + data.author.username + ' replied to you on Camper News.', - 'You can keep this conversation going.', - 'Just head back to the discussion here: http://freecodecamp.com/news/' + data.originalStoryLink, - '- the Free Code Camp Volunteer Team' - ].join('\n') - }; - - transporter.sendMail(mailOptions, function (err) { + associatedContext = associatedContext.pop(); + if (associatedContext) { + associatedContext.comments.push(data._id); + associatedContext.save(function (err) { if (err) { - return err; + return next(err); } + res.send(true); }); } - }); - }); + // Find the author of the parent object + User.findOne( + { 'profile.username': associatedContext.author.username }, + function(err, recipient) { + if (err) { + return next(err); + } + // If the emails of both authors differ, + // only then proceed with email notification + if ( + typeof data.author !== 'undefined' && + data.author.email && + typeof recipient !== 'undefined' && + recipient.email && + (data.author.email !== recipient.email) + ) { + var transporter = nodemailer.createTransport({ + service: 'Mandrill', + auth: { + user: secrets.mandrill.user, + pass: secrets.mandrill.password + } + }); + + var mailOptions = { + to: recipient.email, + from: 'Team@freecodecamp.com', + subject: data.author.username + + ' replied to your post on Camper News', + text: [ + 'Just a quick heads-up: ', + data.author.username, + ' replied to you on Camper News.', + 'You can keep this conversation going.', + 'Just head back to the discussion here: ', + 'http://freecodecamp.com/news/', + data.originalStoryLink, + '- the Free Code Camp Volunteer Team' + ].join('\n') + }; + + transporter.sendMail(mailOptions, function (err) { + if (err) { + return err; + } + }); + } + } + ); + } + ); } catch (e) { - // delete comment return next(err); } }); diff --git a/controllers/user.js b/controllers/user.js index 29840dbc29..ae434c4a22 100644 --- a/controllers/user.js +++ b/controllers/user.js @@ -102,15 +102,13 @@ exports.getEmailSignup = function(req, res) { */ exports.postEmailSignup = function(req, res, next) { + req.assert('email', 'valid email required').isEmail(); + var errors = req.validationErrors(); - - req.assert('email', 'valid email required').isEmail(); - var errors = req.validationErrors(); - - if (errors) { - req.flash('errors', errors); - return res.redirect('/email-signup'); - } + if (errors) { + req.flash('errors', errors); + return res.redirect('/email-signup'); + } var possibleUserData = req.body; @@ -134,7 +132,8 @@ exports.postEmailSignup = function(req, res, next) { password: req.body.password, profile: { username: req.body.username.trim(), - picture: 'https://s3.amazonaws.com/freecodecamp/camper-image-placeholder.png' + picture: + 'https://s3.amazonaws.com/freecodecamp/camper-image-placeholder.png' } }); @@ -149,7 +148,9 @@ exports.postEmailSignup = function(req, res, next) { }); return res.redirect('/email-signup'); } - User.findOne({'profile.username': req.body.username }, function(err, existingUsername) { + User.findOne( + { 'profile.username': req.body.username }, + function(err, existingUsername) { if (err) { return next(err); } @@ -181,8 +182,10 @@ exports.postEmailSignup = function(req, res, next) { text: [ 'Greetings from San Francisco!\n\n', 'Thank you for joining our community.\n', - 'Feel free to email us at this address if you have any questions about Free Code Camp.\n', - 'And if you have a moment, check out our blog: blog.freecodecamp.com.\n', + 'Feel free to email us at this address if you have ', + 'any questions about Free Code Camp.\n', + 'And if you have a moment, check out our blog: ', + 'blog.freecodecamp.com.\n', 'Good luck with the challenges!\n\n', '- the Volunteer Camp Counselor Team' ].join('') @@ -220,28 +223,33 @@ exports.getAccountAngular = function(req, res) { */ exports.checkUniqueUsername = function(req, res, next) { - User.count({'profile.username': req.params.username.toLowerCase()}, function (err, data) { - if (err) { return next(err); } - if (data == 1) { - return res.send(true); - } else { - return res.send(false); - } - }); + User.count( + { 'profile.username': req.params.username.toLowerCase() }, + function (err, data) { + if (err) { return next(err); } + if (data === 1) { + return res.send(true); + } else { + return res.send(false); + } + }); }; /** * Existing username check */ exports.checkExistingUsername = function(req, res, next) { - User.count({'profile.username': req.params.username.toLowerCase()}, function (err, data) { - if (err) { return next(err); } - if (data === 1) { - return res.send(true); - } else { - return res.send(false); - } - }); + User.count( + { 'profile.username': req.params.username.toLowerCase() }, + function (err, data) { + if (err) { return next(err); } + if (data === 1) { + return res.send(true); + } else { + return res.send(false); + } + } + ); }; /** @@ -249,14 +257,17 @@ exports.checkExistingUsername = function(req, res, next) { */ exports.checkUniqueEmail = function(req, res, next) { - User.count({'email': decodeURIComponent(req.params.email).toLowerCase()}, function (err, data) { - if (err) { return next(err); } - if (data === 1) { - return res.send(true); - } else { - return res.send(false); - } - }); + User.count( + { email: decodeURIComponent(req.params.email).toLowerCase() }, + function (err, data) { + if (err) { return next(err); } + if (data === 1) { + return res.send(true); + } else { + return res.send(false); + } + } + ); }; @@ -266,117 +277,133 @@ exports.checkUniqueEmail = function(req, res, next) { */ exports.returnUser = function(req, res, next) { - User.find({'profile.username': req.params.username.toLowerCase()}, function(err, user) { - if (err) { debug('Username err: ', err); next(err); } - if (user[0]) { - user = user[0]; - - user.progressTimestamps = user.progressTimestamps.sort(function(a, b) { - return a - b; - }); - - var timeObject = Object.create(null); - R.forEach(function(time) { - timeObject[moment(time).format('YYYY-MM-DD')] = time; - }, user.progressTimestamps); - - var tmpLongest = 1; - var timeKeys = R.keys(timeObject); - - user.longestStreak = 0; - for (var i = 1; i <= timeKeys.length; i++) { - if (moment(timeKeys[i - 1]).add(1, 'd').toString() - === moment(timeKeys[i]).toString()) { - tmpLongest++; - if (tmpLongest > user.longestStreak) { - user.longestStreak = tmpLongest; - } - } else { - tmpLongest = 1; - } + User.find( + { 'profile.username': req.params.username.toLowerCase() }, + function(err, user) { + if (err) { + debug('Username err: ', err); + return next(err); } + if (user[0]) { + user = user[0]; - timeKeys = timeKeys.reverse(); - tmpLongest = 1; + user.progressTimestamps = user.progressTimestamps.sort(function(a, b) { + return a - b; + }); - user.currentStreak = 1; - var today = moment(Date.now()).format('YYYY-MM-DD'); + var timeObject = Object.create(null); + R.forEach(function(time) { + timeObject[moment(time).format('YYYY-MM-DD')] = time; + }, user.progressTimestamps); - if (moment(today).toString() === moment(timeKeys[0]).toString() || - moment(today).subtract(1, 'd').toString() === - moment(timeKeys[0]).toString()) { + var tmpLongest = 1; + var timeKeys = R.keys(timeObject); + + user.longestStreak = 0; for (var i = 1; i <= timeKeys.length; i++) { - if (moment(timeKeys[i - 1]).subtract(1, 'd').toString() + if (moment(timeKeys[i - 1]).add(1, 'd').toString() === moment(timeKeys[i]).toString()) { - debug(timeKeys[i - 1], timeKeys[i]); tmpLongest++; - if (tmpLongest > user.currentStreak) { - user.currentStreak = tmpLongest; + if (tmpLongest > user.longestStreak) { + user.longestStreak = tmpLongest; } } else { - break; + tmpLongest = 1; } } - } else { + + timeKeys = timeKeys.reverse(); + tmpLongest = 1; + user.currentStreak = 1; - } + var today = moment(Date.now()).format('YYYY-MM-DD'); - user.save(function(err) { - if (err) { - return next(err); + if ( + moment(today).toString() === moment(timeKeys[0]).toString() || + moment(today).subtract(1, 'd').toString() === + moment(timeKeys[0]).toString() + ) { + for (var _i = 1; _i <= timeKeys.length; _i++) { + + if ( + moment(timeKeys[_i - 1]).subtract(1, 'd').toString() === + moment(timeKeys[_i]).toString() + ) { + + debug(timeKeys[_i - 1], timeKeys[_i]); + tmpLongest++; + + if (tmpLongest > user.currentStreak) { + user.currentStreak = tmpLongest; + } + } else { + break; + } + } + } else { + user.currentStreak = 1; } - }); - var data = {}; - var progressTimestamps = user.progressTimestamps; - progressTimestamps.forEach(function(timeStamp) { - data[(timeStamp / 1000)] = 1; - }); + user.save(function(err) { + if (err) { + return next(err); + } - user.currentStreak = user.currentStreak || 1; - user.longestStreak = user.longestStreak || 1; - var challenges = user.completedCoursewares.filter(function ( obj ) { - return !!obj.solution; - }); - res.render('account/show', { - title: 'Camper ' + user.profile.username + '\'s portfolio', - username: user.profile.username, - name: user.profile.name, - location: user.profile.location, - githubProfile: user.profile.githubProfile, - linkedinProfile: user.profile.linkedinProfile, - codepenProfile: user.profile.codepenProfile, - facebookProfile: user.profile.facebookProfile, - twitterHandle: user.profile.twitterHandle, - bio: user.profile.bio, - picture: user.profile.picture, - progressTimestamps: user.progressTimestamps, - website1Link: user.portfolio.website1Link, - website1Title: user.portfolio.website1Title, - website1Image: user.portfolio.website1Image, - website2Link: user.portfolio.website2Link, - website2Title: user.portfolio.website2Title, - website2Image: user.portfolio.website2Image, - website3Link: user.portfolio.website3Link, - website3Title: user.portfolio.website3Title, - website3Image: user.portfolio.website3Image, - challenges: challenges, - bonfires: user.completedChallenges.filter(function(challenge) { - return challenge.challengeType === 5; - }), - calender: data, - moment: moment, - longestStreak: user.longestStreak + (user.longestStreak === 1 ? " day" : " days"), - currentStreak: user.currentStreak + (user.currentStreak === 1 ? " day" : " days") - }); + var data = {}; + var progressTimestamps = user.progressTimestamps; + progressTimestamps.forEach(function(timeStamp) { + data[(timeStamp / 1000)] = 1; + }); - } else { - req.flash('errors', { - msg: "404: We couldn't find a page with that url. Please double check the link." - }); - return res.redirect('/'); + user.currentStreak = user.currentStreak || 1; + user.longestStreak = user.longestStreak || 1; + var challenges = user.completedCoursewares.filter(function ( obj ) { + return !!obj.solution; + }); + + res.render('account/show', { + title: 'Camper ' + user.profile.username + '\'s portfolio', + username: user.profile.username, + name: user.profile.name, + location: user.profile.location, + githubProfile: user.profile.githubProfile, + linkedinProfile: user.profile.linkedinProfile, + codepenProfile: user.profile.codepenProfile, + facebookProfile: user.profile.facebookProfile, + twitterHandle: user.profile.twitterHandle, + bio: user.profile.bio, + picture: user.profile.picture, + progressTimestamps: user.progressTimestamps, + website1Link: user.portfolio.website1Link, + website1Title: user.portfolio.website1Title, + website1Image: user.portfolio.website1Image, + website2Link: user.portfolio.website2Link, + website2Title: user.portfolio.website2Title, + website2Image: user.portfolio.website2Image, + website3Link: user.portfolio.website3Link, + website3Title: user.portfolio.website3Title, + website3Image: user.portfolio.website3Image, + challenges: challenges, + bonfires: user.completedChallenges.filter(function(challenge) { + return challenge.challengeType === 5; + }), + calender: data, + moment: moment, + longestStreak: user.longestStreak + + (user.longestStreak === 1 ? ' day' : ' days'), + currentStreak: user.currentStreak + + (user.currentStreak === 1 ? ' day' : ' days') + }); + }); + } else { + req.flash('errors', { + msg: "404: We couldn't find a page with that url. " + + 'Please double check the link.' + }); + return res.redirect('/'); + } } - }); + ); }; @@ -385,9 +412,9 @@ exports.returnUser = function(req, res, next) { * Update profile information. */ -exports.updateProgress = function(req, res) { +exports.updateProgress = function(req, res, next) { User.findById(req.user.id, function(err, user) { - if (err) return next(err); + if (err) { return next(err); } user.email = req.body.email || ''; user.profile.name = req.body.name || ''; user.profile.gender = req.body.gender || ''; @@ -395,7 +422,7 @@ exports.updateProgress = function(req, res) { user.profile.website = req.body.website || ''; user.save(function(err) { - if (err) return next(err); + if (err) { return next(err); } req.flash('success', { msg: 'Profile information updated.' }); res.redirect('/account'); }); @@ -409,8 +436,8 @@ exports.updateProgress = function(req, res) { exports.postUpdateProfile = function(req, res, next) { - User.findById(req.user.id, function(err, user) { - if (err) return next(err); + User.findById(req.user.id, function(err) { + if (err) { return next(err); } var errors = req.validationErrors(); if (errors) { req.flash('errors', errors); @@ -422,63 +449,72 @@ exports.postUpdateProfile = function(req, res, next) { return next(err); } var user = req.user; - if (existingEmail && existingEmail.email != user.email) { + if (existingEmail && existingEmail.email !== user.email) { req.flash('errors', { - msg: "An account with that email address already exists." + msg: 'An account with that email address already exists.' }); return res.redirect('/account'); } - User.findOne({ 'profile.username': req.body.username }, function(err, existingUsername) { - if (err) { - return next(err); - } - var user = req.user; - if (existingUsername && existingUsername.profile.username !== user.profile.username) { - req.flash('errors', { - msg: 'An account with that username already exists.' - }); - return res.redirect('/account'); - } - user.email = req.body.email.trim() || ''; - user.profile.name = req.body.name.trim() || ''; - user.profile.username = req.body.username.trim() || ''; - user.profile.location = req.body.location.trim() || ''; - user.profile.githubProfile = req.body.githubProfile.trim() || ''; - user.profile.facebookProfile = req.body.facebookProfile.trim() || ''; - user.profile.linkedinProfile = req.body.linkedinProfile.trim() || ''; - user.profile.codepenProfile = req.body.codepenProfile.trim() || ''; - user.profile.twitterHandle = req.body.twitterHandle.trim() || ''; - user.profile.bio = req.body.bio.trim() || ''; - user.profile.picture = req.body.picture.trim() || 'https://s3.amazonaws.com/freecodecamp/camper-image-placeholder.png'; - user.portfolio.website1Title = req.body.website1Title.trim() || ''; - user.portfolio.website1Link = req.body.website1Link.trim() || ''; - user.portfolio.website1Image = req.body.website1Image.trim() || ''; - user.portfolio.website2Title = req.body.website2Title.trim() || ''; - user.portfolio.website2Link = req.body.website2Link.trim() || ''; - user.portfolio.website2Image = req.body.website2Image.trim() || ''; - user.portfolio.website3Title = req.body.website3Title.trim() || ''; - user.portfolio.website3Link = req.body.website3Link.trim() || ''; - user.portfolio.website3Image = req.body.website3Image.trim() || ''; - - - user.save(function (err) { + User.findOne( + { 'profile.username': req.body.username }, + function(err, existingUsername) { if (err) { return next(err); } - resources.updateUserStoryPictures( - user._id.toString(), - user.profile.picture, - user.profile.username, - function(err) { - if (err) { return next(err); } - req.flash('success', { - msg: 'Profile information updated.' - }); - res.redirect('/account'); + var user = req.user; + if ( + existingUsername && + existingUsername.profile.username !== user.profile.username + ) { + req.flash('errors', { + msg: 'An account with that username already exists.' + }); + return res.redirect('/account'); + } + user.email = req.body.email.trim() || ''; + user.profile.name = req.body.name.trim() || ''; + user.profile.username = req.body.username.trim() || ''; + user.profile.location = req.body.location.trim() || ''; + user.profile.githubProfile = req.body.githubProfile.trim() || ''; + user.profile.facebookProfile = req.body.facebookProfile.trim() || ''; + user.profile.linkedinProfile = req.body.linkedinProfile.trim() || ''; + user.profile.codepenProfile = req.body.codepenProfile.trim() || ''; + user.profile.twitterHandle = req.body.twitterHandle.trim() || ''; + user.profile.bio = req.body.bio.trim() || ''; + + user.profile.picture = req.body.picture.trim() || + 'https://s3.amazonaws.com/freecodecamp/' + + 'camper-image-placeholder.png'; + user.portfolio.website1Title = req.body.website1Title.trim() || ''; + user.portfolio.website1Link = req.body.website1Link.trim() || ''; + user.portfolio.website1Image = req.body.website1Image.trim() || ''; + user.portfolio.website2Title = req.body.website2Title.trim() || ''; + user.portfolio.website2Link = req.body.website2Link.trim() || ''; + user.portfolio.website2Image = req.body.website2Image.trim() || ''; + user.portfolio.website3Title = req.body.website3Title.trim() || ''; + user.portfolio.website3Link = req.body.website3Link.trim() || ''; + user.portfolio.website3Image = req.body.website3Image.trim() || ''; + + + user.save(function (err) { + if (err) { + return next(err); } - ); - }); - }); + resources.updateUserStoryPictures( + user._id.toString(), + user.profile.picture, + user.profile.username, + function(err) { + if (err) { return next(err); } + req.flash('success', { + msg: 'Profile information updated.' + }); + res.redirect('/account'); + } + ); + }); + } + ); }); }); }; @@ -538,7 +574,7 @@ exports.getOauthUnlink = function(req, res, next) { User.findById(req.user.id, function(err, user) { if (err) { return next(err); } - user[provider] = undefined; + user[provider] = null; user.tokens = _.reject(user.tokens, function(token) { return token.kind === provider; @@ -557,7 +593,7 @@ exports.getOauthUnlink = function(req, res, next) { * Reset Password page. */ -exports.getReset = function(req, res) { +exports.getReset = function(req, res, next) { if (req.isAuthenticated()) { return res.redirect('/'); } @@ -607,8 +643,8 @@ exports.postReset = function(req, res, next) { } user.password = req.body.password; - user.resetPasswordToken = undefined; - user.resetPasswordExpires = undefined; + user.resetPasswordToken = null; + user.resetPasswordExpires = null; user.save(function(err) { if (err) { return done(err); } From 96556a4a87295f52eb9d3e0d525fdbb76190dee4 Mon Sep 17 00:00:00 2001 From: terakilobyte Date: Fri, 22 May 2015 08:34:28 -0400 Subject: [PATCH 4/5] Fix email-signin redirect when logging in from camper news --- controllers/user.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/controllers/user.js b/controllers/user.js index ae434c4a22..cd961db05a 100644 --- a/controllers/user.js +++ b/controllers/user.js @@ -53,6 +53,9 @@ exports.postSignin = function(req, res, next) { return next(err); } req.flash('success', { msg: 'Success! You are logged in.' }); + if (/hotStories/.test(req.session.returnTo)) { + return res.redirect('../news'); + } return res.redirect(req.session.returnTo || '/'); }); })(req, res, next); From fd8a291ecd4c7a1137c8062225ca98d2577190f5 Mon Sep 17 00:00:00 2001 From: terakilobyte Date: Fri, 22 May 2015 08:39:03 -0400 Subject: [PATCH 5/5] Fix import of constantStrings.json in resources controller --- controllers/resources.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/controllers/resources.js b/controllers/resources.js index 9f80434b59..1f0235697f 100644 --- a/controllers/resources.js +++ b/controllers/resources.js @@ -9,7 +9,7 @@ var async = require('async'), _ = require('lodash'), fs = require('fs'), - constantStrings = require('constantStrings.json'), + constantStrings = require('./constantStrings.json'), User = require('../models/User'), Challenge = require('./../models/Challenge'), Story = require('./../models/Story'),