From 5f94cad8b122b5a2cfc55160cad18e1dcbaae4cf Mon Sep 17 00:00:00 2001
From: valzav <i@valzav.com>
Date: Thu, 15 Sep 2016 18:14:33 -0400
Subject: [PATCH] work in progress

---
 app/assets/static/credit_card.js            |   9 +-
 server/server_pages/credit_card_form.jsx    | 279 +++++++++++---------
 server/server_pages/enter_confirm_email.jsx |  10 +-
 3 files changed, 161 insertions(+), 137 deletions(-)

diff --git a/app/assets/static/credit_card.js b/app/assets/static/credit_card.js
index eb387b387..d16d35cfa 100644
--- a/app/assets/static/credit_card.js
+++ b/app/assets/static/credit_card.js
@@ -9,6 +9,7 @@ $('#credit-card-form').on('submit', function(e){
     event.preventDefault();
     $('form-errors').hide();
     Stripe.card.createToken({
+        name: $('#card-holder-name').val(),
         number: $('#card-number').val(),
         cvc: $('#cvv').val(),
         exp_month: $('#expiry-month').val(),
@@ -20,17 +21,11 @@ $('#credit-card-form').on('submit', function(e){
 function stripeResponseHandler(status, response) {
     var $form = $('#credit-card-form');
     if (response.error) {
-        // Show the errors on the form
         $('#form-errors').show();
         $('#form-errors').html(response.error.message);
         $('#submit-btn').prop("disabled", false);
     } else {
-        // response contains id and card, which contains additional card details
-        var token = response.id;
-        // Insert the token into the form so it gets submitted to the server
-        $form.append($('<input type="hidden" name="stripeToken" />').val(token));
-        // and submit
-        console.log($form.get(0));
+        $form.append($('<input type="hidden" name="stripeToken" />').val(response.id));
         $form.get(0).submit();
     }
 }
diff --git a/server/server_pages/credit_card_form.jsx b/server/server_pages/credit_card_form.jsx
index 553091240..75d3c4dfd 100644
--- a/server/server_pages/credit_card_form.jsx
+++ b/server/server_pages/credit_card_form.jsx
@@ -15,12 +15,8 @@ import Iso from 'iso';
 
 const stripe = Stripe(config.stripe.secret_key);
 
-let assets;
-if (process.env.NODE_ENV === 'production') {
-    assets = Object.assign({}, require('tmp/webpack-stats-prod.json'), {script: []});
-} else {
-    assets = Object.assign({}, require('tmp/webpack-stats-dev.json'), {script: []});
-}
+const assets_file = process.env.NODE_ENV === 'production' ? 'tmp/webpack-stats-prod.json' : 'tmp/webpack-stats-dev.json';
+const assets = Object.assign({}, require(assets_file), {script: []});
 assets.script.push('https://js.stripe.com/v2/');
 assets.script.push('https://ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js');
 assets.script.push('/static/credit_card.js');
@@ -40,6 +36,112 @@ const header = <header className="Header">
     </div>
 </header>;
 
+function renderPage(content) {
+    const body = renderToString(<div className="App">
+        {header}
+        <br />
+        <div className="row">
+            {content}
+        </div>
+    </div>);
+    const props = { body: Iso.render(body, {stripe_key: config.stripe.publishable_key}), title: 'Credit Card Details', assets, meta: [] };
+    return '<!DOCTYPE html>' + renderToString(<ServerHTML { ...props } />);
+}
+
+function renderCreditCardForm(csrf, error) {
+    return <form className="column small-12 medium-10 large-7" id="credit-card-form" action="/credit_card" method="POST">
+        <input type="hidden" name="csrf" value={csrf} />
+        <div className="row">
+            <div className="column">
+                Please enter your credit card details below.<br />
+                <span className="secondary">This information allows Steemit...</span>
+            </div>
+        </div>
+        <hr />
+        <div className="row">
+            <div className="small-3 columns">
+                <label htmlFor="card-holder-name" className="text-right middle">Name on Card</label>
+            </div>
+            <div className="small-9 columns">
+                <input type="text" name="card-holder-name" id="card-holder-name" placeholder="Card Holder's Name" />
+            </div>
+        </div>
+        <div className="row">
+            <div className="small-3 columns">
+                <label htmlFor="card-number" className="text-right middle">Card Number</label>
+            </div>
+            <div className="small-9 columns">
+                <input type="text" name="card-number" id="card-number" placeholder="Debit/Credit Card Number" />
+            </div>
+        </div>
+        <div className="row">
+            <div className="small-3 columns">
+                <label htmlFor="expiry-month" className="text-right middle">Expiration Date</label>
+            </div>
+            <div className="small-5 columns">
+                <select name="expiry-month" id="expiry-month">
+                    <option>Month</option>
+                    <option value="01">Jan (01)</option>
+                    <option value="02">Feb (02)</option>
+                    <option value="03">Mar (03)</option>
+                    <option value="04">Apr (04)</option>
+                    <option value="05">May (05)</option>
+                    <option value="06">June (06)</option>
+                    <option value="07">July (07)</option>
+                    <option value="08">Aug (08)</option>
+                    <option value="09">Sep (09)</option>
+                    <option value="10">Oct (10)</option>
+                    <option value="11">Nov (11)</option>
+                    <option value="12">Dec (12)</option>
+                </select>
+            </div>
+            <div className="small-4 columns">
+                <select name="expiry-year" id="expiry-year">
+                    <option value="16">2016</option>
+                    <option value="17">2017</option>
+                    <option value="18">2018</option>
+                    <option value="19">2019</option>
+                    <option value="20">2020</option>
+                    <option value="21">2021</option>
+                    <option value="22">2022</option>
+                    <option value="23">2023</option>
+                </select>
+            </div>
+        </div>
+        <div className="row">
+            <div className="small-3 columns">
+                <label htmlFor="cvv" className="text-right middle">Card CVV</label>
+            </div>
+            <div className="small-3 columns">
+                <input type="text" name="cvv" id="cvv" placeholder="Security Code" />
+            </div>
+        </div>
+        <div className="row">
+            <div className="small-12 columns">
+                <div id="form-errors" className="error">{error}</div>
+            </div>
+        </div>
+        <div className="row">
+            <div className="small-12 columns">
+                <input type="submit" id="submit-btn" className="button float-right" value="Pay and Continue" />
+            </div>
+        </div>
+    </form>;
+}
+
+function stripeCharge(card, amount) {
+    return new Promise((resolve, reject) => {
+        stripe.charges.create({card, currency: 'usd', amount},
+            (err, charge) => {
+                if (err) {
+                    reject(err);
+                } else {
+                    resolve(charge);
+                }
+            }
+        );
+    });
+}
 
 export default function useCreditCardForm(app) {
     const router = koa_router();
@@ -50,129 +152,60 @@ export default function useCreditCardForm(app) {
         console.log('-- /credit_card -->', this.session.uid, this.session.user);
         const user_id = this.session.user;
         if (!user_id) { this.body = 'user not found'; return; }
-        // const eid = yield models.Identity.findOne(
-        //     {attributes: ['provider_user_id'], where: {user_id, provider: 'credit_card'}, order: 'id DESC'}
-        // );
-        const body = renderToString(<div className="App">
-            {header}
-            <br />
-            <div className="row">
-                <form className="column small-6" id="credit-card-form" action="/charge_credit_card" method="POST">
-                    <input type="hidden" name="csrf" value={this.csrf} />
-                    <div class="row">
-                        Please enter your credit card details below.<br />
-                        <span className="secondary">This information allows Steemit...</span>
-                    </div>
-                    <hr />
-                    <div className="row">
-                        <div className="small-3 columns">
-                            <label htmlFor="card-holder-name" className="text-right middle">Name on Card</label>
-                        </div>
-                        <div className="small-9 columns">
-                            <input type="text" name="card-holder-name" id="card-holder-name" placeholder="Card Holder's Name" />
-                        </div>
-                    </div>
-                    <div className="row">
-                        <div className="small-3 columns">
-                            <label htmlFor="card-number" className="text-right middle">Card Number</label>
-                        </div>
-                        <div className="small-9 columns">
-                            <input type="text" name="card-number" id="card-number" placeholder="Debit/Credit Card Number" />
-                        </div>
-                    </div>
-                    <div className="row">
-                        <div className="small-3 columns">
-                            <label htmlFor="expiry-month" className="text-right middle">Expiration Date</label>
-                        </div>
-                        <div className="small-5 columns">
-                            <select name="expiry-month" id="expiry-month">
-                                <option>Month</option>
-                                <option value="01">Jan (01)</option>
-                                <option value="02">Feb (02)</option>
-                                <option value="03">Mar (03)</option>
-                                <option value="04">Apr (04)</option>
-                                <option value="05">May (05)</option>
-                                <option value="06">June (06)</option>
-                                <option value="07">July (07)</option>
-                                <option value="08">Aug (08)</option>
-                                <option value="09">Sep (09)</option>
-                                <option value="10">Oct (10)</option>
-                                <option value="11">Nov (11)</option>
-                                <option value="12">Dec (12)</option>
-                            </select>
-                        </div>
-                        <div className="small-4 columns">
-                            <select name="expiry-year" id="expiry-year">
-                                <option value="16">2016</option>
-                                <option value="17">2017</option>
-                                <option value="18">2018</option>
-                                <option value="19">2019</option>
-                                <option value="20">2020</option>
-                                <option value="21">2021</option>
-                                <option value="22">2022</option>
-                                <option value="23">2023</option>
-                            </select>
-                        </div>
-                    </div>
-                    <div className="row">
-                        <div className="small-3 columns">
-                            <label htmlFor="cvv" className="text-right middle">Card CVV</label>
-                        </div>
-                        <div className="small-3 columns">
-                            <input type="text" name="cvv" id="cvv" placeholder="Security Code" />
-                        </div>
-                    </div>
-                    <div className="row">
-                        <div className="small-12 columns">
-                            <div id="form-errors" className="error">{this.flash.error}</div>
-                        </div>
-                    </div>
-                    <div className="row">
-                        <div className="small-12 columns">
-                            <input type="submit" id="submit-btn" className="button float-right" value="Pay and Continue" />
-                        </div>
-                    </div>
-                </form>
-            </div>
-        </div>);
-        const props = { body: Iso.render(body, {stripe_key: config.stripe.publishable_key}), title: 'Credit Card Details', assets, meta: [] };
-        this.body = '<!DOCTYPE html>' + renderToString(<ServerHTML { ...props } />);
+        const cid = yield models.Identity.findOne(
+            {attributes: ['id'], where: {user_id, provider: 'credit_card'}}
+        );
+        if (cid) {
+            const content = <div className="column">
+                <p>We have determined that your you already used credit card verification.</p>
+                <a href="/create_account" className="button">Continue</a>
+            </div>;
+            this.body = renderPage(content);
+            return;
+        }
+        this.body = renderPage(renderCreditCardForm(this.csrf, ''));
     });
 
-    router.post('/charge_credit_card', koaBody, function *() {
-        console.log('-- /charge_credit_card -->', this.request.body);
+    router.post('/credit_card', koaBody, function *() {
         if (!checkCSRF(this, this.request.body.csrf)) return;
         const user_id = this.session.user;
         if (!user_id) { this.body = 'user not found'; return; }
 
-        const stripeToken = this.request.body.stripeToken;
-
-        stripe.charges.create({card: stripeToken, currency: 'usd', amount: 100},
-            (err, charge) => {
-                if (err) {
-                    console.log('---> charge error:', err);
-                    // res.send('error');
-                } else {
-                    console.log('---> charge:', charge);
-                    // res.send('success');
-                }
-            }
+        let stripe_res;
+        try {
+            stripe_res = yield stripeCharge(this.request.body.stripeToken, 100);
+        } catch (err) {
+            console.log('---> charge error:', err);
+            this.body = renderPage(renderCreditCardForm(this.csrf, err.raw.message));
+            return;
+        }
+        const card = stripe_res.card;
+        console.log('-- POST /credit_card -->', this.session.uid, this.session.user, card);
+        const cid = yield models.Identity.findOne(
+            {attributes: ['id'], where: {provider: 'credit_card', provider_user_id: card.fingerprint}}
         );
-        // let eid = yield models.Identity.findOne(
-        //     {attributes: ['id', 'email'], where: {user_id, provider: 'email'}, order: 'id'}
-        // );
-        // if (eid) {
-        //     yield eid.update({confirmation_code});
-        // } else {
-        //     eid = yield models.Identity.create({
-        //         provider: 'email',
-        //         user_id,
-        //         uid: this.session.uid,
-        //         email,
-        //         verified: false,
-        //         confirmation_code
-        //     });
-        // }
-        this.body = 'ok';
+        if (cid) {
+            const content = <div className="column">
+                <p>This card was already used.</p>
+                <a href="/create_account" className="button">Continue</a>
+            </div>;
+            this.body = renderPage(content);
+            return;
+        }
+        yield models.Identity.create({
+            provider: 'credit_card',
+            user_id,
+            uid: this.session.uid,
+            name: card.name,
+            provider_user_id: card.fingerprint,
+            verified: false, // is used here to determine if it was used to credit user's account
+        });
+
+        const content = <div className="column">
+            <h4>Congratulations, your identity has been verified.</h4>
+            <p>Your account will be credited with $50 worth of SP.</p>
+            <a href="/create_account" className="button">Continue</a>
+        </div>;
+        this.body = renderPage(content);
     });
 }
diff --git a/server/server_pages/enter_confirm_email.jsx b/server/server_pages/enter_confirm_email.jsx
index 964979ebc..442d0da56 100644
--- a/server/server_pages/enter_confirm_email.jsx
+++ b/server/server_pages/enter_confirm_email.jsx
@@ -11,13 +11,9 @@ import sendEmail from '../sendEmail';
 import {checkCSRF} from '../utils';
 import config from '../../config';
 
-let assets;
-if (process.env.NODE_ENV === 'production') {
-    assets = Object.assign({}, require('tmp/webpack-stats-prod.json'), {script: ['https://www.google.com/recaptcha/api.js']});
-} else {
-    assets = Object.assign({}, require('tmp/webpack-stats-dev.json'));
-    assets.script.push('https://www.google.com/recaptcha/api.js');
-}
+const assets_file = process.env.NODE_ENV === 'production' ? 'tmp/webpack-stats-prod.json' : 'tmp/webpack-stats-dev.json';
+const assets = Object.assign({}, require(assets_file), {script: []});
+assets.script.push('https://www.google.com/recaptcha/api.js');
 
 const header = <header className="Header">
     <div className="Header__top header">
-- 
GitLab