From 96b84678590930dd1147b9c8778a2d6392725e14 Mon Sep 17 00:00:00 2001 From: Kyle Spearrin Date: Fri, 28 Jul 2017 14:29:25 -0400 Subject: [PATCH] support for paypal through braintree --- settings.Preview.json | 3 +- settings.Production.json | 3 +- settings.json | 3 +- ...anizationBillingChangePaymentController.js | 3 + .../organizationBillingController.js | 5 +- .../views/organizationBilling.html | 2 +- src/app/settings.js | 2 +- .../settingsBillingChangePaymentController.js | 56 +- src/app/settings/settingsBillingController.js | 4 +- src/app/settings/settingsPremiumController.js | 53 +- src/app/settings/views/settingsBilling.html | 6 +- .../views/settingsBillingChangePayment.html | 684 +++++++++--------- src/app/settings/views/settingsPremium.html | 684 +++++++++--------- src/index.html | 12 + src/less/vault.less | 4 + 15 files changed, 836 insertions(+), 688 deletions(-) diff --git a/settings.Preview.json b/settings.Preview.json index a0aa8ec5a3..9312e40652 100644 --- a/settings.Preview.json +++ b/settings.Preview.json @@ -2,6 +2,7 @@ "appSettings": { "apiUri": "https://preview-api.bitwarden.com", "identityUri": "https://preview-identity.bitwarden.com", - "stripeKey": "pk_test_KPoCfZXu7mznb9uSCPZ2JpTD" + "stripeKey": "pk_test_KPoCfZXu7mznb9uSCPZ2JpTD", + "braintreeKey": "sandbox_r72q8jq6_9pnxkwm75f87sdc2" } } diff --git a/settings.Production.json b/settings.Production.json index 148fd58a2c..43b77a9d6d 100644 --- a/settings.Production.json +++ b/settings.Production.json @@ -2,6 +2,7 @@ "appSettings": { "apiUri": "https://api.bitwarden.com", "identityUri": "https://identity.bitwarden.com", - "stripeKey": "pk_live_bpN0P37nMxrMQkcaHXtAybJk" + "stripeKey": "pk_live_bpN0P37nMxrMQkcaHXtAybJk", + "braintreeKey": "TODO" } } diff --git a/settings.json b/settings.json index 0b79bed998..4b546a078d 100644 --- a/settings.json +++ b/settings.json @@ -2,6 +2,7 @@ "appSettings": { "apiUri": "http://localhost:4000", "identityUri": "http://localhost:33656", - "stripeKey": "pk_test_KPoCfZXu7mznb9uSCPZ2JpTD" + "stripeKey": "pk_test_KPoCfZXu7mznb9uSCPZ2JpTD", + "braintreeKey": "sandbox_r72q8jq6_9pnxkwm75f87sdc2" } } diff --git a/src/app/organization/organizationBillingChangePaymentController.js b/src/app/organization/organizationBillingChangePaymentController.js index a064db9798..48ce53b4cf 100644 --- a/src/app/organization/organizationBillingChangePaymentController.js +++ b/src/app/organization/organizationBillingChangePaymentController.js @@ -5,6 +5,9 @@ $analytics, toastr, existingPaymentMethod) { $analytics.eventTrack('organizationBillingChangePaymentController', { category: 'Modal' }); $scope.existingPaymentMethod = existingPaymentMethod; + $scope.paymentMethod = 'card'; + $scope.showPaymentOptions = false; + $scope.card = {}; $scope.submit = function () { $scope.submitPromise = stripe.card.createToken($scope.card).then(function (response) { diff --git a/src/app/organization/organizationBillingController.js b/src/app/organization/organizationBillingController.js index 7c01f80ad0..c44d6b34d0 100644 --- a/src/app/organization/organizationBillingController.js +++ b/src/app/organization/organizationBillingController.js @@ -137,9 +137,8 @@ trialEndDate: org.Subscription.TrialEndDate, cancelledDate: org.Subscription.CancelledDate, status: org.Subscription.Status, - cancelled: org.Subscription.Status === 'cancelled', - markedForCancel: (org.Subscription.Status === 'active' || org.Subscription.Status === 'trialing') && - org.Subscription.CancelledDate + cancelled: org.Subscription.Cancelled, + markedForCancel: !org.Subscription.Cancelled && org.Subscription.CancelAtEndDate }; } diff --git a/src/app/organization/views/organizationBilling.html b/src/app/organization/views/organizationBilling.html index 5030eeb60e..843111ea5f 100644 --- a/src/app/organization/views/organizationBilling.html +++ b/src/app/organization/views/organizationBilling.html @@ -141,7 +141,7 @@
+ 'fa-university': paymentSource.type === 1, 'fa-paypal fa-fw text-blue': paymentSource.type === 2}"> {{paymentSource.description}}
diff --git a/src/app/settings.js b/src/app/settings.js index d58fa5b63f..475eb86333 100644 --- a/src/app/settings.js +++ b/src/app/settings.js @@ -1,2 +1,2 @@ angular.module("bit") -.constant("appSettings", {"apiUri":"https://api.bitwarden.com","identityUri":"https://identity.bitwarden.com","stripeKey":"pk_live_bpN0P37nMxrMQkcaHXtAybJk","version":"1.14.0","environment":"Production"}); +.constant("appSettings", {"apiUri":"https://api.bitwarden.com","identityUri":"https://identity.bitwarden.com","stripeKey":"pk_live_bpN0P37nMxrMQkcaHXtAybJk","braintreeKey":"TODO","version":"1.14.0","environment":"Production"}); diff --git a/src/app/settings/settingsBillingChangePaymentController.js b/src/app/settings/settingsBillingChangePaymentController.js index 05025b8080..2afce9ac4f 100644 --- a/src/app/settings/settingsBillingChangePaymentController.js +++ b/src/app/settings/settingsBillingChangePaymentController.js @@ -2,14 +2,51 @@ .module('bit.organization') .controller('settingsBillingChangePaymentController', function ($scope, $state, $uibModalInstance, apiService, stripe, - $analytics, toastr, existingPaymentMethod) { + $analytics, toastr, existingPaymentMethod, appSettings, $timeout) { $analytics.eventTrack('settingsBillingChangePaymentController', { category: 'Modal' }); $scope.existingPaymentMethod = existingPaymentMethod; + $scope.paymentMethod = 'card'; + $scope.dropinLoaded = false; + $scope.showPaymentOptions = true; + $scope.card = {}; + var btInstance = null; + + $scope.changePaymentMethod = function (val) { + $scope.paymentMethod = val; + if ($scope.paymentMethod !== 'paypal') { + return; + } + + braintree.dropin.create({ + authorization: appSettings.braintreeKey, + container: '#bt-dropin-container', + paymentOptionPriority: ['paypal'], + paypal: { + flow: 'vault', + buttonStyle: { + label: 'pay', + size: 'medium', + shape: 'pill', + color: 'blue' + } + } + }, function (createErr, instance) { + if (createErr) { + console.error(createErr); + return; + } + + btInstance = instance; + $timeout(function () { + $scope.dropinLoaded = true; + }); + }); + }; $scope.submit = function () { - $scope.submitPromise = stripe.card.createToken($scope.card).then(function (response) { + $scope.submitPromise = getPaymentToken($scope.card).then(function (token) { var request = { - paymentToken: response.id + paymentToken: token }; return apiService.accounts.putPayment(null, request).$promise; @@ -31,4 +68,17 @@ $scope.close = function () { $uibModalInstance.dismiss('cancel'); }; + + function getPaymentToken(card) { + if ($scope.paymentMethod === 'paypal') { + return btInstance.requestPaymentMethod().then(function (payload) { + return payload.nonce; + }); + } + else { + return stripe.card.createToken(card).then(function (response) { + return response.id; + }); + } + } }); diff --git a/src/app/settings/settingsBillingController.js b/src/app/settings/settingsBillingController.js index 3172f22c24..79605d8471 100644 --- a/src/app/settings/settingsBillingController.js +++ b/src/app/settings/settingsBillingController.js @@ -104,8 +104,8 @@ trialEndDate: billing.Subscription.TrialEndDate, cancelledDate: billing.Subscription.CancelledDate, status: billing.Subscription.Status, - cancelled: billing.Subscription.Status === 'cancelled', - markedForCancel: billing.Subscription.Status === 'active' && billing.Subscription.CancelledDate + cancelled: billing.Subscription.Cancelled, + markedForCancel: !billing.Subscription.Cancelled && billing.Subscription.CancelAtEndDate }; } diff --git a/src/app/settings/settingsPremiumController.js b/src/app/settings/settingsPremiumController.js index 0fabff8f17..618ae099d7 100644 --- a/src/app/settings/settingsPremiumController.js +++ b/src/app/settings/settingsPremiumController.js @@ -2,28 +2,62 @@ .module('bit.settings') .controller('settingsPremiumController', function ($scope, $state, apiService, toastr, $analytics, authService, stripe, - constants) { + constants, $timeout, appSettings) { authService.getUserProfile().then(function (profile) { if (profile.premium) { return $state.go('backend.user.settingsBilling'); } }); + var btInstance = null; $scope.storageGbPrice = constants.storageGb.yearlyPrice; $scope.premiumPrice = constants.premium.price; + $scope.paymentMethod = 'card'; + $scope.dropinLoaded = false; $scope.model = { additionalStorageGb: null }; + $scope.changePaymentMethod = function () { + if ($scope.paymentMethod !== 'paypal') { + return; + } + + braintree.dropin.create({ + authorization: appSettings.braintreeKey, + container: '#bt-dropin-container', + paymentOptionPriority: ['paypal'], + paypal: { + flow: 'vault', + buttonStyle: { + label: 'pay', + size: 'medium', + shape: 'pill', + color: 'blue' + } + } + }, function (createErr, instance) { + if (createErr) { + console.error(createErr); + return; + } + + btInstance = instance; + $timeout(function () { + $scope.dropinLoaded = true; + }); + }); + }; + $scope.totalPrice = function () { return $scope.premiumPrice + (($scope.model.additionalStorageGb || 0) * $scope.storageGbPrice); }; $scope.submit = function (model) { - $scope.submitPromise = stripe.card.createToken(model.card).then(function (response) { + $scope.submitPromise = getPaymentToken(model).then(function (token) { var request = { - paymentToken: response.id, + paymentToken: token, additionalStorageGb: model.additionalStorageGb }; @@ -39,4 +73,17 @@ toastr.success('Premium upgrade complete.', 'Success'); }); }; + + function getPaymentToken(model) { + if ($scope.paymentMethod === 'paypal') { + return btInstance.requestPaymentMethod().then(function (payload) { + return payload.nonce; + }); + } + else { + return stripe.card.createToken(model.card).then(function (response) { + return response.id; + }); + } + } }); diff --git a/src/app/settings/views/settingsBilling.html b/src/app/settings/views/settingsBilling.html index 68e694edb0..2d5bb517d6 100644 --- a/src/app/settings/views/settingsBilling.html +++ b/src/app/settings/views/settingsBilling.html @@ -54,7 +54,7 @@ - - diff --git a/src/app/settings/views/settingsBillingChangePayment.html b/src/app/settings/views/settingsBillingChangePayment.html index 8b93ef8edc..e12e0c772b 100644 --- a/src/app/settings/views/settingsBillingChangePayment.html +++ b/src/app/settings/views/settingsBillingChangePayment.html @@ -13,344 +13,360 @@
  • {{e}}
  • -
    -
    -
    - - -
    -
    +
    + + +
    - -
    -
    -
    - - -
    -
    -
    -
    - - -
    -
    -
    -
    - - -
    -
    +
    +
    -
    -
    -
    - - +
    +
    +
    +
    + + +
    -
    -
    - - +
      +
    • +
    • +
    • +
    • +
    • +
    • +
    +
    +
    +
    + + +
    +
    +
    +
    + + +
    +
    +
    +
    + + +
    +
    +
    +
    +
    +
    + + +
    +
    +
    +
    + + +
    diff --git a/src/app/settings/views/settingsPremium.html b/src/app/settings/views/settingsPremium.html index 4d20727dc9..f9496c4e98 100644 --- a/src/app/settings/views/settingsPremium.html +++ b/src/app/settings/views/settingsPremium.html @@ -89,347 +89,361 @@

    Payment Information

    -
    -
    -
    - - -
    -
    -
    - -
      -
    • -
    • -
    • -
    • -
    • -
    • -
    -
    + + +
    +
    +
    -
    -
    -
    - - +
    +
    +
    +
    + + +
    +
    +
    + +
      +
    • +
    • +
    • +
    • +
    • +
    • +
    -
    -
    - - +
    +
    +
    + + +
    +
    +
    +
    + + +
    +
    +
    +
    + + +
    -
    -
    - - +
    +
    +
    + + +
    -
    -
    -
    -
    -
    - - -
    -
    -
    -
    - - +
    +
    + + +
    diff --git a/src/index.html b/src/index.html index f19048dbc1..152f978105 100644 --- a/src/index.html +++ b/src/index.html @@ -7,18 +7,25 @@ 'self'; script-src 'self' + 'sha256-ryoU+5+IUZTuUyTElqkrQGBJXr1brEv6r2CA62WUw8w=' https://www.google-analytics.com https://js.stripe.com + https://js.braintreegateway.com + https://www.paypalobjects.com https://maxcdn.bootstrapcdn.com https://ajax.googleapis.com; style-src 'self' 'unsafe-inline' https://maxcdn.bootstrapcdn.com + https://assets.braintreegateway.com + https://*.paypal.com https://fonts.googleapis.com; img-src 'self' data: + https://*.paypal.com + https://www.paypalobjects.com https://q.stripe.com https://haveibeenpwned.com https://chart.googleapis.com @@ -30,10 +37,14 @@ child-src 'self' https://js.stripe.com + https://assets.braintreegateway.com + https://*.paypal.com https://*.duosecurity.com; frame-src 'self' https://js.stripe.com + https://assets.braintreegateway.com + https://*.paypal.com https://*.duosecurity.com; connect-src *;"> @@ -43,6 +54,7 @@ bitwarden.com Password Manager +