| 
									
										
										
										
											2015-10-01 20:55:55 -07:00
										 |  |  | import dedent from 'dedent'; | 
					
						
							| 
									
										
										
										
											2015-08-20 09:40:03 -07:00
										 |  |  | import debugFactory from 'debug'; | 
					
						
							| 
									
										
										
										
											2018-09-07 13:35:42 +01:00
										 |  |  | import { pick } from 'lodash'; | 
					
						
							| 
									
										
										
										
											2018-08-23 16:29:26 +01:00
										 |  |  | import { Observable } from 'rx'; | 
					
						
							| 
									
										
										
										
											2015-08-07 13:31:48 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-07 13:32:38 +01:00
										 |  |  | import { homeLocation } from '../../../config/env'; | 
					
						
							| 
									
										
										
										
											2018-08-23 16:29:26 +01:00
										 |  |  | import { | 
					
						
							|  |  |  |   getProgress, | 
					
						
							|  |  |  |   normaliseUserFields, | 
					
						
							|  |  |  |   userPropsForSession | 
					
						
							|  |  |  | } from '../utils/publicUserProps'; | 
					
						
							|  |  |  | import { fixCompletedChallengeItem } from '../../common/utils'; | 
					
						
							| 
									
										
										
										
											2018-09-07 13:32:38 +01:00
										 |  |  | import { ifNoUser401, ifNoUserRedirectTo } from '../utils/middleware'; | 
					
						
							| 
									
										
										
										
											2019-02-26 21:17:57 +00:00
										 |  |  | import { removeCookies } from '../utils/getSetAccessToken'; | 
					
						
							| 
									
										
										
										
											2015-08-07 13:31:48 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-24 14:32:54 +01:00
										 |  |  | const log = debugFactory('fcc:boot:user'); | 
					
						
							| 
									
										
										
										
											2018-09-07 13:32:38 +01:00
										 |  |  | const sendNonUserToHome = ifNoUserRedirectTo(homeLocation); | 
					
						
							| 
									
										
										
										
											2015-08-19 13:05:53 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-29 14:24:17 +00:00
										 |  |  | function bootUser(app) { | 
					
						
							| 
									
										
										
										
											2016-06-17 12:35:10 -07:00
										 |  |  |   const api = app.loopback.Router(); | 
					
						
							| 
									
										
										
										
											2016-12-17 01:44:06 +05:30
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-29 14:24:17 +00:00
										 |  |  |   const getSessionUser = createReadSessionUser(app); | 
					
						
							|  |  |  |   const postReportUserProfile = createPostReportUserProfile(app); | 
					
						
							|  |  |  |   const postDeleteAccount = createPostDeleteAccount(app); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-23 16:29:26 +01:00
										 |  |  |   api.get('/account', sendNonUserToHome, getAccount); | 
					
						
							|  |  |  |   api.get('/account/unlink/:social', sendNonUserToHome, getUnlinkSocial); | 
					
						
							| 
									
										
										
										
											2018-11-29 14:24:17 +00:00
										 |  |  |   api.get('/user/get-session-user', getSessionUser); | 
					
						
							| 
									
										
										
										
											2018-08-23 16:29:26 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-29 14:24:17 +00:00
										 |  |  |   api.post('/account/delete', ifNoUser401, postDeleteAccount); | 
					
						
							| 
									
										
										
										
											2018-08-23 16:29:26 +01:00
										 |  |  |   api.post('/account/reset-progress', ifNoUser401, postResetProgress); | 
					
						
							| 
									
										
										
										
											2018-11-29 14:24:17 +00:00
										 |  |  |   api.post('/user/report-user/', ifNoUser401, postReportUserProfile); | 
					
						
							| 
									
										
										
										
											2016-09-28 21:26:17 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-29 20:52:41 +01:00
										 |  |  |   app.use('/internal', api); | 
					
						
							| 
									
										
										
										
											2018-11-29 14:24:17 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function createReadSessionUser(app) { | 
					
						
							|  |  |  |   const { Donation } = app.models; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return function getSessionUser(req, res, next) { | 
					
						
							|  |  |  |     const queryUser = req.user; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const source = | 
					
						
							|  |  |  |       queryUser && | 
					
						
							|  |  |  |       Observable.forkJoin( | 
					
						
							|  |  |  |         queryUser.getCompletedChallenges$(), | 
					
						
							|  |  |  |         queryUser.getPoints$(), | 
					
						
							|  |  |  |         Donation.getCurrentActiveDonationCount$(), | 
					
						
							|  |  |  |         (completedChallenges, progressTimestamps, activeDonations) => ({ | 
					
						
							|  |  |  |           activeDonations, | 
					
						
							|  |  |  |           completedChallenges, | 
					
						
							|  |  |  |           progress: getProgress(progressTimestamps, queryUser.timezone) | 
					
						
							|  |  |  |         }) | 
					
						
							|  |  |  |       ); | 
					
						
							|  |  |  |     Observable.if( | 
					
						
							|  |  |  |       () => !queryUser, | 
					
						
							|  |  |  |       Observable.of({ user: {}, result: '' }), | 
					
						
							|  |  |  |       Observable.defer(() => source) | 
					
						
							|  |  |  |         .map(({ activeDonations, completedChallenges, progress }) => ({ | 
					
						
							|  |  |  |           user: { | 
					
						
							|  |  |  |             ...queryUser.toJSON(), | 
					
						
							|  |  |  |             ...progress, | 
					
						
							|  |  |  |             completedChallenges: completedChallenges.map( | 
					
						
							|  |  |  |               fixCompletedChallengeItem | 
					
						
							|  |  |  |             ) | 
					
						
							|  |  |  |           }, | 
					
						
							|  |  |  |           sessionMeta: { activeDonations } | 
					
						
							|  |  |  |         })) | 
					
						
							|  |  |  |         .map(({ user, sessionMeta }) => ({ | 
					
						
							|  |  |  |           user: { | 
					
						
							|  |  |  |             [user.username]: { | 
					
						
							|  |  |  |               ...pick(user, userPropsForSession), | 
					
						
							|  |  |  |               isEmailVerified: !!user.emailVerified, | 
					
						
							|  |  |  |               isGithub: !!user.githubProfile, | 
					
						
							|  |  |  |               isLinkedIn: !!user.linkedin, | 
					
						
							|  |  |  |               isTwitter: !!user.twitter, | 
					
						
							|  |  |  |               isWebsite: !!user.website, | 
					
						
							|  |  |  |               ...normaliseUserFields(user) | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |           }, | 
					
						
							|  |  |  |           sessionMeta, | 
					
						
							|  |  |  |           result: user.username | 
					
						
							|  |  |  |         })) | 
					
						
							|  |  |  |     ).subscribe(user => res.json(user), next); | 
					
						
							|  |  |  |   }; | 
					
						
							| 
									
										
										
										
											2018-08-23 16:29:26 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function getAccount(req, res) { | 
					
						
							|  |  |  |   const { username } = req.user; | 
					
						
							|  |  |  |   return res.redirect('/' + username); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2015-06-03 16:31:42 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-23 16:29:26 +01:00
										 |  |  | function getUnlinkSocial(req, res, next) { | 
					
						
							|  |  |  |   const { user } = req; | 
					
						
							|  |  |  |   const { username } = user; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   let social = req.params.social; | 
					
						
							|  |  |  |   if (!social) { | 
					
						
							|  |  |  |     req.flash('danger', 'No social account found'); | 
					
						
							| 
									
										
										
										
											2015-10-01 20:55:55 -07:00
										 |  |  |     return res.redirect('/' + username); | 
					
						
							| 
									
										
										
										
											2015-06-03 16:19:23 -07:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2015-01-24 04:14:41 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-23 16:29:26 +01:00
										 |  |  |   social = social.toLowerCase(); | 
					
						
							|  |  |  |   const validSocialAccounts = ['twitter', 'linkedin']; | 
					
						
							|  |  |  |   if (validSocialAccounts.indexOf(social) === -1) { | 
					
						
							|  |  |  |     req.flash('danger', 'Invalid social account'); | 
					
						
							|  |  |  |     return res.redirect('/' + username); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2016-09-28 21:26:17 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-23 16:29:26 +01:00
										 |  |  |   if (!user[social]) { | 
					
						
							|  |  |  |     req.flash('danger', `No ${social} account associated`); | 
					
						
							|  |  |  |     return res.redirect('/' + username); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const query = { | 
					
						
							|  |  |  |     where: { | 
					
						
							|  |  |  |       provider: social | 
					
						
							| 
									
										
										
										
											2016-09-28 21:26:17 +07:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2018-08-23 16:29:26 +01:00
										 |  |  |   }; | 
					
						
							| 
									
										
										
										
											2016-09-28 21:26:17 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-23 16:29:26 +01:00
										 |  |  |   return user.identities(query, function(err, identities) { | 
					
						
							|  |  |  |     if (err) { | 
					
						
							|  |  |  |       return next(err); | 
					
						
							| 
									
										
										
										
											2016-09-28 21:26:17 +07:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-23 16:29:26 +01:00
										 |  |  |     // assumed user identity is unique by provider
 | 
					
						
							|  |  |  |     let identity = identities.shift(); | 
					
						
							|  |  |  |     if (!identity) { | 
					
						
							|  |  |  |       req.flash('danger', 'No social account found'); | 
					
						
							| 
									
										
										
										
											2016-09-28 21:26:17 +07:00
										 |  |  |       return res.redirect('/' + username); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-23 16:29:26 +01:00
										 |  |  |     return identity.destroy(function(err) { | 
					
						
							|  |  |  |       if (err) { | 
					
						
							|  |  |  |         return next(err); | 
					
						
							| 
									
										
										
										
											2016-09-28 21:26:17 +07:00
										 |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-23 16:29:26 +01:00
										 |  |  |       const updateData = { [social]: null }; | 
					
						
							| 
									
										
										
										
											2016-09-28 21:26:17 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-12 16:58:34 +00:00
										 |  |  |       return user.updateAttributes(updateData, err => { | 
					
						
							|  |  |  |         if (err) { | 
					
						
							|  |  |  |           return next(err); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2018-08-24 14:32:54 +01:00
										 |  |  |         log(`${social} has been unlinked successfully`); | 
					
						
							| 
									
										
										
										
											2016-09-28 21:26:17 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-23 16:29:26 +01:00
										 |  |  |         req.flash('info', `You've successfully unlinked your ${social}.`); | 
					
						
							| 
									
										
										
										
											2018-11-12 16:58:34 +00:00
										 |  |  |         return res.redirectWithFlash(`${homeLocation}/${username}`); | 
					
						
							|  |  |  |       }); | 
					
						
							| 
									
										
										
										
											2018-08-23 16:29:26 +01:00
										 |  |  |     }); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2016-09-28 21:26:17 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-23 16:29:26 +01:00
										 |  |  | function postResetProgress(req, res, next) { | 
					
						
							|  |  |  |   const { user } = req; | 
					
						
							| 
									
										
										
										
											2019-02-26 23:39:51 +00:00
										 |  |  |   return user.updateAttributes( | 
					
						
							| 
									
										
										
										
											2018-08-23 16:29:26 +01:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2019-02-26 23:39:51 +00:00
										 |  |  |       progressTimestamps: [Date.now()], | 
					
						
							| 
									
										
										
										
											2018-08-23 16:29:26 +01:00
										 |  |  |       currentChallengeId: '', | 
					
						
							|  |  |  |       isRespWebDesignCert: false, | 
					
						
							|  |  |  |       is2018DataVisCert: false, | 
					
						
							|  |  |  |       isFrontEndLibsCert: false, | 
					
						
							|  |  |  |       isJsAlgoDataStructCert: false, | 
					
						
							|  |  |  |       isApisMicroservicesCert: false, | 
					
						
							|  |  |  |       isInfosecQaCert: false, | 
					
						
							|  |  |  |       is2018FullStackCert: false, | 
					
						
							|  |  |  |       isFrontEndCert: false, | 
					
						
							|  |  |  |       isBackEndCert: false, | 
					
						
							|  |  |  |       isDataVisCert: false, | 
					
						
							|  |  |  |       isFullStackCert: false, | 
					
						
							|  |  |  |       completedChallenges: [] | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  |     function(err) { | 
					
						
							|  |  |  |       if (err) { | 
					
						
							|  |  |  |         return next(err); | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2019-02-26 23:39:51 +00:00
										 |  |  |       return res.sendStatus(200); | 
					
						
							| 
									
										
										
										
											2018-08-23 16:29:26 +01:00
										 |  |  |     } | 
					
						
							|  |  |  |   ); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2016-09-28 21:26:17 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-23 16:29:26 +01:00
										 |  |  | function createPostDeleteAccount(app) { | 
					
						
							|  |  |  |   const { User } = app.models; | 
					
						
							|  |  |  |   return function postDeleteAccount(req, res, next) { | 
					
						
							| 
									
										
										
										
											2019-02-26 21:17:57 +00:00
										 |  |  |     return User.destroyById(req.user.id, function(err) { | 
					
						
							| 
									
										
										
										
											2018-08-23 16:29:26 +01:00
										 |  |  |       if (err) { | 
					
						
							|  |  |  |         return next(err); | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2015-06-03 16:19:23 -07:00
										 |  |  |       req.logout(); | 
					
						
							| 
									
										
										
										
											2019-02-26 21:17:57 +00:00
										 |  |  |       removeCookies(req, res); | 
					
						
							|  |  |  |       return res.sendStatus(200); | 
					
						
							| 
									
										
										
										
											2016-09-20 12:43:34 -05:00
										 |  |  |     }); | 
					
						
							| 
									
										
										
										
											2018-08-23 16:29:26 +01:00
										 |  |  |   }; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2016-09-20 12:43:34 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-23 16:29:26 +01:00
										 |  |  | function createPostReportUserProfile(app) { | 
					
						
							|  |  |  |   const { Email } = app.models; | 
					
						
							|  |  |  |   return function postReportUserProfile(req, res, next) { | 
					
						
							| 
									
										
										
										
											2016-12-15 02:54:59 +05:30
										 |  |  |     const { user } = req; | 
					
						
							| 
									
										
										
										
											2018-09-07 13:32:38 +01:00
										 |  |  |     const { username } = req.body; | 
					
						
							| 
									
										
										
										
											2016-12-15 02:54:59 +05:30
										 |  |  |     const report = req.sanitize('reportDescription').trimTags(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-07 13:32:38 +01:00
										 |  |  |     log(username); | 
					
						
							|  |  |  |     log(report); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-15 02:54:59 +05:30
										 |  |  |     if (!username || !report || report === '') { | 
					
						
							| 
									
										
										
										
											2018-09-07 13:32:38 +01:00
										 |  |  |       return res.json({ | 
					
						
							|  |  |  |         type: 'danger', | 
					
						
							| 
									
										
										
										
											2019-06-19 15:31:03 +01:00
										 |  |  |         message: 'Check if you have provided a username and a report' | 
					
						
							| 
									
										
										
										
											2018-09-07 13:32:38 +01:00
										 |  |  |       }); | 
					
						
							| 
									
										
										
										
											2016-12-15 02:54:59 +05:30
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2018-08-23 16:29:26 +01:00
										 |  |  |     return Email.send$( | 
					
						
							|  |  |  |       { | 
					
						
							|  |  |  |         type: 'email', | 
					
						
							|  |  |  |         to: 'team@freecodecamp.org', | 
					
						
							|  |  |  |         cc: user.email, | 
					
						
							|  |  |  |         from: 'team@freecodecamp.org', | 
					
						
							| 
									
										
										
										
											2019-02-06 14:19:58 +00:00
										 |  |  |         subject: `Abuse Report : Reporting ${username}'s profile.`, | 
					
						
							| 
									
										
										
										
											2018-08-23 16:29:26 +01:00
										 |  |  |         text: dedent(`
 | 
					
						
							| 
									
										
										
										
											2016-12-15 02:54:59 +05:30
										 |  |  |         Hello Team,\n | 
					
						
							|  |  |  |         This is to report the profile of ${username}.\n | 
					
						
							|  |  |  |         Report Details:\n | 
					
						
							|  |  |  |         ${report}\n\n | 
					
						
							|  |  |  |         Reported by: | 
					
						
							|  |  |  |         Username: ${user.username} | 
					
						
							|  |  |  |         Name: ${user.name} | 
					
						
							|  |  |  |         Email: ${user.email}\n | 
					
						
							|  |  |  |         Thanks and regards, | 
					
						
							|  |  |  |         ${user.name} | 
					
						
							|  |  |  |       `)
 | 
					
						
							| 
									
										
										
										
											2018-08-23 16:29:26 +01:00
										 |  |  |       }, | 
					
						
							|  |  |  |       err => { | 
					
						
							|  |  |  |         if (err) { | 
					
						
							| 
									
										
										
										
											2018-09-07 13:32:38 +01:00
										 |  |  |           err.redirectTo = `${homeLocation}/${username}`; | 
					
						
							| 
									
										
										
										
											2018-08-23 16:29:26 +01:00
										 |  |  |           return next(err); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2016-12-16 10:35:38 +05:30
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-07 13:32:38 +01:00
										 |  |  |         return res.json({ | 
					
						
							|  |  |  |           typer: 'info', | 
					
						
							|  |  |  |           message: `A report was sent to the team with ${user.email} in copy.` | 
					
						
							|  |  |  |         }); | 
					
						
							| 
									
										
										
										
											2018-08-23 16:29:26 +01:00
										 |  |  |       } | 
					
						
							|  |  |  |     ); | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2018-11-29 14:24:17 +00:00
										 |  |  | export default bootUser; |