amazon integration refactor

This commit is contained in:
Gabriel Bazán 2016-07-21 11:18:48 -03:00 committed by Gustavo Maximiliano Cortez
parent 42a8176d7c
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>
</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">
<h1 class="title ellipsis">
Gift cards
@ -32,16 +26,16 @@
Sandbox version. Only for testing purpose
</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">
<div class="size-10 m5t text-gray"><b>Only</b> redeemable on www.amazon.com (USA website)</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="columns">
<button class="m20t button black round expand"
<button class="m20t button black round expand"
ui-sref="buyAmazon">
Buy now
</button>
@ -49,26 +43,39 @@
</div>
<div class="text-left p10h m30v">
Amazon.com Gift Cards never expire and can be redeemed towards millions of items at
Amazon.com Gift Cards never expire and can be redeemed towards millions of items at
<a ng-click="$root.openExternalLink('https://www.amazon.com')">www.amazon.com</a>
</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>
<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)"
class="row collapse last-transactions-content size-12">
<div class="large-2 medium-2 small-2 columns">
<img src="img/a-smile_color_btn.png" alt="{{id}}" width="40">
</div>
<div class="large-4 medium-4 small-4 columns m5t size-18">
{{item.cardInfo.value.amount | currency : '$ ' : 2}}
<div class="large-4 medium-4 small-4 columns m5t size-18" ng-if="item.claimCode">
{{item.amount | currency : '$ ' : 2}}
</div>
<div class="large-4 medium-4 small-4 columns m5t size-18" ng-if="!item.claimCode">
-
</div>
<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-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 class="large-1 medium-1 small-1 columns text-right m10t">
<i class="icon-arrow-right3 size-18"></i>

View File

@ -1,5 +1,5 @@
<div
class="topbar-container"
<div
class="topbar-container"
ng-include="'views/includes/topbar.html'"
ng-init="titleSection='Buy'; goBackToState = 'amazon'; noColor = true">
</div>
@ -18,14 +18,14 @@
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
<div class="p10 m10t">
Amount: {{buy.errorInfo.amount}} {{buy.errorInfo.currencyCode}}<br>
BitPay Invoice ID: {{buy.errorInfo.bitpayInvoiceId}}.
Amount: {{buy.errorInfo.amount}} {{buy.errorInfo.currency}}<br>
BitPay Invoice ID: {{buy.errorInfo.invoiceId}}.
</div>
<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 class="text-center">
<img src="img/a_generic.jpg" alt="Amazon.com Gift Card" width="180">
@ -35,8 +35,8 @@
</div>
<form
class="m30v"
name="buyAmazonForm"
ng-submit="buy.createTx()"
name="buyAmazonForm"
ng-submit="buy.createTx()"
novalidate>
<label>
@ -51,22 +51,22 @@
<a class="postfix button black">USD</a>
</div>
<div
<div
class="m10b"
ng-click="openWalletsModal(buy.allWallets)">
<label>Pay From Copay Wallet</label>
<div class="input">
<input type="text" id="address" name="address" ng-disabled="buy.selectedWalletId"
ng-attr-placeholder="{{'Choose your source wallet'}}"
<input type="text" id="address" name="address" ng-disabled="buy.selectedWalletId"
ng-attr-placeholder="{{'Choose your source wallet'}}"
ng-model="buy.selectedWalletName" required>
<a class="postfix size-12 m0 text-gray">
<i class="icon-wallet size-18"></i>
</a>
</div>
</div>
</div>
<div class="input m20t">
<input class="button black round expand"
<input class="button black round expand"
ng-disabled="!buy.selectedWalletId || !fiat"
type="submit" value="Buy now">
</div>
@ -75,7 +75,7 @@
</div>
<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>
<div class="box-notification m20b">
<span class="text-warning">
@ -88,38 +88,41 @@
resolved retrying the request from your list of cards
</span>
<span ng-show="buy.giftCard.status == 'FAILURE'">
This failure could not be recoverable. Request your refund from your list of cards
This failure could not be recoverable. Request your refund from your list of cards
</span>
<button class="m20t button outline round dark-gray expand" ng-click="$root.go('amazon')">
Back
Back
</button>
</div>
</div>
<div ng-show="buy.giftCard.status == 'SUCCESS'">
<div class="size-12 m10h">
Thank you for participating in the BitPay offer. It is our pleasure to send
you this Amazon.com Gift Card* that can be redeemed towards millions of items at
<a ng-click="$root.openExternalLink('https://www.amazon.com')">www.amazon.com</a>. You may want to print this screen
Thank you for participating in the BitPay offer. It is our pleasure to send
you this Amazon.com Gift Card* that can be redeemed towards millions of items at
<a ng-click="$root.openExternalLink('https://www.amazon.com')">www.amazon.com</a>. You may want to print this screen
for easy reference later--you&rsquo;ll need the gift card claim code below
</div>
<div class="oh m20t size-12 text-center">
<img class="m10h" src="img/a_generic.jpg" alt="Amazon.com Gift Cards" width="200">
<div class="m10t size-14">
Gift Card Amount:
Gift Card Amount:
<span class="text-bold">
{{buy.giftCard.cardInfo.value.amount | currency : '$ ' : 2 }}
{{buy.giftCard.amount | currency : '$ ' : 2 }}
</span>
</div>
<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 class="m10t">
<button class="button black round tiny"
ng-click="$root.openExternalLink('https://www.amazon.com/gc/redeem?claimCode=' + buy.giftCard.gcClaimCode, '_system')">
<button class="button black round tiny"
ng-click="$root.openExternalLink('https://www.amazon.com/gc/redeem?claimCode=' + buy.giftCard.claimCode, '_system')">
Redeem Now
</button>
</div>
<div class="size-12 m10t text-center">
<a ng-click="$root.openExternalLink(buy.giftCard.invoiceUrl)">See invoice</a>
</div>
</div>
</div>
</div>
@ -129,11 +132,11 @@
reseller of Amazon.com Gift Cards. Except as required by law, GCs cannot be transferred for value or redeemed for cash.
GCs may be used only for purchases of eligible goods at Amazon.com or certain of its affiliated websites. Purchases are
deducted from the GC balance. To redeem or view a GC balance, visit &ldquo;Your Account&rdquo; at Amazon.com. Amazon is
not responsible if a GC is lost, stolen, destroyed or used without permission. See
<a ng-click="$root.openExternalLink('https://www.amazon.com/gc-legal')">www.amazon.com/gc-legal</a> for complete terms,
restrictions and exceptions. For any other questions, see
<a ng-click="$root.openExternalLink('https://www.amazon.com/gc')">www.amazon.com/gc</a>. GCs are issued
by ACI Gift Cards, Inc., a Washington corporation. All Amazon &reg;, &trade; &amp; &copy; are IP of
not responsible if a GC is lost, stolen, destroyed or used without permission. See
<a ng-click="$root.openExternalLink('https://www.amazon.com/gc-legal')">www.amazon.com/gc-legal</a> for complete terms,
restrictions and exceptions. For any other questions, see
<a ng-click="$root.openExternalLink('https://www.amazon.com/gc')">www.amazon.com/gc</a>. GCs are issued
by ACI Gift Cards, Inc., a Washington corporation. All Amazon &reg;, &trade; &amp; &copy; are IP of
Amazon.com, Inc. or its affiliates. No expiration date or service fees.
</div>

View File

@ -13,45 +13,48 @@
</section>
</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">
<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">
Gift Card Amount:
Gift Card Amount:
<span class="text-bold">
{{card.cardInfo.value.amount | currency : '$ ' : 2}}
{{card.amount | currency : '$ ' : 2}}
</span>
</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 class="m10t" ng-show="card.cardInfo.cardStatus == 'Fulfilled'">
<button class="button black round tiny"
ng-click="$root.openExternalLink('https://www.amazon.com/gc/redeem?claimCode=' + card.gcClaimCode, '_system')">
<div class="m10t" ng-show="card.cardStatus == 'Fulfilled'">
<button class="button black round tiny"
ng-click="$root.openExternalLink('https://www.amazon.com/gc/redeem?claimCode=' + card.claimCode, '_system')">
Redeem Now
</button>
</div>
<div class="text-warning text-center" ng-if="card.cardInfo.cardStatus == 'RefundedToPurchaser'">
Cancelled (Refunded)
</div>
<div class="size-12 m10t text-center">
<a ng-click="$root.openExternalLink(card.bitpayInvoiceUrl)">See invoice</a>
</div>
<div ng-show="!card.claimCode">
<div class="m10t">
Status:
<span class="text-bold">
PENDING
</span>
</div>
</div>
<div class="size-12 m10t text-center">
<a ng-click="$root.openExternalLink(card.invoiceUrl)">See invoice</a>
</div>
</div>
<div class="box-notification m20b" ng-show="error" ng-click="error = null">
<span class="text-warning">
{{error}}
</span>
</div>
</div>
<div class="text-center size-12" ng-show="card.status != 'SUCCESS'">
<div ng-show="card.status == 'RESEND'">
@ -72,20 +75,17 @@
reseller of Amazon.com Gift Cards. Except as required by law, GCs cannot be transferred for value or redeemed for cash.
GCs may be used only for purchases of eligible goods at Amazon.com or certain of its affiliated websites. Purchases are
deducted from the GC balance. To redeem or view a GC balance, visit &ldquo;Your Account&rdquo; at Amazon.com. Amazon is
not responsible if a GC is lost, stolen, destroyed or used without permission. See
<a ng-click="$root.openExternalLink('https://www.amazon.com/gc-legal')">www.amazon.com/gc-legal</a> for complete terms,
restrictions and exceptions. For any other questions, see
<a ng-click="$root.openExternalLink('https://www.amazon.com/gc')">www.amazon.com/gc</a>. GCs are issued
by ACI Gift Cards, Inc., a Washington corporation. All Amazon &reg;, &trade; &amp; &copy; are IP of
not responsible if a GC is lost, stolen, destroyed or used without permission. See
<a ng-click="$root.openExternalLink('https://www.amazon.com/gc-legal')">www.amazon.com/gc-legal</a> for complete terms,
restrictions and exceptions. For any other questions, see
<a ng-click="$root.openExternalLink('https://www.amazon.com/gc')">www.amazon.com/gc</a>. GCs are issued
by ACI Gift Cards, Inc., a Washington corporation. All Amazon &reg;, &trade; &amp; &copy; are IP of
Amazon.com, Inc. or its affiliates. No expiration date or service fees.
</div>
<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()">
<span class="text-warning">Cancel gift card</span>
</li>
<li class="line-b p10 oh pointer" ng-show="card.status == 'FAILURE' || card.cardInfo.cardStatus == 'RefundedToPurchaser'
|| card.cardInfo.cardStatus == 'Expired'" ng-click="remove()">
<li class="line-b p10 oh pointer" ng-show="card.status == 'FAILURE' || card.cardStatus == 'RefundedToPurchaser'
|| card.cardStatus == 'Expired'" ng-click="remove()">
<span class="text-warning">Remove gift card</span>
</li>
</ul>

View File

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

View File

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

View File

