freeCodeCamp/server/middlewares/migrate-completed-challenge...

128 lines
2.9 KiB
JavaScript

import { Observable, Scheduler } from 'rx';
import { ObjectID } from 'mongodb';
import debug from 'debug';
import idMap from '../utils/bad-id-map';
const log = debug('freecc:migrate');
const challengeTypes = {
html: 0,
js: 1,
video: 2,
zipline: 3,
basejump: 4,
bonfire: 5,
hikes: 6,
step: 7,
waypoint: 0
};
const challengeTypeReg = /^(waypoint|hike|zipline|basejump)/i;
const challengeTypeRegWithColon =
/^(bonfire|checkpoint|waypoint|hike|zipline|basejump):\s+/i;
function updateName(challenge) {
if (
challenge.name &&
challenge.challengeType === 5 &&
challengeTypeReg.test(challenge.name)
) {
challenge.name.replace(challengeTypeReg, match => {
// find the correct type
const type = challengeTypes[''.toLowerCase.call(match)];
// if type found, replace current type
//
if (type) {
challenge.challengeType = type;
}
return match;
});
}
if (challenge.name) {
challenge.oldName = challenge.name;
challenge.name = challenge.name.replace(challengeTypeRegWithColon, '');
}
return challenge;
}
function updateId(challenge) {
if (idMap.hasOwnProperty(challenge.id)) {
challenge.id = idMap[challenge.id];
}
return challenge;
}
// buildChallengeMap(
// userId: String,
// completedChallenges: Object[],
// User: User
// ) => Observable
function buildChallengeMap(userId, completedChallenges = [], User) {
return Observable.from(
completedChallenges,
null,
null,
Scheduler.default
)
.map(challenge => {
return challenge && typeof challenge.toJSON === 'function' ?
challenge.toJSON() :
challenge;
})
.map(updateId)
.filter(({ id, _id }) => ObjectID.isValid(id || _id))
.map(updateName)
.reduce((challengeMap, challenge) => {
const id = challenge.id || challenge._id;
challengeMap[id] = challenge;
return challengeMap;
}, {})
.flatMap(challengeMap => {
const updateData = {
$set: {
challengeMap,
isChallengeMapMigrated: true
}
};
return Observable.fromNodeCallback(User.updateAll, User)(
{ id: userId },
updateData,
{ allowExtendedOperators: true }
);
});
}
export default function migrateCompletedChallenges() {
return ({ user, app }, res, next) => {
const User = app.models.User;
if (!user || user.isChallengeMapMigrated) {
return next();
}
const id = user.id.toString();
return User.findOne$({
where: { id },
fields: { completedChallenges: true }
})
.map(({ completedChallenges = [] } = {}) => completedChallenges)
.flatMap(completedChallenges => {
return buildChallengeMap(
id,
completedChallenges,
User
);
})
.subscribe(
count => log('documents update', count),
// errors go here
next,
next
);
};
}