Merge branch 'master' into remove-angular

Conflicts:
	bower.json
	client/main.js
	server/views/coursewares/showZiplineOrBasejump.jade
	server/views/partials/scripts.jade
This commit is contained in:
Quincy Larson
2015-12-04 18:49:38 -06:00
366 changed files with 12566 additions and 124259 deletions

View File

@@ -4,7 +4,15 @@ import moment from 'moment';
import { Observable, Scheduler } from 'rx';
import assign from 'object.assign';
import debugFactory from 'debug';
import utils from '../utils';
import {
dasherize,
unDasherize,
getMDNLinks,
randomVerb,
randomPhrase,
randomCompliment
} from '../utils';
import {
saveUser,
@@ -16,9 +24,13 @@ import {
ifNoUserSend
} from '../utils/middleware';
import getFromDisk$ from '../utils/getFromDisk$';
const isDev = process.env.NODE_ENV !== 'production';
const isBeta = !!process.env.BETA;
const debug = debugFactory('freecc:challenges');
const challengesRegex = /^(bonfire|waypoint|zipline|basejump)/i;
const firstChallenge = 'waypoint-say-hello-to-html-elements';
const firstChallenge = 'waypoint-learn-how-free-code-camp-works';
const challengeView = {
0: 'coursewares/showHTML',
1: 'coursewares/showJS',
@@ -29,16 +41,14 @@ const challengeView = {
7: 'coursewares/showStep'
};
const dasherize = utils.dasherize;
const unDasherize = utils.unDasherize;
const getMDNLinks = utils.getMDNLinks;
/*
function makeChallengesUnique(challengeArr) {
// clone and reverse challenges
// then filter by unique id's
// then reverse again
return _.uniq(challengeArr.slice().reverse(), 'id').reverse();
}
*/
function numberWithCommas(x) {
return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',');
}
@@ -47,12 +57,12 @@ function updateUserProgress(user, challengeId, completedChallenge) {
let { completedChallenges } = user;
// migrate user challenges object to remove
if (!user.isUniqMigrated) {
/* if (!user.isUniqMigrated) {
user.isUniqMigrated = true;
completedChallenges = user.completedChallenges =
makeChallengesUnique(completedChallenges);
}
}*/
const indexOfChallenge = _.findIndex(completedChallenges, {
id: challengeId
@@ -105,6 +115,9 @@ module.exports = function(app) {
null,
Scheduler.default
))
// filter out all challenges that have isBeta flag set
// except in development or beta site
.filter(challenge => isDev || isBeta || !challenge.isBeta)
.shareReplay();
// create a stream of challenge blocks
@@ -181,7 +194,7 @@ module.exports = function(app) {
);
}
const firstChallengeOfNextBlock$ = blocks$
.elementAtOrDefault(blockIndex + 1, {})
.elementAt(blockIndex + 1, {})
.map(({ challenges = [] }) => challenges[0]);
return blocks$
@@ -226,8 +239,8 @@ module.exports = function(app) {
req.flash('info', {
msg: dedent`
Once you have completed all of our challenges, you should
join our <a href=\"//gitter.im/freecodecamp/HalfWayClub\"
target=\"_blank\">Half Way Club</a> and start getting
join our <a href="https://gitter.im/freecodecamp/HalfWayClub"
target="_blank">Half Way Club</a> and start getting
ready for our nonprofit projects.
`.split('\n').join(' ')
});
@@ -254,7 +267,13 @@ module.exports = function(app) {
.filter((challenge) => {
return testChallengeName.test(challenge.name);
})
.lastOrDefault(null)
.last({ defaultValue: null })
.flatMap(challenge => {
if (challenge && isDev) {
return getFromDisk$(challenge);
}
return Observable.just(challenge);
})
.flatMap(challenge => {
// Handle not found
@@ -281,27 +300,32 @@ module.exports = function(app) {
// save user does nothing if user does not exist
return Observable.just({
title: challenge.name,
dashedName: origChallengeName,
name: challenge.name,
details: challenge.description,
description: challenge.description,
tests: challenge.tests,
challengeSeed: challenge.challengeSeed,
verb: utils.randomVerb(),
phrase: utils.randomPhrase(),
compliment: utils.randomCompliment(),
challengeId: challenge.id,
challengeType: challenge.challengeType,
dashedName: origChallengeName,
challengeSeed: challenge.challengeSeed,
head: challenge.head,
tail: challenge.tail,
tests: challenge.tests,
// video challenges
video: challenge.challengeSeed[0],
// bonfires specific
difficulty: Math.floor(+challenge.difficulty),
bonfires: challenge,
MDNkeys: challenge.MDNlinks,
MDNlinks: getMDNLinks(challenge.MDNlinks),
// htmls specific
environment: utils.whichEnvironment()
verb: randomVerb(),
phrase: randomPhrase(),
compliment: randomCompliment()
});
})
.subscribe(
@@ -510,6 +534,24 @@ module.exports = function(app) {
}
function challengeMap({ user = {} }, res, next) {
// small helper function to determine whether to mark something as new
function shouldShowNew(element, block) {
if (element) {
return (typeof element.releasedOn !== 'undefined' &&
moment(element.releasedOn, 'MMM MMMM DD, YYYY')
.diff(moment(), 'days') >= -30);
} else if (block) {
const newCount = block.reduce((sum, { markNew }) => {
if (markNew) {
return sum + 1;
}
return sum;
}, 0);
return newCount / block.length * 100 === 100;
}
}
let lastCompleted;
const daysRunning = moment().diff(new Date('10/15/2014'), 'days');
@@ -530,6 +572,7 @@ module.exports = function(app) {
if (completedChallenges.indexOf(challenge.id) !== -1) {
challenge.completed = true;
}
challenge.markNew = shouldShowNew(challenge);
return challenge;
})
// group challenges by block | returns a stream of observables
@@ -543,12 +586,16 @@ module.exports = function(app) {
}
return sum;
}, 0);
const isBeta = _.every(blockArray, 'isBeta');
return {
isBeta,
name: blockArray[0].block,
dashedName: dasherize(blockArray[0].block),
markNew: shouldShowNew(null, blockArray),
challenges: blockArray,
completed: completedCount / blockArray.length * 100
completed: completedCount / blockArray.length * 100,
time: blockArray[0] && blockArray[0].time || '???'
};
})
.filter(({ name }) => name !== 'Hikes')
@@ -571,9 +618,12 @@ module.exports = function(app) {
res.render('challengeMap/show', {
blocks,
daysRunning,
globalCompletedCount: numberWithCommas(
5612952 + (Math.floor((Date.now() - 1446268581061) / 2000))
),
camperCount,
lastCompleted,
title: "A map of all Free Code Camp's Challenges"
title: 'A Map to Learn to Code and Become a Software Engineer'
});
},
next