Merge pull request #1850 from matiaspando/feature/backupFlag
Added the flag backupNeeded
This commit is contained in:
commit
3829d6692f
10 changed files with 139 additions and 92 deletions
|
|
@ -1244,6 +1244,21 @@ label.postfix, span.postfix {
|
||||||
height: 80px;
|
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 {
|
a:hover .photo-container {
|
||||||
background: #34495E;
|
background: #34495E;
|
||||||
color: #fff;
|
color: #fff;
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@ angular.module('copayApp.controllers').controller('ImportController',
|
||||||
$scope.$digest();
|
$scope.$digest();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
$scope.getFile = function() {
|
$scope.getFile = function() {
|
||||||
// If we use onloadend, we need to check the readyState.
|
// If we use onloadend, we need to check the readyState.
|
||||||
reader.onloadend = function(evt) {
|
reader.onloadend = function(evt) {
|
||||||
|
|
@ -31,7 +32,7 @@ angular.module('copayApp.controllers').controller('ImportController',
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.import = function(form) {
|
$scope.import = function(form) {
|
||||||
|
|
|
||||||
|
|
@ -62,6 +62,8 @@ function Identity(opts) {
|
||||||
this.walletIds = opts.walletIds || {};
|
this.walletIds = opts.walletIds || {};
|
||||||
this.wallets = opts.wallets || {};
|
this.wallets = opts.wallets || {};
|
||||||
this.focusedTimestamps = opts.focusedTimestamps || {};
|
this.focusedTimestamps = opts.focusedTimestamps || {};
|
||||||
|
this.backupNeeded = opts.backupNeeded || false;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -91,7 +93,9 @@ Identity.prototype.getName = function() {
|
||||||
* @return {undefined}
|
* @return {undefined}
|
||||||
*/
|
*/
|
||||||
Identity.create = function(opts, cb) {
|
Identity.create = function(opts, cb) {
|
||||||
opts = _.extend({}, opts);
|
opts = _.extend({
|
||||||
|
backupNeeded: true
|
||||||
|
}, opts);
|
||||||
|
|
||||||
var iden = new Identity(opts);
|
var iden = new Identity(opts);
|
||||||
iden.store(_.extend(opts, {
|
iden.store(_.extend(opts, {
|
||||||
|
|
@ -265,21 +269,36 @@ Identity.prototype.toObj = function() {
|
||||||
return _.extend({
|
return _.extend({
|
||||||
walletIds: _.isEmpty(this.wallets) ? this.walletsIds : _.keys(this.wallets),
|
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) {
|
Identity.prototype.exportEncryptedWithWalletInfo = function(opts) {
|
||||||
var crypto = opts.cryptoUtil || cryptoUtil;
|
var crypto = opts.cryptoUtil || cryptoUtil;
|
||||||
|
|
||||||
return crypto.encrypt(this.password, this.exportWithWalletInfo(opts));
|
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) {
|
Identity.prototype.exportWithWalletInfo = function(opts) {
|
||||||
return _.extend({
|
return _.extend({
|
||||||
wallets: _.map(this.wallets, function(wallet) {
|
wallets: _.map(this.wallets, function(wallet) {
|
||||||
return wallet.toObj();
|
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
|
* @param {Function} cb
|
||||||
*/
|
*/
|
||||||
Identity.prototype.store = function(opts, cb) {
|
Identity.prototype.store = function(opts, cb) {
|
||||||
log.debug('Storing profile');
|
|
||||||
|
|
||||||
var self = this;
|
var self = this;
|
||||||
opts = opts || {};
|
opts = opts || {};
|
||||||
|
|
||||||
var storeFunction = opts.failIfExists ? self.storage.createItem : self.storage.setItem;
|
var storeFunction = opts.failIfExists ? self.storage.createItem : self.storage.setItem;
|
||||||
|
|
||||||
storeFunction.call(self.storage, this.getId(), this.toObj(), function(err) {
|
storeFunction.call(self.storage, this.getId(), this.toObj(), function(err) {
|
||||||
if (err) return cb(err);
|
if (err) {
|
||||||
|
return cb(err);
|
||||||
|
}
|
||||||
|
|
||||||
if (opts.noWallets)
|
if (opts.noWallets)
|
||||||
return cb();
|
return cb();
|
||||||
|
|
@ -552,13 +571,16 @@ Identity.prototype.createWallet = function(opts, cb) {
|
||||||
|
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
|
|
||||||
var w = new walletClass(opts);
|
var w = new walletClass(opts);
|
||||||
self.bindWallet(w);
|
self.bindWallet(w);
|
||||||
self.updateFocusedTimestamp(w.getId());
|
self.updateFocusedTimestamp(w.getId());
|
||||||
self.storeWallet(w, function(err) {
|
self.storeWallet(w, function(err) {
|
||||||
if (err) return cb(err);
|
if (err) return cb(err);
|
||||||
|
|
||||||
|
self.backupNeeded = true;
|
||||||
self.store({
|
self.store({
|
||||||
noWallets: true
|
noWallets: true,
|
||||||
}, function(err) {
|
}, function(err) {
|
||||||
return cb(err, w);
|
return cb(err, w);
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,7 @@ BackupService.prototype.profileEncrypted = function(iden) {
|
||||||
|
|
||||||
BackupService.prototype.profileDownload = function(iden) {
|
BackupService.prototype.profileDownload = function(iden) {
|
||||||
var ew = this.profileEncrypted(iden);
|
var ew = this.profileEncrypted(iden);
|
||||||
|
iden.setBackupDone();
|
||||||
var name = iden.fullName;
|
var name = iden.fullName;
|
||||||
var filename = name + '-profile.json';
|
var filename = name + '-profile.json';
|
||||||
this._download(ew, name, filename)
|
this._download(ew, name, filename)
|
||||||
|
|
|
||||||
|
|
@ -48,6 +48,7 @@ angular.module('copayApp.services')
|
||||||
passphraseConfig: config.passphraseConfig,
|
passphraseConfig: config.passphraseConfig,
|
||||||
failIfExists: true,
|
failIfExists: true,
|
||||||
}, function(err, iden) {
|
}, function(err, iden) {
|
||||||
|
|
||||||
if (err) return cb(err);
|
if (err) return cb(err);
|
||||||
preconditions.checkState(iden);
|
preconditions.checkState(iden);
|
||||||
root.bind(iden);
|
root.bind(iden);
|
||||||
|
|
|
||||||
|
|
@ -111,7 +111,14 @@ describe('Identity model', function() {
|
||||||
params: params
|
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() {
|
describe('new Identity()', function() {
|
||||||
it('returns an identity', function() {
|
it('returns an identity', function() {
|
||||||
var iden = new Identity(getDefaultParams());
|
var iden = new Identity(getDefaultParams());
|
||||||
|
|
@ -124,7 +131,6 @@ describe('Identity model', function() {
|
||||||
it('should create and store identity', function() {
|
it('should create and store identity', function() {
|
||||||
var args = createIdentity();
|
var args = createIdentity();
|
||||||
args.blockchain.on = sinon.stub();
|
args.blockchain.on = sinon.stub();
|
||||||
sinon.stub(Identity.prototype, 'store').yields(null);
|
|
||||||
Identity.create(args.params, function(err, iden) {
|
Identity.create(args.params, function(err, iden) {
|
||||||
should.not.exist(err);
|
should.not.exist(err);
|
||||||
should.exist(iden);
|
should.exist(iden);
|
||||||
|
|
@ -240,7 +246,6 @@ describe('Identity model', function() {
|
||||||
args = createIdentity();
|
args = createIdentity();
|
||||||
args.params.noWallets = true;
|
args.params.noWallets = true;
|
||||||
var old = Identity.prototype.createWallet;
|
var old = Identity.prototype.createWallet;
|
||||||
sinon.stub(Identity.prototype, 'store').yields(null);
|
|
||||||
Identity.create(args.params, function(err, res) {
|
Identity.create(args.params, function(err, res) {
|
||||||
iden = res;
|
iden = res;
|
||||||
});
|
});
|
||||||
|
|
@ -297,7 +302,6 @@ describe('Identity model', function() {
|
||||||
args.storage.getItem.onFirstCall().callsArgWith(1, null, '{"wallet": "fakeData"}');
|
args.storage.getItem.onFirstCall().callsArgWith(1, null, '{"wallet": "fakeData"}');
|
||||||
var backup = Wallet.fromUntrustedObj;
|
var backup = Wallet.fromUntrustedObj;
|
||||||
args.params.noWallets = true;
|
args.params.noWallets = true;
|
||||||
sinon.stub(Identity.prototype, 'store').yields(null);
|
|
||||||
sinon.stub().returns(args.wallet);
|
sinon.stub().returns(args.wallet);
|
||||||
|
|
||||||
var opts = {
|
var opts = {
|
||||||
|
|
@ -390,8 +394,6 @@ describe('Identity model', function() {
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
args = createIdentity();
|
args = createIdentity();
|
||||||
args.params.Async = net = sinon.stub();
|
args.params.Async = net = sinon.stub();
|
||||||
|
|
||||||
sinon.stub(Identity.prototype, 'store').yields(null);
|
|
||||||
net.cleanUp = sinon.spy();
|
net.cleanUp = sinon.spy();
|
||||||
net.on = sinon.stub();
|
net.on = sinon.stub();
|
||||||
net.start = sinon.spy();
|
net.start = sinon.spy();
|
||||||
|
|
|
||||||
|
|
@ -76,6 +76,7 @@ describe("Angular services", function() {
|
||||||
a[Waddr] = 200;
|
a[Waddr] = 200;
|
||||||
w.getBalance = sinon.stub().yields(null, 100000001, a, 90000002, 5);
|
w.getBalance = sinon.stub().yields(null, 100000001, a, 90000002, 5);
|
||||||
|
|
||||||
|
|
||||||
//retuns values in DEFAULT UNIT(bits)
|
//retuns values in DEFAULT UNIT(bits)
|
||||||
balanceService.update(w, function() {
|
balanceService.update(w, function() {
|
||||||
var b = w.balanceInfo;
|
var b = w.balanceInfo;
|
||||||
|
|
|
||||||
|
|
@ -16,10 +16,13 @@
|
||||||
|
|
||||||
<div class="menu" ng-mouseover="hoverIn()" ng-mouseleave="hoverOut()"
|
<div class="menu" ng-mouseover="hoverIn()" ng-mouseleave="hoverOut()"
|
||||||
ng-click="hoverMenu = !hoverMenu">
|
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">
|
<div class="photo-container">
|
||||||
<img gravatar-src="'{{username}}'" gravatar-size="35">
|
<img gravatar-src="'{{username}}'" gravatar-size="35">
|
||||||
</div>
|
</div>
|
||||||
|
<span class="need-backup" ng-if="!$root.needsEmailConfirmation && $root.iden.backupNeeded">
|
||||||
|
<i class="fi-alert vm"></i>
|
||||||
|
</span>
|
||||||
<span class="m15t">{{username}} </span>
|
<span class="m15t">{{username}} </span>
|
||||||
<i class="icon-arrow-down2 size-16 vm"></i>
|
<i class="icon-arrow-down2 size-16 vm"></i>
|
||||||
</a>
|
</a>
|
||||||
|
|
@ -33,7 +36,8 @@
|
||||||
<i class="icon-download size-18 m10r"></i> {{'Import wallet'|translate}}</a></li>
|
<i class="icon-download size-18 m10r"></i> {{'Import wallet'|translate}}</a></li>
|
||||||
<li class="divider"></li>
|
<li class="divider"></li>
|
||||||
<li><a href="#!/profile" title="Profile">
|
<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()">
|
<li><a href="#!/" title="Close" ng-click="signout()">
|
||||||
<i class="icon-power size-18 m10r"></i> {{'Close'|translate}}</a></li>
|
<i class="icon-power size-18 m10r"></i> {{'Close'|translate}}</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="large-7 medium-7 columns">
|
<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>
|
<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>
|
||||||
<div class="large-3 medium-3 columns">
|
<div class="large-3 medium-3 columns">
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue