Files
freeCodeCamp/server/services/map.js
Berkeley Martinez 606bfd7c88 Fix(accounts): show challenge info on user profile
This changes the behavior of the user profile page to pull the current
challenge info from our challenge map and overwrite the user challenge.
This should also make name changes point to the correct challenge
regardless of the info saved to the user profile
2016-08-01 18:48:31 -07:00

129 lines
3.6 KiB
JavaScript

import { Observable } from 'rx';
import debug from 'debug';
import { unDasherize } from '../utils';
import { mapChallengeToLang, cachedMap, getMapForLang } from '../utils/map';
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');
function shouldNotFilterComingSoon({ isComingSoon, isBeta: challengeIsBeta }) {
return isDev ||
!isComingSoon ||
(isBeta && challengeIsBeta);
}
function getFirstChallenge(challengeMap$) {
return challengeMap$
.map(({ entities: { superBlock, block, challenge }, result }) => {
return challenge[
block[
superBlock[
result[0]
].blocks[0]
].challenges[0]
];
});
}
// this is a hard search
// falls back to soft search
function getChallengeAndBlock(
challengeDashedName,
blockDashedName,
challengeMap$,
lang
) {
return challengeMap$
.flatMap(({ entities }) => {
const block = entities.block[blockDashedName];
const challenge = entities.challenge[challengeDashedName];
if (
!block ||
!challenge ||
!shouldNotFilterComingSoon(challenge)
) {
return getChallengeByDashedName(
challengeDashedName,
challengeMap$,
lang
);
}
return Observable.just({
redirect: block.dashedName !== blockDashedName ?
`/challenges/${block.dashedName}/${challenge.dashedName}` :
false,
entities: {
challenge: {
[challenge.dashedName]: mapChallengeToLang(challenge, lang)
}
},
result: {
block: block.dashedName,
challenge: challenge.dashedName
}
});
});
}
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 shouldNotFilterComingSoon(challenge) &&
testChallengeName.test(challenge.name);
})
.last({ defaultValue: null })
.flatMap(challengeOrNull => {
if (challengeOrNull) {
return Observable.just(challengeOrNull);
}
return getFirstChallenge(challengeMap$);
})
.map(challenge => ({
redirect:
`/challenges/${challenge.block}/${challenge.dashedName}`,
entities: {
challenge: {
[challenge.dashedName]: mapChallengeToLang(challenge, lang)
}
},
result: {
challenge: challenge.dashedName,
block: challenge.block
}
}));
}
export default function mapService(app) {
const Block = app.models.Block;
const challengeMap$ = cachedMap(Block);
return {
name: 'map',
read: (req, resource, { lang, block, dashedName } = {}, config, cb) => {
log(`${lang} language requested`);
if (block && dashedName) {
return getChallengeAndBlock(dashedName, block, challengeMap$, lang)
.subscribe(challenge => cb(null, challenge), cb);
}
if (dashedName) {
return getChallengeByDashedName(dashedName, challengeMap$, lang)
.subscribe(challenge => cb(null, challenge), cb);
}
return challengeMap$
.map(getMapForLang(lang))
.subscribe(map => cb(null, map), cb);
}
};
}