| 
									
										
										
										
											2018-06-07 22:35:06 +01:00
										 |  |  | import Stripe from 'stripe'; | 
					
						
							| 
									
										
										
										
											2019-02-07 19:03:18 +05:30
										 |  |  | import debug from 'debug'; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-31 16:04:04 +01:00
										 |  |  | import keys from '../../../config/secrets'; | 
					
						
							| 
									
										
										
										
											2018-06-07 22:35:06 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-07 19:03:18 +05:30
										 |  |  | const log = debug('fcc:boot:donate'); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-18 08:47:10 -06:00
										 |  |  | export default function donateBoot(app, done) { | 
					
						
							|  |  |  |   let stripe = false; | 
					
						
							| 
									
										
										
										
											2018-06-07 22:35:06 +01:00
										 |  |  |   const { User } = app.models; | 
					
						
							|  |  |  |   const api = app.loopback.Router(); | 
					
						
							|  |  |  |   const donateRouter = app.loopback.Router(); | 
					
						
							| 
									
										
										
										
											2018-06-18 08:47:10 -06:00
										 |  |  |   const subscriptionPlans = [500, 1000, 3500, 5000, 25000].reduce( | 
					
						
							|  |  |  |     (accu, current) => ({ | 
					
						
							|  |  |  |       ...accu, | 
					
						
							|  |  |  |       [current]: { | 
					
						
							|  |  |  |         amount: current, | 
					
						
							|  |  |  |         interval: 'month', | 
					
						
							|  |  |  |         product: { | 
					
						
							|  |  |  |           name: | 
					
						
							|  |  |  |             'Monthly Donation to freeCodeCamp.org - ' + | 
					
						
							|  |  |  |             `Thank you ($${current / 100})` | 
					
						
							| 
									
										
										
										
											2019-02-06 14:19:58 +00:00
										 |  |  |         }, | 
					
						
							|  |  |  |         currency: 'usd', | 
					
						
							|  |  |  |         id: `monthly-donation-${current}` | 
					
						
							| 
									
										
										
										
											2018-06-18 08:47:10 -06:00
										 |  |  |       } | 
					
						
							| 
									
										
										
										
											2019-02-18 19:32:49 +00:00
										 |  |  |     }), | 
					
						
							|  |  |  |     {} | 
					
						
							| 
									
										
										
										
											2018-06-18 08:47:10 -06:00
										 |  |  |   ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   function connectToStripe() { | 
					
						
							|  |  |  |     return new Promise(function(resolve) { | 
					
						
							|  |  |  |       // connect to stripe API
 | 
					
						
							|  |  |  |       stripe = Stripe(keys.stripe.secret); | 
					
						
							|  |  |  |       // parse stripe plans
 | 
					
						
							|  |  |  |       stripe.plans.list({}, function(err, plans) { | 
					
						
							|  |  |  |         if (err) { | 
					
						
							|  |  |  |           throw err; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         const requiredPlans = Object.keys(subscriptionPlans).map( | 
					
						
							|  |  |  |           key => subscriptionPlans[key].id | 
					
						
							|  |  |  |         ); | 
					
						
							|  |  |  |         const availablePlans = plans.data.map(plan => plan.id); | 
					
						
							|  |  |  |         requiredPlans.forEach(planId => { | 
					
						
							|  |  |  |           if (!availablePlans.includes(planId)) { | 
					
						
							|  |  |  |             const key = planId.split('-').slice(-1)[0]; | 
					
						
							|  |  |  |             createStripePlan(subscriptionPlans[key]); | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |       resolve(); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   function createStripePlan(plan) { | 
					
						
							|  |  |  |     stripe.plans.create(plan, function(err) { | 
					
						
							|  |  |  |       if (err) { | 
					
						
							|  |  |  |         console.log(err); | 
					
						
							|  |  |  |         throw err; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       console.log(`${plan.id} created`); | 
					
						
							| 
									
										
										
										
											2019-02-06 14:19:58 +00:00
										 |  |  |       return; | 
					
						
							|  |  |  |     }); | 
					
						
							| 
									
										
										
										
											2018-06-18 08:47:10 -06:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2018-06-07 22:35:06 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |   function createStripeDonation(req, res) { | 
					
						
							|  |  |  |     const { user, body } = req; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (!body || !body.amount) { | 
					
						
							|  |  |  |       return res.status(400).send({ error: 'Amount Required' }); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-18 19:32:49 +00:00
										 |  |  |     const { | 
					
						
							|  |  |  |       amount, | 
					
						
							|  |  |  |       token: { email, id } | 
					
						
							|  |  |  |     } = body; | 
					
						
							| 
									
										
										
										
											2018-06-07 22:35:06 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-18 19:32:49 +00:00
										 |  |  |     const fccUser = user | 
					
						
							|  |  |  |       ? Promise.resolve(user) | 
					
						
							|  |  |  |       : new Promise((resolve, reject) => | 
					
						
							|  |  |  |           User.findOrCreate( | 
					
						
							|  |  |  |             { where: { email } }, | 
					
						
							|  |  |  |             { email }, | 
					
						
							|  |  |  |             (err, instance, isNew) => { | 
					
						
							|  |  |  |               log('is new user instance: ', isNew); | 
					
						
							|  |  |  |               if (err) { | 
					
						
							|  |  |  |                 return reject(err); | 
					
						
							|  |  |  |               } | 
					
						
							|  |  |  |               return resolve(instance); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |           ) | 
					
						
							|  |  |  |         ); | 
					
						
							| 
									
										
										
										
											2018-06-07 22:35:06 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     let donatingUser = {}; | 
					
						
							|  |  |  |     let donation = { | 
					
						
							|  |  |  |       email, | 
					
						
							|  |  |  |       amount, | 
					
						
							|  |  |  |       provider: 'stripe', | 
					
						
							|  |  |  |       startDate: new Date(Date.now()).toISOString() | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-18 19:32:49 +00:00
										 |  |  |     return fccUser | 
					
						
							|  |  |  |       .then(user => { | 
					
						
							| 
									
										
										
										
											2018-06-07 22:35:06 +01:00
										 |  |  |         donatingUser = user; | 
					
						
							| 
									
										
										
										
											2019-02-18 19:32:49 +00:00
										 |  |  |         return stripe.customers.create({ | 
					
						
							|  |  |  |           email, | 
					
						
							|  |  |  |           card: id | 
					
						
							|  |  |  |         }); | 
					
						
							| 
									
										
										
										
											2019-02-06 14:19:58 +00:00
										 |  |  |       }) | 
					
						
							|  |  |  |       .then(customer => { | 
					
						
							|  |  |  |         donation.customerId = customer.id; | 
					
						
							|  |  |  |         return stripe.subscriptions.create({ | 
					
						
							|  |  |  |           customer: customer.id, | 
					
						
							|  |  |  |           items: [ | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |               plan: `monthly-donation-${amount}` | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |           ] | 
					
						
							| 
									
										
										
										
											2018-06-18 08:47:10 -06:00
										 |  |  |         }); | 
					
						
							| 
									
										
										
										
											2019-02-06 14:19:58 +00:00
										 |  |  |       }) | 
					
						
							|  |  |  |       .then(subscription => { | 
					
						
							|  |  |  |         donation.subscriptionId = subscription.id; | 
					
						
							|  |  |  |         return res.send(subscription); | 
					
						
							|  |  |  |       }) | 
					
						
							|  |  |  |       .then(() => { | 
					
						
							| 
									
										
										
										
											2019-02-18 19:32:49 +00:00
										 |  |  |         donatingUser | 
					
						
							|  |  |  |           .createDonation(donation) | 
					
						
							|  |  |  |           .toPromise() | 
					
						
							| 
									
										
										
										
											2019-02-06 14:19:58 +00:00
										 |  |  |           .catch(err => { | 
					
						
							|  |  |  |             throw new Error(err); | 
					
						
							|  |  |  |           }); | 
					
						
							|  |  |  |       }) | 
					
						
							|  |  |  |       .catch(err => { | 
					
						
							|  |  |  |         if (err.type === 'StripeCardError') { | 
					
						
							|  |  |  |           return res.status(402).send({ error: err.message }); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         return res.status(500).send({ error: 'Donation Failed' }); | 
					
						
							|  |  |  |       }); | 
					
						
							| 
									
										
										
										
											2018-06-07 22:35:06 +01:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-18 08:47:10 -06:00
										 |  |  |   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'; | 
					
						
							| 
									
										
										
										
											2018-06-07 22:35:06 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-18 08:47:10 -06:00
										 |  |  |   if (secretInvalid || publicInvalid) { | 
					
						
							| 
									
										
										
										
											2019-08-19 01:19:40 +05:30
										 |  |  |     if (process.env.FREECODECAMP_NODE_ENV === 'production') { | 
					
						
							| 
									
										
										
										
											2018-06-18 08:47:10 -06:00
										 |  |  |       throw new Error('Stripe API keys are required to boot the server!'); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     console.info('No Stripe API keys were found, moving on...'); | 
					
						
							|  |  |  |     done(); | 
					
						
							|  |  |  |   } else { | 
					
						
							|  |  |  |     api.post('/charge-stripe', createStripeDonation); | 
					
						
							|  |  |  |     donateRouter.use('/donate', api); | 
					
						
							|  |  |  |     app.use(donateRouter); | 
					
						
							| 
									
										
										
										
											2019-02-07 19:03:18 +05:30
										 |  |  |     app.use('/internal', donateRouter); | 
					
						
							|  |  |  |     app.use('/unauthenticated', donateRouter); | 
					
						
							| 
									
										
										
										
											2018-06-18 08:47:10 -06:00
										 |  |  |     connectToStripe().then(done); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2018-06-07 22:35:06 +01:00
										 |  |  | } |