amazon integration refactor

This commit is contained in:
Gabriel Bazán 2016-07-21 11:18:48 -03:00 committed by Gustavo Maximiliano Cortez
commit 6dff2840c8
No known key found for this signature in database
GPG key ID: 15EDAD8D9F2EB1AF
12 changed files with 336 additions and 454 deletions

View file

@ -9,12 +9,6 @@
</a> </a>
</section> </section>
<section class="right-small">
<a class="p10" ui-sref="buyAmazon">
<i class="fi-shopping-cart size-24"></i>
</a>
</section>
<section class="middle tab-bar-section"> <section class="middle tab-bar-section">
<h1 class="title ellipsis"> <h1 class="title ellipsis">
Gift cards Gift cards
@ -32,12 +26,12 @@
Sandbox version. Only for testing purpose Sandbox version. Only for testing purpose
</div> </div>
<div class="m20t text-center" ng-click="amazon.init()"> <div class="m20t text-center" ng-click="amazon.updatePendingGiftCards()">
<img src="img/GCs-logo-cllb.png" alt="Amazon.com Gift Card" width="200"> <img src="img/GCs-logo-cllb.png" alt="Amazon.com Gift Card" width="200">
<div class="size-10 m5t text-gray"><b>Only</b> redeemable on www.amazon.com (USA website)</div> <div class="size-10 m5t text-gray"><b>Only</b> redeemable on www.amazon.com (USA website)</div>
</div> </div>
<div ng-if="!amazon.giftCards" class="m20t text-center size-12"> <div ng-if="!giftCards" class="m20t text-center size-12">
<div class="row"> <div class="row">
<div class="columns"> <div class="columns">
@ -54,21 +48,34 @@
</div> </div>
</div> </div>
<div ng-if="amazon.giftCards"> <div class="p20t" ng-if="giftCards">
<ul class="no-bullet m0 size-14">
<li class="line-b line-t p10 pointer" href ui-sref="buyAmazon">
<i class="fi-shopping-cart size-24 p10 vm dib"></i>
<span class="m10 text-normal text-bold">Buy Gift Card</span>
<span class="right text-gray p15t">
<i class="icon-arrow-right3 size-24 right"></i>
</span>
</li>
</ul>
<h4 class="title">Your cards</h4> <h4 class="title">Your cards</h4>
<div ng-repeat="(id, item) in amazon.giftCards | orderObjectBy:'date':true track by $index" <div ng-repeat="(id, item) in giftCards | orderObjectBy:'date':true track by $index"
ng-click="amazon.openCardModal(item)" ng-click="amazon.openCardModal(item)"
class="row collapse last-transactions-content size-12"> class="row collapse last-transactions-content size-12">
<div class="large-2 medium-2 small-2 columns"> <div class="large-2 medium-2 small-2 columns">
<img src="img/a-smile_color_btn.png" alt="{{id}}" width="40"> <img src="img/a-smile_color_btn.png" alt="{{id}}" width="40">
</div> </div>
<div class="large-4 medium-4 small-4 columns m5t size-18"> <div class="large-4 medium-4 small-4 columns m5t size-18" ng-if="item.claimCode">
{{item.cardInfo.value.amount | currency : '$ ' : 2}} {{item.amount | currency : '$ ' : 2}}
</div>
<div class="large-4 medium-4 small-4 columns m5t size-18" ng-if="!item.claimCode">
-
</div> </div>
<div class="large-5 medium-5 small-5 columns text-right m10t"> <div class="large-5 medium-5 small-5 columns text-right m10t">
<span class="text-warning" ng-if="item.status == 'FAILURE'">Error</span> <span class="text-warning" ng-if="item.status == 'FAILURE'">Error</span>
<span class="text-secondary" ng-if="item.status == 'RESEND'">Resend is required</span> <span class="text-secondary" ng-if="item.status == 'RESEND'">Resend is required</span>
<span class="text-gray" ng-if="item.status == 'SUCCESS'">{{item.date * 1000 | amTimeAgo}}</span> <span class="text-gray" ng-if="item.status == 'PENDING'">Pending to confirmation</span>
<span class="text-gray" ng-if="item.status == 'SUCCESS'">{{item.date | amTimeAgo}}</span>
</div> </div>
<div class="large-1 medium-1 small-1 columns text-right m10t"> <div class="large-1 medium-1 small-1 columns text-right m10t">
<i class="icon-arrow-right3 size-18"></i> <i class="icon-arrow-right3 size-18"></i>

View file

