From d3b56989c42d5cae43c639ab6f65d51ab00d09f9 Mon Sep 17 00:00:00 2001 From: Michael Q Larson Date: Mon, 22 Dec 2014 14:26:02 -0800 Subject: [PATCH 01/20] comment new relic --- app.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app.js b/app.js index cb0abde460..ba8d06029d 100644 --- a/app.js +++ b/app.js @@ -1,7 +1,7 @@ /** * Module dependencies. */ -require('newrelic'); +//require('newrelic'); var express = require('express'); var debug = require('debug')('freecc:server'); var cookieParser = require('cookie-parser'); From 2245aa6818480672efbf231834612a33ed7e27ba Mon Sep 17 00:00:00 2001 From: Michael Q Larson Date: Mon, 22 Dec 2014 14:33:25 -0800 Subject: [PATCH 02/20] update the api controller --- app.js | 2 +- controllers/api.js | 465 --------------------------------------------- 2 files changed, 1 insertion(+), 466 deletions(-) diff --git a/app.js b/app.js index ba8d06029d..cb0abde460 100644 --- a/app.js +++ b/app.js @@ -1,7 +1,7 @@ /** * Module dependencies. */ -//require('newrelic'); +require('newrelic'); var express = require('express'); var debug = require('debug')('freecc:server'); var cookieParser = require('cookie-parser'); diff --git a/controllers/api.js b/controllers/api.js index b395a756a6..41b38606e5 100644 --- a/controllers/api.js +++ b/controllers/api.js @@ -6,16 +6,9 @@ var async = require('async'); var cheerio = require('cheerio'); var request = require('request'); var graph = require('fbgraph'); -var LastFmNode = require('lastfm').LastFmNode; -var tumblr = require('tumblr.js'); -var foursquare = require('node-foursquare')({ secrets: secrets.foursquare }); var Github = require('github-api'); var Twit = require('twit'); -var stripe = require('stripe')(secrets.stripe.secretKey); -var twilio = require('twilio')(secrets.twilio.sid, secrets.twilio.token); var Linkedin = require('node-linkedin')(secrets.linkedin.clientID, secrets.linkedin.clientSecret, secrets.linkedin.callbackURL); -var clockwork = require('clockwork')({key: secrets.clockwork.apiKey}); -var ig = require('instagram-node').instagram(); var Y = require('yui/yql'); var _ = require('lodash'); @@ -30,64 +23,6 @@ exports.getApi = function(req, res) { }); }; -/** - * GET /api/foursquare - * Foursquare API example. - */ - -exports.getFoursquare = function(req, res, next) { - var token = _.find(req.user.tokens, { kind: 'foursquare' }); - async.parallel({ - trendingVenues: function(callback) { - foursquare.Venues.getTrending('40.7222756', '-74.0022724', { limit: 50 }, token.accessToken, function(err, results) { - callback(err, results); - }); - }, - venueDetail: function(callback) { - foursquare.Venues.getVenue('49da74aef964a5208b5e1fe3', token.accessToken, function(err, results) { - callback(err, results); - }); - }, - userCheckins: function(callback) { - foursquare.Users.getCheckins('self', null, token.accessToken, function(err, results) { - callback(err, results); - }); - } - }, - function(err, results) { - if (err) return next(err); - res.render('api/foursquare', { - title: 'Foursquare API', - trendingVenues: results.trendingVenues, - venueDetail: results.venueDetail, - userCheckins: results.userCheckins - }); - }); -}; - -/** - * GET /api/tumblr - * Tumblr API example. - */ - -exports.getTumblr = function(req, res, next) { - var token = _.find(req.user.tokens, { kind: 'tumblr' }); - var client = tumblr.createClient({ - consumer_key: secrets.tumblr.consumerKey, - consumer_secret: secrets.tumblr.consumerSecret, - token: token.accessToken, - token_secret: token.tokenSecret - }); - client.posts('withinthisnightmare.tumblr.com', { type: 'photo' }, function(err, data) { - if (err) return next(err); - res.render('api/tumblr', { - title: 'Tumblr API', - blog: data.blog, - photoset: data.posts[0].photos - }); - }); -}; - /** * GET /api/facebook * Facebook API example. @@ -118,26 +53,6 @@ exports.getFacebook = function(req, res, next) { }); }; -/** - * GET /api/scraping - * Web scraping example using Cheerio library. - */ - -exports.getScraping = function(req, res, next) { - request.get('https://news.ycombinator.com/', function(err, request, body) { - if (err) return next(err); - var $ = cheerio.load(body); - var links = []; - $('.title a[href^="http"], a[href^="https"]').each(function() { - links.push($(this)); - }); - res.render('api/scraping', { - title: 'Web Scraping', - links: links - }); - }); -}; - /** * GET /api/github * GitHub API Example. @@ -154,112 +69,6 @@ exports.getGithub = function(req, res, next) { repo: repo }); }); - -}; - -/** - * GET /api/aviary - * Aviary image processing example. - */ - -exports.getAviary = function(req, res) { - res.render('api/aviary', { - title: 'Aviary API' - }); -}; - -/** - * GET /api/nyt - * New York Times API example. - */ - -exports.getNewYorkTimes = function(req, res, next) { - var query = querystring.stringify({ 'api-key': secrets.nyt.key, 'list-name': 'young-adult' }); - var url = 'http://api.nytimes.com/svc/books/v2/lists?' + query; - request.get(url, function(err, request, body) { - if (err) return next(err); - if (request.statusCode === 403) return next(Error('Missing or Invalid New York Times API Key')); - var bestsellers = JSON.parse(body); - res.render('api/nyt', { - title: 'New York Times API', - books: bestsellers.results - }); - }); -}; - -/** - * GET /api/lastfm - * Last.fm API example. - */ - -exports.getLastfm = function(req, res, next) { - var lastfm = new LastFmNode(secrets.lastfm); - async.parallel({ - artistInfo: function(done) { - lastfm.request('artist.getInfo', { - artist: 'The Pierces', - handlers: { - success: function(data) { - done(null, data); - }, - error: function(err) { - done(err); - } - } - }); - }, - artistTopTracks: function(done) { - lastfm.request('artist.getTopTracks', { - artist: 'The Pierces', - handlers: { - success: function(data) { - var tracks = []; - _.each(data.toptracks.track, function(track) { - tracks.push(track); - }); - done(null, tracks.slice(0,10)); - }, - error: function(err) { - done(err); - } - } - }); - }, - artistTopAlbums: function(done) { - lastfm.request('artist.getTopAlbums', { - artist: 'The Pierces', - handlers: { - success: function(data) { - var albums = []; - _.each(data.topalbums.album, function(album) { - albums.push(album.image.slice(-1)[0]['#text']); - }); - done(null, albums.slice(0, 4)); - }, - error: function(err) { - done(err); - } - } - }); - } - }, - function(err, results) { - if (err) return next(err.message); - var artist = { - name: results.artistInfo.artist.name, - image: results.artistInfo.artist.image.slice(-1)[0]['#text'], - tags: results.artistInfo.artist.tags.tag, - bio: results.artistInfo.artist.bio.summary, - stats: results.artistInfo.artist.stats, - similar: results.artistInfo.artist.similar.artist, - topAlbums: results.artistTopAlbums, - topTracks: results.artistTopTracks - }; - res.render('api/lastfm', { - title: 'Last.fm API', - artist: artist - }); - }); }; /** @@ -310,221 +119,6 @@ exports.postTwitter = function(req, res, next) { }); }; -/** - * GET /api/steam - * Steam API example. - */ - -exports.getSteam = function(req, res, next) { - var steamId = '76561197982488301'; - var query = { l: 'english', steamid: steamId, key: secrets.steam.apiKey }; - async.parallel({ - playerAchievements: function(done) { - query.appid = '49520'; - var qs = querystring.stringify(query); - request.get({ url: 'http://api.steampowered.com/ISteamUserStats/GetPlayerAchievements/v0001/?' + qs, json: true }, function(error, request, body) { - if (request.statusCode === 401) return done(new Error('Missing or Invalid Steam API Key')); - done(error, body); - }); - }, - playerSummaries: function(done) { - query.steamids = steamId; - var qs = querystring.stringify(query); - request.get({ url: 'http://api.steampowered.com/ISteamUser/GetPlayerSummaries/v0002/?' + qs, json: true }, function(err, request, body) { - if (request.statusCode === 401) return done(new Error('Missing or Invalid Steam API Key')); - done(err, body); - }); - }, - ownedGames: function(done) { - query.include_appinfo = 1; - query.include_played_free_games = 1; - var qs = querystring.stringify(query); - request.get({ url: 'http://api.steampowered.com/IPlayerService/GetOwnedGames/v0001/?' + qs, json: true }, function(err, request, body) { - if (request.statusCode === 401) return done(new Error('Missing or Invalid Steam API Key')); - done(err, body); - }); - } - }, - function(err, results) { - if (err) return next(err); - res.render('api/steam', { - title: 'Steam Web API', - ownedGames: results.ownedGames.response.games, - playerAchievemments: results.playerAchievements.playerstats, - playerSummary: results.playerSummaries.response.players[0] - }); - }); -}; - -/** - * GET /api/stripe - * Stripe API example. - */ - -exports.getStripe = function(req, res) { - res.render('api/stripe', { - title: 'Stripe API', - publishableKey: secrets.stripe.publishableKey - }); -}; - -/** - * POST /api/stripe - * Make a payment. - */ - -exports.postStripe = function(req, res, next) { - var stripeToken = req.body.stripeToken; - var stripeEmail = req.body.stripeEmail; - stripe.charges.create({ - amount: 395, - currency: 'usd', - card: stripeToken, - description: stripeEmail - }, function(err, charge) { - if (err && err.type === 'StripeCardError') { - req.flash('errors', { msg: 'Your card has been declined.' }); - res.redirect('/api/stripe'); - } - req.flash('success', { msg: 'Your card has been charged successfully.' }); - res.redirect('/api/stripe'); - }); -}; - -/** - * GET /api/twilio - * Twilio API example. - */ - -exports.getTwilio = function(req, res) { - res.render('api/twilio', { - title: 'Twilio API' - }); -}; - -/** - * POST /api/twilio - * Send a text message using Twilio. - */ - -exports.postTwilio = function(req, res, next) { - req.assert('number', 'Phone number is required.').notEmpty(); - req.assert('message', 'Message cannot be blank.').notEmpty(); - var errors = req.validationErrors(); - if (errors) { - req.flash('errors', errors); - return res.redirect('/api/twilio'); - } - var message = { - to: req.body.number, - from: '+13472235148', - body: req.body.message - }; - twilio.sendMessage(message, function(err, responseData) { - if (err) return next(err.message); - req.flash('success', { msg: 'Text sent to ' + responseData.to + '.'}); - res.redirect('/api/twilio'); - }); -}; - -/** - * GET /api/clockwork - * Clockwork SMS API example. - */ - -exports.getClockwork = function(req, res) { - res.render('api/clockwork', { - title: 'Clockwork SMS API' - }); -}; - -/** - * POST /api/clockwork - * Send a text message using Clockwork SMS - */ - -exports.postClockwork = function(req, res, next) { - var message = { - To: req.body.telephone, - From: 'Hackathon', - Content: 'Hello from the Hackathon Starter' - }; - clockwork.sendSms(message, function(err, responseData) { - if (err) return next(err.errDesc); - req.flash('success', { msg: 'Text sent to ' + responseData.responses[0].to }); - res.redirect('/api/clockwork'); - }); -}; - -/** - * GET /api/venmo - * Venmo API example. - */ - -exports.getVenmo = function(req, res, next) { - var token = _.find(req.user.tokens, { kind: 'venmo' }); - var query = querystring.stringify({ access_token: token.accessToken }); - async.parallel({ - getProfile: function(done) { - request.get({ url: 'https://api.venmo.com/v1/me?' + query, json: true }, function(err, request, body) { - done(err, body); - }); - }, - getRecentPayments: function(done) { - request.get({ url: 'https://api.venmo.com/v1/payments?' + query, json: true }, function(err, request, body) { - done(err, body); - }); - } - }, - function(err, results) { - if (err) return next(err); - res.render('api/venmo', { - title: 'Venmo API', - profile: results.getProfile.data, - recentPayments: results.getRecentPayments.data - }); - }); -}; - -/** - * POST /api/venmo - * Send money. - */ - -exports.postVenmo = function(req, res, next) { - req.assert('user', 'Phone, Email or Venmo User ID cannot be blank').notEmpty(); - req.assert('note', 'Please enter a message to accompany the payment').notEmpty(); - req.assert('amount', 'The amount you want to pay cannot be blank').notEmpty(); - var errors = req.validationErrors(); - if (errors) { - req.flash('errors', errors); - return res.redirect('/api/venmo'); - } - var token = _.find(req.user.tokens, { kind: 'venmo' }); - var formData = { - access_token: token.accessToken, - note: req.body.note, - amount: req.body.amount - }; - if (validator.isEmail(req.body.user)) { - formData.email = req.body.user; - } else if (validator.isNumeric(req.body.user) && - validator.isLength(req.body.user, 10, 11)) { - formData.phone = req.body.user; - } else { - formData.user_id = req.body.user; - } - request.post('https://api.venmo.com/v1/payments', { form: formData }, function(err, request, body) { - if (err) return next(err); - if (request.statusCode !== 200) { - req.flash('errors', { msg: JSON.parse(body).error.message }); - return res.redirect('/api/venmo'); - } - req.flash('success', { msg: 'Venmo money transfer complete' }); - res.redirect('/api/venmo'); - }); -}; - /** * GET /api/linkedin * LinkedIn API example. @@ -540,63 +134,4 @@ exports.getLinkedin = function(req, res, next) { profile: $in }); }); -}; - -/** - * GET /api/instagram - * Instagram API example. - */ - -exports.getInstagram = function(req, res, next) { - var token = _.find(req.user.tokens, { kind: 'instagram' }); - ig.use({ client_id: secrets.instagram.clientID, client_secret: secrets.instagram.clientSecret }); - ig.use({ access_token: token.accessToken }); - async.parallel({ - searchByUsername: function(done) { - ig.user_search('richellemead', function(err, users, limit) { - done(err, users); - }); - }, - searchByUserId: function(done) { - ig.user('175948269', function(err, user) { - done(err, user); - }); - }, - popularImages: function(done) { - ig.media_popular(function(err, medias) { - done(err, medias); - }); - }, - myRecentMedia: function(done) { - ig.user_self_media_recent(function(err, medias, pagination, limit) { - done(err, medias); - }); - } - }, function(err, results) { - if (err) return next(err); - res.render('api/instagram', { - title: 'Instagram API', - usernames: results.searchByUsername, - userById: results.searchByUserId, - popularImages: results.popularImages, - myRecentMedia: results.myRecentMedia - }); - }); -}; - -/** - * GET /api/yahoo - * Yahoo API example. - */ - -exports.getYahoo = function(req, res) { - Y.YQL('SELECT * FROM weather.forecast WHERE (location = 10007)', function(response) { - var location = response.query.results.channel.location; - var condition = response.query.results.channel.item.condition; - res.render('api/yahoo', { - title: 'Yahoo API', - location: location, - condition: condition - }); - }); }; \ No newline at end of file From b7ec61c4c366a41b7c5dda715ff644578d39ac3c Mon Sep 17 00:00:00 2001 From: Michael Q Larson Date: Mon, 22 Dec 2014 14:57:07 -0800 Subject: [PATCH 03/20] probably fix crashing sites --- views/partials/navbar.jade | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/views/partials/navbar.jade b/views/partials/navbar.jade index ea6aeeaf43..6c406569f4 100644 --- a/views/partials/navbar.jade +++ b/views/partials/navbar.jade @@ -27,26 +27,26 @@ a(href='/') span.ion-map | My Challenges - - if (cc[1] > 0) - li.hamburger - a(href='https://gitter.im/FreeCodeCamp/FreeCodeCamp', target='_blank') - span.ion-coffee - | Chat Room - - else + - if (cc && cc[1] < 1) li.hamburger.disabled a(href='https://gitter.im/FreeCodeCamp/FreeCodeCamp', target='_blank') span.ion-coffee | Chat Room (do Challenge 1 first) - - if (cc[2] > 0) - li.hamburger - a(href='http://forum.freecodecamp.com/', target='_blank') - span.ion-planet - | Forum - else + li.hamburger + a(href='https://gitter.im/FreeCodeCamp/FreeCodeCamp', target='_blank') + span.ion-coffee + | Chat Room + - if (cc && cc[2] < 1) li.hamburger.disabled a(href='http://forum.freecodecamp.com/', target='_blank') span.ion-planet | Forum (do Challenge 2 first) + - else + li.hamburger + a(href='http://forum.freecodecamp.com/', target='_blank') + span.ion-planet + | Forum li.hamburger a(href='/account') span.ion-person From 2d9c0d9900adf26c8cb1e408e2a7fda843f399bc Mon Sep 17 00:00:00 2001 From: Michael Q Larson Date: Mon, 22 Dec 2014 15:02:41 -0800 Subject: [PATCH 04/20] add link to photo --- app.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app.js b/app.js index cb0abde460..91082c8457 100644 --- a/app.js +++ b/app.js @@ -121,7 +121,7 @@ app.use(helmet.contentSecurityPolicy({ scriptSrc: ['*.optimizely.com'].concat(trusted), 'connect-src': process.env.NODE_ENV === 'development' ? ['ws://localhost:3001/', 'http://localhost:3001/'] : [], styleSrc: trusted, - imgSrc: ['*.evernote.com', '*.amazonaws.com', "data:"].concat(trusted), + imgSrc: ['*.evernote.com', '*.amazonaws.com', "data:", '*.licdn.com'].concat(trusted), fontSrc: ["'self", '*.googleapis.com'].concat(trusted), mediaSrc: ['*.amazonaws.com', '*.twitter.com'], frameSrc: ['*.gitter.im', '*.vimeo.com', '*.twitter.com'], From 4066872b8daee4ac46a1441a979c9bf4bd0fbda1 Mon Sep 17 00:00:00 2001 From: Michael Q Larson Date: Mon, 22 Dec 2014 15:07:32 -0800 Subject: [PATCH 05/20] add rafflecopter to whitelist --- app.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app.js b/app.js index 91082c8457..cb3dd70d51 100644 --- a/app.js +++ b/app.js @@ -104,7 +104,8 @@ var trusted = [ '*.twimg.com', "*.githubusercontent.com", "'unsafe-eval'", - "'unsafe-inline'" + "'unsafe-inline'", + "*.rafflecopter.com" ]; //var connectSrc; //if (process.env.NODE_ENV === 'development') { From bf0c6fa4d64099c7941cdb793cf64319dd0a6e46 Mon Sep 17 00:00:00 2001 From: Michael Q Larson Date: Mon, 22 Dec 2014 15:30:38 -0800 Subject: [PATCH 06/20] second attempt at fixing rafflecopter --- app.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app.js b/app.js index cb3dd70d51..55012e706c 100644 --- a/app.js +++ b/app.js @@ -105,7 +105,8 @@ var trusted = [ "*.githubusercontent.com", "'unsafe-eval'", "'unsafe-inline'", - "*.rafflecopter.com" + "*.rafflecopter.com", + "wss://*.rafflecopter.com" ]; //var connectSrc; //if (process.env.NODE_ENV === 'development') { From f658dca06802058eb32ce704d815734c44e001b7 Mon Sep 17 00:00:00 2001 From: Michael Q Larson Date: Mon, 22 Dec 2014 15:33:33 -0800 Subject: [PATCH 07/20] third attempt at fixing web sockets for rafflecopter --- app.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app.js b/app.js index 55012e706c..32dfb47488 100644 --- a/app.js +++ b/app.js @@ -106,7 +106,7 @@ var trusted = [ "'unsafe-eval'", "'unsafe-inline'", "*.rafflecopter.com", - "wss://*.rafflecopter.com" + "ws://api.rafflecopter.com" ]; //var connectSrc; //if (process.env.NODE_ENV === 'development') { From 4c9dcfdae6b19edb8dfe7b9fe324978852a701f9 Mon Sep 17 00:00:00 2001 From: Michael Q Larson Date: Mon, 22 Dec 2014 15:35:38 -0800 Subject: [PATCH 08/20] yet another attempt at fixing websockets --- app.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app.js b/app.js index 32dfb47488..94ab55ebfa 100644 --- a/app.js +++ b/app.js @@ -106,7 +106,7 @@ var trusted = [ "'unsafe-eval'", "'unsafe-inline'", "*.rafflecopter.com", - "ws://api.rafflecopter.com" + "wss://api.rafflecopter.com" ]; //var connectSrc; //if (process.env.NODE_ENV === 'development') { From ebf85277be609d5985136ef5435bbb2cdffe65e3 Mon Sep 17 00:00:00 2001 From: Michael Q Larson Date: Mon, 22 Dec 2014 15:37:46 -0800 Subject: [PATCH 09/20] another attempt by whitelisting FCC websockets itself --- app.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app.js b/app.js index 94ab55ebfa..74fb4985c3 100644 --- a/app.js +++ b/app.js @@ -106,7 +106,8 @@ var trusted = [ "'unsafe-eval'", "'unsafe-inline'", "*.rafflecopter.com", - "wss://api.rafflecopter.com" + "ws://api.rafflecopter.com", + "ws://www.freecodecamp.com" ]; //var connectSrc; //if (process.env.NODE_ENV === 'development') { From dafae0b06c01a15491dec7ad2a72b4f1ba5b7765 Mon Sep 17 00:00:00 2001 From: Michael Q Larson Date: Mon, 22 Dec 2014 15:42:39 -0800 Subject: [PATCH 10/20] make show views work without authenticated user --- app.js | 6 +- views/partials/challenges.jade | 122 ++++++++++++++++----------------- 2 files changed, 63 insertions(+), 65 deletions(-) diff --git a/app.js b/app.js index 74fb4985c3..495548c510 100644 --- a/app.js +++ b/app.js @@ -105,9 +105,7 @@ var trusted = [ "*.githubusercontent.com", "'unsafe-eval'", "'unsafe-inline'", - "*.rafflecopter.com", - "ws://api.rafflecopter.com", - "ws://www.freecodecamp.com" + "*.rafflecopter.com" ]; //var connectSrc; //if (process.env.NODE_ENV === 'development') { @@ -122,7 +120,7 @@ debug(trusted); app.use(helmet.contentSecurityPolicy({ defaultSrc: trusted, scriptSrc: ['*.optimizely.com'].concat(trusted), - 'connect-src': process.env.NODE_ENV === 'development' ? ['ws://localhost:3001/', 'http://localhost:3001/'] : [], + 'connect-src': process.env.NODE_ENV === 'development' ? ['ws://localhost:3001/', 'http://localhost:3001/'] : ["ws://api.rafflecopter.com", "ws://www.freecodecamp.com"], styleSrc: trusted, imgSrc: ['*.evernote.com', '*.amazonaws.com', "data:", '*.licdn.com'].concat(trusted), fontSrc: ["'self", '*.googleapis.com'].concat(trusted), diff --git a/views/partials/challenges.jade b/views/partials/challenges.jade index a4d259ae79..28170de001 100644 --- a/views/partials/challenges.jade +++ b/views/partials/challenges.jade @@ -3,184 +3,184 @@ .panel-body ol(start='0') li - a(href="/challenges/0", class="#{ cc[0] > 0 ? 'strikethrough' : '' }") Learn how Free Code Camp Works + a(href="/challenges/0", class="#{ cc && cc[0] > 0 ? 'strikethrough' : '' }") Learn how Free Code Camp Works |   (2 minutes) li - a(href="/challenges/1", class="#{ cc[1] > 0 ? 'strikethrough' : '' }") Join Our Chat Room + a(href="/challenges/1", class="#{ cc && cc[1] > 0 ? 'strikethrough' : '' }") Join Our Chat Room |   (5 minutes) li - a(href="/challenges/2", class="#{ cc[2] > 0 ? 'strikethrough' : '' }") Subscribe to Our Subreddit + a(href="/challenges/2", class="#{ cc && cc[2] > 0 ? 'strikethrough' : '' }") Subscribe to Our Subreddit |   (5 minutes) li - a(href="/challenges/3", class="#{ cc[3] > 0 ? 'strikethrough' : '' }") Build a Personal Website + a(href="/challenges/3", class="#{ cc && cc[3] > 0 ? 'strikethrough' : '' }") Build a Personal Website |   (60 minutes) li - a(href="/challenges/4", class="#{ cc[4] > 0 ? 'strikethrough' : '' }") Build a Responsive Blog Theme + a(href="/challenges/4", class="#{ cc && cc[4] > 0 ? 'strikethrough' : '' }") Build a Responsive Blog Theme |   (60 minutes) li - a(href="/challenges/5", class="#{ cc[5] > 0 ? 'strikethrough' : '' }") Build a Small Business Website + a(href="/challenges/5", class="#{ cc && cc[5] > 0 ? 'strikethrough' : '' }") Build a Small Business Website |   (60 minutes) li - a(href="/challenges/6", class="#{ cc[6] > 0 ? 'strikethrough' : '' }") Tweak HTML and CSS in CodePen + a(href="/challenges/6", class="#{ cc && cc[6] > 0 ? 'strikethrough' : '' }") Tweak HTML and CSS in CodePen |   (10 minutes) li - a(href="/challenges/7", class="#{ cc[7] > 0 ? 'strikethrough' : '' }") Build a CSS Robot + a(href="/challenges/7", class="#{ cc && cc[7] > 0 ? 'strikethrough' : '' }") Build a CSS Robot |   (60 minutes) li - a(href="/challenges/8", class="#{ cc[8] > 0 ? 'strikethrough' : '' }") Get Started with jQuery + a(href="/challenges/8", class="#{ cc && cc[8] > 0 ? 'strikethrough' : '' }") Get Started with jQuery |   (30 minutes) li - a(href="/challenges/9", class="#{ cc[9] > 0 ? 'strikethrough' : '' }") Traverse the DOM + a(href="/challenges/9", class="#{ cc && cc[9] > 0 ? 'strikethrough' : '' }") Traverse the DOM |   (30 minutes) li - a(href="/challenges/10", class="#{ cc[10] > 0 ? 'strikethrough' : '' }") Work with the DOM + a(href="/challenges/10", class="#{ cc && cc[10] > 0 ? 'strikethrough' : '' }") Work with the DOM |   (30 minutes) li - a(href="/challenges/11", class="#{ cc[11] > 0 ? 'strikethrough' : '' }") Listen for DOM Events + a(href="/challenges/11", class="#{ cc && cc[11] > 0 ? 'strikethrough' : '' }") Listen for DOM Events |   (30 minutes) li - a(href="/challenges/12", class="#{ cc[12] > 0 ? 'strikethrough' : '' }") Use jQuery for Styling + a(href="/challenges/12", class="#{ cc && cc[12] > 0 ? 'strikethrough' : '' }") Use jQuery for Styling |   (30 minutes) li - a(href="/challenges/13", class="#{ cc[13] > 0 ? 'strikethrough' : '' }") Build a MadLibs Game + a(href="/challenges/13", class="#{ cc && cc[13] > 0 ? 'strikethrough' : '' }") Build a MadLibs Game |   (60 minutes) li - a(href="/challenges/14", class="#{ cc[14] > 0 ? 'strikethrough' : '' }") Discover Chrome's DevTools + a(href="/challenges/14", class="#{ cc && cc[14] > 0 ? 'strikethrough' : '' }") Discover Chrome's DevTools |   (90 minutes) li - a(href="/challenges/15", class="#{ cc[15] > 0 ? 'strikethrough' : '' }") Tackle jQuery Exercises + a(href="/challenges/15", class="#{ cc && cc[15] > 0 ? 'strikethrough' : '' }") Tackle jQuery Exercises |   (60 minutes) li - a(href="/challenges/16", class="#{ cc[16] > 0 ? 'strikethrough' : '' }") Customize Bootstrap + a(href="/challenges/16", class="#{ cc && cc[16] > 0 ? 'strikethrough' : '' }") Customize Bootstrap |   (10 minutes) li - a(href="/challenges/17", class="#{ cc[17] > 0 ? 'strikethrough' : '' }") Inject Animation into CSS + a(href="/challenges/17", class="#{ cc && cc[17] > 0 ? 'strikethrough' : '' }") Inject Animation into CSS |   (15 minutes) li - a(href="/challenges/18", class="#{ cc[18] > 0 ? 'strikethrough' : '' }") Learn Basic Computer Science + a(href="/challenges/18", class="#{ cc && cc[18] > 0 ? 'strikethrough' : '' }") Learn Basic Computer Science |   (120 minutes) li - a(href="/challenges/19", class="#{ cc[19] > 0 ? 'strikethrough' : '' }") Learn Loops + a(href="/challenges/19", class="#{ cc && cc[19] > 0 ? 'strikethrough' : '' }") Learn Loops |   (120 minutes) li - a(href="/challenges/20", class="#{ cc[20] > 0 ? 'strikethrough' : '' }") Learn Computer Hardware + a(href="/challenges/20", class="#{ cc && cc[20] > 0 ? 'strikethrough' : '' }") Learn Computer Hardware |   (120 minutes) li - a(href="/challenges/21", class="#{ cc[21] > 0 ? 'strikethrough' : '' }") Learn Computer Networking + a(href="/challenges/21", class="#{ cc && cc[21] > 0 ? 'strikethrough' : '' }") Learn Computer Networking |   (120 minutes) li - a(href="/challenges/22", class="#{ cc[22] > 0 ? 'strikethrough' : '' }") Learn Boolean Logic + a(href="/challenges/22", class="#{ cc && cc[22] > 0 ? 'strikethrough' : '' }") Learn Boolean Logic |   (120 minutes) li - a(href="/challenges/23", class="#{ cc[23] > 0 ? 'strikethrough' : '' }") Learn Computer Security + a(href="/challenges/23", class="#{ cc && cc[23] > 0 ? 'strikethrough' : '' }") Learn Computer Security |   (120 minutes) li - a(href="/challenges/24", class="#{ cc[24] > 0 ? 'strikethrough' : '' }") Build an Adventure Game + a(href="/challenges/24", class="#{ cc && cc[24] > 0 ? 'strikethrough' : '' }") Build an Adventure Game |   (60 minutes) li - a(href="/challenges/25", class="#{ cc[25] > 0 ? 'strikethrough' : '' }") Build Rock Paper Scissors + a(href="/challenges/25", class="#{ cc && cc[25] > 0 ? 'strikethrough' : '' }") Build Rock Paper Scissors |   (60 minutes) li - a(href="/challenges/26", class="#{ cc[26] > 0 ? 'strikethrough' : '' }") Learn JavaScript For Loops + a(href="/challenges/26", class="#{ cc && cc[26] > 0 ? 'strikethrough' : '' }") Learn JavaScript For Loops |   (60 minutes) li - a(href="/challenges/27", class="#{ cc[27] > 0 ? 'strikethrough' : '' }") Learn JavaScript While Loops + a(href="/challenges/27", class="#{ cc && cc[27] > 0 ? 'strikethrough' : '' }") Learn JavaScript While Loops |   (60 minutes) li - a(href="/challenges/28", class="#{ cc[28] > 0 ? 'strikethrough' : '' }") Learn Control Flow + a(href="/challenges/28", class="#{ cc && cc[28] > 0 ? 'strikethrough' : '' }") Learn Control Flow |   (60 minutes) li - a(href="/challenges/29", class="#{ cc[29] > 0 ? 'strikethrough' : '' }") Build a Contact List + a(href="/challenges/29", class="#{ cc && cc[29] > 0 ? 'strikethrough' : '' }") Build a Contact List |   (60 minutes) li - a(href="/challenges/30", class="#{ cc[30] > 0 ? 'strikethrough' : '' }") Build an Address Book + a(href="/challenges/30", class="#{ cc && cc[30] > 0 ? 'strikethrough' : '' }") Build an Address Book |   (60 minutes) li - a(href="/challenges/31", class="#{ cc[31] > 0 ? 'strikethrough' : '' }") Build a Cash Register + a(href="/challenges/31", class="#{ cc && cc[31] > 0 ? 'strikethrough' : '' }") Build a Cash Register |   (60 minutes) li - a(href="/challenges/32", class="#{ cc[32] > 0 ? 'strikethrough' : '' }") Get Help the Hacker Way + a(href="/challenges/32", class="#{ cc && cc[32] > 0 ? 'strikethrough' : '' }") Get Help the Hacker Way |   (30 minutes) li - a(href="/challenges/33", class="#{ cc[33] > 0 ? 'strikethrough' : '' }") Learn Regular Expressions + a(href="/challenges/33", class="#{ cc && cc[33] > 0 ? 'strikethrough' : '' }") Learn Regular Expressions |   (60 minutes) li - a(href="/challenges/34", class="#{ cc[34] > 0 ? 'strikethrough' : '' }") Pair Program on CoderByte + a(href="/challenges/34", class="#{ cc && cc[34] > 0 ? 'strikethrough' : '' }") Pair Program on CoderByte |   (60 minutes) li - a(href="/challenges/35", class="#{ cc[35] > 0 ? 'strikethrough' : '' }") Learn Relational Database Theory + a(href="/challenges/35", class="#{ cc && cc[35] > 0 ? 'strikethrough' : '' }") Learn Relational Database Theory |   (30 minutes) li - a(href="/challenges/36", class="#{ cc[36] > 0 ? 'strikethrough' : '' }") Pair Program to Query SQL pt 1 + a(href="/challenges/36", class="#{ cc && cc[36] > 0 ? 'strikethrough' : '' }") Pair Program to Query SQL pt 1 |   (90 minutes) li - a(href="/challenges/37", class="#{ cc[37] > 0 ? 'strikethrough' : '' }") Pair Program to Query SQL pt 2 + a(href="/challenges/37", class="#{ cc && cc[37] > 0 ? 'strikethrough' : '' }") Pair Program to Query SQL pt 2 |   (60 minutes) li - a(href="/challenges/38", class="#{ cc[38] > 0 ? 'strikethrough' : '' }") Pair Program to modify SQL pt 1 + a(href="/challenges/38", class="#{ cc && cc[38] > 0 ? 'strikethrough' : '' }") Pair Program to modify SQL pt 1 |   (90 minutes) li - a(href="/challenges/39", class="#{ cc[39] > 0 ? 'strikethrough' : '' }") Pair Program to modify SQL pt 2 + a(href="/challenges/39", class="#{ cc && cc[39] > 0 ? 'strikethrough' : '' }") Pair Program to modify SQL pt 2 |   (60 minutes) li - a(href="/challenges/40", class="#{ cc[40] > 0 ? 'strikethrough' : '' }") Learn JSON + a(href="/challenges/40", class="#{ cc && cc[40] > 0 ? 'strikethrough' : '' }") Learn JSON |   (30 minutes) li - a(href="/challenges/41", class="#{ cc[41] > 0 ? 'strikethrough' : '' }") Manage Source Code with Git + a(href="/challenges/41", class="#{ cc && cc[41] > 0 ? 'strikethrough' : '' }") Manage Source Code with Git |   (30 minutes) li - a(href="/challenges/42", class="#{ cc[42] > 0 ? 'strikethrough' : '' }") Get Started with Node.js + a(href="/challenges/42", class="#{ cc && cc[42] > 0 ? 'strikethrough' : '' }") Get Started with Node.js |   (45 minutes) li - a(href="/challenges/43", class="#{ cc[43] > 0 ? 'strikethrough' : '' }") Try Node.js Events + a(href="/challenges/43", class="#{ cc && cc[43] > 0 ? 'strikethrough' : '' }") Try Node.js Events |   (45 minutes) li - a(href="/challenges/44", class="#{ cc[44] > 0 ? 'strikethrough' : '' }") Try Node.js Streams + a(href="/challenges/44", class="#{ cc && cc[44] > 0 ? 'strikethrough' : '' }") Try Node.js Streams |   (45 minutes) li - a(href="/challenges/45", class="#{ cc[45] > 0 ? 'strikethrough' : '' }") Learn how Node.js Modules Work + a(href="/challenges/45", class="#{ cc && cc[45] > 0 ? 'strikethrough' : '' }") Learn how Node.js Modules Work |   (45 minutes) li - a(href="/challenges/46", class="#{ cc[46] > 0 ? 'strikethrough' : '' }") Start an Express.js Server + a(href="/challenges/46", class="#{ cc && cc[46] > 0 ? 'strikethrough' : '' }") Start an Express.js Server |   (45 minutes) li - a(href="/challenges/47", class="#{ cc[47] > 0 ? 'strikethrough' : '' }") Use Socket.io + a(href="/challenges/47", class="#{ cc && cc[47] > 0 ? 'strikethrough' : '' }") Use Socket.io |   (45 minutes) li - a(href="/challenges/48", class="#{ cc[48] > 0 ? 'strikethrough' : '' }") Use Redis to Persist Data + a(href="/challenges/48", class="#{ cc && cc[48] > 0 ? 'strikethrough' : '' }") Use Redis to Persist Data |   (45 minutes) li - a(href="/challenges/49", class="#{ cc[49] > 0 ? 'strikethrough' : '' }") Dive Deeper into Express.js + a(href="/challenges/49", class="#{ cc && cc[49] > 0 ? 'strikethrough' : '' }") Dive Deeper into Express.js |   (45 minutes) li - a(href="/challenges/50", class="#{ cc[50] > 0 ? 'strikethrough' : '' }") Set up Express.js Middleware + a(href="/challenges/50", class="#{ cc && cc[50] > 0 ? 'strikethrough' : '' }") Set up Express.js Middleware |   (45 minutes) li - a(href="/challenges/51", class="#{ cc[51] > 0 ? 'strikethrough' : '' }") Take Advantage of Parameters + a(href="/challenges/51", class="#{ cc && cc[51] > 0 ? 'strikethrough' : '' }") Take Advantage of Parameters |   (45 minutes) li - a(href="/challenges/52", class="#{ cc[52] > 0 ? 'strikethrough' : '' }") Add the Body Parser + a(href="/challenges/52", class="#{ cc && cc[52] > 0 ? 'strikethrough' : '' }") Add the Body Parser |   (45 minutes) li - a(href="/challenges/53", class="#{ cc[53] > 0 ? 'strikethrough' : '' }") Configure Routes in Express.js + a(href="/challenges/53", class="#{ cc && cc[53] > 0 ? 'strikethrough' : '' }") Configure Routes in Express.js |   (45 minutes) li - a(href="/challenges/54", class="#{ cc[54] > 0 ? 'strikethrough' : '' }") Try MongoDB + a(href="/challenges/54", class="#{ cc && cc[54] > 0 ? 'strikethrough' : '' }") Try MongoDB |   (30 minutes) li - a(href="/challenges/55", class="#{ cc[55] > 0 ? 'strikethrough' : '' }") Get Started with Angular.js + a(href="/challenges/55", class="#{ cc && cc[55] > 0 ? 'strikethrough' : '' }") Get Started with Angular.js |   (45 minutes) li - a(href="/challenges/56", class="#{ cc[56] > 0 ? 'strikethrough' : '' }") Apply Angular.js Directives + a(href="/challenges/56", class="#{ cc && cc[56] > 0 ? 'strikethrough' : '' }") Apply Angular.js Directives |   (45 minutes) li - a(href="/challenges/57", class="#{ cc[57] > 0 ? 'strikethrough' : '' }") Power Forms with Angular.js + a(href="/challenges/57", class="#{ cc && cc[57] > 0 ? 'strikethrough' : '' }") Power Forms with Angular.js |   (45 minutes) li - a(href="/challenges/58", class="#{ cc[58] > 0 ? 'strikethrough' : '' }") Customize Angular.js Directives + a(href="/challenges/58", class="#{ cc && cc[58] > 0 ? 'strikethrough' : '' }") Customize Angular.js Directives |   (45 minutes) li - a(href="/challenges/59", class="#{ cc[59] > 0 ? 'strikethrough' : '' }") Create Angular.js Services + a(href="/challenges/59", class="#{ cc && cc[59] > 0 ? 'strikethrough' : '' }") Create Angular.js Services |   (45 minutes) - a.btn.btn-primary(href="/done-with-first-100-hours", class="#{ cc[59] > 0 ? '' : 'disabled' }") I've finished all Free Code Camp challenges and all the Easy and Medium CoderByte Challenges \ No newline at end of file + a.btn.btn-primary(href="/done-with-first-100-hours", class="#{ cc && cc[59] > 0 ? '' : 'disabled' }") I've finished all Free Code Camp challenges and all the Easy and Medium CoderByte Challenges \ No newline at end of file From b18020518b78d361324c94de5205ca45eb7617b7 Mon Sep 17 00:00:00 2001 From: Michael Q Larson Date: Mon, 22 Dec 2014 15:45:03 -0800 Subject: [PATCH 11/20] another attempt at fixing rafflecopter --- app.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app.js b/app.js index 495548c510..4ebd939c4f 100644 --- a/app.js +++ b/app.js @@ -120,7 +120,8 @@ debug(trusted); app.use(helmet.contentSecurityPolicy({ defaultSrc: trusted, scriptSrc: ['*.optimizely.com'].concat(trusted), - 'connect-src': process.env.NODE_ENV === 'development' ? ['ws://localhost:3001/', 'http://localhost:3001/'] : ["ws://api.rafflecopter.com", "ws://www.freecodecamp.com"], + 'connect-src': process.env.NODE_ENV === 'development' ? ['ws://localhost:3001/', 'http://localhost:3001/'] : [], + connectSources: ["ws://api.rafflecopter.com", "ws://www.freecodecamp.com"], styleSrc: trusted, imgSrc: ['*.evernote.com', '*.amazonaws.com', "data:", '*.licdn.com'].concat(trusted), fontSrc: ["'self", '*.googleapis.com'].concat(trusted), From d8158041defece093e30cc45fe4ca09798a1307d Mon Sep 17 00:00:00 2001 From: Michael Q Larson Date: Mon, 22 Dec 2014 15:46:12 -0800 Subject: [PATCH 12/20] another fix for rafflecopter --- app.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app.js b/app.js index 4ebd939c4f..7fb4d85099 100644 --- a/app.js +++ b/app.js @@ -121,7 +121,7 @@ app.use(helmet.contentSecurityPolicy({ defaultSrc: trusted, scriptSrc: ['*.optimizely.com'].concat(trusted), 'connect-src': process.env.NODE_ENV === 'development' ? ['ws://localhost:3001/', 'http://localhost:3001/'] : [], - connectSources: ["ws://api.rafflecopter.com", "ws://www.freecodecamp.com"], + connectSources: ["ws://api.rafflecopter.com", "wss://api.rafflecopter.com", "ws://www.freecodecamp.com"], styleSrc: trusted, imgSrc: ['*.evernote.com', '*.amazonaws.com', "data:", '*.licdn.com'].concat(trusted), fontSrc: ["'self", '*.googleapis.com'].concat(trusted), From ae9c61fc64006a96b4a6d777934b45ff59497755 Mon Sep 17 00:00:00 2001 From: Michael Q Larson Date: Mon, 22 Dec 2014 15:54:43 -0800 Subject: [PATCH 13/20] another attempt at fixing --- app.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app.js b/app.js index 7fb4d85099..7010379fb0 100644 --- a/app.js +++ b/app.js @@ -121,7 +121,7 @@ app.use(helmet.contentSecurityPolicy({ defaultSrc: trusted, scriptSrc: ['*.optimizely.com'].concat(trusted), 'connect-src': process.env.NODE_ENV === 'development' ? ['ws://localhost:3001/', 'http://localhost:3001/'] : [], - connectSources: ["ws://api.rafflecopter.com", "wss://api.rafflecopter.com", "ws://www.freecodecamp.com"], + connectSources: ["ws://api.rafflecopter.com", "wss://api.rafflecopter.com", "ws://www.freecodecamp.com"].concat(trusted), styleSrc: trusted, imgSrc: ['*.evernote.com', '*.amazonaws.com', "data:", '*.licdn.com'].concat(trusted), fontSrc: ["'self", '*.googleapis.com'].concat(trusted), From aebb9b3efd499154db8e85800c2eb9450ef5cfa8 Mon Sep 17 00:00:00 2001 From: Michael Q Larson Date: Mon, 22 Dec 2014 16:16:10 -0800 Subject: [PATCH 14/20] may have fixed websockets whitelisting issue --- app.js | 9 +++++---- gulpfile.js | 1 - 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/app.js b/app.js index 7010379fb0..e5e9f8038b 100644 --- a/app.js +++ b/app.js @@ -2,6 +2,7 @@ * Module dependencies. */ require('newrelic'); +require('dotenv').load(); var express = require('express'); var debug = require('debug')('freecc:server'); var cookieParser = require('cookie-parser'); @@ -98,6 +99,7 @@ var trusted = [ '*.freecodecamp.com', "*.google-analytics.com", "*.googleapis.com", + "*.google.com", "*.gstatic.com", "*.doubleclick.net", "*.twitter.com", @@ -120,13 +122,12 @@ debug(trusted); app.use(helmet.contentSecurityPolicy({ defaultSrc: trusted, scriptSrc: ['*.optimizely.com'].concat(trusted), - 'connect-src': process.env.NODE_ENV === 'development' ? ['ws://localhost:3001/', 'http://localhost:3001/'] : [], - connectSources: ["ws://api.rafflecopter.com", "wss://api.rafflecopter.com", "ws://www.freecodecamp.com"].concat(trusted), + 'connect-src': ["ws://*.rafflecopter.com", "wss://*.rafflecopter.com", "ws://www.freecodecamp.com", 'ws://localhost:3001/', 'http://localhost:3001/'], styleSrc: trusted, - imgSrc: ['*.evernote.com', '*.amazonaws.com', "data:", '*.licdn.com'].concat(trusted), + imgSrc: ['*.evernote.com', '*.amazonaws.com', "data:", '*.licdn.com', '*.gravatar.com', '*.youtube.com'].concat(trusted), fontSrc: ["'self", '*.googleapis.com'].concat(trusted), mediaSrc: ['*.amazonaws.com', '*.twitter.com'], - frameSrc: ['*.gitter.im', '*.vimeo.com', '*.twitter.com'], + frameSrc: ['*.gitter.im', '*.vimeo.com', '*.twitter.com', '*.rafflecopter.com'], // sandbox: ['allow-forms', 'allow-scripts'], // reportUri: '/report-violation', reportOnly: false, // set to true if you only want to report errors diff --git a/gulpfile.js b/gulpfile.js index faf61f7339..bc0d2f2c21 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -58,7 +58,6 @@ gulp.task('sync', ['serve'], function() { ], port: 3001, open: true, - browser: ['safari', 'google chrome'], reloadDelay: reloadDelay }); }); From 33324fdf017771685f118e6f7163e702d0c7eb28 Mon Sep 17 00:00:00 2001 From: Michael Q Larson Date: Mon, 22 Dec 2014 16:47:02 -0800 Subject: [PATCH 15/20] attempt to fix raffle --- app.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/app.js b/app.js index e5e9f8038b..769101f0f3 100644 --- a/app.js +++ b/app.js @@ -107,7 +107,8 @@ var trusted = [ "*.githubusercontent.com", "'unsafe-eval'", "'unsafe-inline'", - "*.rafflecopter.com" + "*.rafflecopter.com", + "localhost:3001" ]; //var connectSrc; //if (process.env.NODE_ENV === 'development') { @@ -122,7 +123,7 @@ debug(trusted); app.use(helmet.contentSecurityPolicy({ defaultSrc: trusted, scriptSrc: ['*.optimizely.com'].concat(trusted), - 'connect-src': ["ws://*.rafflecopter.com", "wss://*.rafflecopter.com", "ws://www.freecodecamp.com", 'ws://localhost:3001/', 'http://localhost:3001/'], + 'connect-src': ["ws://*.rafflecopter.com", "wss://*.rafflecopter.com","https://*.rafflecopter.com", "ws://www.freecodecamp.com", 'ws://localhost:3001/', 'http://localhost:3001', 'http://www.freecodecamp.com'], styleSrc: trusted, imgSrc: ['*.evernote.com', '*.amazonaws.com', "data:", '*.licdn.com', '*.gravatar.com', '*.youtube.com'].concat(trusted), fontSrc: ["'self", '*.googleapis.com'].concat(trusted), From 7a5224b876bd73aacb54a4fa9198e8012c0f0eef Mon Sep 17 00:00:00 2001 From: Michael Q Larson Date: Mon, 22 Dec 2014 16:56:09 -0800 Subject: [PATCH 16/20] reverse change to challenge checkoff --- views/partials/challenges.jade | 126 ++++++++++++++++----------------- 1 file changed, 63 insertions(+), 63 deletions(-) diff --git a/views/partials/challenges.jade b/views/partials/challenges.jade index 28170de001..789a3eea86 100644 --- a/views/partials/challenges.jade +++ b/views/partials/challenges.jade @@ -3,184 +3,184 @@ .panel-body ol(start='0') li - a(href="/challenges/0", class="#{ cc && cc[0] > 0 ? 'strikethrough' : '' }") Learn how Free Code Camp Works + a(href="/challenges/0", class="#{ cc[0] > 0 ? 'strikethrough' : '' }") Learn how Free Code Camp Works |   (2 minutes) li - a(href="/challenges/1", class="#{ cc && cc[1] > 0 ? 'strikethrough' : '' }") Join Our Chat Room + a(href="/challenges/1", class="#{ cc[1] > 0 ? 'strikethrough' : '' }") Join Our Chat Room |   (5 minutes) li - a(href="/challenges/2", class="#{ cc && cc[2] > 0 ? 'strikethrough' : '' }") Subscribe to Our Subreddit + a(href="/challenges/2", class="#{ cc[2] > 0 ? 'strikethrough' : '' }") Subscribe to Our Subreddit |   (5 minutes) li - a(href="/challenges/3", class="#{ cc && cc[3] > 0 ? 'strikethrough' : '' }") Build a Personal Website + a(href="/challenges/3", class="#{ cc[3] > 0 ? 'strikethrough' : '' }") Build a Personal Website |   (60 minutes) li - a(href="/challenges/4", class="#{ cc && cc[4] > 0 ? 'strikethrough' : '' }") Build a Responsive Blog Theme + a(href="/challenges/4", class="#{ cc[4] > 0 ? 'strikethrough' : '' }") Build a Responsive Blog Theme |   (60 minutes) li - a(href="/challenges/5", class="#{ cc && cc[5] > 0 ? 'strikethrough' : '' }") Build a Small Business Website + a(href="/challenges/5", class="#{ cc[5] > 0 ? 'strikethrough' : '' }") Build a Small Business Website |   (60 minutes) li - a(href="/challenges/6", class="#{ cc && cc[6] > 0 ? 'strikethrough' : '' }") Tweak HTML and CSS in CodePen + a(href="/challenges/6", class="#{ cc[6] > 0 ? 'strikethrough' : '' }") Tweak HTML and CSS in CodePen |   (10 minutes) li - a(href="/challenges/7", class="#{ cc && cc[7] > 0 ? 'strikethrough' : '' }") Build a CSS Robot + a(href="/challenges/7", class="#{ cc[7] > 0 ? 'strikethrough' : '' }") Build a CSS Robot |   (60 minutes) li - a(href="/challenges/8", class="#{ cc && cc[8] > 0 ? 'strikethrough' : '' }") Get Started with jQuery + a(href="/challenges/8", class="#{ cc[8] > 0 ? 'strikethrough' : '' }") Get Started with jQuery |   (30 minutes) li - a(href="/challenges/9", class="#{ cc && cc[9] > 0 ? 'strikethrough' : '' }") Traverse the DOM + a(href="/challenges/9", class="#{ cc[9] > 0 ? 'strikethrough' : '' }") Traverse the DOM |   (30 minutes) li - a(href="/challenges/10", class="#{ cc && cc[10] > 0 ? 'strikethrough' : '' }") Work with the DOM + a(href="/challenges/10", class="#{ cc[10] > 0 ? 'strikethrough' : '' }") Work with the DOM |   (30 minutes) li - a(href="/challenges/11", class="#{ cc && cc[11] > 0 ? 'strikethrough' : '' }") Listen for DOM Events + a(href="/challenges/11", class="#{ cc[11] > 0 ? 'strikethrough' : '' }") Listen for DOM Events |   (30 minutes) li - a(href="/challenges/12", class="#{ cc && cc[12] > 0 ? 'strikethrough' : '' }") Use jQuery for Styling + a(href="/challenges/12", class="#{ cc[12] > 0 ? 'strikethrough' : '' }") Use jQuery for Styling |   (30 minutes) li - a(href="/challenges/13", class="#{ cc && cc[13] > 0 ? 'strikethrough' : '' }") Build a MadLibs Game + a(href="/challenges/13", class="#{ cc[13] > 0 ? 'strikethrough' : '' }") Build a MadLibs Game |   (60 minutes) li - a(href="/challenges/14", class="#{ cc && cc[14] > 0 ? 'strikethrough' : '' }") Discover Chrome's DevTools + a(href="/challenges/14", class="#{ cc[14] > 0 ? 'strikethrough' : '' }") Discover Chrome's DevTools |   (90 minutes) li - a(href="/challenges/15", class="#{ cc && cc[15] > 0 ? 'strikethrough' : '' }") Tackle jQuery Exercises + a(href="/challenges/15", class="#{ cc[15] > 0 ? 'strikethrough' : '' }") Tackle jQuery Exercises |   (60 minutes) li - a(href="/challenges/16", class="#{ cc && cc[16] > 0 ? 'strikethrough' : '' }") Customize Bootstrap + a(href="/challenges/16", class="#{ cc[16] > 0 ? 'strikethrough' : '' }") Customize Bootstrap |   (10 minutes) li - a(href="/challenges/17", class="#{ cc && cc[17] > 0 ? 'strikethrough' : '' }") Inject Animation into CSS + a(href="/challenges/17", class="#{ cc[17] > 0 ? 'strikethrough' : '' }") Inject Animation into CSS |   (15 minutes) li - a(href="/challenges/18", class="#{ cc && cc[18] > 0 ? 'strikethrough' : '' }") Learn Basic Computer Science + a(href="/challenges/18", class="#{ cc[18] > 0 ? 'strikethrough' : '' }") Learn Basic Computer Science |   (120 minutes) li - a(href="/challenges/19", class="#{ cc && cc[19] > 0 ? 'strikethrough' : '' }") Learn Loops + a(href="/challenges/19", class="#{ cc[19] > 0 ? 'strikethrough' : '' }") Learn Loops |   (120 minutes) li - a(href="/challenges/20", class="#{ cc && cc[20] > 0 ? 'strikethrough' : '' }") Learn Computer Hardware + a(href="/challenges/20", class="#{ cc[20] > 0 ? 'strikethrough' : '' }") Learn Computer Hardware |   (120 minutes) li - a(href="/challenges/21", class="#{ cc && cc[21] > 0 ? 'strikethrough' : '' }") Learn Computer Networking - |   (120 minutes) - li - a(href="/challenges/22", class="#{ cc && cc[22] > 0 ? 'strikethrough' : '' }") Learn Boolean Logic + a(href="/challenges/21", class="#{ cc[21] > 0 ? 'strikethrough' : '' }") Learn Computer Networking |   (120 minutes) li - a(href="/challenges/23", class="#{ cc && cc[23] > 0 ? 'strikethrough' : '' }") Learn Computer Security + a(href="/challenges/22", class="#{ cc[22] > 0 ? 'strikethrough' : '' }") Learn Boolean Logic |   (120 minutes) li - a(href="/challenges/24", class="#{ cc && cc[24] > 0 ? 'strikethrough' : '' }") Build an Adventure Game + a(href="/challenges/23", class="#{ cc[23] > 0 ? 'strikethrough' : '' }") Learn Computer Security + |   (120 minutes) + li + a(href="/challenges/24", class="#{ cc[24] > 0 ? 'strikethrough' : '' }") Build an Adventure Game |   (60 minutes) li - a(href="/challenges/25", class="#{ cc && cc[25] > 0 ? 'strikethrough' : '' }") Build Rock Paper Scissors + a(href="/challenges/25", class="#{ cc[25] > 0 ? 'strikethrough' : '' }") Build Rock Paper Scissors |   (60 minutes) li - a(href="/challenges/26", class="#{ cc && cc[26] > 0 ? 'strikethrough' : '' }") Learn JavaScript For Loops + a(href="/challenges/26", class="#{ cc[26] > 0 ? 'strikethrough' : '' }") Learn JavaScript For Loops |   (60 minutes) li - a(href="/challenges/27", class="#{ cc && cc[27] > 0 ? 'strikethrough' : '' }") Learn JavaScript While Loops + a(href="/challenges/27", class="#{ cc[27] > 0 ? 'strikethrough' : '' }") Learn JavaScript While Loops |   (60 minutes) li - a(href="/challenges/28", class="#{ cc && cc[28] > 0 ? 'strikethrough' : '' }") Learn Control Flow + a(href="/challenges/28", class="#{ cc[28] > 0 ? 'strikethrough' : '' }") Learn Control Flow |   (60 minutes) li - a(href="/challenges/29", class="#{ cc && cc[29] > 0 ? 'strikethrough' : '' }") Build a Contact List + a(href="/challenges/29", class="#{ cc[29] > 0 ? 'strikethrough' : '' }") Build a Contact List |   (60 minutes) li - a(href="/challenges/30", class="#{ cc && cc[30] > 0 ? 'strikethrough' : '' }") Build an Address Book + a(href="/challenges/30", class="#{ cc[30] > 0 ? 'strikethrough' : '' }") Build an Address Book |   (60 minutes) li - a(href="/challenges/31", class="#{ cc && cc[31] > 0 ? 'strikethrough' : '' }") Build a Cash Register + a(href="/challenges/31", class="#{ cc[31] > 0 ? 'strikethrough' : '' }") Build a Cash Register |   (60 minutes) li - a(href="/challenges/32", class="#{ cc && cc[32] > 0 ? 'strikethrough' : '' }") Get Help the Hacker Way + a(href="/challenges/32", class="#{ cc[32] > 0 ? 'strikethrough' : '' }") Get Help the Hacker Way |   (30 minutes) li - a(href="/challenges/33", class="#{ cc && cc[33] > 0 ? 'strikethrough' : '' }") Learn Regular Expressions + a(href="/challenges/33", class="#{ cc[33] > 0 ? 'strikethrough' : '' }") Learn Regular Expressions |   (60 minutes) li - a(href="/challenges/34", class="#{ cc && cc[34] > 0 ? 'strikethrough' : '' }") Pair Program on CoderByte + a(href="/challenges/34", class="#{ cc[34] > 0 ? 'strikethrough' : '' }") Pair Program on CoderByte |   (60 minutes) li - a(href="/challenges/35", class="#{ cc && cc[35] > 0 ? 'strikethrough' : '' }") Learn Relational Database Theory + a(href="/challenges/35", class="#{ cc[35] > 0 ? 'strikethrough' : '' }") Learn Relational Database Theory |   (30 minutes) li - a(href="/challenges/36", class="#{ cc && cc[36] > 0 ? 'strikethrough' : '' }") Pair Program to Query SQL pt 1 + a(href="/challenges/36", class="#{ cc[36] > 0 ? 'strikethrough' : '' }") Pair Program to Query SQL pt 1 |   (90 minutes) li - a(href="/challenges/37", class="#{ cc && cc[37] > 0 ? 'strikethrough' : '' }") Pair Program to Query SQL pt 2 + a(href="/challenges/37", class="#{ cc[37] > 0 ? 'strikethrough' : '' }") Pair Program to Query SQL pt 2 |   (60 minutes) li - a(href="/challenges/38", class="#{ cc && cc[38] > 0 ? 'strikethrough' : '' }") Pair Program to modify SQL pt 1 + a(href="/challenges/38", class="#{ cc[38] > 0 ? 'strikethrough' : '' }") Pair Program to modify SQL pt 1 |   (90 minutes) li - a(href="/challenges/39", class="#{ cc && cc[39] > 0 ? 'strikethrough' : '' }") Pair Program to modify SQL pt 2 + a(href="/challenges/39", class="#{ cc[39] > 0 ? 'strikethrough' : '' }") Pair Program to modify SQL pt 2 |   (60 minutes) li - a(href="/challenges/40", class="#{ cc && cc[40] > 0 ? 'strikethrough' : '' }") Learn JSON + a(href="/challenges/40", class="#{ cc[40] > 0 ? 'strikethrough' : '' }") Learn JSON |   (30 minutes) li - a(href="/challenges/41", class="#{ cc && cc[41] > 0 ? 'strikethrough' : '' }") Manage Source Code with Git + a(href="/challenges/41", class="#{ cc[41] > 0 ? 'strikethrough' : '' }") Manage Source Code with Git |   (30 minutes) li - a(href="/challenges/42", class="#{ cc && cc[42] > 0 ? 'strikethrough' : '' }") Get Started with Node.js + a(href="/challenges/42", class="#{ cc[42] > 0 ? 'strikethrough' : '' }") Get Started with Node.js |   (45 minutes) li - a(href="/challenges/43", class="#{ cc && cc[43] > 0 ? 'strikethrough' : '' }") Try Node.js Events + a(href="/challenges/43", class="#{ cc[43] > 0 ? 'strikethrough' : '' }") Try Node.js Events |   (45 minutes) li - a(href="/challenges/44", class="#{ cc && cc[44] > 0 ? 'strikethrough' : '' }") Try Node.js Streams + a(href="/challenges/44", class="#{ cc[44] > 0 ? 'strikethrough' : '' }") Try Node.js Streams |   (45 minutes) li - a(href="/challenges/45", class="#{ cc && cc[45] > 0 ? 'strikethrough' : '' }") Learn how Node.js Modules Work + a(href="/challenges/45", class="#{ cc[45] > 0 ? 'strikethrough' : '' }") Learn how Node.js Modules Work |   (45 minutes) li - a(href="/challenges/46", class="#{ cc && cc[46] > 0 ? 'strikethrough' : '' }") Start an Express.js Server + a(href="/challenges/46", class="#{ cc[46] > 0 ? 'strikethrough' : '' }") Start an Express.js Server |   (45 minutes) li - a(href="/challenges/47", class="#{ cc && cc[47] > 0 ? 'strikethrough' : '' }") Use Socket.io + a(href="/challenges/47", class="#{ cc[47] > 0 ? 'strikethrough' : '' }") Use Socket.io |   (45 minutes) li - a(href="/challenges/48", class="#{ cc && cc[48] > 0 ? 'strikethrough' : '' }") Use Redis to Persist Data + a(href="/challenges/48", class="#{ cc[48] > 0 ? 'strikethrough' : '' }") Use Redis to Persist Data |   (45 minutes) li - a(href="/challenges/49", class="#{ cc && cc[49] > 0 ? 'strikethrough' : '' }") Dive Deeper into Express.js + a(href="/challenges/49", class="#{ cc[49] > 0 ? 'strikethrough' : '' }") Dive Deeper into Express.js |   (45 minutes) li - a(href="/challenges/50", class="#{ cc && cc[50] > 0 ? 'strikethrough' : '' }") Set up Express.js Middleware + a(href="/challenges/50", class="#{ cc[50] > 0 ? 'strikethrough' : '' }") Set up Express.js Middleware |   (45 minutes) li - a(href="/challenges/51", class="#{ cc && cc[51] > 0 ? 'strikethrough' : '' }") Take Advantage of Parameters + a(href="/challenges/51", class="#{ cc[51] > 0 ? 'strikethrough' : '' }") Take Advantage of Parameters |   (45 minutes) li - a(href="/challenges/52", class="#{ cc && cc[52] > 0 ? 'strikethrough' : '' }") Add the Body Parser + a(href="/challenges/52", class="#{ cc[52] > 0 ? 'strikethrough' : '' }") Add the Body Parser |   (45 minutes) li - a(href="/challenges/53", class="#{ cc && cc[53] > 0 ? 'strikethrough' : '' }") Configure Routes in Express.js + a(href="/challenges/53", class="#{ cc[53] > 0 ? 'strikethrough' : '' }") Configure Routes in Express.js |   (45 minutes) li - a(href="/challenges/54", class="#{ cc && cc[54] > 0 ? 'strikethrough' : '' }") Try MongoDB + a(href="/challenges/54", class="#{ cc[54] > 0 ? 'strikethrough' : '' }") Try MongoDB |   (30 minutes) li - a(href="/challenges/55", class="#{ cc && cc[55] > 0 ? 'strikethrough' : '' }") Get Started with Angular.js + a(href="/challenges/55", class="#{ cc[55] > 0 ? 'strikethrough' : '' }") Get Started with Angular.js |   (45 minutes) li - a(href="/challenges/56", class="#{ cc && cc[56] > 0 ? 'strikethrough' : '' }") Apply Angular.js Directives + a(href="/challenges/56", class="#{ cc[56] > 0 ? 'strikethrough' : '' }") Apply Angular.js Directives |   (45 minutes) li - a(href="/challenges/57", class="#{ cc && cc[57] > 0 ? 'strikethrough' : '' }") Power Forms with Angular.js + a(href="/challenges/57", class="#{ cc[57] > 0 ? 'strikethrough' : '' }") Power Forms with Angular.js |   (45 minutes) li - a(href="/challenges/58", class="#{ cc && cc[58] > 0 ? 'strikethrough' : '' }") Customize Angular.js Directives + a(href="/challenges/58", class="#{ cc[58] > 0 ? 'strikethrough' : '' }") Customize Angular.js Directives |   (45 minutes) li - a(href="/challenges/59", class="#{ cc && cc[59] > 0 ? 'strikethrough' : '' }") Create Angular.js Services + a(href="/challenges/59", class="#{ cc[59] > 0 ? 'strikethrough' : '' }") Create Angular.js Services |   (45 minutes) - a.btn.btn-primary(href="/done-with-first-100-hours", class="#{ cc && cc[59] > 0 ? '' : 'disabled' }") I've finished all Free Code Camp challenges and all the Easy and Medium CoderByte Challenges \ No newline at end of file + a.btn.btn-primary(href="/done-with-first-100-hours", class="#{ cc[59] > 0 ? '' : 'disabled' }") I've finished all Free Code Camp challenges and all the Easy and Medium CoderByte Challenges \ No newline at end of file From 3eb09ab63778ddb97eb69a4ef7f9374ac6297f04 Mon Sep 17 00:00:00 2001 From: Michael Q Larson Date: Mon, 22 Dec 2014 21:07:50 -0800 Subject: [PATCH 17/20] start reworking challenge views --- app.js | 1 - controllers/challenges.js | 15 +-- views/challenges/show.jade | 2 +- views/partials/challenges.jade | 185 +-------------------------------- 4 files changed, 14 insertions(+), 189 deletions(-) diff --git a/app.js b/app.js index 769101f0f3..976ab9b713 100644 --- a/app.js +++ b/app.js @@ -195,7 +195,6 @@ app.post( app.get( '/challenges/:challengeNumber', - passportConf.isAuthenticated, challengesController.returnChallenge); app.all('/account', passportConf.isAuthenticated); app.get('/account', userController.getAccount); diff --git a/controllers/challenges.js b/controllers/challenges.js index 382aa369a5..83e5b09c58 100644 --- a/controllers/challenges.js +++ b/controllers/challenges.js @@ -8,18 +8,19 @@ var _ = require('lodash'); exports.returnChallenge = function(req, res, next) { var challengeNumber = parseInt(req.params.challengeNumber) || 0; if (challengeNumber > 59) { challengeNumber = 0; } - Challenge.findOne({challengeNumber: challengeNumber}, function (err, c) { + Challenge.find({}, function (err, c) { if (err) { console.error('Challenge err: ', err); next(err); } res.render('challenges/show', { - title: 'Challenge: ' + c.name, - name: c.name, - video: c.video, - time: c.time, - steps: c.steps, - cc: req.user.challengesHash + title: 'Challenge: ' + c[challengeNumber].name, + name: c[challengeNumber].name, + video: c[challengeNumber].video, + time: c[challengeNumber].time, + steps: c[challengeNumber].steps, + cc: req.user ? req.user.challengesHash : undefined, + challenges: c }); }); }; \ No newline at end of file diff --git a/views/challenges/show.jade b/views/challenges/show.jade index 902730d664..33f15599c9 100644 --- a/views/challenges/show.jade +++ b/views/challenges/show.jade @@ -15,7 +15,7 @@ block content .btn.btn-primary.btn-big.btn-block.completed-challenge I've completed this challenge .ten-pixel-break .btn.btn-success.btn-large.btn-block.skip-challenge I want to skip this challenge for now - - if (cc[2] > 0) + - if (cc && cc[2] > 0) .panel-footer.text-center span Need a break? Check out our:  a(href="https://gitter.im/FreeCodeCamp/FreeCodeCamp", target="_blank") Chat Room diff --git a/views/partials/challenges.jade b/views/partials/challenges.jade index 789a3eea86..d6a42bc96a 100644 --- a/views/partials/challenges.jade +++ b/views/partials/challenges.jade @@ -2,185 +2,10 @@ .panel-heading Challenges .panel-body ol(start='0') + for challenge in challenges li - a(href="/challenges/0", class="#{ cc[0] > 0 ? 'strikethrough' : '' }") Learn how Free Code Camp Works - |   (2 minutes) - li - a(href="/challenges/1", class="#{ cc[1] > 0 ? 'strikethrough' : '' }") Join Our Chat Room - |   (5 minutes) - li - a(href="/challenges/2", class="#{ cc[2] > 0 ? 'strikethrough' : '' }") Subscribe to Our Subreddit - |   (5 minutes) - li - a(href="/challenges/3", class="#{ cc[3] > 0 ? 'strikethrough' : '' }") Build a Personal Website - |   (60 minutes) - li - a(href="/challenges/4", class="#{ cc[4] > 0 ? 'strikethrough' : '' }") Build a Responsive Blog Theme - |   (60 minutes) - li - a(href="/challenges/5", class="#{ cc[5] > 0 ? 'strikethrough' : '' }") Build a Small Business Website - |   (60 minutes) - li - a(href="/challenges/6", class="#{ cc[6] > 0 ? 'strikethrough' : '' }") Tweak HTML and CSS in CodePen - |   (10 minutes) - li - a(href="/challenges/7", class="#{ cc[7] > 0 ? 'strikethrough' : '' }") Build a CSS Robot - |   (60 minutes) - li - a(href="/challenges/8", class="#{ cc[8] > 0 ? 'strikethrough' : '' }") Get Started with jQuery - |   (30 minutes) - li - a(href="/challenges/9", class="#{ cc[9] > 0 ? 'strikethrough' : '' }") Traverse the DOM - |   (30 minutes) - li - a(href="/challenges/10", class="#{ cc[10] > 0 ? 'strikethrough' : '' }") Work with the DOM - |   (30 minutes) - li - a(href="/challenges/11", class="#{ cc[11] > 0 ? 'strikethrough' : '' }") Listen for DOM Events - |   (30 minutes) - li - a(href="/challenges/12", class="#{ cc[12] > 0 ? 'strikethrough' : '' }") Use jQuery for Styling - |   (30 minutes) - li - a(href="/challenges/13", class="#{ cc[13] > 0 ? 'strikethrough' : '' }") Build a MadLibs Game - |   (60 minutes) - li - a(href="/challenges/14", class="#{ cc[14] > 0 ? 'strikethrough' : '' }") Discover Chrome's DevTools - |   (90 minutes) - li - a(href="/challenges/15", class="#{ cc[15] > 0 ? 'strikethrough' : '' }") Tackle jQuery Exercises - |   (60 minutes) - li - a(href="/challenges/16", class="#{ cc[16] > 0 ? 'strikethrough' : '' }") Customize Bootstrap - |   (10 minutes) - li - a(href="/challenges/17", class="#{ cc[17] > 0 ? 'strikethrough' : '' }") Inject Animation into CSS - |   (15 minutes) - li - a(href="/challenges/18", class="#{ cc[18] > 0 ? 'strikethrough' : '' }") Learn Basic Computer Science - |   (120 minutes) - li - a(href="/challenges/19", class="#{ cc[19] > 0 ? 'strikethrough' : '' }") Learn Loops - |   (120 minutes) - li - a(href="/challenges/20", class="#{ cc[20] > 0 ? 'strikethrough' : '' }") Learn Computer Hardware - |   (120 minutes) - li - a(href="/challenges/21", class="#{ cc[21] > 0 ? 'strikethrough' : '' }") Learn Computer Networking - |   (120 minutes) - li - a(href="/challenges/22", class="#{ cc[22] > 0 ? 'strikethrough' : '' }") Learn Boolean Logic - |   (120 minutes) - li - a(href="/challenges/23", class="#{ cc[23] > 0 ? 'strikethrough' : '' }") Learn Computer Security - |   (120 minutes) - li - a(href="/challenges/24", class="#{ cc[24] > 0 ? 'strikethrough' : '' }") Build an Adventure Game - |   (60 minutes) - li - a(href="/challenges/25", class="#{ cc[25] > 0 ? 'strikethrough' : '' }") Build Rock Paper Scissors - |   (60 minutes) - li - a(href="/challenges/26", class="#{ cc[26] > 0 ? 'strikethrough' : '' }") Learn JavaScript For Loops - |   (60 minutes) - li - a(href="/challenges/27", class="#{ cc[27] > 0 ? 'strikethrough' : '' }") Learn JavaScript While Loops - |   (60 minutes) - li - a(href="/challenges/28", class="#{ cc[28] > 0 ? 'strikethrough' : '' }") Learn Control Flow - |   (60 minutes) - li - a(href="/challenges/29", class="#{ cc[29] > 0 ? 'strikethrough' : '' }") Build a Contact List - |   (60 minutes) - li - a(href="/challenges/30", class="#{ cc[30] > 0 ? 'strikethrough' : '' }") Build an Address Book - |   (60 minutes) - li - a(href="/challenges/31", class="#{ cc[31] > 0 ? 'strikethrough' : '' }") Build a Cash Register - |   (60 minutes) - li - a(href="/challenges/32", class="#{ cc[32] > 0 ? 'strikethrough' : '' }") Get Help the Hacker Way - |   (30 minutes) - li - a(href="/challenges/33", class="#{ cc[33] > 0 ? 'strikethrough' : '' }") Learn Regular Expressions - |   (60 minutes) - li - a(href="/challenges/34", class="#{ cc[34] > 0 ? 'strikethrough' : '' }") Pair Program on CoderByte - |   (60 minutes) - li - a(href="/challenges/35", class="#{ cc[35] > 0 ? 'strikethrough' : '' }") Learn Relational Database Theory - |   (30 minutes) - li - a(href="/challenges/36", class="#{ cc[36] > 0 ? 'strikethrough' : '' }") Pair Program to Query SQL pt 1 - |   (90 minutes) - li - a(href="/challenges/37", class="#{ cc[37] > 0 ? 'strikethrough' : '' }") Pair Program to Query SQL pt 2 - |   (60 minutes) - li - a(href="/challenges/38", class="#{ cc[38] > 0 ? 'strikethrough' : '' }") Pair Program to modify SQL pt 1 - |   (90 minutes) - li - a(href="/challenges/39", class="#{ cc[39] > 0 ? 'strikethrough' : '' }") Pair Program to modify SQL pt 2 - |   (60 minutes) - li - a(href="/challenges/40", class="#{ cc[40] > 0 ? 'strikethrough' : '' }") Learn JSON - |   (30 minutes) - li - a(href="/challenges/41", class="#{ cc[41] > 0 ? 'strikethrough' : '' }") Manage Source Code with Git - |   (30 minutes) - li - a(href="/challenges/42", class="#{ cc[42] > 0 ? 'strikethrough' : '' }") Get Started with Node.js - |   (45 minutes) - li - a(href="/challenges/43", class="#{ cc[43] > 0 ? 'strikethrough' : '' }") Try Node.js Events - |   (45 minutes) - li - a(href="/challenges/44", class="#{ cc[44] > 0 ? 'strikethrough' : '' }") Try Node.js Streams - |   (45 minutes) - li - a(href="/challenges/45", class="#{ cc[45] > 0 ? 'strikethrough' : '' }") Learn how Node.js Modules Work - |   (45 minutes) - li - a(href="/challenges/46", class="#{ cc[46] > 0 ? 'strikethrough' : '' }") Start an Express.js Server - |   (45 minutes) - li - a(href="/challenges/47", class="#{ cc[47] > 0 ? 'strikethrough' : '' }") Use Socket.io - |   (45 minutes) - li - a(href="/challenges/48", class="#{ cc[48] > 0 ? 'strikethrough' : '' }") Use Redis to Persist Data - |   (45 minutes) - li - a(href="/challenges/49", class="#{ cc[49] > 0 ? 'strikethrough' : '' }") Dive Deeper into Express.js - |   (45 minutes) - li - a(href="/challenges/50", class="#{ cc[50] > 0 ? 'strikethrough' : '' }") Set up Express.js Middleware - |   (45 minutes) - li - a(href="/challenges/51", class="#{ cc[51] > 0 ? 'strikethrough' : '' }") Take Advantage of Parameters - |   (45 minutes) - li - a(href="/challenges/52", class="#{ cc[52] > 0 ? 'strikethrough' : '' }") Add the Body Parser - |   (45 minutes) - li - a(href="/challenges/53", class="#{ cc[53] > 0 ? 'strikethrough' : '' }") Configure Routes in Express.js - |   (45 minutes) - li - a(href="/challenges/54", class="#{ cc[54] > 0 ? 'strikethrough' : '' }") Try MongoDB - |   (30 minutes) - li - a(href="/challenges/55", class="#{ cc[55] > 0 ? 'strikethrough' : '' }") Get Started with Angular.js - |   (45 minutes) - li - a(href="/challenges/56", class="#{ cc[56] > 0 ? 'strikethrough' : '' }") Apply Angular.js Directives - |   (45 minutes) - li - a(href="/challenges/57", class="#{ cc[57] > 0 ? 'strikethrough' : '' }") Power Forms with Angular.js - |   (45 minutes) - li - a(href="/challenges/58", class="#{ cc[58] > 0 ? 'strikethrough' : '' }") Customize Angular.js Directives - |   (45 minutes) - li - a(href="/challenges/59", class="#{ cc[59] > 0 ? 'strikethrough' : '' }") Create Angular.js Services - |   (45 minutes) + a(href="/challenges/#{challenge.challengeNumber}", class="#{ (cc && cc[challenge.challengeNumber] > 0) ? 'strikethrough' : '' }") #{challenge.name} + |   (#{challenge.time} mins) - a.btn.btn-primary(href="/done-with-first-100-hours", class="#{ cc[59] > 0 ? '' : 'disabled' }") I've finished all Free Code Camp challenges and all the Easy and Medium CoderByte Challenges \ No newline at end of file + + a.btn.btn-primary(href="/done-with-first-100-hours", class="#{ cc && cc[59] > 0 ? 'disabled' : '' }") I've finished all Free Code Camp challenges and all the Easy and Medium CoderByte Challenges \ No newline at end of file From ca6652a791178291934ca2ee5e481fc0b84d83e9 Mon Sep 17 00:00:00 2001 From: Michael Q Larson Date: Tue, 23 Dec 2014 08:22:50 -0800 Subject: [PATCH 18/20] refactor views to remove hardcoded challenge data --- controllers/user.js | 16 ++- seed_data/challenges.json | 4 +- views/account/profile.jade | 246 +-------------------------------- views/partials/challenges.jade | 3 +- 4 files changed, 21 insertions(+), 248 deletions(-) diff --git a/controllers/user.js b/controllers/user.js index 48048b0c7c..1da0cb9f34 100644 --- a/controllers/user.js +++ b/controllers/user.js @@ -6,6 +6,7 @@ var passport = require('passport'); var User = require('../models/User'); var secrets = require('../config/secrets'); var moment = require('moment'); +var Challenge = require('./../models/Challenge'); /** * GET /login @@ -130,10 +131,17 @@ exports.postEmailSignup = function(req, res, next) { */ exports.getAccount = function(req, res) { - res.render('account/profile', { - title: 'Manage your Free Code Camp Account', - cc: req.user.challengesHash, - moment: moment + Challenge.find({}, function (err, c) { + if (err) { + console.error('Challenge err: ', err); + next(err); + } + res.render('account/profile', { + title: 'Manage your Free Code Camp Account', + cc: c, + ch: req.user.challengesHash, + moment: moment + }); }); }; diff --git a/seed_data/challenges.json b/seed_data/challenges.json index 77161bfa46..fce4df3015 100644 --- a/seed_data/challenges.json +++ b/seed_data/challenges.json @@ -192,8 +192,8 @@ ] }, { - "name": "Customize Bootstrap with Bootswatch", - "time": 10, + "name": "Customize Bootstrap", + "time": 15, "video": "110752741", "challengeNumber": 16, "steps": [ diff --git a/views/account/profile.jade b/views/account/profile.jade index 4f883901cb..422cb6f5b5 100644 --- a/views/account/profile.jade +++ b/views/account/profile.jade @@ -40,246 +40,12 @@ block content tr th Challenge th Date Finished - if cc[0] > 0 - tr - td Learn how Free Code Camp Works - td=moment(cc[0], 'X').format("MMM DD, YYYY") - if cc[1] > 0 - tr - td Join Our Chat Room - td=moment(cc[1], 'X').format("MMM DD, YYYY") - if cc[2] > 0 - tr - td Subscribe to Our Subreddit - td=moment(cc[2], 'X').format("MMM DD, YYYY") - if cc[3] > 0 - tr - td Build a Personal Website - td=moment(cc[3], 'X').format("MMM DD, YYYY") - if cc[4] > 0 - tr - td Build a Responsive Blog Theme - td=moment(cc[4], 'X').format("MMM DD, YYYY") - if cc[5] > 0 - tr - td Build a Small Business Website - td=moment(cc[5], 'X').format("MMM DD, YYYY") - if cc[6] > 0 - tr - td Tweak HTML and CSS in CodePen - td=moment(cc[6], 'X').format("MMM DD, YYYY") - if cc[7] > 0 - tr - td Build a CSS Robot - td=moment(cc[7], 'X').format("MMM DD, YYYY") - if cc[8] > 0 - tr - td Get Started with jQuery - td=moment(cc[8], 'X').format("MMM DD, YYYY") - if cc[9] > 0 - tr - td Traverse the DOM - td=moment(cc[9], 'X').format("MMM DD, YYYY") - if cc[10] > 0 - tr - td Work with the DOM - td=moment(cc[10], 'X').format("MMM DD, YYYY") - if cc[11] > 0 - tr - td Listen for DOM Events - td=moment(cc[11], 'X').format("MMM DD, YYYY") - if cc[12] > 0 - tr - td Use jQuery for Styling - td=moment(cc[12], 'X').format("MMM DD, YYYY") - if cc[13] > 0 - tr - td Build a MadLibs Game - td=moment(cc[13], 'X').format("MMM DD, YYYY") - if cc[14] > 0 - tr - td Discover Chrome's DevTools - td=moment(cc[14], 'X').format("MMM DD, YYYY") - if cc[15] > 0 - tr - td Tackle jQuery Exercises - td=moment(cc[15], 'X').format("MMM DD, YYYY") - if cc[16] > 0 - tr - td Customize Bootstrap - td=moment(cc[16], 'X').format("MMM DD, YYYY") - if cc[17] > 0 - tr - td Inject Animation into CSS - td=moment(cc[17], 'X').format("MMM DD, YYYY") - if cc[18] > 0 - tr - td Learn Basic Computer Science - td=moment(cc[18], 'X').format("MMM DD, YYYY") - if cc[19] > 0 - tr - td Learn Loops - td=moment(cc[19], 'X').format("MMM DD, YYYY") - if cc[20] > 0 - tr - td Learn Computer Hardware - td=moment(cc[20], 'X').format("MMM DD, YYYY") - if cc[21] > 0 - tr - td Learn Computer Networking - td=moment(cc[21], 'X').format("MMM DD, YYYY") - if cc[22] > 0 - tr - td Learn Boolean Logic - td=moment(cc[22], 'X').format("MMM DD, YYYY") - if cc[23] > 0 - tr - td Learn Computer Security - td=moment(cc[23], 'X').format("MMM DD, YYYY") - if cc[24] > 0 - tr - td Build an Adventure Game - td=moment(cc[24], 'X').format("MMM DD, YYYY") - if cc[25] > 0 - tr - td Build Rock Paper Scissors - td=moment(cc[25], 'X').format("MMM DD, YYYY") - if cc[26] > 0 - tr - td Learn JavaScript For Loops - td=moment(cc[26], 'X').format("MMM DD, YYYY") - if cc[27] > 0 - tr - td Learn JavaScript While Loops - td=moment(cc[27], 'X').format("MMM DD, YYYY") - if cc[28] > 0 - tr - td Learn Control Flow - td=moment(cc[28], 'X').format("MMM DD, YYYY") - if cc[29] > 0 - tr - td Build a Contact List - td=moment(cc[29], 'X').format("MMM DD, YYYY") - if cc[30] > 0 - tr - td Build an Address Book - td=moment(cc[30], 'X').format("MMM DD, YYYY") - if cc[31] > 0 - tr - td Build a Cash Register - td=moment(cc[31], 'X').format("MMM DD, YYYY") - if cc[32] > 0 - tr - td Get Help the Hacker Way - td=moment(cc[32], 'X').format("MMM DD, YYYY") - if cc[33] > 0 - tr - td Learn Regular Expressions - td=moment(cc[33], 'X').format("MMM DD, YYYY") - if cc[34] > 0 - tr - td Pair Program on CoderByte - td=moment(cc[34], 'X').format("MMM DD, YYYY") - if cc[35] > 0 - tr - td Learn Relational Database Theory - td=moment(cc[35], 'X').format("MMM DD, YYYY") - if cc[36] > 0 - tr - td Pair Program to Query SQL pt 1 - td=moment(cc[36], 'X').format("MMM DD, YYYY") - if cc[37] > 0 - tr - td Pair Program to Query SQL pt 2 - td=moment(cc[37], 'X').format("MMM DD, YYYY") - if cc[38] > 0 - tr - td Pair Program to modify SQL pt 1 - td=moment(cc[38], 'X').format("MMM DD, YYYY") - if cc[39] > 0 - tr - td Pair Program to modify SQL pt 2 - td=moment(cc[39], 'X').format("MMM DD, YYYY") - if cc[40] > 0 - tr - td Learn JSON - td=moment(cc[40], 'X').format("MMM DD, YYYY") - if cc[41] > 0 - tr - td Manage Source Code with Git - td=moment(cc[41], 'X').format("MMM DD, YYYY") - if cc[42] > 0 - tr - td Get Started with Node.js - td=moment(cc[42], 'X').format("MMM DD, YYYY") - if cc[43] > 0 - tr - td Try Node.js Events - td=moment(cc[43], 'X').format("MMM DD, YYYY") - if cc[44] > 0 - tr - td Try Node.js Streams - td=moment(cc[44], 'X').format("MMM DD, YYYY") - if cc[45] > 0 - tr - td Learn how Node.js Modules Work - td=moment(cc[45], 'X').format("MMM DD, YYYY") - if cc[46] > 0 - tr - td Start an Express.js Server - td=moment(cc[46], 'X').format("MMM DD, YYYY") - if cc[47] > 0 - tr - td Use Socket.io - td=moment(cc[47], 'X').format("MMM DD, YYYY") - if cc[48] > 0 - tr - td Use Redis to Persist Data - td=moment(cc[48], 'X').format("MMM DD, YYYY") - if cc[49] > 0 - tr - td Dive Deeper into Express.js - td=moment(cc[49], 'X').format("MMM DD, YYYY") - if cc[50] > 0 - tr - td Set up Express.js Middleware - td=moment(cc[50], 'X').format("MMM DD, YYYY") - if cc[51] > 0 - tr - td Take Advantage of Parameters - td=moment(cc[51], 'X').format("MMM DD, YYYY") - if cc[52] > 0 - tr - td Add the Body Parser - td=moment(cc[52], 'X').format("MMM DD, YYYY") - if cc[53] > 0 - tr - td Configure Routes in Express.js - td=moment(cc[53], 'X').format("MMM DD, YYYY") - if cc[54] > 0 - tr - td Try MongoDB - td=moment(cc[54], 'X').format("MMM DD, YYYY") - if cc[55] > 0 - tr - td Get Started with Angular.js - td=moment(cc[55], 'X').format("MMM DD, YYYY") - if cc[56] > 0 - tr - td Apply Angular.js Directives - td=moment(cc[56], 'X').format("MMM DD, YYYY") - if cc[57] > 0 - tr - td Power Forms with Angular.js - td=moment(cc[57], 'X').format("MMM DD, YYYY") - if cc[58] > 0 - tr - td Customize Angular.js Directives - td=moment(cc[58], 'X').format("MMM DD, YYYY") - if cc[59] > 0 - tr - td Create Angular.js Services - td=moment(cc[59], 'X').format("MMM DD, YYYY") + for challenge in cc + if ch[challenge.challengeNumber] > 0 + tr + td= cc[challenge.challengeNumber].name + td= moment(ch[challenge.challengeNumber], 'X').format("MMM DD, YYYY") + h3 Danger Zone button.btn.btn-danger.confirm-deletion span.ion-trash-b diff --git a/views/partials/challenges.jade b/views/partials/challenges.jade index d6a42bc96a..25b47ce541 100644 --- a/views/partials/challenges.jade +++ b/views/partials/challenges.jade @@ -7,5 +7,4 @@ a(href="/challenges/#{challenge.challengeNumber}", class="#{ (cc && cc[challenge.challengeNumber] > 0) ? 'strikethrough' : '' }") #{challenge.name} |   (#{challenge.time} mins) - - a.btn.btn-primary(href="/done-with-first-100-hours", class="#{ cc && cc[59] > 0 ? 'disabled' : '' }") I've finished all Free Code Camp challenges and all the Easy and Medium CoderByte Challenges \ No newline at end of file + a.btn.btn-primary(href="/done-with-first-100-hours", class="#{ ((cc && cc[59] > 0) || (!cc)) ? 'disabled' : '' }") I've finished all Free Code Camp challenges and all the Easy and Medium CoderByte Challenges \ No newline at end of file From a032be6a0b05c0f3bbd0663fedf83a5d8ddb7250 Mon Sep 17 00:00:00 2001 From: Michael Q Larson Date: Tue, 23 Dec 2014 11:20:31 -0800 Subject: [PATCH 19/20] fix finished challenges button --- seed_data/challenges.json | 4 ++-- views/partials/challenges.jade | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/seed_data/challenges.json b/seed_data/challenges.json index fce4df3015..c85a0eca54 100644 --- a/seed_data/challenges.json +++ b/seed_data/challenges.json @@ -36,7 +36,7 @@ { "name": "Join our Forum", "time": 5, - "video": "114578442", + "video": "115275066", "challengeNumber": 2, "steps": [ "Go to Free Code Camp's forum: http://forum.freecodecamp.com.", @@ -46,7 +46,7 @@ "Click on the \"Introduce yourself here\" discussion.", "Here you can read through other Free Code Camp community members' self introductions.", "Go ahead and type a brief self introduction of your own.", - "Click on the \"Categories\" drop-down menu. You should see a category called \"Local Chapters\". Click that. If your city isn't already on the list, you can create a topic for it. Otherwise, you can also introduce yourself to the other Code Campers from your city.", + "Click on the \"Categories\" drop-down menu. You should see a category called \"Local Chapters\". Click that. If your city isn't already on the list, create a topic for it. Otherwise, introduce yourself to the other Code Campers from your city.", "Come back here daily to ask questions, engage in discussions, and share links to helpful coding tools." ] }, diff --git a/views/partials/challenges.jade b/views/partials/challenges.jade index 25b47ce541..de9fd2c3c6 100644 --- a/views/partials/challenges.jade +++ b/views/partials/challenges.jade @@ -7,4 +7,4 @@ a(href="/challenges/#{challenge.challengeNumber}", class="#{ (cc && cc[challenge.challengeNumber] > 0) ? 'strikethrough' : '' }") #{challenge.name} |   (#{challenge.time} mins) - a.btn.btn-primary(href="/done-with-first-100-hours", class="#{ ((cc && cc[59] > 0) || (!cc)) ? 'disabled' : '' }") I've finished all Free Code Camp challenges and all the Easy and Medium CoderByte Challenges \ No newline at end of file + a.btn.btn-primary(href="/done-with-first-100-hours", class="#{ ((cc && cc[59] === 0) || (!cc)) ? 'disabled' : '' }") I've finished all Free Code Camp challenges and all the Easy and Medium CoderByte Challenges \ No newline at end of file From 3ac4ecdd08f016012d7c7b87d26363143c8d675a Mon Sep 17 00:00:00 2001 From: Michael Q Larson Date: Tue, 23 Dec 2014 12:16:23 -0800 Subject: [PATCH 20/20] add twitter social functionality --- controllers/challenges.js | 5 +++++ views/challenges/show.jade | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/controllers/challenges.js b/controllers/challenges.js index 83e5b09c58..3e38ef7c82 100644 --- a/controllers/challenges.js +++ b/controllers/challenges.js @@ -7,6 +7,8 @@ var _ = require('lodash'); exports.returnChallenge = function(req, res, next) { var challengeNumber = parseInt(req.params.challengeNumber) || 0; + var verbs = ['ACED', 'NAILED', 'ROCKED', 'SCORCHED', 'DEVASTATED', 'OWNED', 'CRUSHED', 'CONQUERED', 'KILLED', 'SHREDDED', 'ANNIHILATED', 'NUKED'] + var phrases = ['Shout it from on top of a mountain', 'Tell everyone and their dogs', "Show them. Show them all!", "Inspire your friends", "Tell the world of your greatness", "Look accomplished on social media", 'Share news of your grand endeavor', 'Establish your alibi for the past two hours', "Prove to mom that computers aren't just for games"] if (challengeNumber > 59) { challengeNumber = 0; } Challenge.find({}, function (err, c) { if (err) { @@ -19,7 +21,10 @@ exports.returnChallenge = function(req, res, next) { video: c[challengeNumber].video, time: c[challengeNumber].time, steps: c[challengeNumber].steps, + number: challengeNumber, cc: req.user ? req.user.challengesHash : undefined, + verb: verbs[Math.floor(Math.random()*verbs.length)], + phrase: phrases[Math.floor(Math.random()*phrases.length)], challenges: c }); }); diff --git a/views/challenges/show.jade b/views/challenges/show.jade index 33f15599c9..2af4860aa5 100644 --- a/views/challenges/show.jade +++ b/views/challenges/show.jade @@ -34,6 +34,11 @@ block content .animated.zoomInUp.delay-1 span.landing-icon.ion-checkmark-circled.text-primary a.animated.fadeIn.delay-2.btn.btn-lg.btn-primary.btn-block.next-button(name='_csrf', value=_csrf, aria-hidden='true') Take me to my next challenge + if (cc && cc[2] > 0) + a.animated.fadeIn.delay-2.btn-twitter.btn.btn-lg.btn-info.btn-block(href="https://twitter.com/intent/tweet?text=I%20just%20#{verb}%20Free%20Code%20Camp%20Challenge%20%23#{number}:%20#{name}&url=http%3A%2F%2Ffreecodecamp.com/challenges/#{number}&hashtags=learntocode, javascript") + i.fa.fa-twitter   + = phrase + #skip-dialog.modal .modal-dialog.animated.zoomIn.fast-animation .modal-content