2016-02-09 21:22:43 +00:00
|
|
|
import { Observable, Scheduler } from 'rx';
|
2016-02-10 22:32:14 +00:00
|
|
|
import { ObjectID } from 'mongodb';
|
2016-02-09 21:22:43 +00:00
|
|
|
import debug from 'debug';
|
|
|
|
|
2016-02-11 00:34:09 +00:00
|
|
|
import idMap from '../utils/bad-id-map';
|
|
|
|
|
2016-02-09 21:22:43 +00:00
|
|
|
const log = debug('freecc:migrate');
|
2016-02-10 21:26:32 +00:00
|
|
|
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;
|
|
|
|
}
|
2016-02-09 21:22:43 +00:00
|
|
|
|
2016-02-10 23:18:48 +00:00
|
|
|
function updateId(challenge) {
|
2016-02-11 00:31:59 +00:00
|
|
|
if (idMap.hasOwnProperty(challenge.id)) {
|
2016-02-10 23:18:48 +00:00
|
|
|
challenge.id = idMap[challenge.id];
|
|
|
|
}
|
2016-02-11 00:45:57 +00:00
|
|
|
|
2016-02-10 23:18:48 +00:00
|
|
|
return challenge;
|
|
|
|
}
|
|
|
|
|
2016-02-09 21:22:43 +00:00
|
|
|
// buildChallengeMap(
|
|
|
|
// userId: String,
|
|
|
|
// completedChallenges: Object[],
|
|
|
|
// User: User
|
|
|
|
// ) => Observable
|
|
|
|
function buildChallengeMap(userId, completedChallenges = [], User) {
|
|
|
|
return Observable.from(
|
|
|
|
completedChallenges,
|
|
|
|
null,
|
|
|
|
null,
|
|
|
|
Scheduler.default
|
|
|
|
)
|
2016-02-11 00:45:57 +00:00
|
|
|
.map(challenge => {
|
|
|
|
return challenge && typeof challenge.toJSON === 'function' ?
|
|
|
|
challenge.toJSON() :
|
|
|
|
challenge;
|
|
|
|
})
|
2016-02-10 23:18:48 +00:00
|
|
|
.map(updateId)
|
2016-02-11 00:34:09 +00:00
|
|
|
.filter(({ id, _id }) => ObjectID.isValid(id || _id))
|
2016-02-10 21:26:32 +00:00
|
|
|
.map(updateName)
|
2016-02-09 21:22:43 +00:00
|
|
|
.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();
|
|
|
|
}
|
|
|
|
return buildChallengeMap(
|
|
|
|
user.id.toString(),
|
|
|
|
user.completedChallenges,
|
|
|
|
User
|
|
|
|
)
|
|
|
|
.subscribe(
|
|
|
|
count => log('documents update', count),
|
|
|
|
// errors go here
|
|
|
|
next,
|
|
|
|
next
|
|
|
|
);
|
|
|
|
};
|
|
|
|
}
|