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
129 lines
3.6 KiB
JavaScript
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);
|
|
}
|
|
};
|
|
}
|