mirror of https://github.com/BTCPrivate/copay.git
Merge pull request #1850 from matiaspando/feature/backupFlag
Added the flag backupNeeded
This commit is contained in:
commit
3829d6692f
|
@ -1244,6 +1244,21 @@ label.postfix, span.postfix {
|
|||
height: 80px;
|
||||
}
|
||||
|
||||
.need-backup {
|
||||
background: #C0392A;
|
||||
-moz-box-shadow: 1px 1px 0px 0px #A02F23;
|
||||
box-shadow: 1px 1px 0px 0px #A02F23;
|
||||
position: absolute;
|
||||
top: 22px;
|
||||
left: 0px;
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
border-radius: 100%;
|
||||
font-size: 9px;
|
||||
padding-top: 2px;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
a:hover .photo-container {
|
||||
background: #34495E;
|
||||
color: #fff;
|
||||
|
|
|
@ -18,71 +18,72 @@ angular.module('copayApp.controllers').controller('ImportController',
|
|||
$scope.$digest();
|
||||
}
|
||||
|
||||
$scope.getFile = function() {
|
||||
// If we use onloadend, we need to check the readyState.
|
||||
reader.onloadend = function(evt) {
|
||||
if (evt.target.readyState == FileReader.DONE) { // DONE == 2
|
||||
var encryptedObj = evt.target.result;
|
||||
|
||||
$scope.getFile = function() {
|
||||
// If we use onloadend, we need to check the readyState.
|
||||
reader.onloadend = function(evt) {
|
||||
if (evt.target.readyState == FileReader.DONE) { // DONE == 2
|
||||
var encryptedObj = evt.target.result;
|
||||
updateStatus('Importing wallet - Procesing backup...');
|
||||
identityService.importWallet(encryptedObj, $scope.password, {}, function(err) {
|
||||
if (err) {
|
||||
$scope.loading = false;
|
||||
$scope.error = 'Could not read wallet. Please check your password';
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
$scope.import = function(form) {
|
||||
$scope.loading = true;
|
||||
|
||||
if (form.$invalid) {
|
||||
$scope.loading = false;
|
||||
$scope.error = 'There is an error in the form';
|
||||
return;
|
||||
}
|
||||
|
||||
var backupFile = $scope.file;
|
||||
var backupText = form.backupText.$modelValue;
|
||||
var backupOldWallet = form.backupOldWallet.$modelValue;
|
||||
var password = form.password.$modelValue;
|
||||
|
||||
if (backupOldWallet) {
|
||||
backupText = backupOldWallet.value;
|
||||
}
|
||||
|
||||
if (!backupFile && !backupText) {
|
||||
$scope.loading = false;
|
||||
$scope.error = 'Please, select your backup file';
|
||||
return;
|
||||
}
|
||||
|
||||
$scope.importOpts = {};
|
||||
|
||||
var skipFields = [];
|
||||
|
||||
if ($scope.skipPublicKeyRing)
|
||||
skipFields.push('publicKeyRing');
|
||||
|
||||
if ($scope.skipTxProposals)
|
||||
skipFields.push('txProposals');
|
||||
|
||||
if (skipFields)
|
||||
$scope.importOpts.skipFields = skipFields;
|
||||
|
||||
|
||||
if (backupFile) {
|
||||
reader.readAsBinaryString(backupFile);
|
||||
} else {
|
||||
updateStatus('Importing wallet - Procesing backup...');
|
||||
identityService.importWallet(encryptedObj, $scope.password, {}, function(err){
|
||||
identityService.importWallet(encryptedObj, $scope.password, $scope.importOpts, function(err) {
|
||||
if (err) {
|
||||
$scope.loading = false;
|
||||
$scope.error = 'Could not read wallet. Please check your password';
|
||||
}
|
||||
copay.Compatibility.deleteOldWallet(backupOldWallet);
|
||||
});
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
$scope.import = function(form) {
|
||||
$scope.loading = true;
|
||||
|
||||
if (form.$invalid) {
|
||||
$scope.loading = false;
|
||||
$scope.error = 'There is an error in the form';
|
||||
return;
|
||||
}
|
||||
|
||||
var backupFile = $scope.file;
|
||||
var backupText = form.backupText.$modelValue;
|
||||
var backupOldWallet = form.backupOldWallet.$modelValue;
|
||||
var password = form.password.$modelValue;
|
||||
|
||||
if (backupOldWallet) {
|
||||
backupText = backupOldWallet.value;
|
||||
}
|
||||
|
||||
if (!backupFile && !backupText) {
|
||||
$scope.loading = false;
|
||||
$scope.error = 'Please, select your backup file';
|
||||
return;
|
||||
}
|
||||
|
||||
$scope.importOpts = {};
|
||||
|
||||
var skipFields = [];
|
||||
|
||||
if ($scope.skipPublicKeyRing)
|
||||
skipFields.push('publicKeyRing');
|
||||
|
||||
if ($scope.skipTxProposals)
|
||||
skipFields.push('txProposals');
|
||||
|
||||
if (skipFields)
|
||||
$scope.importOpts.skipFields = skipFields;
|
||||
|
||||
|
||||
if (backupFile) {
|
||||
reader.readAsBinaryString(backupFile);
|
||||
} else {
|
||||
updateStatus('Importing wallet - Procesing backup...');
|
||||
identityService.importWallet(encryptedObj, $scope.password, $scope.importOpts, function(err){
|
||||
if (err) {
|
||||
$scope.loading = false;
|
||||
$scope.error = 'Could not read wallet. Please check your password';
|
||||
}
|
||||
copay.Compatibility.deleteOldWallet(backupOldWallet);
|
||||
});
|
||||
}
|
||||
};
|
||||
});
|
||||
});
|
||||
|
|
|
@ -14,7 +14,7 @@ angular.module('copayApp.controllers').controller('ProfileController', function(
|
|||
$scope.backupProfilePlainText = backupService.profileEncrypted($rootScope.iden);
|
||||
$scope.hideViewProfileBackup = true;
|
||||
};
|
||||
|
||||
|
||||
$scope.deleteWallet = function(w) {
|
||||
if (!w) return;
|
||||
identityService.deleteWallet(w, function(err) {
|
||||
|
@ -28,8 +28,8 @@ angular.module('copayApp.controllers').controller('ProfileController', function(
|
|||
|
||||
$scope.init = function() {
|
||||
if ($rootScope.quotaPerItem) {
|
||||
$scope.perItem = $filter('noFractionNumber')($rootScope.quotaPerItem/1000,1);
|
||||
$scope.nrWallets =parseInt($rootScope.quotaItems) - 1;
|
||||
$scope.perItem = $filter('noFractionNumber')($rootScope.quotaPerItem / 1000, 1);
|
||||
$scope.nrWallets = parseInt($rootScope.quotaItems) - 1;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -37,13 +37,13 @@ angular.module('copayApp.controllers').controller('ProfileController', function(
|
|||
if (!$rootScope.iden) return;
|
||||
|
||||
var wallets = $rootScope.iden.listWallets();
|
||||
var max =$rootScope.quotaPerItem;
|
||||
var max = $rootScope.quotaPerItem;
|
||||
|
||||
_.each(wallets, function(w) {
|
||||
var bits = w.sizes().total;
|
||||
w.kb = $filter('noFractionNumber')(bits/1000, 1);
|
||||
w.kb = $filter('noFractionNumber')(bits / 1000, 1);
|
||||
if (max) {
|
||||
w.usage = $filter('noFractionNumber')(bits/max * 100, 0);
|
||||
w.usage = $filter('noFractionNumber')(bits / max * 100, 0);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -73,15 +73,15 @@ angular.module('copayApp.controllers').controller('ProfileController', function(
|
|||
});
|
||||
};
|
||||
|
||||
$scope.deleteProfile = function () {
|
||||
identityService.deleteProfile(function (err, res) {
|
||||
$scope.deleteProfile = function() {
|
||||
identityService.deleteProfile(function(err, res) {
|
||||
if (err) {
|
||||
log.warn(err);
|
||||
notification.error('Error', 'Could not delete profile');
|
||||
return;
|
||||
}
|
||||
$location.path('/');
|
||||
setTimeout(function () {
|
||||
$location.path('/');
|
||||
setTimeout(function() {
|
||||
notification.error('Success', 'Profile successfully deleted');
|
||||
}, 1);
|
||||
});
|
||||
|
|
|
@ -62,6 +62,8 @@ function Identity(opts) {
|
|||
this.walletIds = opts.walletIds || {};
|
||||
this.wallets = opts.wallets || {};
|
||||
this.focusedTimestamps = opts.focusedTimestamps || {};
|
||||
this.backupNeeded = opts.backupNeeded || false;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
@ -91,7 +93,9 @@ Identity.prototype.getName = function() {
|
|||
* @return {undefined}
|
||||
*/
|
||||
Identity.create = function(opts, cb) {
|
||||
opts = _.extend({}, opts);
|
||||
opts = _.extend({
|
||||
backupNeeded: true
|
||||
}, opts);
|
||||
|
||||
var iden = new Identity(opts);
|
||||
iden.store(_.extend(opts, {
|
||||
|
@ -265,21 +269,36 @@ Identity.prototype.toObj = function() {
|
|||
return _.extend({
|
||||
walletIds: _.isEmpty(this.wallets) ? this.walletsIds : _.keys(this.wallets),
|
||||
},
|
||||
_.pick(this, 'version', 'fullName', 'password', 'email', 'focusedTimestamps'));
|
||||
_.pick(this, 'version', 'fullName', 'password', 'email', 'backupNeeded', 'focusedTimestamps'));
|
||||
};
|
||||
|
||||
Identity.prototype.exportEncryptedWithWalletInfo = function(opts) {
|
||||
var crypto = opts.cryptoUtil || cryptoUtil;
|
||||
|
||||
return crypto.encrypt(this.password, this.exportWithWalletInfo(opts));
|
||||
};
|
||||
|
||||
Identity.prototype.setBackupNeeded = function() {
|
||||
this.backupNeeded = true;
|
||||
this.store({
|
||||
noWallets: true
|
||||
}, function() {});
|
||||
}
|
||||
|
||||
Identity.prototype.setBackupDone = function() {
|
||||
this.backupNeeded = false;
|
||||
this.store({
|
||||
noWallets: true
|
||||
}, function() {});
|
||||
}
|
||||
|
||||
Identity.prototype.exportWithWalletInfo = function(opts) {
|
||||
return _.extend({
|
||||
wallets: _.map(this.wallets, function(wallet) {
|
||||
return wallet.toObj();
|
||||
})
|
||||
},
|
||||
_.pick(this, 'version', 'fullName', 'password', 'email')
|
||||
_.pick(this, 'version', 'fullName', 'password', 'email', 'backupNeeded')
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -288,15 +307,15 @@ Identity.prototype.exportWithWalletInfo = function(opts) {
|
|||
* @param {Function} cb
|
||||
*/
|
||||
Identity.prototype.store = function(opts, cb) {
|
||||
log.debug('Storing profile');
|
||||
|
||||
var self = this;
|
||||
opts = opts || {};
|
||||
|
||||
var storeFunction = opts.failIfExists ? self.storage.createItem : self.storage.setItem;
|
||||
|
||||
storeFunction.call(self.storage, this.getId(), this.toObj(), function(err) {
|
||||
if (err) return cb(err);
|
||||
if (err) {
|
||||
return cb(err);
|
||||
}
|
||||
|
||||
if (opts.noWallets)
|
||||
return cb();
|
||||
|
@ -323,9 +342,9 @@ Identity.prototype.remove = function(opts, cb) {
|
|||
if (err) return cb(err);
|
||||
cb();
|
||||
});
|
||||
}, function (err) {
|
||||
}, function(err) {
|
||||
if (err) return cb(err);
|
||||
|
||||
|
||||
self.storage.removeItem(self.getId(), function(err) {
|
||||
if (err) return cb(err);
|
||||
self.emitAndKeepAlive('closed');
|
||||
|
@ -552,13 +571,16 @@ Identity.prototype.createWallet = function(opts, cb) {
|
|||
|
||||
var self = this;
|
||||
|
||||
|
||||
var w = new walletClass(opts);
|
||||
self.bindWallet(w);
|
||||
self.updateFocusedTimestamp(w.getId());
|
||||
self.storeWallet(w, function(err) {
|
||||
if (err) return cb(err);
|
||||
|
||||
self.backupNeeded = true;
|
||||
self.store({
|
||||
noWallets: true
|
||||
noWallets: true,
|
||||
}, function(err) {
|
||||
return cb(err, w);
|
||||
});
|
||||
|
|
|
@ -38,6 +38,7 @@ BackupService.prototype.profileEncrypted = function(iden) {
|
|||
|
||||
BackupService.prototype.profileDownload = function(iden) {
|
||||
var ew = this.profileEncrypted(iden);
|
||||
iden.setBackupDone();
|
||||
var name = iden.fullName;
|
||||
var filename = name + '-profile.json';
|
||||
this._download(ew, name, filename)
|
||||
|
|
|
@ -48,6 +48,7 @@ angular.module('copayApp.services')
|
|||
passphraseConfig: config.passphraseConfig,
|
||||
failIfExists: true,
|
||||
}, function(err, iden) {
|
||||
|
||||
if (err) return cb(err);
|
||||
preconditions.checkState(iden);
|
||||
root.bind(iden);
|
||||
|
@ -68,19 +69,19 @@ angular.module('copayApp.services')
|
|||
};
|
||||
|
||||
root.setServerStatus = function(headers) {
|
||||
if (!headers)
|
||||
if (!headers)
|
||||
return;
|
||||
|
||||
if (headers['X-Email-Needs-Validation'])
|
||||
$rootScope.needsEmailConfirmation = true;
|
||||
if (headers['X-Email-Needs-Validation'])
|
||||
$rootScope.needsEmailConfirmation = true;
|
||||
else
|
||||
$rootScope.needsEmailConfirmation = null;
|
||||
$rootScope.needsEmailConfirmation = null;
|
||||
|
||||
if (headers['X-Quota-Per-Item'])
|
||||
$rootScope.quotaPerItem = parseInt(headers['X-Quota-Per-Item']);
|
||||
if (headers['X-Quota-Per-Item'])
|
||||
$rootScope.quotaPerItem = parseInt(headers['X-Quota-Per-Item']);
|
||||
|
||||
if (headers['X-Quota-Items-Limit'])
|
||||
$rootScope.quotaItems = parseInt(headers['X-Quota-Items-Limit']);
|
||||
if (headers['X-Quota-Items-Limit'])
|
||||
$rootScope.quotaItems = parseInt(headers['X-Quota-Items-Limit']);
|
||||
};
|
||||
|
||||
root.open = function(email, password, cb) {
|
||||
|
@ -102,7 +103,7 @@ angular.module('copayApp.services')
|
|||
});
|
||||
};
|
||||
|
||||
root.deleteProfile = function (cb) {
|
||||
root.deleteProfile = function(cb) {
|
||||
$rootScope.iden.remove(null, cb);
|
||||
};
|
||||
|
||||
|
|
|
@ -111,7 +111,14 @@ describe('Identity model', function() {
|
|||
params: params
|
||||
};
|
||||
};
|
||||
|
||||
var orig;
|
||||
beforeEach(function() {
|
||||
orig = Identity.prototype.store;
|
||||
sinon.stub(Identity.prototype, 'store').yields(null);
|
||||
});
|
||||
afterEach(function() {
|
||||
Identity.prototype.store = orig;
|
||||
});
|
||||
describe('new Identity()', function() {
|
||||
it('returns an identity', function() {
|
||||
var iden = new Identity(getDefaultParams());
|
||||
|
@ -124,7 +131,6 @@ describe('Identity model', function() {
|
|||
it('should create and store identity', function() {
|
||||
var args = createIdentity();
|
||||
args.blockchain.on = sinon.stub();
|
||||
sinon.stub(Identity.prototype, 'store').yields(null);
|
||||
Identity.create(args.params, function(err, iden) {
|
||||
should.not.exist(err);
|
||||
should.exist(iden);
|
||||
|
@ -240,7 +246,6 @@ describe('Identity model', function() {
|
|||
args = createIdentity();
|
||||
args.params.noWallets = true;
|
||||
var old = Identity.prototype.createWallet;
|
||||
sinon.stub(Identity.prototype, 'store').yields(null);
|
||||
Identity.create(args.params, function(err, res) {
|
||||
iden = res;
|
||||
});
|
||||
|
@ -297,7 +302,6 @@ describe('Identity model', function() {
|
|||
args.storage.getItem.onFirstCall().callsArgWith(1, null, '{"wallet": "fakeData"}');
|
||||
var backup = Wallet.fromUntrustedObj;
|
||||
args.params.noWallets = true;
|
||||
sinon.stub(Identity.prototype, 'store').yields(null);
|
||||
sinon.stub().returns(args.wallet);
|
||||
|
||||
var opts = {
|
||||
|
@ -390,8 +394,6 @@ describe('Identity model', function() {
|
|||
beforeEach(function() {
|
||||
args = createIdentity();
|
||||
args.params.Async = net = sinon.stub();
|
||||
|
||||
sinon.stub(Identity.prototype, 'store').yields(null);
|
||||
net.cleanUp = sinon.spy();
|
||||
net.on = sinon.stub();
|
||||
net.start = sinon.spy();
|
||||
|
|
|
@ -76,6 +76,7 @@ describe("Angular services", function() {
|
|||
a[Waddr] = 200;
|
||||
w.getBalance = sinon.stub().yields(null, 100000001, a, 90000002, 5);
|
||||
|
||||
|
||||
//retuns values in DEFAULT UNIT(bits)
|
||||
balanceService.update(w, function() {
|
||||
var b = w.balanceInfo;
|
||||
|
@ -90,7 +91,7 @@ describe("Angular services", function() {
|
|||
expect(b.balanceByAddr[Waddr]).to.equal(2);
|
||||
expect(b.safeUnspentCount).to.equal(5);
|
||||
expect(b.topAmount).to.equal(899800.02);
|
||||
},false);
|
||||
}, false);
|
||||
}));
|
||||
|
||||
});
|
||||
|
|
|
@ -16,10 +16,13 @@
|
|||
|
||||
<div class="menu" ng-mouseover="hoverIn()" ng-mouseleave="hoverOut()"
|
||||
ng-click="hoverMenu = !hoverMenu">
|
||||
<a class="dropdown ellipsis text-gray" ng-class="{'hover': hoverMenu}">
|
||||
<a class="dropdown ellipsis text-gray pr" ng-class="{'hover': hoverMenu}">
|
||||
<div class="photo-container">
|
||||
<img gravatar-src="'{{username}}'" gravatar-size="35">
|
||||
</div>
|
||||
<span class="need-backup" ng-if="!$root.needsEmailConfirmation && $root.iden.backupNeeded">
|
||||
<i class="fi-alert vm"></i>
|
||||
</span>
|
||||
<span class="m15t">{{username}} </span>
|
||||
<i class="icon-arrow-down2 size-16 vm"></i>
|
||||
</a>
|
||||
|
@ -33,7 +36,8 @@
|
|||
<i class="icon-download size-18 m10r"></i> {{'Import wallet'|translate}}</a></li>
|
||||
<li class="divider"></li>
|
||||
<li><a href="#!/profile" title="Profile">
|
||||
<i class="icon-person size-18 m10r"></i> {{'Profile'|translate}}</a></li>
|
||||
<i class="icon-person size-18 m10r"></i> {{'Profile'|translate}}<span class="size-10 text-warning" ng-if="!$root.needsEmailConfirmation && $root.iden.backupNeeded"> [ Needs Backup ]</span></a>
|
||||
</li>
|
||||
<li><a href="#!/" title="Close" ng-click="signout()">
|
||||
<i class="icon-power size-18 m10r"></i> {{'Close'|translate}}</a></li>
|
||||
</ul>
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
</a>
|
||||
</div>
|
||||
<div class="large-7 medium-7 columns">
|
||||
<h2>Backup Profile</h2>
|
||||
<h2>Profile <span class="size-12 text-warning" ng-if="$root.iden.backupNeeded"> [ Needs Backup ]</span></h2>
|
||||
<p translate class="text-gray">It's important to backup your profile so that you can recover it in case of disaster. The backup will include all your profile's wallets</p>
|
||||
</div>
|
||||
<div class="large-3 medium-3 columns">
|
||||
|
|
Loading…
Reference in New Issue