@ -1,24 +1,70 @@
'use strict';
angular.module('copayApp.controllers').controller('amazonController',
function($scope, $timeout, $ionicModal, lodash, configService, amazonService) {
angular.module('copayApp.controllers').controller('amazonController',
function($scope, $timeout, $ionicModal, $log, lodash, bwcError, configService, amazonService) {
this.init = function() {
var self = this;
var network = configService.getSync().amazon.testnet ? 'testnet' : 'livenet';
self.sandbox = network == 'testnet' ? true : false;
amazonService.setCredentials(network);
amazonService.getGiftCards(function(err, gcds) {
amazonService.getPendingGiftCards(function(err, gcds) {
if (err) {
self.error = err;
return;
}
self.giftCards = lodash.isEmpty(gcds) ? null : gcds;
$scope.giftCards = lodash.isEmpty(gcds) ? null : gcds;
$timeout(function() {
$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) {
var self = this;

View File

@ -1,7 +1,7 @@
'use strict';
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 client;
@ -17,11 +17,9 @@ angular.module('copayApp.controllers').controller('buyAmazonController',
this.init = function() {
var network = configService.getSync().amazon.testnet ? 'testnet' : 'livenet';
amazonService.setCredentials(network);
amazonService.healthCheckRequest();
amazonService.initUuid();
self.allWallets = profileService.getWallets(network, 1);
client = profileService.focusedClient;
if (client && client.credentials.m == 1) {
if (client && client.credentials.m == 1 && client.credentials.network == network) {
$timeout(function() {
self.selectedWalletId = client.credentials.walletId;
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 dataSrc = {
price: $scope.fiat,
currency: currency_code,
orderId: self.selectedWalletName
amount: $scope.fiat
};
var outputs = [];
var config = configService.getSync();
@ -74,8 +71,7 @@ angular.module('copayApp.controllers').controller('buyAmazonController',
ongoingProcess.set('Processing Transaction...', true);
$timeout(function() {
amazonService.createBitPayInvoice(dataSrc, function(err, data) {
amazonService.createBitPayInvoice(dataSrc, function(err, dataInvoice) {
if (err) {
ongoingProcess.set('Processing Transaction...', false);
self.error = bwcError.msg(err);
@ -85,79 +81,131 @@ angular.module('copayApp.controllers').controller('buyAmazonController',
return;
}
var address, comment, amount;
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);
amazonService.getBitPayInvoice(dataInvoice.invoiceId, function(err, invoice) {
if (err) {
ongoingProcess.set('Processing Transaction...', false);
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) {
ongoingProcess.set('Processing Transaction...', false);
self.error = bwcError.msg(err);
$timeout(function() {
$scope.$digest();
});
return;
}
var gift = {
amount: dataSrc.price,
currencyCode: dataSrc.currency,
bitpayInvoiceId: data.data.id,
bitpayInvoiceUrl: data.data.url
};
ongoingProcess.set('Processing Transaction...', true);
amazonService.createGiftCard(gift, function(err, giftCard) {
ongoingProcess.set('Processing Transaction...', false);
var address, comment, amount;
address = invoice.bitcoinAddress;
amount = parseInt((invoice.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) {
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) {
ongoingProcess.set('Processing Transaction...', false);
self.error = bwcError.msg(err);
self.errorInfo = gift;
$timeout(function() {
$scope.$digest();
});
return;
}
amazonService.setAmountByDay(dataSrc.price);
self.giftCard = giftCard;
$timeout(function() {
$scope.$digest();
});
var count = 0;
ongoingProcess.set('Processing Transaction...', true);
dataSrc.accessKey = dataInvoice.accessKey;
dataSrc.invoiceId = invoice.id;
dataSrc.invoiceUrl = invoice.url;
dataSrc.invoiceTime = invoice.invoiceTime;
self.debounceCreate(count, dataSrc);
});
});
}
}
});
});
});
});
}, 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) {
fingerprintService.check(client, function(err) {

View File

@ -1,6 +1,7 @@
'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 SOFT_CONFIRMATION_LIMIT = 12;
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.glideraEnabled = configService.getSync().glidera.enabled;
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) {
var fc = profileService.focusedClient;
return fc && fc.credentials.walletId == walletId;

View File

@ -1,53 +1,45 @@
'use strict';
angular.module('copayApp.controllers').controller('amazonCardDetailsController', function($scope, $timeout, amazonService, 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();
});
};
angular.module('copayApp.controllers').controller('amazonCardDetailsController', function($scope, $log, $timeout, bwcError, amazonService, lodash, ongoingProcess) {
$scope.remove = function() {
amazonService.saveGiftCard($scope.card, {remove: true}, function(err) {
amazonService.savePendingGiftCard($scope.card, {
remove: true
}, function(err) {
$scope.$emit('UpdateAmazonList');
$scope.cancel();
});
};
$scope.refreshGiftCard = function() {
var dataSrc = {
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);
amazonService.getPendingGiftCards(function(err, gcds) {
if (err) {
$scope.error = err;
self.error = err;
return;
}
$scope.$emit('UpdateAmazonList');
$scope.card = data;
$timeout(function() {
$scope.$digest();
lodash.forEach(gcds, function(dataFromStorage) {
if (dataFromStorage.status == 'PENDING' && dataFromStorage.invoiceId == $scope.card.invoiceId) {
$log.debug("creating gift card");
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,35 +3,20 @@
angular.module('copayApp.services').factory('amazonService', function($http, $log, lodash, moment, storageService, configService, platformInfo) {
var root = {};
var credentials = {};
var DAILYLIMIT = 500;
root.setCredentials = function(network) {
credentials.AMAZON_SANDBOX = network == 'testnet' ? true : false;
credentials.AMAZON_SERVICE_NAME = 'AGCODService';
if (network == 'testnet') {
credentials.BITPAY_API_URL = window.amazon_sandbox_bitpay_api_url;
credentials.BITPAY_API_TOKEN = window.amazon_sandbox_bitpay_api_token;
credentials.AMAZON_ACCESS_KEY = window.amazon_sandbox_access_key;
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 {
} else {
credentials.BITPAY_API_URL = window.amazon_bitpay_api_url;
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;
};
};
var _getUuid = function(cb) {
var isCordova = platformInfo.isCordova;
if (isCordova) {
window.plugins.uniqueDeviceID.get(function(uuid) {
return cb(uuid);
@ -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) {
return {
method: 'GET',
@ -212,41 +49,9 @@ angular.module('copayApp.services').factory('amazonService', function($http, $lo
},
data: data
};
};
root.createBitPayInvoice = function(data, 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) {
root.savePendingGiftCard = function(gc, opts, cb) {
var network = configService.getSync().amazon.testnet ? 'testnet' : 'livenet';
storageService.getAmazonGiftCards(network, function(err, oldGiftCards) {
if (lodash.isString(oldGiftCards)) {
@ -256,12 +61,12 @@ angular.module('copayApp.services').factory('amazonService', function($http, $lo
gc = JSON.parse(gc);
}
var inv = oldGiftCards || {};
inv[gc.gcId] = gc;
inv[gc.invoiceId] = gc;
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) {
delete(inv[gc.gcId]);
delete(inv[gc.invoiceId]);
}
inv = JSON.stringify(inv);
@ -271,81 +76,64 @@ angular.module('copayApp.services').factory('amazonService', function($http, $lo
});
};
root.getGiftCards = function(cb) {
var network = configService.getSync().amazon.testnet ? 'testnet' : 'livenet';
root.getPendingGiftCards = function(cb) {
var network = configService.getSync().amazon.testnet ? 'testnet' : 'livenet';
storageService.getAmazonGiftCards(network, function(err, giftCards) {
var _gcds = giftCards ? JSON.parse(giftCards) : null;
return cb(err, _gcds);
});
};
root.createGiftCard = function(dataSrc, cb) {
var environment = credentials.AMAZON_SANDBOX ? 'T' : 'P'; // T: test - P: production
var now = moment().unix();
var requestId = dataSrc.creationRequestId || credentials.AMAZON_PARTNER_ID + environment + now;
var data = {
'creationRequestId': requestId,
'partnerId': credentials.AMAZON_PARTNER_ID,
'value': {
'currencyCode': dataSrc.currencyCode,
'amount': dataSrc.amount
}
};
root.createBitPayInvoice = function(data, cb) {
_getUuid(function(uuid) {
if (lodash.isEmpty(uuid)) return cb('CAN_NOT_GET_UUID');
var dataSrc = {
currency: data.currency,
amount: data.amount,
clientId: uuid
};
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);
$http(_postBitPay('/amazon-gift/pay', 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.message);
return cb(data.data);
});
}, function(data) {
$log.error('Amazon.com Gift Card Create/Update: ERROR ' + data.statusText);
return cb(data.statusText);
});
};
root.cancelGiftCard = function(dataSrc, cb) {
var data = {
'creationRequestId': dataSrc.creationRequestId,
'partnerId': credentials.AMAZON_PARTNER_ID,
'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);
root.getBitPayInvoice = function(id, cb) {
$http(_getBitPay('/invoices/' + id)).then(function(data) {
$log.info('BitPay Get Invoice: SUCCESS');
return cb(null, data.data.data);
}, function(data) {
$log.error('Amazon.com Gift Card Cancel: ERROR ' + data.statusText);
return cb(data.statusText);
$log.error('BitPay Get Invoice: ERROR ' + data.data.error);
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;
});

View File

@ -317,7 +317,7 @@ angular.module('copayApp.services')
});
});
};
root.setAmazonGiftCards = function(network, gcs, cb) {
storage.set('amazonGiftCards-' + network, gcs, cb);
};
@ -330,17 +330,5 @@ angular.module('copayApp.services')
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;
});

View File

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