@ -18,11 +18,11 @@
There was an error when trying to buy gift card, but the funds were sent to BitPay Invoice. Please, contact There was an error when trying to buy gift card, but the funds were sent to BitPay Invoice. Please, contact
BitPay to refund your bitcoin BitPay to refund your bitcoin
<div class="p10 m10t"> <div class="p10 m10t">
Amount: {{buy.errorInfo.amount}} {{buy.errorInfo.currencyCode}}<br> Amount: {{buy.errorInfo.amount}} {{buy.errorInfo.currency}}<br>
BitPay Invoice ID: {{buy.errorInfo.bitpayInvoiceId}}. BitPay Invoice ID: {{buy.errorInfo.invoiceId}}.
</div> </div>
<div class="text-center"> <div class="text-center">
<a ng-click="$root.openExternalLink(buy.errorInfo.bitpayInvoiceUrl)">Open invoice</a> <a ng-click="$root.openExternalLink(buy.errorInfo.invoiceUrl)">Open invoice</a>
</div> </div>
</div> </div>
</div> </div>
@ -75,7 +75,7 @@
</div> </div>
<div class="m10t" ng-show="buy.giftCard"> <div class="m10t" ng-show="buy.giftCard">
<div class="m10h" ng-show="buy.giftCard.status != 'SUCCESS'"> <div class="m10h" ng-show="buy.giftCard.status != 'SUCCESS' && buy.giftCard.status != 'PENDING'">
<h1 class="text-center">Gift card could not be created</h1> <h1 class="text-center">Gift card could not be created</h1>
<div class="box-notification m20b"> <div class="box-notification m20b">
<span class="text-warning"> <span class="text-warning">
@ -108,18 +108,21 @@
<div class="m10t size-14"> <div class="m10t size-14">
Gift Card Amount: Gift Card Amount:
<span class="text-bold"> <span class="text-bold">
{{buy.giftCard.cardInfo.value.amount | currency : '$ ' : 2 }} {{buy.giftCard.amount | currency : '$ ' : 2 }}
</span> </span>
</div> </div>
<div class="size-14"> <div class="size-14">
Claim code: <span class="text-bold enable_text_select">{{buy.giftCard.gcClaimCode}}</span> Claim code: <span class="text-bold enable_text_select">{{buy.giftCard.claimCode}}</span>
</div> </div>
<div class="m10t"> <div class="m10t">
<button class="button black round tiny" <button class="button black round tiny"
ng-click="$root.openExternalLink('https://www.amazon.com/gc/redeem?claimCode=' + buy.giftCard.gcClaimCode, '_system')"> ng-click="$root.openExternalLink('https://www.amazon.com/gc/redeem?claimCode=' + buy.giftCard.claimCode, '_system')">
Redeem Now Redeem Now
</button> </button>
</div> </div>
<div class="size-12 m10t text-center">
<a ng-click="$root.openExternalLink(buy.giftCard.invoiceUrl)">See invoice</a>
</div>
</div> </div>
</div> </div>
</div> </div>

View file

@ -13,38 +13,41 @@
</section> </section>
</nav> </nav>
<ion-content overflow-scroll="true"> <ion-content class="has-header" overflow-scroll="true">
<div class="modal-content fix-modals-touch"> <div class="modal-content">
<div class="header-modal text-center"> <div class="header-modal text-center">
<img src="img/a_generic.jpg" alt="Amazon.com Gift Card" width="230" ng-click="refreshGiftCard()"> <img src="img/a_generic.jpg" alt="Amazon.com Gift Card" width="230" ng-click="refreshGiftCard()">
<div ng-show="card.gcClaimCode"> <div ng-show="card.claimCode">
<div class="m10t"> <div class="m10t">
Gift Card Amount: Gift Card Amount:
<span class="text-bold"> <span class="text-bold">
{{card.cardInfo.value.amount | currency : '$ ' : 2}} {{card.amount | currency : '$ ' : 2}}
</span> </span>
</div> </div>
<div> <div>
Claim code: <span class="text-bold enable_text_select">{{card.gcClaimCode}}</span> Claim code: <span class="text-bold enable_text_select">{{card.claimCode}}</span>
</div> </div>
<div class="m10t" ng-show="card.cardInfo.cardStatus == 'Fulfilled'"> <div class="m10t" ng-show="card.cardStatus == 'Fulfilled'">
<button class="button black round tiny" <button class="button black round tiny"
ng-click="$root.openExternalLink('https://www.amazon.com/gc/redeem?claimCode=' + card.gcClaimCode, '_system')"> ng-click="$root.openExternalLink('https://www.amazon.com/gc/redeem?claimCode=' + card.claimCode, '_system')">
Redeem Now Redeem Now
</button> </button>
</div> </div>
</div>
<div class="text-warning text-center" ng-if="card.cardInfo.cardStatus == 'RefundedToPurchaser'"> <div ng-show="!card.claimCode">
Cancelled (Refunded) <div class="m10t">
</div> Status:
<span class="text-bold">
<div class="size-12 m10t text-center"> PENDING
<a ng-click="$root.openExternalLink(card.bitpayInvoiceUrl)">See invoice</a> </span>
</div> </div>
</div> </div>
<div class="size-12 m10t text-center">
<a ng-click="$root.openExternalLink(card.invoiceUrl)">See invoice</a>
</div>
</div> </div>
<div class="box-notification m20b" ng-show="error" ng-click="error = null"> <div class="box-notification m20b" ng-show="error" ng-click="error = null">
@ -81,11 +84,8 @@
</div> </div>
<ul class="no-bullet size-14 m30v text-center"> <ul class="no-bullet size-14 m30v text-center">
<li class="line-b p10 oh pointer" ng-show="card.status == 'SUCCESS' && card.cardInfo.cardStatus == 'Fulfilled'" ng-click="cancelGiftCard()"> <li class="line-b p10 oh pointer" ng-show="card.status == 'FAILURE' || card.cardStatus == 'RefundedToPurchaser'
<span class="text-warning">Cancel gift card</span> || card.cardStatus == 'Expired'" ng-click="remove()">
</li>
<li class="line-b p10 oh pointer" ng-show="card.status == 'FAILURE' || card.cardInfo.cardStatus == 'RefundedToPurchaser'
|| card.cardInfo.cardStatus == 'Expired'" ng-click="remove()">
<span class="text-warning">Remove gift card</span> <span class="text-warning">Remove gift card</span>
</li> </li>
</ul> </ul>

View file

