diff --git a/src/js/controllers/bitpayCard.js b/src/js/controllers/bitpayCard.js
index 40187b4ef..0c8a85bd3 100644
--- a/src/js/controllers/bitpayCard.js
+++ b/src/js/controllers/bitpayCard.js
@@ -1,13 +1,13 @@
'use strict';
-angular.module('copayApp.controllers').controller('bitpayCardController', function($scope, $timeout, $log, $state, lodash, bitpayCardService, moment, popupService, gettextCatalog, $ionicHistory) {
+angular.module('copayApp.controllers').controller('bitpayCardController', function($scope, $timeout, $log, $state, lodash, bitpayCardService, moment, popupService, gettextCatalog, $ionicHistory, bitpayService) {
var self = this;
var runningBalance;
$scope.dateRange = {
value: 'last30Days'
};
- $scope.network = bitpayCardService.getEnvironment();
+ $scope.network = bitpayService.getEnvironment();
var updateHistoryFromCache = function(cb) {
bitpayCardService.getBitpayDebitCardsHistory($scope.cardId, function(err, data) {
diff --git a/src/js/controllers/bitpayCardIntro.js b/src/js/controllers/bitpayCardIntro.js
index 49f29ffe8..59eb0a29b 100644
--- a/src/js/controllers/bitpayCardIntro.js
+++ b/src/js/controllers/bitpayCardIntro.js
@@ -1,64 +1,48 @@
'use strict';
-angular.module('copayApp.controllers').controller('bitpayCardIntroController', function($scope, $log, $state, $ionicHistory, storageService, externalLinkService, bitpayCardService, gettextCatalog, popupService, appIdentityService) {
-
- var checkOtp = function(obj, cb) {
- if (obj.otp) {
- var msg = gettextCatalog.getString('Enter Two Factor for BitPay Card');
- popupService.showPrompt(null, msg, null, function(res) {
- cb(res);
- });
- } else {
- cb();
- }
- };
+angular.module('copayApp.controllers').controller('bitpayCardIntroController', function($scope, $log, $state, $ionicHistory, storageService, externalLinkService, bitpayCardService, gettextCatalog, popupService, appIdentityService, bitpayService) {
$scope.$on("$ionicView.beforeEnter", function(event, data) {
-
if (data.stateParams && data.stateParams.secret) {
- var obj = {
+ var pairData = {
secret: data.stateParams.secret,
email: data.stateParams.email,
otp: data.stateParams.otp
};
- checkOtp(obj, function(otp) {
- obj.otp = otp;
- bitpayCardService.bitAuthPair(obj, function(err, data) {
- if (err) {
- popupService.showAlert(gettextCatalog.getString('Error'), err);
- return;
- }
- var title = gettextCatalog.getString('Add BitPay Card Account?');
- var msg = gettextCatalog.getString('Would you like to add this account ({{email}}) to your wallet?', {
- email: obj.email
- });
- var ok = gettextCatalog.getString('Add Account');
- var cancel = gettextCatalog.getString('Go back');
- popupService.showConfirm(title, msg, ok, cancel, function(res) {
- if (res) {
- // Set flag for nextStep
- storageService.setNextStep('BitpayCard', 'true', function(err) {});
- // Save data
- bitpayCardService.setBitpayDebitCards(data, function(err) {
- if (err) return;
- $ionicHistory.nextViewOptions({
- disableAnimate: true
- });
- $state.go('tabs.home').then(function() {
- if (data.cards[0]) {
- $state.transitionTo('tabs.bitpayCard', {
- id: data.cards[0].id
- });
- }
- });
- });
+ var pairingReason = gettextCatalog.getString('add your BitPay Visa® card(s)');
+ bitpayService.pair(pairData, pairingReason, function(err, paired, apiContext) {
+ if (err) {
+ popupService.showAlert(gettextCatalog.getString('Error'), err);
+ return;
+ }
+ if (paired) {
+ bitpayCardService.fetchBitpayDebitCards(apiContext, function(err, data) {
+ if (err) {
+ popupService.showAlert(gettextCatalog.getString('Error'), err);
+ return;
}
+ // Set flag for nextStep
+ storageService.setNextStep('BitpayCard', 'true', function(err) {});
+ // Save data
+ bitpayCardService.setBitpayDebitCards(data, function(err) {
+ if (err) return;
+ $ionicHistory.nextViewOptions({
+ disableAnimate: true
+ });
+ $state.go('tabs.home').then(function() {
+ if (data.cards[0]) {
+ $state.transitionTo('tabs.bitpayCard', {
+ id: data.cards[0].id
+ });
+ }
+ });
+ });
});
- });
+ }
});
} else {
- appIdentityService.getIdentity(bitpayCardService.getEnvironment(), function(err, appIdentity) {
+ appIdentityService.getIdentity(bitpayService.getEnvironment(), function(err, appIdentity) {
if (err) popupService.showAlert(null, err);
- else $log.info('App identity: Ok.');
+ else $log.info('App identity: OK');
});
}
});
diff --git a/src/js/services/bitpayCardService.js b/src/js/services/bitpayCardService.js
index bf57b805a..ce8e787c7 100644
--- a/src/js/services/bitpayCardService.js
+++ b/src/js/services/bitpayCardService.js
@@ -1,9 +1,7 @@
'use strict';
-angular.module('copayApp.services').factory('bitpayCardService', function($http, $log, lodash, storageService, bitauthService, platformInfo, moment, appIdentityService) {
+angular.module('copayApp.services').factory('bitpayCardService', function($log, $rootScope, lodash, storageService, bitauthService, platformInfo, moment, appIdentityService, bitpayService) {
var root = {};
- var BITPAY_CARD_NETWORK = 'livenet';
- var BITPAY_CARD_API_URL = BITPAY_CARD_NETWORK == 'livenet' ? 'https://bitpay.com' : 'https://test.bitpay.com';
var _setError = function(msg, e) {
$log.error(msg);
@@ -11,64 +9,6 @@ angular.module('copayApp.services').factory('bitpayCardService', function($http,
return error;
};
- var _get = function(endpoint) {
- return {
- method: 'GET',
- url: BITPAY_CARD_API_URL + endpoint,
- headers: {
- 'content-type': 'application/json'
- }
- };
- };
-
- var _post = function(endpoint, json, appIdentity) {
- var dataToSign = BITPAY_CARD_API_URL + endpoint + JSON.stringify(json);
- var signedData = bitauthService.sign(dataToSign, appIdentity.priv);
-
- return {
- method: 'POST',
- url: BITPAY_CARD_API_URL + endpoint,
- headers: {
- 'content-type': 'application/json',
- 'x-identity': appIdentity.pub,
- 'x-signature': signedData
- },
- data: json
- };
- };
-
- var _postAuth = function(endpoint, json, appIdentity) {
- json['params'].signature = bitauthService.sign(JSON.stringify(json.params), appIdentity.priv);
- json['params'].pubkey = appIdentity.pub;
- json['params'] = JSON.stringify(json.params);
-
- var ret = {
- method: 'POST',
- url: BITPAY_CARD_API_URL + endpoint,
- headers: {
- 'content-type': 'application/json'
- },
- data: json
- };
-
- $log.debug('post auth:' + JSON.stringify(ret));
- return ret;
- };
-
- var _afterBitAuthSuccess = function(token, obj, appIdentity, cb) {
- var json = {
- method: 'getDebitCards'
- };
- // Get Debit Cards
- $http(_post('/api/v2/' + token, json, appIdentity)).then(function(data) {
- if (data && data.data.error) return cb(data.data.error);
- $log.info('BitPay Get Debit Cards: SUCCESS');
- return cb(data.data.error, {token: token, cards: data.data.data, email: obj.email});
- }, function(data) {
- return cb(_setError('BitPay Card Error: Get Debit Cards', data));
- });
- };
-
var _processTransactions = function(invoices, history) {
invoices = invoices || [];
for (var i = 0; i < invoices.length; i++) {
@@ -99,35 +39,17 @@ angular.module('copayApp.services').factory('bitpayCardService', function($http,
return history;
};
- root.getEnvironment = function() {
- return BITPAY_CARD_NETWORK;
- };
-
- root.bitAuthPair = function(obj, cb) {
- var deviceName = 'Unknown device';
- if (platformInfo.isNW) {
- deviceName = require('os').platform();
- } else if (platformInfo.isCordova) {
- deviceName = device.model;
- }
+ root.fetchBitpayDebitCards = function(apiContext, cb) {
var json = {
- method: 'createToken',
- params: {
- secret: obj.secret,
- version: 2,
- deviceName: deviceName,
- code: obj.otp
- }
+ method: 'getDebitCards'
};
- appIdentityService.getIdentity(root.getEnvironment(), function(err, appIdentity) {
- if (err) return cb(err);
- $http(_postAuth('/api/v2/', json, appIdentity)).then(function(data) {
- if (data && data.data.error) return cb(data.data.error);
- $log.info('BitPay Card BitAuth Create Token: SUCCESS');
- _afterBitAuthSuccess(data.data.data, obj, appIdentity, cb);
- }, function(data) {
- return cb(_setError('BitPay Card Error Create Token: BitAuth', data));
- });
+ // Get Debit Cards
+ bitpayService.post('/api/v2/' + apiContext.token, json, function(data) {
+ if (data && data.data.error) return cb(data.data.error);
+ $log.info('BitPay Get Debit Cards: SUCCESS');
+ return cb(data.data.error, {token: apiContext.token, cards: data.data.data, email: apiContext.pairData.email});
+ }, function(data) {
+ return cb(_setError('BitPay Card Error: Get Debit Cards', data));
});
};
@@ -138,14 +60,14 @@ angular.module('copayApp.services').factory('bitpayCardService', function($http,
method: 'getInvoiceHistory',
params: JSON.stringify(params)
};
- appIdentityService.getIdentity(root.getEnvironment(), function(err, appIdentity) {
+ appIdentityService.getIdentity(bitpayService.getEnvironment(), function(err, appIdentity) {
if (err) return cb(err);
root.getBitpayDebitCards(function(err, data) {
if (err) return cb(err);
var card = lodash.find(data, {id : cardId});
if (!card) return cb(_setError('Card not found'));
// Get invoices
- $http(_post('/api/v2/' + card.token, json, appIdentity)).then(function(data) {
+ bitpayService.post('/api/v2/' + card.token, json, function(data) {
$log.info('BitPay Get Invoices: SUCCESS');
invoices = data.data.data || [];
if (lodash.isEmpty(invoices)) $log.info('No invoices');
@@ -154,7 +76,7 @@ angular.module('copayApp.services').factory('bitpayCardService', function($http,
params: JSON.stringify(params)
};
// Get transactions list
- $http(_post('/api/v2/' + card.token, json, appIdentity)).then(function(data) {
+ bitpayService.post('/api/v2/' + card.token, json, function(data) {
$log.info('BitPay Get Transactions: SUCCESS');
transactions = data.data.data || {};
transactions['txs'] = _processTransactions(invoices, transactions.transactionList);
@@ -163,7 +85,7 @@ angular.module('copayApp.services').factory('bitpayCardService', function($http,
return cb(_setError('BitPay Card Error: Get Transactions', data));
});
}, function(data) {
- return cb(_setError('BitPay Card Error: Get Invoices', data));
+ return cb(_setError('BitPay Card Error: Get Invoices', data));
});
});
});
@@ -175,13 +97,13 @@ angular.module('copayApp.services').factory('bitpayCardService', function($http,
method: 'generateTopUpInvoice',
params: JSON.stringify(params)
};
- appIdentityService.getIdentity(root.getEnvironment(), function(err, appIdentity) {
+ appIdentityService.getIdentity(bitpayService.getEnvironment(), function(err, appIdentity) {
if (err) return cb(err);
root.getBitpayDebitCards(function(err, data) {
if (err) return cb(err);
var card = lodash.find(data, {id : cardId});
if (!card) return cb(_setError('Card not found'));
- $http(_post('/api/v2/' + card.token, json, appIdentity)).then(function(data) {
+ bitpayService.post('/api/v2/' + card.token, json, function(data) {
$log.info('BitPay TopUp: SUCCESS');
if(data.data.error) {
return cb(data.data.error);
@@ -196,7 +118,7 @@ angular.module('copayApp.services').factory('bitpayCardService', function($http,
};
root.getInvoice = function(id, cb) {
- $http(_get('/invoices/' + id)).then(function(data) {
+ bitpayService.get('/invoices/' + id, function(data) {
$log.info('BitPay Get Invoice: SUCCESS');
return cb(data.data.error, data.data.data);
}, function(data) {
@@ -205,7 +127,7 @@ angular.module('copayApp.services').factory('bitpayCardService', function($http,
};
root.getBitpayDebitCards = function(cb) {
- storageService.getBitpayDebitCards(BITPAY_CARD_NETWORK, function(err, data) {
+ storageService.getBitpayDebitCards(bitpayService.getEnvironment(), function(err, data) {
if (err) return cb(err);
if (lodash.isString(data)) {
data = JSON.parse(data);
@@ -217,14 +139,14 @@ angular.module('copayApp.services').factory('bitpayCardService', function($http,
root.setBitpayDebitCards = function(data, cb) {
data = JSON.stringify(data);
- storageService.setBitpayDebitCards(BITPAY_CARD_NETWORK, data, function(err) {
+ storageService.setBitpayDebitCards(bitpayService.getEnvironment(), data, function(err) {
if (err) return cb(err);
return cb();
});
};
root.getBitpayDebitCardsHistory = function(cardId, cb) {
- storageService.getBitpayDebitCardsHistory(BITPAY_CARD_NETWORK, function(err, data) {
+ storageService.getBitpayDebitCardsHistory(bitpayService.getEnvironment(), function(err, data) {
if (err) return cb(err);
if (lodash.isString(data)) {
data = JSON.parse(data);
@@ -236,7 +158,7 @@ angular.module('copayApp.services').factory('bitpayCardService', function($http,
};
root.setBitpayDebitCardsHistory = function(cardId, data, opts, cb) {
- storageService.getBitpayDebitCardsHistory(BITPAY_CARD_NETWORK, function(err, oldData) {
+ storageService.getBitpayDebitCardsHistory(bitpayService.getEnvironment(), function(err, oldData) {
if (lodash.isString(oldData)) {
oldData = JSON.parse(oldData);
}
@@ -250,19 +172,19 @@ angular.module('copayApp.services').factory('bitpayCardService', function($http,
}
inv = JSON.stringify(inv);
- storageService.setBitpayDebitCardsHistory(BITPAY_CARD_NETWORK, inv, function(err) {
+ storageService.setBitpayDebitCardsHistory(bitpayService.getEnvironment(), inv, function(err) {
return cb(err);
});
});
};
root.remove = function(card, cb) {
- storageService.removeBitpayDebitCard(BITPAY_CARD_NETWORK, card, function(err) {
+ storageService.removeBitpayDebitCard(bitpayService.getEnvironment(), card, function(err) {
if (err) {
$log.error('Error removing BitPay debit card: ' + err);
// Continue, try to remove/cleanup card history
}
- storageService.removeBitpayDebitCardHistory(BITPAY_CARD_NETWORK, card, function(err) {
+ storageService.removeBitpayDebitCardHistory(bitpayService.getEnvironment(), card, function(err) {
if (err) {
$log.error('Error removing BitPay debit card transaction history: ' + err);
return cb(err);
@@ -274,7 +196,7 @@ angular.module('copayApp.services').factory('bitpayCardService', function($http,
};
root.getRates = function(currency, cb) {
- $http(_get('/rates/' + currency)).then(function(data) {
+ bitpayService.get('/rates/' + currency, function(data) {
$log.info('BitPay Get Rates: SUCCESS');
return cb(data.data.error, data.data.data);
}, function(data) {
diff --git a/src/js/services/bitpayService.js b/src/js/services/bitpayService.js
new file mode 100644
index 000000000..12c3177e6
--- /dev/null
+++ b/src/js/services/bitpayService.js
@@ -0,0 +1,193 @@
+'use strict';
+
+angular.module('copayApp.services').factory('bitpayService', function($log, $http, platformInfo, appIdentityService, bitauthService, storageService, gettextCatalog, popupService) {
+ var root = {};
+
+ var NETWORK = 'livenet';
+ var BITPAY_API_URL = NETWORK == 'livenet' ? 'https://bitpay.com' : 'https://test.bitpay.com';
+
+ root.getEnvironment = function() {
+ return NETWORK;
+ };
+
+ /*
+ * Pair this app with the bitpay server using the specified pairing data.
+ * An app identity will be created if one does not already exist.
+ * Pairing data is provided by an input URI provided by the bitpay server.
+ *
+ * pairData - data needed to complete the pairing process
+ * {
+ * secret: shared pairing secret
+ * email: email address associated with bitpay account
+ * otp: two-factor one-time use password
+ * }
+ *
+ * pairingReason - text string to be embedded into popup message. If `null` then the reason
+ * message is not shown to the UI.
+ * "To {{reason}} you must pair this app with your BitPay account ({{email}})."
+ *
+ * cb - callback after completion
+ * callback(err, paired, apiContext)
+ *
+ * err - something unexpected happened which prevented the pairing
+ *
+ * paired - boolean indicating whether the pairing was compledted by the user
+ *
+ * apiContext - the context needed for making future api calls
+ * {
+ * token: api token for use in future calls
+ * pairData: the input pair data
+ * appIdentity: the identity of this app
+ * }
+ */
+ root.pair = function(pairData, pairingReason, cb) {
+ checkOtp(pairData, function(otp) {
+ pairData.otp = otp;
+ var deviceName = 'Unknown device';
+ if (platformInfo.isNW) {
+ deviceName = require('os').platform();
+ } else if (platformInfo.isCordova) {
+ deviceName = device.model;
+ }
+ var json = {
+ method: 'createToken',
+ params: {
+ secret: pairData.secret,
+ version: 2,
+ deviceName: deviceName,
+ code: pairData.otp
+ }
+ };
+ appIdentityService.getIdentity(root.getEnvironment(), function(err, appIdentity) {
+ if (err) return cb(err);
+ $http(_postAuth('/api/v2/', json, appIdentity)).then(function(data) {
+ if (data && data.data.error) return cb(data.data.error);
+ $log.info('BitPay service BitAuth create token: SUCCESS');
+ var title = gettextCatalog.getString('Add BitPay Account?');
+ var msgDetail = 'Add this BitPay account ({{email}})?';
+ if (pairingReason) {
+ msgDetail = 'To {{reason}} you must first add your BitPay account.
{{email}}';
+ }
+ var msg = gettextCatalog.getString(msgDetail, {
+ reason: pairingReason,
+ email: pairData.email
+ });
+ var ok = gettextCatalog.getString('Add Account');
+ var cancel = gettextCatalog.getString('Go back');
+ popupService.showConfirm(title, msg, ok, cancel, function(res) {
+ if (res) {
+ var acctData = {
+ token: data.data.data,
+ email: pairData.email
+ };
+ setBitpayAccount(acctData, function(err) {
+ if (err) return cb(err);
+ return cb(null, true, {
+ token: acctData.token,
+ pairData: pairData,
+ appIdentity: appIdentity
+ });
+ });
+ } else {
+ $log.info('User cancelled BitPay pairing process');
+ return cb(null, false);
+ }
+ });
+ }, function(data) {
+ return cb(_setError('BitPay service BitAuth create token: ERROR ', data));
+ });
+ });
+ });
+ };
+
+ root.get = function(endpoint, successCallback, errorCallback) {
+ $http(_get(endpoint)).then(function(data) {
+ successCallback(data);
+ }, function(data) {
+ errorCallback(data);
+ });
+ };
+
+ root.post = function(endpoint, json, successCallback, errorCallback) {
+ appIdentityService.getIdentity(NETWORK, function(err, appIdentity) {
+ if (err) return errorCallback(err);
+ $http(_post(endpoint, json, appIdentity)).then(function(data) {
+ successCallback(data);
+ }, function(data) {
+ errorCallback(data);
+ });
+ });
+ };
+
+ var checkOtp = function(pairData, cb) {
+ if (pairData.otp) {
+ var msg = gettextCatalog.getString('Enter Two Factor for your BitPay account');
+ popupService.showPrompt(null, msg, null, function(res) {
+ cb(res);
+ });
+ } else {
+ cb();
+ }
+ };
+
+ var setBitpayAccount = function(accountData, cb) {
+ var data = JSON.stringify(accountData);
+ storageService.setBitpayAccount(root.getEnvironment(), data, function(err) {
+ if (err) return cb(err);
+ return cb();
+ });
+ };
+
+ var _get = function(endpoint) {
+ return {
+ method: 'GET',
+ url: BITPAY_API_URL + endpoint,
+ headers: {
+ 'content-type': 'application/json'
+ }
+ };
+ };
+
+ var _post = function(endpoint, json, appIdentity) {
+ var dataToSign = BITPAY_API_URL + endpoint + JSON.stringify(json);
+ var signedData = bitauthService.sign(dataToSign, appIdentity.priv);
+
+ return {
+ method: 'POST',
+ url: BITPAY_API_URL + endpoint,
+ headers: {
+ 'content-type': 'application/json',
+ 'x-identity': appIdentity.pub,
+ 'x-signature': signedData
+ },
+ data: json
+ };
+ };
+
+ var _postAuth = function(endpoint, json, appIdentity) {
+ json['params'].signature = bitauthService.sign(JSON.stringify(json.params), appIdentity.priv);
+ json['params'].pubkey = appIdentity.pub;
+ json['params'] = JSON.stringify(json.params);
+
+ var ret = {
+ method: 'POST',
+ url: BITPAY_API_URL + endpoint,
+ headers: {
+ 'content-type': 'application/json'
+ },
+ data: json
+ };
+
+ $log.debug('post auth:' + JSON.stringify(ret));
+ return ret;
+ };
+
+ var _setError = function(msg, e) {
+ $log.error(msg);
+ var error = (e && e.data && e.data.error) ? e.data.error : msg;
+ return error;
+ };
+
+ return root;
+
+});
diff --git a/src/js/services/incomingData.js b/src/js/services/incomingData.js
index 7600dcb79..1d40a3032 100644
--- a/src/js/services/incomingData.js
+++ b/src/js/services/incomingData.js
@@ -130,20 +130,27 @@ angular.module('copayApp.services').factory('incomingData', function($log, $stat
url: data
});
- // BitPayCard Authentication
+ // BitPay Authentication
} else if (data && data.indexOf($window.appConfig.name + '://') === 0) {
var secret = getParameterByName('secret', data);
var email = getParameterByName('email', data);
var otp = getParameterByName('otp', data);
+ var reason = getParameterByName('r', data);
+
$state.go('tabs.home', {}, {
'reload': true,
'notify': $state.current.name == 'tabs.home' ? false : true
}).then(function() {
- $state.transitionTo('tabs.bitpayCardIntro', {
- secret: secret,
- email: email,
- otp: otp
- });
+ switch (reason) {
+ default:
+ case '0': /* For BitPay card binding */
+ $state.transitionTo('tabs.bitpayCardIntro', {
+ secret: secret,
+ email: email,
+ otp: otp
+ });
+ break;
+ }
});
return true;
diff --git a/src/js/services/storageService.js b/src/js/services/storageService.js
index bd1d41fd8..3643dc724 100644
--- a/src/js/services/storageService.js
+++ b/src/js/services/storageService.js
@@ -78,6 +78,14 @@ angular.module('copayApp.services')
//
// UPGRADING STORAGE
//
+ // TODO: prior to upgrading storage a backup of all storage should be captured and made available
+ // for export for recovery/debugging.
+ //
+ // Upgraders are executed in numerical order per the '##_' object key prefix. Each upgrader will run.
+ // Each upgrader should detect storage configuraton and fail-safe; no upgrader should damage the ability
+ // of another to function properly (in order). Each upgrader should upgrade storage incrementally; storage
+ // upgrade is not complete until all upgraders have run.
+ //
// 1. Write a function to upgrade the desired storage key(s). The function should have the protocol:
//
// _upgrade_x(key, network, cb), where:
@@ -91,12 +99,15 @@ angular.module('copayApp.services')
// when a storage key is involved in multiple upgraders as well as predicte the order in which upgrades
// occur the `_upgrader` object key should be prefixed with '##_' (e.g., '01_') to create a unique and
// sortable name. This format is interpreted by the _upgrade() function.
- //
- // Upgraders are executed in numerical order per the '##_' object key prefix.
+ //
+ // 3. Any dependency functions called by upgraders should be copied/factored out and remain unchanged as
+ // long as the upgrader remains in effect. By convention the dependency function is prefixed by '##_' to
+ // match the upgrader key.
//
var _upgraders = {
'00_bitpayDebitCards' : _upgrade_bitpayDebitCards, // 2016-11: Upgrade bitpayDebitCards-x to bitpayAccounts-x
- '01_bitpayCardCredentials' : _upgrade_bitpayCardCredentials // 2016-11: Upgrade bitpayCardCredentials-x to appIdentity-x
+ '01_bitpayCardCredentials' : _upgrade_bitpayCardCredentials, // 2016-11: Upgrade bitpayCardCredentials-x to appIdentity-x
+ '02_bitpayAccounts' : _upgrade_bitpayAccounts // 2016-12: Reorganize the object
};
function _upgrade_bitpayDebitCards(key, network, cb) {
@@ -109,7 +120,7 @@ angular.module('copayApp.services')
data = JSON.parse(data);
}
data = data || {};
- root.setBitpayDebitCards(network, data, function(err) {
+ _00_setBitpayDebitCards(network, data, function(err) {
if (err) return cb(err);
storage.remove(key, function() {
cb(null, 'replaced with \'bitpayAccounts\'');
@@ -131,7 +142,7 @@ angular.module('copayApp.services')
data = JSON.parse(data);
}
data = data || {};
- root.setAppIdentity(network, data, function(err) {
+ _01_setAppIdentity(network, data, function(err) {
if (err) return cb(err);
storage.remove(key, function() {
cb(null, 'replaced with \'appIdentity\'');
@@ -142,6 +153,105 @@ angular.module('copayApp.services')
}
});
};
+
+ function _upgrade_bitpayAccounts(key, network, cb) {
+ key += '-' + network;
+ storage.get(key, function(err, data) {
+ if (err) return cb(err);
+ if (lodash.isString(data)) {
+ data = JSON.parse(data);
+ }
+ data = data || {};
+ var upgraded = '';
+ Object.keys(data).forEach(function(key) {
+ // Keys are account emails
+ if (!data[key]['bitpayApi-' + network].token) {
+ // Needs upgrade
+ upgraded += ' ' + key;
+ var acctData = {
+ token: data[key]['bitpayDebitCards-' + network].token,
+ email: key
+ };
+ _02_setBitpayAccount(network, data, function(err) {
+ if (err) return cb(err);
+
+ _02_setBitpayDebitCards(network, data[key]['bitpayDebitCards-' + network], function(err) {
+ if (err) return cb(err);
+ });
+ });
+ }
+ });
+ if (upgraded.length > 0) {
+ cb(null, 'upgraded \'bitpayAccounts\':' + upgraded);
+ } else {
+ cb();
+ }
+ });
+ };
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // UPGRADER DEPENDENCIES
+ // These functions remain as long as the upgrader remains in effect.
+ //
+ var _00_setBitpayDebitCards = function(network, data, cb) {
+ if (lodash.isString(data)) {
+ data = JSON.parse(data);
+ }
+ data = data || {};
+ if (lodash.isEmpty(data) || !data.email) return cb('No card(s) to set');
+ storage.get('bitpayAccounts-' + network, function(err, bitpayAccounts) {
+ if (err) return cb(err);
+ if (lodash.isString(bitpayAccounts)) {
+ bitpayAccounts = JSON.parse(bitpayAccounts);
+ }
+ bitpayAccounts = bitpayAccounts || {};
+ bitpayAccounts[data.email] = bitpayAccounts[data.email] || {};
+ bitpayAccounts[data.email]['bitpayDebitCards-' + network] = data;
+ storage.set('bitpayAccounts-' + network, JSON.stringify(bitpayAccounts), cb);
+ });
+ };
+
+ var _01_setAppIdentity = function(network, data, cb) {
+ storage.set('appIdentity-' + network, data, cb);
+ };
+
+ var _02_setBitpayAccount = function(network, data, cb) {
+ if (lodash.isString(data)) {
+ data = JSON.parse(data);
+ }
+ data = data || {};
+ if (lodash.isEmpty(data) || !data.email) return cb('No account to set');
+ storage.get('bitpayAccounts-' + network, function(err, bitpayAccounts) {
+ if (err) return cb(err);
+ if (lodash.isString(bitpayAccounts)) {
+ bitpayAccounts = JSON.parse(bitpayAccounts);
+ }
+ bitpayAccounts = bitpayAccounts || {};
+ bitpayAccounts[data.email] = bitpayAccounts[data.email] || {};
+ bitpayAccounts[data.email]['bitpayApi-' + network] = bitpayAccounts[data.email]['bitpayApi-' + network] || {};
+ bitpayAccounts[data.email]['bitpayApi-' + network].token = data.token;
+ storage.set('bitpayAccounts-' + network, JSON.stringify(bitpayAccounts), cb);
+ });
+ };
+
+ var _02_setBitpayDebitCards = function(network, data, cb) {
+ if (lodash.isString(data)) {
+ data = JSON.parse(data);
+ }
+ data = data || {};
+ if (lodash.isEmpty(data) || !data.email) return cb('No card(s) to set');
+ storage.get('bitpayAccounts-' + network, function(err, bitpayAccounts) {
+ if (err) return cb(err);
+ if (lodash.isString(bitpayAccounts)) {
+ bitpayAccounts = JSON.parse(bitpayAccounts);
+ }
+ bitpayAccounts = bitpayAccounts || {};
+ bitpayAccounts[data.email] = bitpayAccounts[data.email] || {};
+ bitpayAccounts[data.email]['bitpayDebitCards-' + network] = data.cards;
+ storage.set('bitpayAccounts-' + network, JSON.stringify(bitpayAccounts), cb);
+ });
+ };
//
////////////////////////////////////////////////////////////////////////////
@@ -467,6 +577,16 @@ angular.module('copayApp.services')
});
};
+ // data: {
+ // cards: [
+ // eid: card id
+ // id: card id
+ // lastFourDigits: card number
+ // token: card token
+ // ]
+ // email: account email
+ // token: account token
+ // }
root.setBitpayDebitCards = function(network, data, cb) {
if (lodash.isString(data)) {
data = JSON.parse(data);
@@ -480,11 +600,19 @@ angular.module('copayApp.services')
}
bitpayAccounts = bitpayAccounts || {};
bitpayAccounts[data.email] = bitpayAccounts[data.email] || {};
- bitpayAccounts[data.email]['bitpayDebitCards-' + network] = data;
+ bitpayAccounts[data.email]['bitpayDebitCards-' + network] = data.cards;
storage.set('bitpayAccounts-' + network, JSON.stringify(bitpayAccounts), cb);
});
};
+ // cb(err, cards)
+ // cards: [
+ // eid: card id
+ // id: card id
+ // lastFourDigits: card number
+ // token: card token
+ // email: account email
+ // ]
root.getBitpayDebitCards = function(network, cb) {
storage.get('bitpayAccounts-' + network, function(err, bitpayAccounts) {
if (lodash.isString(bitpayAccounts)) {
@@ -494,7 +622,7 @@ angular.module('copayApp.services')
var cards = [];
Object.keys(bitpayAccounts).forEach(function(email) {
// For the UI, add the account email to the card object.
- var acctCards = bitpayAccounts[email]['bitpayDebitCards-' + network].cards;
+ var acctCards = bitpayAccounts[email]['bitpayDebitCards-' + network] || [];
for (var i = 0; i < acctCards.length; i++) {
acctCards[i].email = email;
}
@@ -504,6 +632,12 @@ angular.module('copayApp.services')
});
};
+ // card: {
+ // eid: card id
+ // id: card id
+ // lastFourDigits: card number
+ // token: card token
+ // }
root.removeBitpayDebitCard = function(network, card, cb) {
if (lodash.isString(card)) {
card = JSON.parse(card);
@@ -516,12 +650,14 @@ angular.module('copayApp.services')
bitpayAccounts = JSON.parse(bitpayAccounts);
}
bitpayAccounts = bitpayAccounts || {};
- Object.keys(bitpayAccounts).forEach(function(userId) {
- var data = bitpayAccounts[userId]['bitpayDebitCards-' + network];
- var newCards = lodash.reject(data.cards, {
+ Object.keys(bitpayAccounts).forEach(function(email) {
+ var data = bitpayAccounts[email]['bitpayDebitCards-' + network];
+ var newCards = lodash.reject(data, {
'eid': card.eid
});
+ data = {};
data.cards = newCards;
+ data.email = email;
root.setBitpayDebitCards(network, data, function(err) {
if (err) cb(err);
// If there are no more cards in storage then re-enable the next step entry.
@@ -538,6 +674,59 @@ angular.module('copayApp.services')
});
};
+ // data: {
+ // email: account email
+ // token: account token
+ // }
+ root.setBitpayAccount = function(network, data, cb) {
+ if (lodash.isString(data)) {
+ data = JSON.parse(data);
+ }
+ data = data || {};
+ if (lodash.isEmpty(data) || !data.email) return cb('No account to set');
+ storage.get('bitpayAccounts-' + network, function(err, bitpayAccounts) {
+ if (err) return cb(err);
+ if (lodash.isString(bitpayAccounts)) {
+ bitpayAccounts = JSON.parse(bitpayAccounts);
+ }
+ bitpayAccounts = bitpayAccounts || {};
+ bitpayAccounts[data.email] = bitpayAccounts[data.email] || {};
+ bitpayAccounts[data.email]['bitpayApi-' + network] = bitpayAccounts[data.email]['bitpayApi-' + network] || {};
+ bitpayAccounts[data.email]['bitpayApi-' + network].token = data.token;
+ storage.set('bitpayAccounts-' + network, JSON.stringify(bitpayAccounts), cb);
+ });
+ };
+
+ // cb(err, accounts)
+ // accounts: {
+ // email_1: {
+ // bitpayApi-: {
+ // token: account token
+ // }
+ // bitpayDebitCards-: {
+ //
+ // }
+ // }
+ // ...
+ // email_n: {
+ // bitpayApi-: {
+ // token: account token
+ // }
+ // bitpayDebitCards-: {
+ //
+ // }
+ // }
+ // }
+ root.getBitpayAccounts = function(network, cb) {
+ storage.get('bitpayAccounts-' + network, function(err, bitpayAccounts) {
+ if (err) return cb(err);
+ if (lodash.isString(bitpayAccounts)) {
+ bitpayAccounts = JSON.parse(bitpayAccounts);
+ }
+ cb(err, bitpayAccounts);
+ });
+ };
+
root.setAppIdentity = function(network, data, cb) {
storage.set('appIdentity-' + network, data, cb);
};