Merge pull request #8416 from BerkeleyTrue/feature/notify-on-completion
feature: notify camper by email on completion
This commit is contained in:
6
server/boot/a-extendEmail.js
Normal file
6
server/boot/a-extendEmail.js
Normal file
@ -0,0 +1,6 @@
|
||||
import { Observable } from 'rx';
|
||||
|
||||
export default function extendEmail(app) {
|
||||
const { Email } = app.models;
|
||||
Email.send$ = Observable.fromNodeCallback(Email.send, Email);
|
||||
}
|
@ -1,4 +1,7 @@
|
||||
import _ from 'lodash';
|
||||
import moment from 'moment';
|
||||
import loopback from 'loopback';
|
||||
import path from 'path';
|
||||
import dedent from 'dedent';
|
||||
import { Observable } from 'rx';
|
||||
import debug from 'debug';
|
||||
@ -23,6 +26,20 @@ import {
|
||||
import certTypes from '../utils/certTypes.json';
|
||||
|
||||
const log = debug('fcc:certification');
|
||||
const renderCertifedEmail = loopback.template(path.join(
|
||||
__dirname,
|
||||
'..',
|
||||
'views',
|
||||
'emails',
|
||||
'certified.ejs'
|
||||
));
|
||||
const renderNotifyEmail = loopback.template(path.join(
|
||||
__dirname,
|
||||
'..',
|
||||
'views',
|
||||
'emails',
|
||||
'a-new-user.ejs'
|
||||
));
|
||||
const sendMessageToNonUser = ifNoUserSend(
|
||||
'must be logged in to complete.'
|
||||
);
|
||||
@ -46,9 +63,85 @@ function getIdsForCert$(id, Challenge) {
|
||||
.shareReplay();
|
||||
}
|
||||
|
||||
// getFormatedDate(challengeMap: Object, challengeId: String) => String, throws
|
||||
function getFormatedDate(challengeMap, challengeId) {
|
||||
return moment(challengeMap[challengeId].completedDate)
|
||||
.format('MMM Do, YYYY');
|
||||
}
|
||||
|
||||
// sendCertifiedEmail(
|
||||
// {
|
||||
// email: String,
|
||||
// username: String,
|
||||
// isFrontEndCert: Boolean,
|
||||
// isBackEndCert: Boolean,
|
||||
// isDataVisCert: Boolean
|
||||
// },
|
||||
// send$: Observable
|
||||
// ) => Observable
|
||||
function sendCertifiedEmail(
|
||||
{
|
||||
email,
|
||||
name,
|
||||
username,
|
||||
isFrontEndCert,
|
||||
isBackEndCert,
|
||||
isDataVisCert,
|
||||
challengeMap
|
||||
},
|
||||
send$
|
||||
) {
|
||||
if (
|
||||
!isFrontEndCert ||
|
||||
!isBackEndCert ||
|
||||
!isDataVisCert
|
||||
) {
|
||||
return Observable.just(false);
|
||||
}
|
||||
let frontEndDate;
|
||||
let backEndDate;
|
||||
let dataVisDate;
|
||||
try {
|
||||
frontEndDate = getFormatedDate(challengeMap, frontEndChallengeId);
|
||||
backEndDate = getFormatedDate(challengeMap, backEndChallengeId);
|
||||
dataVisDate = getFormatedDate(challengeMap, dataVisChallengeId);
|
||||
} catch (err) {
|
||||
return Observable.throw(err);
|
||||
}
|
||||
|
||||
const notifyTeam = {
|
||||
type: 'email',
|
||||
to: 'Michael@FreeCodeCamp.com',
|
||||
from: 'Team@FreeCodeCamp.com',
|
||||
subject: 'A new user has arrived!',
|
||||
text: renderNotifyEmail({
|
||||
username,
|
||||
name,
|
||||
frontEndDate,
|
||||
dataVisDate,
|
||||
backEndDate
|
||||
})
|
||||
};
|
||||
const notifyUser = {
|
||||
type: 'email',
|
||||
to: email,
|
||||
from: 'Michael@FreeCodeCamp.com',
|
||||
subject: 'Congratulation on gaining your third certification!',
|
||||
text: renderCertifedEmail({
|
||||
username,
|
||||
name
|
||||
})
|
||||
};
|
||||
return Observable.combineLatest(
|
||||
send$(notifyTeam),
|
||||
send$(notifyUser),
|
||||
() => true
|
||||
);
|
||||
}
|
||||
|
||||
export default function certificate(app) {
|
||||
const router = app.loopback.Router();
|
||||
const { Challenge } = app.models;
|
||||
const { Email, Challenge } = app.models;
|
||||
|
||||
const certTypeIds = {
|
||||
[certTypes.frontEnd]: getIdsForCert$(frontEndChallengeId, Challenge),
|
||||
@ -94,9 +187,11 @@ export default function certificate(app) {
|
||||
challengeType
|
||||
} = challenge;
|
||||
if (
|
||||
!user[certType] &&
|
||||
isCertified(tests, user.challengeMap)
|
||||
user[certType] ||
|
||||
!isCertified(tests, user.challengeMap)
|
||||
) {
|
||||
return Observable.just(false);
|
||||
}
|
||||
const updateData = {
|
||||
$set: {
|
||||
[`challengeMap.${id}`]: {
|
||||
@ -108,13 +203,23 @@ export default function certificate(app) {
|
||||
[certType]: true
|
||||
}
|
||||
};
|
||||
|
||||
return req.user.update$(updateData)
|
||||
// If user has commited to nonprofit,
|
||||
// this will complete his pledge
|
||||
.flatMap(
|
||||
() => completeCommitment$(user),
|
||||
({ count }, pledgeOrMessage) => {
|
||||
// set here so sendCertifiedEmail works properly
|
||||
// not used otherwise
|
||||
user[certType] = true;
|
||||
user.challengeMap[id] = { completedDate: new Date() };
|
||||
return Observable.combineLatest(
|
||||
// update user data
|
||||
user.update$(updateData),
|
||||
// If user has committed to nonprofit,
|
||||
// this will complete their pledge
|
||||
completeCommitment$(user),
|
||||
// sends notification email is user has all three certs
|
||||
// if not it noop
|
||||
sendCertifiedEmail(user, Email.send$),
|
||||
({ count }, pledgeOrMessage) => ({ count, pledgeOrMessage })
|
||||
)
|
||||
.map(
|
||||
({ count, pledgeOrMessage }) => {
|
||||
if (typeof pledgeOrMessage === 'string') {
|
||||
log(pledgeOrMessage);
|
||||
}
|
||||
@ -122,8 +227,6 @@ export default function certificate(app) {
|
||||
return true;
|
||||
}
|
||||
);
|
||||
}
|
||||
return Observable.just(false);
|
||||
})
|
||||
.subscribe(
|
||||
(didCertify) => {
|
||||
|
@ -474,12 +474,7 @@ module.exports = function(app) {
|
||||
return Observable.just()
|
||||
.doOnCompleted(() => {
|
||||
req.flash('info', {
|
||||
msg: dedent`
|
||||
Once you have completed all of our challenges, you should
|
||||
join our <a href="https://gitter.im/freecodecamp/HalfWayClub"
|
||||
target="_blank">Half Way Club</a> and start getting
|
||||
ready for our nonprofit projects.
|
||||
`.split('\n').join(' ')
|
||||
msg: 'You\'ve completed the last challenge!'
|
||||
});
|
||||
return res.redirect('/map');
|
||||
});
|
||||
|
7
server/views/emails/a-new-user.ejs
Normal file
7
server/views/emails/a-new-user.ejs
Normal file
@ -0,0 +1,7 @@
|
||||
Camper <%= username %> has completed all three certifications!
|
||||
|
||||
Completed front end cert on <%= frontEndDate %>.
|
||||
Completed data vis cert on <%= dataVisDate %>.
|
||||
Completed back end cert on <%= backEndDate %>.
|
||||
|
||||
https://www.freecodecamp.com/<%= username %>
|
13
server/views/emails/certified.ejs
Normal file
13
server/views/emails/certified.ejs
Normal file
@ -0,0 +1,13 @@
|
||||
Hi <%= name || username %>,
|
||||
|
||||
Congratulations on recently completing all three Free Code Camp certifications. But you have not yet finished Free Code Camp. The most important part still remains: the nonprofit projects.
|
||||
|
||||
These will help you contextualize and apply the raw skills you've picked up. You'll practice by building full stack JavaScript apps that real people will use. And in the end, you'll have code in production that you can showcase in your portfolio. This will be critical to your job search.
|
||||
|
||||
Please fill this out immediately: http://bit.ly/20VwLg0
|
||||
|
||||
Once you fill this out we will get back to you as quickly as possible to get you started.
|
||||
|
||||
Best,
|
||||
|
||||
Michael - nonprofit guy @ Free Code Camp
|
Reference in New Issue
Block a user