feat(challenge-redirect): Make '/challenge' and '/map' redirect to learn (#17144)
* feat(challenge-redirect): Make '/challenge' and '/map' redirect to learn * fix(linting): Generate pathMigrationMap on 'prelint-js' * fix(script): fix "only once" script * fix(lock): Fix lock file
This commit is contained in:
committed by
mrugesh mohapatra
parent
058ec5d247
commit
5eb90ed8c8
1
.gitignore
vendored
1
.gitignore
vendored
@ -43,6 +43,7 @@ seed/unpacked
|
|||||||
server/rev-manifest.json
|
server/rev-manifest.json
|
||||||
server/manifests/*
|
server/manifests/*
|
||||||
!server/manifests/README.md
|
!server/manifests/README.md
|
||||||
|
server/resources/pathMigration.json
|
||||||
|
|
||||||
public/js/main*
|
public/js/main*
|
||||||
public/js/commonFramework*
|
public/js/commonFramework*
|
||||||
|
14
gulpfile.js
14
gulpfile.js
@ -38,7 +38,9 @@ const Rx = require('rx'),
|
|||||||
|
|
||||||
// rev
|
// rev
|
||||||
rev = require('gulp-rev'),
|
rev = require('gulp-rev'),
|
||||||
revDel = require('rev-del');
|
revDel = require('rev-del'),
|
||||||
|
|
||||||
|
{ createPathMigrationMap } = require('./seed/createPathMigrationMap');
|
||||||
|
|
||||||
Rx.config.longStackSupport = true;
|
Rx.config.longStackSupport = true;
|
||||||
const sync = browserSync.create('fcc-sync-server');
|
const sync = browserSync.create('fcc-sync-server');
|
||||||
@ -395,6 +397,10 @@ gulp.task('build-manifest', buildDependents, function() {
|
|||||||
.pipe(gulp.dest('server/'));
|
.pipe(gulp.dest('server/'));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
gulp.task('generate-migration-map', done => {
|
||||||
|
createPathMigrationMap().then(done);
|
||||||
|
});
|
||||||
|
|
||||||
gulp.task('build', [
|
gulp.task('build', [
|
||||||
'less',
|
'less',
|
||||||
'js',
|
'js',
|
||||||
@ -402,7 +408,8 @@ gulp.task('build', [
|
|||||||
'pack-frame-runner',
|
'pack-frame-runner',
|
||||||
'move-webpack-manifest',
|
'move-webpack-manifest',
|
||||||
'clean-webpack-manifest',
|
'clean-webpack-manifest',
|
||||||
'build-manifest'
|
'build-manifest',
|
||||||
|
'generate-migration-map'
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const watchDependents = [
|
const watchDependents = [
|
||||||
@ -424,5 +431,6 @@ gulp.task('default', [
|
|||||||
'serve',
|
'serve',
|
||||||
'watch',
|
'watch',
|
||||||
'dev-server',
|
'dev-server',
|
||||||
'pack-frame-runner'
|
'pack-frame-runner',
|
||||||
|
'generate-migration-map'
|
||||||
]);
|
]);
|
||||||
|
16
package-lock.json
generated
16
package-lock.json
generated
@ -11364,17 +11364,23 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"loopback-component-passport": {
|
"loopback-component-passport": {
|
||||||
"version": "git+https://github.com/freeCodeCamp/loopback-component-passport.git#e158f6bbd631e00e0194515ae25b9971c58a1121",
|
"version": "git+https://github.com/freeCodeCamp/loopback-component-passport.git#6097e69ec12ecfb306c8c83aa6af66f7e25fbb95",
|
||||||
"requires": {
|
"requires": {
|
||||||
"passport": "0.4.0",
|
"passport": "0.4.0",
|
||||||
"strong-globalize": "2.10.0",
|
"strong-globalize": "2.10.0",
|
||||||
"underscore": "1.8.3"
|
"underscore": "1.9.0",
|
||||||
|
"uuid": "3.2.1"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"underscore": {
|
"underscore": {
|
||||||
"version": "1.8.3",
|
"version": "1.9.0",
|
||||||
"resolved": "https://registry.npmjs.org/underscore/-/underscore-1.8.3.tgz",
|
"resolved": "https://registry.npmjs.org/underscore/-/underscore-1.9.0.tgz",
|
||||||
"integrity": "sha1-Tz+1OxBuYJf8+ctBCfKl6b36UCI="
|
"integrity": "sha512-4IV1DSSxC1QK48j9ONFK1MoIAKKkbE8i7u55w2R6IqBqbT7A/iG7aZBCR2Bi8piF0Uz+i/MG1aeqLwl/5vqF+A=="
|
||||||
|
},
|
||||||
|
"uuid": {
|
||||||
|
"version": "3.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.2.1.tgz",
|
||||||
|
"integrity": "sha512-jZnMwlb9Iku/O3smGWvZhauCf6cvvpKi4BKRiliS3cxnI+Gz9j5MEpTz2UFuXiKPJocb7gnsLHwiS05ige5BEA=="
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -17,8 +17,8 @@
|
|||||||
"lint-utils": "jsonlint-cli server/utils/*.json",
|
"lint-utils": "jsonlint-cli server/utils/*.json",
|
||||||
"lint-js": "eslint --ext=.js,.jsx gulpfile.js server/ common/ config/ client/",
|
"lint-js": "eslint --ext=.js,.jsx gulpfile.js server/ common/ config/ client/",
|
||||||
"lint-json": "npm run lint-server && npm run lint-challenges && npm run lint-resources && npm run lint-utils",
|
"lint-json": "npm run lint-server && npm run lint-challenges && npm run lint-resources && npm run lint-utils",
|
||||||
"only-once": "npm run create-rev && echo '/****/' && echo 'Seeding Database' && echo '/****/' && node seed && echo '/****/' && echo 'Seeding Completed' && echo '/****/'",
|
"only-once": "npm run prelint-js && echo '/****/' && echo 'Seeding Database' && echo '/****/' && node seed && echo '/****/' && echo 'Seeding Completed' && echo '/****/'",
|
||||||
"prelint-js": "npm run create-rev",
|
"prelint-js": "npm run create-rev && gulp generate-migration-map",
|
||||||
"pretest": "npm run create-rev && npm run lint",
|
"pretest": "npm run create-rev && npm run lint",
|
||||||
"prestart-production": "gulp build -p",
|
"prestart-production": "gulp build -p",
|
||||||
"seed": "node seed",
|
"seed": "node seed",
|
||||||
|
60
seed/createPathMigrationMap.js
Normal file
60
seed/createPathMigrationMap.js
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
require('babel-register');
|
||||||
|
|
||||||
|
const fs = require('fs');
|
||||||
|
const path = require('path');
|
||||||
|
const { Observable } = require('rx');
|
||||||
|
const getChallenges = require('./getChallenges');
|
||||||
|
const { dasherize } = require('../server/utils');
|
||||||
|
|
||||||
|
let pathMap = {};
|
||||||
|
|
||||||
|
function createPathMigrationMap() {
|
||||||
|
return new Promise(resolve => {
|
||||||
|
Observable.of(getChallenges())
|
||||||
|
.map(blocks => {
|
||||||
|
blocks.forEach(block => {
|
||||||
|
const {name: blockName, superBlock, challenges } = block;
|
||||||
|
if (!(dasherize(superBlock) in pathMap)) {
|
||||||
|
pathMap[dasherize(superBlock)] = {};
|
||||||
|
}
|
||||||
|
if (!(dasherize(blockName) in pathMap[superBlock])) {
|
||||||
|
pathMap[dasherize(superBlock)][dasherize(blockName)] = challenges
|
||||||
|
.map(({ title, challengeType }) => ({
|
||||||
|
dashedName: dasherize(title),
|
||||||
|
challengeType
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.subscribe(() => {}, console.error, () => {
|
||||||
|
const migMap = Object.keys(pathMap)
|
||||||
|
.filter(key => !key.includes('certificate'))
|
||||||
|
.map(superBlock => {
|
||||||
|
return Object.keys(pathMap[superBlock])
|
||||||
|
.map(block => {
|
||||||
|
return pathMap[superBlock][block]
|
||||||
|
.reduce((map, {dashedName, challengeType}) => ({
|
||||||
|
...map,
|
||||||
|
[dashedName]: challengeType === 7 ?
|
||||||
|
`/${superBlock}/${block}` :
|
||||||
|
`/${superBlock}/${block}/${dashedName}`
|
||||||
|
}), {});
|
||||||
|
}).reduce((acc, current) => ({
|
||||||
|
...acc,
|
||||||
|
...current
|
||||||
|
}), {});
|
||||||
|
}).reduce((acc, current) => ({
|
||||||
|
...acc,
|
||||||
|
...current
|
||||||
|
}), {});
|
||||||
|
fs.writeFileSync(
|
||||||
|
path.resolve(__dirname, '../server/resources/pathMigration.json'),
|
||||||
|
JSON.stringify(migMap, null, 2)
|
||||||
|
);
|
||||||
|
resolve();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
exports.createPathMigrationMap = createPathMigrationMap;
|
@ -5,9 +5,14 @@ import dedent from 'dedent';
|
|||||||
|
|
||||||
import { ifNoUserSend } from '../utils/middleware';
|
import { ifNoUserSend } from '../utils/middleware';
|
||||||
import { getChallengeById, cachedMap } from '../utils/map';
|
import { getChallengeById, cachedMap } from '../utils/map';
|
||||||
|
import { dasherize } from '../utils';
|
||||||
|
|
||||||
|
import pathMigrations from '../resources/pathMigration.json';
|
||||||
|
|
||||||
const log = debug('fcc:boot:challenges');
|
const log = debug('fcc:boot:challenges');
|
||||||
|
|
||||||
|
const learnURL = 'https://learn.freecodecamp.org';
|
||||||
|
|
||||||
function buildUserUpdate(
|
function buildUserUpdate(
|
||||||
user,
|
user,
|
||||||
challengeId,
|
challengeId,
|
||||||
@ -122,6 +127,12 @@ export default function(app) {
|
|||||||
redirectToCurrentChallenge
|
redirectToCurrentChallenge
|
||||||
);
|
);
|
||||||
|
|
||||||
|
router.get('/challenges', redirectToLearn);
|
||||||
|
|
||||||
|
router.get('/challenges/*', redirectToLearn);
|
||||||
|
|
||||||
|
router.get('/map', redirectToLearn);
|
||||||
|
|
||||||
app.use(api);
|
app.use(api);
|
||||||
app.use('/:lang', router);
|
app.use('/:lang', router);
|
||||||
|
|
||||||
@ -348,7 +359,7 @@ export default function(app) {
|
|||||||
const challengeId = user && user.currentChallengeId;
|
const challengeId = user && user.currentChallengeId;
|
||||||
return getChallengeById(map, challengeId)
|
return getChallengeById(map, challengeId)
|
||||||
.map(challenge => {
|
.map(challenge => {
|
||||||
const { block, dashedName } = challenge;
|
const { block, dashedName, superBlock } = challenge;
|
||||||
if (!dashedName || !block) {
|
if (!dashedName || !block) {
|
||||||
// this should normally not be hit if database is properly seeded
|
// this should normally not be hit if database is properly seeded
|
||||||
throw new Error(dedent`
|
throw new Error(dedent`
|
||||||
@ -358,11 +369,20 @@ export default function(app) {
|
|||||||
db may not be properly seeded.
|
db may not be properly seeded.
|
||||||
`);
|
`);
|
||||||
}
|
}
|
||||||
return `/challenges/${block}/${dashedName}`;
|
return `${learnURL}/${dasherize(superBlock)}/${block}/${dashedName}`;
|
||||||
})
|
})
|
||||||
.subscribe(
|
.subscribe(
|
||||||
redirect => res.redirect(redirect || '/'),
|
redirect => res._oldRedirect(redirect || learnURL),
|
||||||
next
|
next
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function redirectToLearn(req, res) {
|
||||||
|
const maybeChallenge = _.last(req.path.split('/'));
|
||||||
|
if (maybeChallenge in pathMigrations) {
|
||||||
|
const redirectPath = pathMigrations[maybeChallenge];
|
||||||
|
return res.status(302)._oldRedirect(`${learnURL}${redirectPath}`);
|
||||||
|
}
|
||||||
|
return res.status(302)._oldRedirect(learnURL);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
3
server/boot/react.js
vendored
3
server/boot/react.js
vendored
@ -17,9 +17,6 @@ const isDev = process.env.NODE_ENV !== 'production';
|
|||||||
// add routes here as they slowly get reactified
|
// add routes here as they slowly get reactified
|
||||||
// remove their individual controllers
|
// remove their individual controllers
|
||||||
const routes = [
|
const routes = [
|
||||||
'/challenges',
|
|
||||||
'/challenges/*',
|
|
||||||
'/map',
|
|
||||||
'/settings',
|
'/settings',
|
||||||
'/settings/*',
|
'/settings/*',
|
||||||
'/portfolio/:username'
|
'/portfolio/:username'
|
||||||
|
Reference in New Issue
Block a user