128 lines
		
	
	
		
			2.9 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			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
 | |
|       );
 | |
|   };
 | |
| }
 |