From aeec1bb9e6c7da6b8a8034659429c3eda3f23def Mon Sep 17 00:00:00 2001
From: Mrugesh Mohapatra
Date: Wed, 13 Nov 2019 19:40:49 +0530
Subject: [PATCH] feat(donate): integrate servicebot
---
api-server/server/boot/donate.js | 58 ++++-
api-server/server/utils/publicUserProps.js | 3 +-
.../Donation/components/DonateCompletion.js | 2 +-
.../Donation/components/DonateForm.js | 16 +-
.../components/DonateFormChildViewForHOC.js | 3 +
.../components/DonateServicebotEmbed.js | 71 ++++++
client/src/pages/donate.js | 58 ++++-
client/src/pages/donation/settings.js | 209 ++++++++++++++++++
client/src/utils/ajax.js | 4 +
client/src/utils/scriptLoaders.js | 8 +
config/env.js | 4 +-
config/secrets.js | 15 +-
12 files changed, 411 insertions(+), 40 deletions(-)
create mode 100644 client/src/components/Donation/components/DonateServicebotEmbed.js
create mode 100644 client/src/pages/donation/settings.js
diff --git a/api-server/server/boot/donate.js b/api-server/server/boot/donate.js
index 2cbd3058c3..18b48ab28d 100644
--- a/api-server/server/boot/donate.js
+++ b/api-server/server/boot/donate.js
@@ -1,5 +1,6 @@
import Stripe from 'stripe';
import debug from 'debug';
+import crypto from 'crypto';
import { isEmail, isNumeric } from 'validator';
import keys from '../../../config/secrets';
@@ -108,18 +109,12 @@ export default function donateBoot(app, done) {
function createStripeDonation(req, res) {
const { user, body } = req;
- if (!user) {
+ if (!user || !body) {
return res
.status(500)
.send({ error: 'User must be signed in for this request.' });
}
- if (!body || !body.amount || !body.duration) {
- return res.status(500).send({
- error: 'The donation form had invalid values for this submission.'
- });
- }
-
const {
amount,
duration,
@@ -218,12 +213,54 @@ export default function donateBoot(app, done) {
});
}
+ function createHmacHash(req, res) {
+ const { user, body } = req;
+
+ if (!user || !body) {
+ return res
+ .status(500)
+ .send({ error: 'User must be signed in for this request.' });
+ }
+
+ const { email } = body;
+
+ if (!isEmail('' + email)) {
+ return res
+ .status(500)
+ .send({ error: 'The email is invalid for this request.' });
+ }
+
+ if (!user.donationEmails.includes(email)) {
+ return res.status(500).send({
+ error: `User does not have the email: ${email} associated with their donations.`
+ });
+ }
+
+ log(`creating HMAC hash for ${email}`);
+ return Promise.resolve(email)
+ .then(email =>
+ crypto
+ .createHmac('sha256', keys.servicebot.hmacKey)
+ .update(email)
+ .digest('hex')
+ )
+ .then(hash => res.status(200).json({ hash }))
+ .catch(() =>
+ res
+ .status(500)
+ .send({ error: 'Donation failed due to a server error.' })
+ );
+ }
+
const pubKey = keys.stripe.public;
const secKey = keys.stripe.secret;
- const secretInvalid = !secKey || secKey === 'sk_from_stipe_dashboard';
- const publicInvalid = !pubKey || pubKey === 'pk_from_stipe_dashboard';
+ const hmacKey = keys.servicebot.hmacKey;
+ const secretInvalid = !secKey || secKey === 'sk_from_stripe_dashboard';
+ const publicInvalid = !pubKey || pubKey === 'pk_from_stripe_dashboard';
+ const hmacKeyInvalid =
+ !hmacKey || hmacKey === 'secret_key_from_servicebot_dashboard';
- if (secretInvalid || publicInvalid) {
+ if (secretInvalid || publicInvalid || hmacKeyInvalid) {
if (process.env.FREECODECAMP_NODE_ENV === 'production') {
throw new Error('Stripe API keys are required to boot the server!');
}
@@ -231,6 +268,7 @@ export default function donateBoot(app, done) {
done();
} else {
api.post('/charge-stripe', createStripeDonation);
+ api.post('/create-hmac-hash', createHmacHash);
donateRouter.use('/donate', api);
app.use(donateRouter);
app.use('/internal', donateRouter);
diff --git a/api-server/server/utils/publicUserProps.js b/api-server/server/utils/publicUserProps.js
index ec7df9f9b5..71becb1ac3 100644
--- a/api-server/server/utils/publicUserProps.js
+++ b/api-server/server/utils/publicUserProps.js
@@ -51,7 +51,8 @@ export const userPropsForSession = [
'completedProjectCount',
'completedCertCount',
'completedLegacyCertCount',
- 'acceptedPrivacyTerms'
+ 'acceptedPrivacyTerms',
+ 'donationEmails'
];
export function normaliseUserFields(user) {
diff --git a/client/src/components/Donation/components/DonateCompletion.js b/client/src/components/Donation/components/DonateCompletion.js
index 99718a160a..9637d423d8 100644
--- a/client/src/components/Donation/components/DonateCompletion.js
+++ b/client/src/components/Donation/components/DonateCompletion.js
@@ -42,7 +42,7 @@ function DonateCompletion({ processing, reset, success, error = null }) {
You can update your supporter status at any time from the 'manage
- your existing donation' section on this page.
+ your existing donation' section below on this page.
+ You can update your PayPal donation{' '}
+
+ directly on PayPal
+
+ .
+
+
+
+
+
+
+
Still need help?
+
+ If you can't see your donation here, forward a donation receipt
+ you have recieved in your email to team@freeCodeCamp.org and
+ tell us how we can help you with it.
+