freeCodeCamp/server/services/map.js

134 lines
3.8 KiB
JavaScript
Raw Normal View History

2016-03-12 05:45:58 +00:00
import { Observable } from 'rx';
import debug from 'debug';
import { unDasherize } from '../utils';
import { mapChallengeToLang, cachedMap, getMapForLang } from '../utils/map';
2016-03-12 05:45:58 +00:00
const isDev = process.env.NODE_ENV !== 'production';
const isBeta = !!process.env.BETA;
const challengesRegex = /^(bonfire|waypoint|zipline|basejump|checkpoint)/i;
const log = debug('fcc:services:map');
2016-06-17 19:35:10 +00:00
// if challenge is not isComingSoon or isBeta => load
// if challenge is commingSoon we are in beta||dev => load
// if challenge is beta and we are in beta||dev => load
// else hide
function loadComingSoonOrBetaChallenge({
isComingSoon,
isBeta: challengeIsBeta
}) {
return !(isComingSoon || challengeIsBeta) || isDev || isBeta;
}
function getFirstChallenge(challengeMap$) {
return challengeMap$
.map(({ entities: { superBlock, block, challenge }, result }) => {
return challenge[
block[
superBlock[
result[0]
].blocks[0]
].challenges[0]
];
});
}
2016-06-09 23:02:51 +00:00
// this is a hard search
// falls back to soft search
function getChallengeAndBlock(
challengeDashedName,
blockDashedName,
2016-06-17 19:35:10 +00:00
challengeMap$,
lang
2016-06-09 23:02:51 +00:00
) {
return challengeMap$
.flatMap(({ entities }) => {
const block = entities.block[blockDashedName];
const challenge = entities.challenge[challengeDashedName];
if (
!block ||
!challenge ||
!loadComingSoonOrBetaChallenge(challenge)
2016-06-09 23:02:51 +00:00
) {
2016-06-17 19:35:10 +00:00
return getChallengeByDashedName(
challengeDashedName,
challengeMap$,
lang
);
2016-06-09 23:02:51 +00:00
}
return Observable.just({
redirect: block.dashedName !== blockDashedName ?
`/challenges/${block.dashedName}/${challenge.dashedName}` :
false,
entities: {
challenge: {
2016-06-17 19:35:10 +00:00
[challenge.dashedName]: mapChallengeToLang(challenge, lang)
2016-06-09 23:02:51 +00:00
}
},
result: {
block: block.dashedName,
challenge: challenge.dashedName
}
});
});
}
2016-06-17 19:35:10 +00:00
function getChallengeByDashedName(dashedName, challengeMap$, lang) {
const challengeName = unDasherize(dashedName)
.replace(challengesRegex, '');
const testChallengeName = new RegExp(challengeName, 'i');
log('looking for %s', testChallengeName);
return challengeMap$
.map(({ entities }) => entities.challenge)
.flatMap(challengeMap => {
return Observable.from(Object.keys(challengeMap))
.map(key => challengeMap[key]);
})
.filter(challenge => {
return loadComingSoonOrBetaChallenge(challenge) &&
testChallengeName.test(challenge.name);
})
.last({ defaultValue: null })
.flatMap(challengeOrNull => {
if (challengeOrNull) {
return Observable.just(challengeOrNull);
}
return getFirstChallenge(challengeMap$);
})
.map(challenge => ({
2016-06-09 23:02:51 +00:00
redirect:
`/challenges/${challenge.block}/${challenge.dashedName}`,
2016-06-17 19:35:10 +00:00
entities: {
challenge: {
[challenge.dashedName]: mapChallengeToLang(challenge, lang)
}
},
2016-06-09 23:02:51 +00:00
result: {
challenge: challenge.dashedName,
block: challenge.block
2016-06-09 23:02:51 +00:00
}
}));
}
2016-03-12 05:45:58 +00:00
export default function mapService(app) {
const Block = app.models.Block;
const challengeMap$ = cachedMap(Block);
return {
name: 'map',
2016-06-17 19:35:10 +00:00
read: (req, resource, { lang, block, dashedName } = {}, config, cb) => {
log(`${lang} language requested`);
2016-06-09 23:02:51 +00:00
if (block && dashedName) {
2016-06-17 19:35:10 +00:00
return getChallengeAndBlock(dashedName, block, challengeMap$, lang)
2016-06-09 23:02:51 +00:00
.subscribe(challenge => cb(null, challenge), cb);
}
if (dashedName) {
2016-06-17 19:35:10 +00:00
return getChallengeByDashedName(dashedName, challengeMap$, lang)
.subscribe(challenge => cb(null, challenge), cb);
}
2016-06-17 19:35:10 +00:00
return challengeMap$
.map(getMapForLang(lang))
.subscribe(map => cb(null, map), cb);
2016-03-12 05:45:58 +00:00
}
};
}