| 
									
										
										
										
											2015-10-02 11:47:36 -07:00
										 |  |  | import _ from 'lodash'; | 
					
						
							| 
									
										
										
										
											2016-05-03 00:45:34 -07:00
										 |  |  | import loopback from 'loopback'; | 
					
						
							|  |  |  | import path from 'path'; | 
					
						
							| 
									
										
										
										
											2015-10-02 11:47:36 -07:00
										 |  |  | import dedent from 'dedent'; | 
					
						
							|  |  |  | import { Observable } from 'rx'; | 
					
						
							| 
									
										
										
										
											2016-02-09 20:54:49 -08:00
										 |  |  | import debug from 'debug'; | 
					
						
							| 
									
										
										
										
											2017-08-26 00:27:05 +02:00
										 |  |  | import { isEmail } from 'validator'; | 
					
						
							| 
									
										
										
										
											2018-09-04 14:54:23 +01:00
										 |  |  | import format from 'date-fns/format'; | 
					
						
							| 
									
										
										
										
											2015-10-02 11:47:36 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-04 14:54:23 +01:00
										 |  |  | import { ifNoUser401 } from '../utils/middleware'; | 
					
						
							| 
									
										
										
										
											2016-02-09 20:54:49 -08:00
										 |  |  | import { observeQuery } from '../utils/rx'; | 
					
						
							| 
									
										
										
										
											2015-10-05 19:58:44 -07:00
										 |  |  | import { | 
					
						
							| 
									
										
										
										
											2018-02-27 14:03:06 +00:00
										 |  |  |   legacyFrontEndChallengeId, | 
					
						
							|  |  |  |   legacyBackEndChallengeId, | 
					
						
							|  |  |  |   legacyDataVisId, | 
					
						
							| 
									
										
										
										
											2017-12-21 01:15:23 +00:00
										 |  |  |   respWebDesignId, | 
					
						
							|  |  |  |   frontEndLibsId, | 
					
						
							|  |  |  |   jsAlgoDataStructId, | 
					
						
							| 
									
										
										
										
											2018-02-27 14:03:06 +00:00
										 |  |  |   dataVis2018Id, | 
					
						
							| 
									
										
										
										
											2017-12-21 01:15:23 +00:00
										 |  |  |   apisMicroservicesId, | 
					
						
							| 
									
										
										
										
											2018-08-02 20:13:10 +05:30
										 |  |  |   infosecQaId, | 
					
						
							|  |  |  |   fullStackId | 
					
						
							| 
									
										
										
										
											2015-10-05 19:58:44 -07:00
										 |  |  | } from '../utils/constantStrings.json'; | 
					
						
							| 
									
										
										
										
											2018-02-27 14:03:06 +00:00
										 |  |  | import certTypes from '../utils/certTypes.json'; | 
					
						
							|  |  |  | import superBlockCertTypeMap from '../utils/superBlockCertTypeMap'; | 
					
						
							| 
									
										
										
										
											2018-09-04 14:54:23 +01:00
										 |  |  | import { completeCommitment$ } from '../utils/commit'; | 
					
						
							| 
									
										
										
										
											2015-10-06 21:08:24 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-27 11:34:44 -08:00
										 |  |  | const log = debug('fcc:certification'); | 
					
						
							| 
									
										
										
										
											2018-09-04 14:54:23 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | export default function bootCertificate(app) { | 
					
						
							|  |  |  |   const api = app.loopback.Router(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const certTypeIds = createCertTypeIds(app); | 
					
						
							|  |  |  |   const showCert = createShowCert(app); | 
					
						
							|  |  |  |   const verifyCert = createVerifyCert(certTypeIds, app); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-25 12:51:17 +01:00
										 |  |  |   api.put('/certificate/verify', ifNoUser401, ifNoSuperBlock404, verifyCert); | 
					
						
							| 
									
										
										
										
											2018-09-04 14:54:23 +01:00
										 |  |  |   api.get('/certificate/showCert/:username/:cert', showCert); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   app.use('/internal', api); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const noNameMessage = dedent`
 | 
					
						
							|  |  |  |   We need your name so we can put it on your certification. | 
					
						
							|  |  |  |   Add your name to your account settings and click the save button. | 
					
						
							|  |  |  |   Then we can issue your certification. | 
					
						
							|  |  |  |   `;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const notCertifiedMessage = name => dedent`
 | 
					
						
							| 
									
										
										
										
											2018-09-25 12:51:17 +01:00
										 |  |  |   It looks like you have not completed the necessary steps. | 
					
						
							|  |  |  |   Please complete the required projects to claim the | 
					
						
							|  |  |  |   ${name} Certification | 
					
						
							| 
									
										
										
										
											2018-09-04 14:54:23 +01:00
										 |  |  |   `;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const alreadyClaimedMessage = name => dedent`
 | 
					
						
							| 
									
										
										
										
											2018-09-25 12:51:17 +01:00
										 |  |  |     It looks like you already have claimed the ${name} Certification | 
					
						
							| 
									
										
										
										
											2018-09-04 14:54:23 +01:00
										 |  |  |     `;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const successMessage = (username, name) => dedent`
 | 
					
						
							|  |  |  |     @${username}, you have successfully claimed | 
					
						
							| 
									
										
										
										
											2018-09-25 12:51:17 +01:00
										 |  |  |     the ${name} Certification! | 
					
						
							| 
									
										
										
										
											2018-09-04 14:54:23 +01:00
										 |  |  |     Congratulations on behalf of the freeCodeCamp.org team! | 
					
						
							|  |  |  |     `;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function ifNoSuperBlock404(req, res, next) { | 
					
						
							|  |  |  |   const { superBlock } = req.body; | 
					
						
							|  |  |  |   if (superBlock && superBlocks.includes(superBlock)) { | 
					
						
							|  |  |  |     return next(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   return res.status(404).end(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const renderCertifedEmail = loopback.template( | 
					
						
							|  |  |  |   path.join(__dirname, '..', 'views', 'emails', 'certified.ejs') | 
					
						
							|  |  |  | ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function createCertTypeIds(app) { | 
					
						
							|  |  |  |   const { Challenge } = app.models; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return { | 
					
						
							|  |  |  |     // legacy
 | 
					
						
							|  |  |  |     [certTypes.frontEnd]: getIdsForCert$(legacyFrontEndChallengeId, Challenge), | 
					
						
							|  |  |  |     [certTypes.backEnd]: getIdsForCert$(legacyBackEndChallengeId, Challenge), | 
					
						
							|  |  |  |     [certTypes.dataVis]: getIdsForCert$(legacyDataVisId, Challenge), | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // modern
 | 
					
						
							|  |  |  |     [certTypes.respWebDesign]: getIdsForCert$(respWebDesignId, Challenge), | 
					
						
							|  |  |  |     [certTypes.frontEndLibs]: getIdsForCert$(frontEndLibsId, Challenge), | 
					
						
							|  |  |  |     [certTypes.dataVis2018]: getIdsForCert$(dataVis2018Id, Challenge), | 
					
						
							|  |  |  |     [certTypes.jsAlgoDataStruct]: getIdsForCert$(jsAlgoDataStructId, Challenge), | 
					
						
							|  |  |  |     [certTypes.apisMicroservices]: getIdsForCert$( | 
					
						
							|  |  |  |       apisMicroservicesId, | 
					
						
							|  |  |  |       Challenge | 
					
						
							|  |  |  |     ), | 
					
						
							|  |  |  |     [certTypes.infosecQa]: getIdsForCert$(infosecQaId, Challenge), | 
					
						
							|  |  |  |     [certTypes.fullStack]: getIdsForCert$(fullStackId, Challenge) | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2015-10-02 11:47:36 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-15 14:56:26 +01:00
										 |  |  | function isCertified(ids, completedChallenges = []) { | 
					
						
							| 
									
										
										
										
											2018-09-04 14:54:23 +01:00
										 |  |  |   return _.every(ids, ({ id }) => | 
					
						
							|  |  |  |     _.find(completedChallenges, ({ id: completedId }) => completedId === id) | 
					
						
							| 
									
										
										
										
											2018-05-15 14:56:26 +01:00
										 |  |  |   ); | 
					
						
							| 
									
										
										
										
											2015-10-02 11:47:36 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-27 14:03:06 +00:00
										 |  |  | const certIds = { | 
					
						
							|  |  |  |   [certTypes.frontEnd]: legacyFrontEndChallengeId, | 
					
						
							|  |  |  |   [certTypes.backEnd]: legacyBackEndChallengeId, | 
					
						
							|  |  |  |   [certTypes.dataVis]: legacyDataVisId, | 
					
						
							|  |  |  |   [certTypes.respWebDesign]: respWebDesignId, | 
					
						
							|  |  |  |   [certTypes.frontEndLibs]: frontEndLibsId, | 
					
						
							|  |  |  |   [certTypes.jsAlgoDataStruct]: jsAlgoDataStructId, | 
					
						
							|  |  |  |   [certTypes.dataVis2018]: dataVis2018Id, | 
					
						
							|  |  |  |   [certTypes.apisMicroservices]: apisMicroservicesId, | 
					
						
							| 
									
										
										
										
											2018-08-02 20:13:10 +05:30
										 |  |  |   [certTypes.infosecQa]: infosecQaId, | 
					
						
							|  |  |  |   [certTypes.fullStack]: fullStackId | 
					
						
							| 
									
										
										
										
											2018-02-27 14:03:06 +00:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const certText = { | 
					
						
							| 
									
										
										
										
											2018-05-15 14:56:26 +01:00
										 |  |  |   [certTypes.frontEnd]: 'Legacy Front End', | 
					
						
							|  |  |  |   [certTypes.backEnd]: 'Legacy Back End', | 
					
						
							|  |  |  |   [certTypes.dataVis]: 'Legacy Data Visualization', | 
					
						
							| 
									
										
										
										
											2018-09-04 14:54:23 +01:00
										 |  |  |   [certTypes.fullStack]: 'Full Stack', | 
					
						
							| 
									
										
										
										
											2018-05-15 14:56:26 +01:00
										 |  |  |   [certTypes.respWebDesign]: 'Responsive Web Design', | 
					
						
							|  |  |  |   [certTypes.frontEndLibs]: 'Front End Libraries', | 
					
						
							| 
									
										
										
										
											2018-09-04 14:54:23 +01:00
										 |  |  |   [certTypes.jsAlgoDataStruct]: 'JavaScript Algorithms and Data Structures', | 
					
						
							| 
									
										
										
										
											2018-05-15 14:56:26 +01:00
										 |  |  |   [certTypes.dataVis2018]: 'Data Visualization', | 
					
						
							|  |  |  |   [certTypes.apisMicroservices]: 'APIs and Microservices', | 
					
						
							|  |  |  |   [certTypes.infosecQa]: 'Information Security and Quality Assurance' | 
					
						
							| 
									
										
										
										
											2018-02-27 14:03:06 +00:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-04 14:54:23 +01:00
										 |  |  | const completionHours = { | 
					
						
							|  |  |  |   [certTypes.frontEnd]: 400, | 
					
						
							|  |  |  |   [certTypes.backEnd]: 400, | 
					
						
							|  |  |  |   [certTypes.dataVis]: 400, | 
					
						
							|  |  |  |   [certTypes.fullStack]: 1800, | 
					
						
							|  |  |  |   [certTypes.respWebDesign]: 300, | 
					
						
							|  |  |  |   [certTypes.frontEndLibs]: 300, | 
					
						
							|  |  |  |   [certTypes.jsAlgoDataStruct]: 300, | 
					
						
							|  |  |  |   [certTypes.dataVis2018]: 300, | 
					
						
							|  |  |  |   [certTypes.apisMicroservices]: 300, | 
					
						
							|  |  |  |   [certTypes.infosecQa]: 300 | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-11 15:58:37 -08:00
										 |  |  | function getIdsForCert$(id, Challenge) { | 
					
						
							| 
									
										
										
										
											2018-09-04 14:54:23 +01:00
										 |  |  |   return observeQuery(Challenge, 'findById', id, { | 
					
						
							|  |  |  |     id: true, | 
					
						
							|  |  |  |     tests: true, | 
					
						
							|  |  |  |     name: true, | 
					
						
							|  |  |  |     challengeType: true | 
					
						
							|  |  |  |   }).shareReplay(); | 
					
						
							| 
									
										
										
										
											2016-01-11 15:58:37 -08:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2015-10-02 11:47:36 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-04 14:54:23 +01:00
										 |  |  | const superBlocks = Object.keys(superBlockCertTypeMap); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-03 00:45:34 -07:00
										 |  |  | function sendCertifiedEmail( | 
					
						
							|  |  |  |   { | 
					
						
							| 
									
										
										
										
											2018-07-02 09:06:35 +01:00
										 |  |  |     email = '', | 
					
						
							| 
									
										
										
										
											2016-05-03 00:45:34 -07:00
										 |  |  |     name, | 
					
						
							|  |  |  |     username, | 
					
						
							| 
									
										
										
										
											2017-12-21 01:15:23 +00:00
										 |  |  |     isRespWebDesignCert, | 
					
						
							|  |  |  |     isFrontEndLibsCert, | 
					
						
							|  |  |  |     isJsAlgoDataStructCert, | 
					
						
							|  |  |  |     isDataVisCert, | 
					
						
							|  |  |  |     isApisMicroservicesCert, | 
					
						
							|  |  |  |     isInfosecQaCert | 
					
						
							| 
									
										
										
										
											2016-05-03 00:45:34 -07:00
										 |  |  |   }, | 
					
						
							|  |  |  |   send$ | 
					
						
							|  |  |  | ) { | 
					
						
							|  |  |  |   if ( | 
					
						
							| 
									
										
										
										
											2017-08-26 00:27:05 +02:00
										 |  |  |     !isEmail(email) || | 
					
						
							| 
									
										
										
										
											2017-12-21 01:15:23 +00:00
										 |  |  |     !isRespWebDesignCert || | 
					
						
							|  |  |  |     !isFrontEndLibsCert || | 
					
						
							|  |  |  |     !isJsAlgoDataStructCert || | 
					
						
							|  |  |  |     !isDataVisCert || | 
					
						
							|  |  |  |     !isApisMicroservicesCert || | 
					
						
							|  |  |  |     !isInfosecQaCert | 
					
						
							| 
									
										
										
										
											2016-05-03 00:45:34 -07:00
										 |  |  |   ) { | 
					
						
							|  |  |  |     return Observable.just(false); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   const notifyUser = { | 
					
						
							|  |  |  |     type: 'email', | 
					
						
							|  |  |  |     to: email, | 
					
						
							| 
									
										
										
										
											2017-09-08 10:52:40 -07:00
										 |  |  |     from: 'team@freeCodeCamp.org', | 
					
						
							|  |  |  |     subject: dedent`
 | 
					
						
							|  |  |  |       Congratulations on completing all of the | 
					
						
							| 
									
										
										
										
											2018-05-21 16:21:15 +01:00
										 |  |  |       freeCodeCamp certifications! | 
					
						
							| 
									
										
										
										
											2017-09-08 10:52:40 -07:00
										 |  |  |     `,
 | 
					
						
							| 
									
										
										
										
											2016-05-03 00:45:34 -07:00
										 |  |  |     text: renderCertifedEmail({ | 
					
						
							|  |  |  |       username, | 
					
						
							|  |  |  |       name | 
					
						
							|  |  |  |     }) | 
					
						
							|  |  |  |   }; | 
					
						
							| 
									
										
										
										
											2017-08-26 00:27:05 +02:00
										 |  |  |   return send$(notifyUser).map(() => true); | 
					
						
							| 
									
										
										
										
											2016-05-03 00:45:34 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-25 12:51:17 +01:00
										 |  |  | function getUserIsCertMap(user) { | 
					
						
							|  |  |  |   const { | 
					
						
							|  |  |  |     isRespWebDesignCert = false, | 
					
						
							|  |  |  |     isJsAlgoDataStructCert = false, | 
					
						
							|  |  |  |     isFrontEndLibsCert = false, | 
					
						
							|  |  |  |     is2018DataVisCert = false, | 
					
						
							|  |  |  |     isApisMicroservicesCert = false, | 
					
						
							|  |  |  |     isInfosecQaCert = false, | 
					
						
							|  |  |  |     isFrontEndCert = false, | 
					
						
							|  |  |  |     isBackEndCert = false, | 
					
						
							|  |  |  |     isDataVisCert = false, | 
					
						
							|  |  |  |     isFullStackCert = false | 
					
						
							|  |  |  |   } = user; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return { | 
					
						
							|  |  |  |     isRespWebDesignCert, | 
					
						
							|  |  |  |     isJsAlgoDataStructCert, | 
					
						
							|  |  |  |     isFrontEndLibsCert, | 
					
						
							|  |  |  |     is2018DataVisCert, | 
					
						
							|  |  |  |     isApisMicroservicesCert, | 
					
						
							|  |  |  |     isInfosecQaCert, | 
					
						
							|  |  |  |     isFrontEndCert, | 
					
						
							|  |  |  |     isBackEndCert, | 
					
						
							|  |  |  |     isDataVisCert, | 
					
						
							|  |  |  |     isFullStackCert | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-04 14:54:23 +01:00
										 |  |  | function createVerifyCert(certTypeIds, app) { | 
					
						
							|  |  |  |   const { Email } = app.models; | 
					
						
							|  |  |  |   return function verifyCert(req, res, next) { | 
					
						
							|  |  |  |     const { | 
					
						
							|  |  |  |       body: { superBlock }, | 
					
						
							|  |  |  |       user | 
					
						
							|  |  |  |     } = req; | 
					
						
							| 
									
										
										
										
											2018-02-27 14:03:06 +00:00
										 |  |  |     log(superBlock); | 
					
						
							| 
									
										
										
										
											2018-02-16 23:18:53 +00:00
										 |  |  |     let certType = superBlockCertTypeMap[superBlock]; | 
					
						
							|  |  |  |     log(certType); | 
					
						
							| 
									
										
										
										
											2018-09-04 14:54:23 +01:00
										 |  |  |     return user | 
					
						
							|  |  |  |       .getCompletedChallenges$() | 
					
						
							| 
									
										
										
										
											2018-02-27 14:03:06 +00:00
										 |  |  |       .flatMap(() => certTypeIds[certType]) | 
					
						
							|  |  |  |       .flatMap(challenge => { | 
					
						
							| 
									
										
										
										
											2018-05-15 14:56:26 +01:00
										 |  |  |         const certName = certText[certType]; | 
					
						
							| 
									
										
										
										
											2018-02-16 23:18:53 +00:00
										 |  |  |         if (user[certType]) { | 
					
						
							| 
									
										
										
										
											2018-05-15 14:56:26 +01:00
										 |  |  |           return Observable.just(alreadyClaimedMessage(certName)); | 
					
						
							| 
									
										
										
										
											2018-02-16 23:18:53 +00:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2018-08-02 20:13:10 +05:30
										 |  |  | 
 | 
					
						
							|  |  |  |         let updateData = { | 
					
						
							| 
									
										
										
										
											2018-09-04 14:54:23 +01:00
										 |  |  |           [certType]: true | 
					
						
							| 
									
										
										
										
											2018-08-02 20:13:10 +05:30
										 |  |  |         }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (challenge) { | 
					
						
							| 
									
										
										
										
											2018-09-04 14:54:23 +01:00
										 |  |  |           const { id, tests, challengeType } = challenge; | 
					
						
							|  |  |  |           if ( | 
					
						
							|  |  |  |             !user[certType] && | 
					
						
							|  |  |  |             !isCertified(tests, user.completedChallenges) | 
					
						
							|  |  |  |           ) { | 
					
						
							| 
									
										
										
										
											2018-08-02 20:13:10 +05:30
										 |  |  |             return Observable.just(notCertifiedMessage(certName)); | 
					
						
							|  |  |  |           } | 
					
						
							| 
									
										
										
										
											2018-09-04 14:54:23 +01:00
										 |  |  |           updateData = { | 
					
						
							|  |  |  |             ...updateData, | 
					
						
							|  |  |  |             completedChallenges: [ | 
					
						
							|  |  |  |               ...user.completedChallenges, | 
					
						
							|  |  |  |               { | 
					
						
							|  |  |  |                 id, | 
					
						
							|  |  |  |                 completedDate: new Date(), | 
					
						
							|  |  |  |                 challengeType | 
					
						
							|  |  |  |               } | 
					
						
							|  |  |  |             ] | 
					
						
							| 
									
										
										
										
											2018-08-02 20:13:10 +05:30
										 |  |  |           }; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (!user.name) { | 
					
						
							|  |  |  |           return Observable.just(noNameMessage); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2016-05-03 00:45:34 -07:00
										 |  |  |         // set here so sendCertifiedEmail works properly
 | 
					
						
							|  |  |  |         // not used otherwise
 | 
					
						
							|  |  |  |         user[certType] = true; | 
					
						
							|  |  |  |         return Observable.combineLatest( | 
					
						
							|  |  |  |           // update user data
 | 
					
						
							|  |  |  |           user.update$(updateData), | 
					
						
							|  |  |  |           // If user has committed to nonprofit,
 | 
					
						
							|  |  |  |           // this will complete their pledge
 | 
					
						
							|  |  |  |           completeCommitment$(user), | 
					
						
							| 
									
										
										
										
											2018-05-15 14:56:26 +01:00
										 |  |  |           // sends notification email is user has all 6 certs
 | 
					
						
							| 
									
										
										
										
											2016-05-03 00:45:34 -07:00
										 |  |  |           // if not it noop
 | 
					
						
							|  |  |  |           sendCertifiedEmail(user, Email.send$), | 
					
						
							|  |  |  |           ({ count }, pledgeOrMessage) => ({ count, pledgeOrMessage }) | 
					
						
							| 
									
										
										
										
											2018-09-04 14:54:23 +01:00
										 |  |  |         ).map(({ count, pledgeOrMessage }) => { | 
					
						
							|  |  |  |           if (typeof pledgeOrMessage === 'string') { | 
					
						
							|  |  |  |             log(pledgeOrMessage); | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |           log(`${count} documents updated`); | 
					
						
							|  |  |  |           return successMessage(user.username, certName); | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  |       }) | 
					
						
							|  |  |  |       .subscribe(message => { | 
					
						
							|  |  |  |         return res.status(200).json({ | 
					
						
							| 
									
										
										
										
											2018-09-25 12:51:17 +01:00
										 |  |  |           response: { | 
					
						
							|  |  |  |             type: message.includes('Congratulations') ? 'success' : 'info', | 
					
						
							|  |  |  |             message | 
					
						
							|  |  |  |           }, | 
					
						
							|  |  |  |           isCertMap: getUserIsCertMap(user) | 
					
						
							| 
									
										
										
										
											2018-09-04 14:54:23 +01:00
										 |  |  |         }); | 
					
						
							|  |  |  |       }, next); | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function createShowCert(app) { | 
					
						
							|  |  |  |   const { User } = app.models; | 
					
						
							| 
									
										
										
										
											2015-10-02 11:47:36 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-04 14:54:23 +01:00
										 |  |  |   function findUserByUsername$(username, fields) { | 
					
						
							|  |  |  |     return observeQuery(User, 'findOne', { | 
					
						
							|  |  |  |       where: { username }, | 
					
						
							|  |  |  |       fields | 
					
						
							|  |  |  |     }); | 
					
						
							| 
									
										
										
										
											2015-10-02 11:47:36 -07:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2018-02-27 14:03:06 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-04 14:54:23 +01:00
										 |  |  |   return function showCert(req, res, next) { | 
					
						
							| 
									
										
										
										
											2018-02-27 14:03:06 +00:00
										 |  |  |     let { username, cert } = req.params; | 
					
						
							|  |  |  |     username = username.toLowerCase(); | 
					
						
							|  |  |  |     const certType = superBlockCertTypeMap[cert]; | 
					
						
							|  |  |  |     const certId = certIds[certType]; | 
					
						
							| 
									
										
										
										
											2018-09-04 14:54:23 +01:00
										 |  |  |     const certTitle = certText[certType]; | 
					
						
							|  |  |  |     const completionTime = completionHours[certType] || 300; | 
					
						
							|  |  |  |     return findUserByUsername$(username, { | 
					
						
							|  |  |  |       isCheater: true, | 
					
						
							|  |  |  |       isFrontEndCert: true, | 
					
						
							|  |  |  |       isBackEndCert: true, | 
					
						
							|  |  |  |       isFullStackCert: true, | 
					
						
							|  |  |  |       isRespWebDesignCert: true, | 
					
						
							|  |  |  |       isFrontEndLibsCert: true, | 
					
						
							|  |  |  |       isJsAlgoDataStructCert: true, | 
					
						
							|  |  |  |       isDataVisCert: true, | 
					
						
							|  |  |  |       is2018DataVisCert: true, | 
					
						
							|  |  |  |       isApisMicroservicesCert: true, | 
					
						
							|  |  |  |       isInfosecQaCert: true, | 
					
						
							|  |  |  |       isHonest: true, | 
					
						
							|  |  |  |       username: true, | 
					
						
							|  |  |  |       name: true, | 
					
						
							|  |  |  |       completedChallenges: true, | 
					
						
							|  |  |  |       profileUI: true | 
					
						
							|  |  |  |     }).subscribe(user => { | 
					
						
							|  |  |  |       if (!user) { | 
					
						
							|  |  |  |         return res.json({ | 
					
						
							|  |  |  |           messages: [ | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |               type: 'info', | 
					
						
							|  |  |  |               message: `We could not find a user with the username "${username}"` | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |           ] | 
					
						
							|  |  |  |         }); | 
					
						
							| 
									
										
										
										
											2018-02-27 14:03:06 +00:00
										 |  |  |       } | 
					
						
							| 
									
										
										
										
											2018-09-04 14:54:23 +01:00
										 |  |  |       const { isLocked, showCerts } = user.profileUI; | 
					
						
							| 
									
										
										
										
											2018-02-27 14:03:06 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-04 14:54:23 +01:00
										 |  |  |       if (!user.name) { | 
					
						
							|  |  |  |         return res.json({ | 
					
						
							|  |  |  |           messages: [ | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |               type: 'info', | 
					
						
							|  |  |  |               message: dedent`
 | 
					
						
							| 
									
										
										
										
											2018-02-27 14:03:06 +00:00
										 |  |  |               This user needs to add their name to their account | 
					
						
							| 
									
										
										
										
											2018-05-20 04:07:41 +01:00
										 |  |  |               in order for others to be able to view their certification. | 
					
						
							| 
									
										
										
										
											2018-02-27 14:03:06 +00:00
										 |  |  |             `
 | 
					
						
							| 
									
										
										
										
											2018-09-04 14:54:23 +01:00
										 |  |  |             } | 
					
						
							|  |  |  |           ] | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2018-02-27 14:03:06 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-04 14:54:23 +01:00
										 |  |  |       if (user.isCheater) { | 
					
						
							|  |  |  |         return res.json({ | 
					
						
							|  |  |  |           messages: [ | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |               type: 'info', | 
					
						
							|  |  |  |               message: | 
					
						
							|  |  |  |                 'This user is not eligible for freeCodeCamp.org ' + | 
					
						
							|  |  |  |                 'certifications at this time' | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |           ] | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2018-02-27 14:03:06 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-04 14:54:23 +01:00
										 |  |  |       if (isLocked) { | 
					
						
							|  |  |  |         return res.json({ | 
					
						
							|  |  |  |           messages: [ | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |               type: 'info', | 
					
						
							|  |  |  |               message: dedent`
 | 
					
						
							| 
									
										
										
										
											2018-02-27 14:03:06 +00:00
										 |  |  |               ${username} has chosen to make their profile | 
					
						
							|  |  |  |                 private. They will need to make their profile public | 
					
						
							| 
									
										
										
										
											2018-05-20 04:07:41 +01:00
										 |  |  |                 in order for others to be able to view their certification. | 
					
						
							|  |  |  |             `
 | 
					
						
							| 
									
										
										
										
											2018-09-04 14:54:23 +01:00
										 |  |  |             } | 
					
						
							|  |  |  |           ] | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2018-05-20 04:07:41 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-04 14:54:23 +01:00
										 |  |  |       if (!showCerts) { | 
					
						
							|  |  |  |         return res.json({ | 
					
						
							|  |  |  |           messages: [ | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |               type: 'info', | 
					
						
							|  |  |  |               message: dedent`
 | 
					
						
							| 
									
										
										
										
											2018-05-20 04:07:41 +01:00
										 |  |  |               ${username} has chosen to make their certifications | 
					
						
							|  |  |  |                 private. They will need to make their certifications public | 
					
						
							|  |  |  |                 in order for others to be able to view them. | 
					
						
							| 
									
										
										
										
											2018-02-27 14:03:06 +00:00
										 |  |  |             `
 | 
					
						
							| 
									
										
										
										
											2018-09-04 14:54:23 +01:00
										 |  |  |             } | 
					
						
							|  |  |  |           ] | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2018-02-27 14:03:06 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-04 14:54:23 +01:00
										 |  |  |       if (!user.isHonest) { | 
					
						
							|  |  |  |         return res.json({ | 
					
						
							|  |  |  |           messages: [ | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |               type: 'info', | 
					
						
							|  |  |  |               message: dedent`
 | 
					
						
							| 
									
										
										
										
											2018-02-27 14:03:06 +00:00
										 |  |  |               ${username} has not yet agreed to our Academic Honesty Pledge. | 
					
						
							|  |  |  |             `
 | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2018-09-04 14:54:23 +01:00
										 |  |  |           ] | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       if (user[certType]) { | 
					
						
							|  |  |  |         const { completedChallenges = [] } = user; | 
					
						
							|  |  |  |         const { completedDate = new Date() } = | 
					
						
							|  |  |  |           _.find(completedChallenges, ({ id }) => certId === id) || {}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         const { username, name } = user; | 
					
						
							|  |  |  |         return res.json({ | 
					
						
							|  |  |  |           certTitle, | 
					
						
							|  |  |  |           username, | 
					
						
							|  |  |  |           name, | 
					
						
							|  |  |  |           date: format(new Date(completedDate), 'MMMM D, YYYY'), | 
					
						
							|  |  |  |           completionTime | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       return res.json({ | 
					
						
							|  |  |  |         messages: [ | 
					
						
							|  |  |  |           { | 
					
						
							|  |  |  |             type: 'info', | 
					
						
							|  |  |  |             message: `It looks like user ${username} is not ${ | 
					
						
							|  |  |  |               certText[certType] | 
					
						
							|  |  |  |             } certified`
 | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |         ] | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |     }, next); | 
					
						
							|  |  |  |   }; | 
					
						
							| 
									
										
										
										
											2015-10-02 11:47:36 -07:00
										 |  |  | } |