@ -11,7 +11,8 @@
</h1> </h1>
</ion-header-bar> </ion-header-bar>
<ion-content> <ion-content ng-style="{'background-color': '#F6F7F9'}">
<div class="modal-content"> <div class="modal-content">
<div class="box-notification text-center size-12 text-warning m10t" ng-show="error"> <div class="box-notification text-center size-12 text-warning m10t" ng-show="error">
<i class="fi-error"></i> {{error}} <i class="fi-error"></i> {{error}}

View file

@ -25,7 +25,6 @@
</div> </div>
</div> </div>
<div class="oh" ng-show="!index.noFocusedWallet"> <div class="oh" ng-show="!index.noFocusedWallet">
<!-- <!--

View file

@ -1,24 +1,70 @@
'use strict'; 'use strict';
angular.module('copayApp.controllers').controller('amazonController', angular.module('copayApp.controllers').controller('amazonController',
function($scope, $timeout, $ionicModal, lodash, configService, amazonService) { function($scope, $timeout, $ionicModal, $log, lodash, bwcError, configService, amazonService) {
this.init = function() { this.init = function() {
var self = this; var self = this;
var network = configService.getSync().amazon.testnet ? 'testnet' : 'livenet'; var network = configService.getSync().amazon.testnet ? 'testnet' : 'livenet';
self.sandbox = network == 'testnet' ? true : false; self.sandbox = network == 'testnet' ? true : false;
amazonService.setCredentials(network); amazonService.setCredentials(network);
amazonService.getGiftCards(function(err, gcds) { amazonService.getPendingGiftCards(function(err, gcds) {
if (err) { if (err) {
self.error = err; self.error = err;
return; return;
} }
self.giftCards = lodash.isEmpty(gcds) ? null : gcds; $scope.giftCards = lodash.isEmpty(gcds) ? null : gcds;
$timeout(function() { $timeout(function() {
$scope.$digest(); $scope.$digest();
}); });
}); });
}; this.updatePendingGiftCards();
}
this.updatePendingGiftCards = lodash.debounce(function() {
amazonService.getPendingGiftCards(function(err, gcds) {
lodash.forEach(gcds, function(dataFromStorage) {
if (dataFromStorage.status == 'PENDING') {
$log.debug("creating gift card");
amazonService.createGiftCard(dataFromStorage, function(err, giftCard) {
if (err) {
$log.debug(bwcError.msg(err));
return;
}
if (giftCard.status != 'PENDING') {
var newData = {};
lodash.merge(newData, dataFromStorage, giftCard);
if (newData.status == 'expired') {
amazonService.savePendingGiftCard(newData, {
remove: true
}, function(err) {
return;
});
}
amazonService.savePendingGiftCard(newData, null, function(err) {
$log.debug("Saving new gift card");
amazonService.getPendingGiftCards(function(err, gcds) {
if (err) {
self.error = err;
return;
}
$scope.giftCards = gcds;
$timeout(function() {
$scope.$digest();
});
});
});
} else $log.debug("pending gift card not available yet");
});
}
});
});
}, 1000);
this.openCardModal = function(card) { this.openCardModal = function(card) {
var self = this; var self = this;

View file

@ -1,7 +1,7 @@
'use strict'; 'use strict';
angular.module('copayApp.controllers').controller('buyAmazonController', angular.module('copayApp.controllers').controller('buyAmazonController',
function($rootScope, $scope, $ionicModal, $log, $timeout, lodash, profileService, bwcError, configService, walletService, fingerprintService, amazonService, ongoingProcess) { function($rootScope, $scope, $ionicModal, $log, $timeout, $state, lodash, profileService, bwcError, configService, walletService, fingerprintService, amazonService, ongoingProcess) {
var self = this; var self = this;
var client; var client;
@ -17,11 +17,9 @@ angular.module('copayApp.controllers').controller('buyAmazonController',
this.init = function() { this.init = function() {
var network = configService.getSync().amazon.testnet ? 'testnet' : 'livenet'; var network = configService.getSync().amazon.testnet ? 'testnet' : 'livenet';
amazonService.setCredentials(network); amazonService.setCredentials(network);
amazonService.healthCheckRequest();
amazonService.initUuid();
self.allWallets = profileService.getWallets(network, 1); self.allWallets = profileService.getWallets(network, 1);
client = profileService.focusedClient; client = profileService.focusedClient;
if (client && client.credentials.m == 1) { if (client && client.credentials.m == 1 && client.credentials.network == network) {
$timeout(function() { $timeout(function() {
self.selectedWalletId = client.credentials.walletId; self.selectedWalletId = client.credentials.walletId;
self.selectedWalletName = client.credentials.walletName; self.selectedWalletName = client.credentials.walletName;
@ -62,9 +60,8 @@ angular.module('copayApp.controllers').controller('buyAmazonController',
var currency_code = configService.getSync().amazon.testnet ? window.amazon_sandbox_currency_code : window.amazon_currency_code; var currency_code = configService.getSync().amazon.testnet ? window.amazon_sandbox_currency_code : window.amazon_currency_code;
var dataSrc = { var dataSrc = {
price: $scope.fiat,
currency: currency_code, currency: currency_code,
orderId: self.selectedWalletName amount: $scope.fiat
}; };
var outputs = []; var outputs = [];
var config = configService.getSync(); var config = configService.getSync();
@ -74,8 +71,7 @@ angular.module('copayApp.controllers').controller('buyAmazonController',
ongoingProcess.set('Processing Transaction...', true); ongoingProcess.set('Processing Transaction...', true);
$timeout(function() { $timeout(function() {
amazonService.createBitPayInvoice(dataSrc, function(err, dataInvoice) {
amazonService.createBitPayInvoice(dataSrc, function(err, data) {
if (err) { if (err) {
ongoingProcess.set('Processing Transaction...', false); ongoingProcess.set('Processing Transaction...', false);
self.error = bwcError.msg(err); self.error = bwcError.msg(err);
@ -85,79 +81,131 @@ angular.module('copayApp.controllers').controller('buyAmazonController',
return; return;
} }
var address, comment, amount; amazonService.getBitPayInvoice(dataInvoice.invoiceId, function(err, invoice) {
address = data.data.bitcoinAddress;
amount = parseInt((data.data.btcPrice * 100000000).toFixed(0));
comment = 'Amazon.com Gift Card';
outputs.push({
'toAddress': address,
'amount': amount,
'message': comment
});
var txp = {
toAddress: address,
amount: amount,
outputs: outputs,
message: comment,
payProUrl: null,
excludeUnconfirmedUtxos: configWallet.spendUnconfirmed ? false : true,
feeLevel: walletSettings.feeLevel || 'normal'
};
walletService.createTx(client, txp, function(err, createdTxp) {
ongoingProcess.set('Processing Transaction...', false);
if (err) { if (err) {
ongoingProcess.set('Processing Transaction...', false);
self.error = bwcError.msg(err); self.error = bwcError.msg(err);
$timeout(function() { $timeout(function() {
$scope.$digest(); $scope.$digest();
}); });
return; return;
} }
$scope.$emit('Local/NeedsConfirmation', createdTxp, function(accept) {
if (accept) { var address, comment, amount;
self.confirmTx(createdTxp, function(err, tx) {
if (err) { address = invoice.bitcoinAddress;
ongoingProcess.set('Processing Transaction...', false); amount = parseInt((invoice.btcPrice * 100000000).toFixed(0));
self.error = bwcError.msg(err); comment = 'Amazon.com Gift Card';
$timeout(function() {
$scope.$digest(); outputs.push({
}); 'toAddress': address,
return; 'amount': amount,
} 'message': comment
var gift = { });
amount: dataSrc.price,
currencyCode: dataSrc.currency, var txp = {
bitpayInvoiceId: data.data.id, toAddress: address,
bitpayInvoiceUrl: data.data.url amount: amount,
}; outputs: outputs,
ongoingProcess.set('Processing Transaction...', true); message: comment,
amazonService.createGiftCard(gift, function(err, giftCard) { payProUrl: null,
ongoingProcess.set('Processing Transaction...', false); excludeUnconfirmedUtxos: configWallet.spendUnconfirmed ? false : true,
feeLevel: walletSettings.feeLevel || 'normal'
};
walletService.createTx(client, txp, function(err, createdTxp) {
ongoingProcess.set('Processing Transaction...', false);
if (err) {
self.error = bwcError.msg(err);
$timeout(function() {
$scope.$digest();
});
return;
}
$scope.$emit('Local/NeedsConfirmation', createdTxp, function(accept) {
if (accept) {
self.confirmTx(createdTxp, function(err, tx) {
if (err) { if (err) {
ongoingProcess.set('Processing Transaction...', false);
self.error = bwcError.msg(err); self.error = bwcError.msg(err);
self.errorInfo = gift;
$timeout(function() { $timeout(function() {
$scope.$digest(); $scope.$digest();
}); });
return; return;
} }
amazonService.setAmountByDay(dataSrc.price); var count = 0;
self.giftCard = giftCard; ongoingProcess.set('Processing Transaction...', true);
$timeout(function() {
$scope.$digest(); dataSrc.accessKey = dataInvoice.accessKey;
}); dataSrc.invoiceId = invoice.id;
dataSrc.invoiceUrl = invoice.url;
dataSrc.invoiceTime = invoice.invoiceTime;
self.debounceCreate(count, dataSrc);
}); });
}); }
} });
}); });
}); });
}); });
}, 100); }, 100);
}; };
self.debounceCreate = lodash.throttle(function(count, dataSrc) {
self.debounceCreateGiftCard(count, dataSrc);
}, 8000, {
'leading': true
});
self.debounceCreateGiftCard = function(count, dataSrc) {
amazonService.createGiftCard(dataSrc, function(err, giftCard) {
$log.debug("creating gift card " + count);
if (err) {
ongoingProcess.set('Processing Transaction...', false);
self.error = bwcError.msg(err);
self.errorInfo = dataSrc;
$timeout(function() {
$scope.$digest();
});
return;
}
if (giftCard.status == 'PENDING' && count < 3) {
$log.debug("pending gift card not available yet");
self.debounceCreate(count + 1, dataSrc, dataSrc);
return;
}
var now = moment().unix();
var newData = giftCard;
newData['invoiceId'] = dataSrc.invoiceId;
newData['accessKey'] = dataSrc.accessKey;
newData['invoiceUrl'] = dataSrc.invoiceUrl;
newData['amount'] = dataSrc.amount;
newData['date'] = dataSrc.invoiceTime || now;
if (newData.status == 'expired') {
amazonService.savePendingGiftCard(newData, {
remove: true
}, function(err) {
return;
});
}
amazonService.savePendingGiftCard(newData, null, function(err) {
ongoingProcess.set('Processing Transaction...', false);
$log.debug("Saving new gift card with status: " + newData.status);
self.giftCard = newData;
if (newData.status == 'PENDING') $state.transitionTo('amazon');
$timeout(function() {
$scope.$digest();
});
});
});
}
this.confirmTx = function(txp, cb) { this.confirmTx = function(txp, cb) {
fingerprintService.check(client, function(err) { fingerprintService.check(client, function(err) {

View file

@ -1,6 +1,7 @@
'use strict'; 'use strict';
angular.module('copayApp.controllers').controller('indexController', function($rootScope, $scope, $log, $filter, $timeout, $ionicScrollDelegate, $ionicPopup, $ionicSideMenuDelegate, latestReleaseService, feeService, bwcService, pushNotificationsService, lodash, go, profileService, configService, rateService, storageService, addressService, gettext, gettextCatalog, amMoment, addonManager, bwcError, txFormatService, uxLanguage, glideraService, coinbaseService, platformInfo, addressbookService, openURLService, ongoingProcess) { angular.module('copayApp.controllers').controller('indexController', function($rootScope, $scope, $log, $filter, $timeout, $ionicScrollDelegate, $ionicPopup, $ionicSideMenuDelegate, $httpBackend, latestReleaseService, feeService, bwcService, pushNotificationsService, lodash, go, profileService, configService, rateService, storageService, addressService, gettext, gettextCatalog, amMoment, addonManager, bwcError, txFormatService, uxLanguage, glideraService, coinbaseService, amazonService, platformInfo, addressbookService, openURLService, ongoingProcess) {
var self = this; var self = this;
var SOFT_CONFIRMATION_LIMIT = 12; var SOFT_CONFIRMATION_LIMIT = 12;
var errors = bwcService.getErrors(); var errors = bwcService.getErrors();
@ -1041,10 +1042,6 @@ angular.module('copayApp.controllers').controller('indexController', function($r
}); });
}; };
self.initAmazon = function() {
self.amazonEnabled = configService.getSync().amazon.enabled;
};
self.initGlidera = function(accessToken) { self.initGlidera = function(accessToken) {
self.glideraEnabled = configService.getSync().glidera.enabled; self.glideraEnabled = configService.getSync().glidera.enabled;
self.glideraTestnet = configService.getSync().glidera.testnet; self.glideraTestnet = configService.getSync().glidera.testnet;
@ -1394,6 +1391,15 @@ angular.module('copayApp.controllers').controller('indexController', function($r
}); });
}; };
self.initAmazon = function() {
self.amazonEnabled = configService.getSync().amazon.enabled;
self.amazonTestnet = configService.getSync().amazon.testnet;
var network = self.amazonTestnet ? 'testnet' : 'livenet';
if (!self.amazonEnabled) return;
amazonService.setCredentials(network);
};
self.isInFocus = function(walletId) { self.isInFocus = function(walletId) {
var fc = profileService.focusedClient; var fc = profileService.focusedClient;
return fc && fc.credentials.walletId == walletId; return fc && fc.credentials.walletId == walletId;

View file

@ -1,53 +1,45 @@
'use strict'; 'use strict';
angular.module('copayApp.controllers').controller('amazonCardDetailsController', function($scope, $timeout, amazonService, ongoingProcess) { angular.module('copayApp.controllers').controller('amazonCardDetailsController', function($scope, $log, $timeout, bwcError, amazonService, lodash, ongoingProcess) {
$scope.cancelGiftCard = function() {
var dataSrc = {
creationRequestId: $scope.card.creationRequestId,
gcId: $scope.card.gcId,
bitpayInvoiceId: $scope.card.bitpayInvoiceId,
bitpayInvoiceUrl: $scope.card.bitpayInvoiceUrl,
date: $scope.card.date
};
ongoingProcess.set('Canceling gift card...', true);
amazonService.cancelGiftCard(dataSrc, function(err, data) {
ongoingProcess.set('Canceling gift card...', false);
if (err || data.status != 'SUCCESS') {
$scope.error = err || data.status;
return;
}
$scope.refreshGiftCard();
});
};
$scope.remove = function() { $scope.remove = function() {
amazonService.saveGiftCard($scope.card, {remove: true}, function(err) { amazonService.savePendingGiftCard($scope.card, {
remove: true
}, function(err) {
$scope.$emit('UpdateAmazonList'); $scope.$emit('UpdateAmazonList');
$scope.cancel(); $scope.cancel();
}); });
}; };
$scope.refreshGiftCard = function() { $scope.refreshGiftCard = function() {
var dataSrc = { amazonService.getPendingGiftCards(function(err, gcds) {
creationRequestId: $scope.card.creationRequestId,
amount: $scope.card.cardInfo.value.amount,
currencyCode: $scope.card.cardInfo.value.currencyCode,
bitpayInvoiceId: $scope.card.bitpayInvoiceId,
bitpayInvoiceUrl: $scope.card.bitpayInvoiceUrl,
date: $scope.card.date
};
ongoingProcess.set('Updating gift card...', true);
amazonService.createGiftCard(dataSrc, function(err, data) {
ongoingProcess.set('Updating gift card...', false);
if (err) { if (err) {
$scope.error = err; self.error = err;
return; return;
} }
$scope.$emit('UpdateAmazonList'); lodash.forEach(gcds, function(dataFromStorage) {
$scope.card = data; if (dataFromStorage.status == 'PENDING' && dataFromStorage.invoiceId == $scope.card.invoiceId) {
$timeout(function() { $log.debug("creating gift card");
$scope.$digest(); amazonService.createGiftCard(dataFromStorage, function(err, giftCard) {
if (err) {
self.error = bwcError.msg(err);
$log.debug(bwcError.msg(err));
return;
}
if (!lodash.isEmpty(giftCard)) {
var newData = {};
lodash.merge(newData, dataFromStorage, giftCard);
amazonService.savePendingGiftCard(newData, null, function(err) {
$log.debug("Saving new gift card");
$scope.card = newData;
$scope.$emit('UpdateAmazonList');
$timeout(function() {
$scope.$digest();
});
});
} else $log.debug("pending gift card not available yet");
});
}
}); });
}); });
}; };

View file

@ -3,29 +3,14 @@
angular.module('copayApp.services').factory('amazonService', function($http, $log, lodash, moment, storageService, configService, platformInfo) { angular.module('copayApp.services').factory('amazonService', function($http, $log, lodash, moment, storageService, configService, platformInfo) {
var root = {}; var root = {};
var credentials = {}; var credentials = {};
var DAILYLIMIT = 500;
root.setCredentials = function(network) { root.setCredentials = function(network) {
credentials.AMAZON_SANDBOX = network == 'testnet' ? true : false;
credentials.AMAZON_SERVICE_NAME = 'AGCODService';
if (network == 'testnet') { if (network == 'testnet') {
credentials.BITPAY_API_URL = window.amazon_sandbox_bitpay_api_url; credentials.BITPAY_API_URL = window.amazon_sandbox_bitpay_api_url;
credentials.BITPAY_API_TOKEN = window.amazon_sandbox_bitpay_api_token; credentials.BITPAY_API_TOKEN = window.amazon_sandbox_bitpay_api_token;
credentials.AMAZON_ACCESS_KEY = window.amazon_sandbox_access_key; } else {
credentials.AMAZON_SECRET_KEY = window.amazon_sandbox_secret_key;
credentials.AMAZON_PARTNER_ID = window.amazon_sandbox_partner_id;
credentials.AMAZON_REGION = window.amazon_sandbox_region;
credentials.AMAZON_ENDPOINT = window.amazon_sandbox_endpoint;
}
else {
credentials.BITPAY_API_URL = window.amazon_bitpay_api_url; credentials.BITPAY_API_URL = window.amazon_bitpay_api_url;
credentials.BITPAY_API_TOKEN = window.amazon_bitpay_api_token; credentials.BITPAY_API_TOKEN = window.amazon_bitpay_api_token;
credentials.AMAZON_ACCESS_KEY = window.amazon_access_key;
credentials.AMAZON_SECRET_KEY = window.amazon_secret_key;
credentials.AMAZON_PARTNER_ID = window.amazon_partner_id;
credentials.AMAZON_REGION = window.amazon_region;
credentials.AMAZON_ENDPOINT = window.amazon_endpoint;
}; };
}; };
@ -44,154 +29,6 @@ angular.module('copayApp.services').factory('amazonService', function($http, $lo
} }
}; };
var _checkLimits = function(amount, cb) {
var network = configService.getSync().amazon.testnet ? 'testnet' : 'livenet';
var dateStamp = moment.utc().format('YYYY-MM-DD');
storageService.getAmazon(network, function(err, amazon) {
if (err) $log.error(err);
if (lodash.isEmpty(amazon)) return cb('CAN_NOT_GET_DATA_FROM_STORAGE');
if (lodash.isString(amazon)) {
amazon = JSON.parse(amazon);
}
if (amazon.date == dateStamp && (amazon.amount + amount) > DAILYLIMIT)
return cb('EXCEEDED_DAILY_LIMIT');
return cb();
});
};
root.healthCheckRequest = function() {
$http({
method: 'GET',
url: credentials.AMAZON_ENDPOINT + '/sping',
headers: {
'content-type': 'application/json'
}
}).then(function(data) {
$log.info('Amazon Health Check: SUCCESS');
}, function(data) {
$log.error('Amazon Health Check: ERROR ' + data.data.error);
});
};
root.initUuid = function() {
var network = configService.getSync().amazon.testnet ? 'testnet' : 'livenet';
var dateStamp = moment.utc().format('YYYY-MM-DD');
_getUuid(function(uuid) {
storageService.getAmazon(network, function(err, amazon) {
if (err) $log.error(err);
if (lodash.isEmpty(amazon))
amazon = {
uuid: uuid,
date: dateStamp,
amount: 0
};
if (lodash.isString(amazon)) {
amazon = JSON.parse(amazon);
}
amazon.uuid = uuid;
if (amazon.date != dateStamp) {
amazon.date = dateStamp;
amazon.amount = 0;
}
amazon = JSON.stringify(amazon);
storageService.setAmazon(network, amazon, function(err) {
if (err) $log.error(err);
});
});
});
};
root.setAmountByDay = function(amount) {
var network = configService.getSync().amazon.testnet ? 'testnet' : 'livenet';
var dateStamp = moment.utc().format('YYYY-MM-DD');
storageService.getAmazon(network, function(err, amazon) {
if (err) $log.error(err);
if (lodash.isString(amazon)) {
amazon = JSON.parse(amazon);
}
if (amazon.date == dateStamp) {
amazon.amount = amazon.amount + amount;
} else {
amazon.date = dateStamp;
amazon.amount = amount;
}
amazon = JSON.stringify(amazon);
storageService.setAmazon(network, amazon, function(err) {
if (err) $log.error(err);
});
});
};
var _getSignatureKey = function() {
var key = credentials.AMAZON_SECRET_KEY;
var dateStamp = moment.utc().format('YYYYMMDD');
var regionName = credentials.AMAZON_REGION;
var serviceName = credentials.AMAZON_SERVICE_NAME;
var kDate= CryptoJS.HmacSHA256(dateStamp, "AWS4" + key, { asBytes: true});
var kRegion= CryptoJS.HmacSHA256(regionName, kDate, { asBytes: true });
var kService=CryptoJS.HmacSHA256(serviceName, kRegion, { asBytes: true });
var kSigning= CryptoJS.HmacSHA256("aws4_request", kService, { asBytes: true });
return kSigning;
}
var _getHeaders = function(data, method, endpoint, amz_target) {
var content_type = 'application/json';
var accept = 'application/json';
var amz_date = moment.utc().format('YYYYMMDD[T]HHmmss[Z]');
var date_stamp = moment.utc().format('YYYYMMDD');
var canonical_querystring = '';
/************* TASK 1: CREATE A CANONICAL REQUEST *************/
var canonical_headers =
'accept:' + accept + '\n' +
'content-type:' + content_type + '\n' +
'host:' + credentials.AMAZON_ENDPOINT.replace('https://', '') + '\n' +
'x-amz-date:' + amz_date + '\n' +
'x-amz-target:' + amz_target + '\n';
var signed_headers = 'accept;content-type;host;x-amz-date;x-amz-target';
data = JSON.stringify(data);
var payload_hash = CryptoJS.SHA256(data).toString(CryptoJS.enc.Hex);
var canonical_request = method + '\n' + endpoint + '\n' + canonical_querystring + '\n' + canonical_headers + '\n' + signed_headers + '\n' + payload_hash;
/************* TASK 2: CREATE THE STRING TO SIGN *************/
var algorithm = 'AWS4-HMAC-SHA256';
var credential_scope = date_stamp + '/' + credentials.AMAZON_REGION + '/' + credentials.AMAZON_SERVICE_NAME + '/' + 'aws4_request';
var hashed_canonical_request = CryptoJS.SHA256(canonical_request).toString(CryptoJS.enc.Hex);
var string_to_sign = algorithm + '\n' + amz_date + '\n' + credential_scope + '\n' + hashed_canonical_request;
/************* TASK 3: CALCULATE THE SIGNATURE *************/
var signing_key = _getSignatureKey();
var signature = CryptoJS.HmacSHA256(string_to_sign, signing_key).toString(CryptoJS.enc.Hex)
var authorization_header = algorithm + ' ' + 'Credential=' + credentials.AMAZON_ACCESS_KEY + '/' + credential_scope + ', ' + 'SignedHeaders=' + signed_headers + ', ' + 'Signature=' + signature;
/************* TASK 4: ADD SIGNING INFORMATION TO THE REQUEST *************/
return {
'Content-Type': content_type,
'Accept': accept,
'X-Amz-Date': amz_date,
'X-Amz-Target': amz_target,
'Authorization': authorization_header
};
};
var _getBitPay = function(endpoint) { var _getBitPay = function(endpoint) {
return { return {
method: 'GET', method: 'GET',
@ -214,39 +51,7 @@ angular.module('copayApp.services').factory('amazonService', function($http, $lo
}; };
}; };
root.createBitPayInvoice = function(data, cb) { root.savePendingGiftCard = function(gc, opts, cb) {
_getUuid(function(uuid) {
if (lodash.isEmpty(uuid)) return cb('CAN_NOT_GET_UUID');
var dataSrc = {
price: data.price,
currency: data.currency,
orderId: data.orderId,
posData: '{uuid:' + uuid + '}'
};
_checkLimits(data.price, function(err) {
if (err) return cb(err);
$http(_postBitPay('/invoices', dataSrc)).then(function(data) {
$log.info('BitPay Create Invoice: SUCCESS');
return cb(null, data.data);
}, function(data) {
$log.error('BitPay Create Invoice: ERROR ' + data.data.error);
return cb(data.data.error);
});
});
});
};
root.getBitPayInvoice = function(id, cb) {
$http(_getBitPay('/invoices/' + id)).then(function(data) {
$log.info('BitPay Get Invoice: SUCCESS');
return cb(null, data.data);
}, function(data) {
$log.error('BitPay Get Invoice: ERROR ' + data.data.error);
return cb(data.data.error);
});
};
root.saveGiftCard = function(gc, opts, cb) {
var network = configService.getSync().amazon.testnet ? 'testnet' : 'livenet'; var network = configService.getSync().amazon.testnet ? 'testnet' : 'livenet';
storageService.getAmazonGiftCards(network, function(err, oldGiftCards) { storageService.getAmazonGiftCards(network, function(err, oldGiftCards) {
if (lodash.isString(oldGiftCards)) { if (lodash.isString(oldGiftCards)) {
@ -256,12 +61,12 @@ angular.module('copayApp.services').factory('amazonService', function($http, $lo
gc = JSON.parse(gc); gc = JSON.parse(gc);
} }
var inv = oldGiftCards || {}; var inv = oldGiftCards || {};
inv[gc.gcId] = gc; inv[gc.invoiceId] = gc;
if (opts && (opts.error || opts.status)) { if (opts && (opts.error || opts.status)) {
inv[gc.gcId] = lodash.assign(inv[gc.gcId], opts); inv[gc.invoiceId] = lodash.assign(inv[gc.invoiceId], opts);
} }
if (opts && opts.remove) { if (opts && opts.remove) {
delete(inv[gc.gcId]); delete(inv[gc.invoiceId]);
} }
inv = JSON.stringify(inv); inv = JSON.stringify(inv);
@ -271,7 +76,7 @@ angular.module('copayApp.services').factory('amazonService', function($http, $lo
}); });
}; };
root.getGiftCards = function(cb) { root.getPendingGiftCards = function(cb) {
var network = configService.getSync().amazon.testnet ? 'testnet' : 'livenet'; var network = configService.getSync().amazon.testnet ? 'testnet' : 'livenet';
storageService.getAmazonGiftCards(network, function(err, giftCards) { storageService.getAmazonGiftCards(network, function(err, giftCards) {
var _gcds = giftCards ? JSON.parse(giftCards) : null; var _gcds = giftCards ? JSON.parse(giftCards) : null;
@ -279,73 +84,56 @@ angular.module('copayApp.services').factory('amazonService', function($http, $lo
}); });
}; };
root.createGiftCard = function(dataSrc, cb) { root.createBitPayInvoice = function(data, cb) {
var environment = credentials.AMAZON_SANDBOX ? 'T' : 'P'; // T: test - P: production _getUuid(function(uuid) {
var now = moment().unix(); if (lodash.isEmpty(uuid)) return cb('CAN_NOT_GET_UUID');
var requestId = dataSrc.creationRequestId || credentials.AMAZON_PARTNER_ID + environment + now; var dataSrc = {
currency: data.currency,
amount: data.amount,
clientId: uuid
};
var data = { $http(_postBitPay('/amazon-gift/pay', dataSrc)).then(function(data) {
'creationRequestId': requestId, $log.info('BitPay Create Invoice: SUCCESS');
'partnerId': credentials.AMAZON_PARTNER_ID, return cb(null, data.data);
'value': { }, function(data) {
'currencyCode': dataSrc.currencyCode, $log.error('BitPay Create Invoice: ERROR ' + data.data.message);
'amount': dataSrc.amount return cb(data.data);
}
};
var method = 'POST';
var endpoint = '/CreateGiftCard';
var amz_target = 'com.amazonaws.agcod.AGCODService.CreateGiftCard';
var headers = _getHeaders(data, method, endpoint, amz_target);
$http({
'method': method,
'url': credentials.AMAZON_ENDPOINT + endpoint,
'data': JSON.stringify(data),
'headers': headers
}).then(function(data) {
$log.info('Amazon.com Gift Card Create/Update: SUCCESS');
var newData = data.data;
newData['bitpayInvoiceId'] = dataSrc.bitpayInvoiceId;
newData['bitpayInvoiceUrl'] = dataSrc.bitpayInvoiceUrl;
newData['date'] = dataSrc.date || now;
root.saveGiftCard(newData, null, function(err) {
return cb(null, newData);
}); });
}, function(data) {
$log.error('Amazon.com Gift Card Create/Update: ERROR ' + data.statusText);
return cb(data.statusText);
}); });
}; };
root.cancelGiftCard = function(dataSrc, cb) { root.getBitPayInvoice = function(id, cb) {
var data = { $http(_getBitPay('/invoices/' + id)).then(function(data) {
'creationRequestId': dataSrc.creationRequestId, $log.info('BitPay Get Invoice: SUCCESS');
'partnerId': credentials.AMAZON_PARTNER_ID, return cb(null, data.data.data);
'gcId': dataSrc.gcId,
};
var method = 'POST';
var endpoint = '/CancelGiftCard';
var amz_target = 'com.amazonaws.agcod.AGCODService.CancelGiftCard';
var headers = _getHeaders(data, method, endpoint, amz_target);
$http({
'method': method,
'url': credentials.AMAZON_ENDPOINT + endpoint,
'data': JSON.stringify(data),
'headers': headers
}).then(function(data) {
$log.info('Amazon.com Gift Card Cancel: SUCCESS');
return cb(null, data.data);
}, function(data) { }, function(data) {
$log.error('Amazon.com Gift Card Cancel: ERROR ' + data.statusText); $log.error('BitPay Get Invoice: ERROR ' + data.data.error);
return cb(data.statusText); return cb(data.data.error);
}); });
}; };
root.createGiftCard = function(dataInvoice, cb) {
_getUuid(function(uuid) {
var dataSrc = {
"clientId": uuid,
"invoiceId": dataInvoice.invoiceId,
"accessKey": dataInvoice.accessKey
};
$http(_postBitPay('/amazon-gift/redeem', dataSrc)).then(function(data) {
var status = data.data.status == ('new' || 'paid') ? 'PENDING' : data.data.status;
data.data.status = status;
data.data.clientId = uuid;
$log.info('Amazon.com Gift Card Create/Update: ' + status);
return cb(null, data.data);
}, function(data) {
$log.error('Amazon.com Gift Card Create/Update: ' + data.data.message);
return cb(data.data);
});
})
};
return root; return root;
}); });

View file

@ -330,17 +330,5 @@ angular.module('copayApp.services')
storage.remove('amazonGiftCards-' + network, cb); storage.remove('amazonGiftCards-' + network, cb);
}; };
root.setAmazon = function(network, data, cb) {
storage.set('amazon-' + network, data, cb);
};
root.getAmazon = function(network, cb) {
storage.get('amazon-' + network, cb);
};
root.removeAmazon = function(network, cb) {
storage.remove('amazon-' + network, cb);
};
return root; return root;
}); });

View file

@ -729,6 +729,10 @@ ul.manage li {
padding: 20px; padding: 20px;
} }
.p15t {
padding-top: 15px;
}
.p20t { .p20t {
padding-top: 20px; padding-top: 20px;
} }