161 lines
		
	
	
		
			4.1 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			161 lines
		
	
	
		
			4.1 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
import Stripe from 'stripe';
 | 
						|
import debug from 'debug';
 | 
						|
 | 
						|
import keys from '../../../config/secrets';
 | 
						|
 | 
						|
const log = debug('fcc:boot:donate');
 | 
						|
 | 
						|
export default function donateBoot(app, done) {
 | 
						|
  let stripe = false;
 | 
						|
  const { User } = app.models;
 | 
						|
  const api = app.loopback.Router();
 | 
						|
  const donateRouter = app.loopback.Router();
 | 
						|
  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})`
 | 
						|
        },
 | 
						|
        currency: 'usd',
 | 
						|
        id: `monthly-donation-${current}`
 | 
						|
      }
 | 
						|
    }),
 | 
						|
    {}
 | 
						|
  );
 | 
						|
 | 
						|
  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`);
 | 
						|
      return;
 | 
						|
    });
 | 
						|
  }
 | 
						|
 | 
						|
  function createStripeDonation(req, res) {
 | 
						|
    const { user, body } = req;
 | 
						|
 | 
						|
    if (!body || !body.amount) {
 | 
						|
      return res.status(400).send({ error: 'Amount Required' });
 | 
						|
    }
 | 
						|
 | 
						|
    const {
 | 
						|
      amount,
 | 
						|
      token: { email, id }
 | 
						|
    } = body;
 | 
						|
 | 
						|
    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);
 | 
						|
            }
 | 
						|
          )
 | 
						|
        );
 | 
						|
 | 
						|
    let donatingUser = {};
 | 
						|
    let donation = {
 | 
						|
      email,
 | 
						|
      amount,
 | 
						|
      provider: 'stripe',
 | 
						|
      startDate: new Date(Date.now()).toISOString()
 | 
						|
    };
 | 
						|
 | 
						|
    return fccUser
 | 
						|
      .then(user => {
 | 
						|
        donatingUser = user;
 | 
						|
        return stripe.customers.create({
 | 
						|
          email,
 | 
						|
          card: id
 | 
						|
        });
 | 
						|
      })
 | 
						|
      .then(customer => {
 | 
						|
        donation.customerId = customer.id;
 | 
						|
        return stripe.subscriptions.create({
 | 
						|
          customer: customer.id,
 | 
						|
          items: [
 | 
						|
            {
 | 
						|
              plan: `monthly-donation-${amount}`
 | 
						|
            }
 | 
						|
          ]
 | 
						|
        });
 | 
						|
      })
 | 
						|
      .then(subscription => {
 | 
						|
        donation.subscriptionId = subscription.id;
 | 
						|
        return res.send(subscription);
 | 
						|
      })
 | 
						|
      .then(() => {
 | 
						|
        donatingUser
 | 
						|
          .createDonation(donation)
 | 
						|
          .toPromise()
 | 
						|
          .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' });
 | 
						|
      });
 | 
						|
  }
 | 
						|
 | 
						|
  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';
 | 
						|
 | 
						|
  if (secretInvalid || publicInvalid) {
 | 
						|
    if (process.env.NODE_ENV === 'production') {
 | 
						|
      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);
 | 
						|
    app.use('/internal', donateRouter);
 | 
						|
    app.use('/unauthenticated', donateRouter);
 | 
						|
    connectToStripe().then(done);
 | 
						|
  }
 | 
						|
}
 |