diff --git a/js/models/Identity.js b/js/models/Identity.js index 84cb41595..b774891c8 100644 --- a/js/models/Identity.js +++ b/js/models/Identity.js @@ -123,7 +123,7 @@ Identity.prototype.validate = function(authcode, cb) { */ Identity.open = function(email, password, opts, cb) { var iden = new Identity(email, password, opts); - iden.read(function(err){ + iden.read(function(err) { return cb(err, iden); }); }; @@ -143,8 +143,21 @@ Identity.isAvailable = function(email, opts, cb) { Identity.prototype.store = function(opts, cb) { - console.log('[Identity.js.142] TODO .store'); //TODO - return cb(); + var self = this; + self.profile.store(function() { + var l = self.wallets.length, + i = 0; + if (!l) return cb(); + + _.each(self.wallets, function(w) { + w.store(function(err) { + if (err) return cb(err); + + if (++i == l) + return cb(); + }) + }); + }); }; @@ -155,8 +168,8 @@ Identity.prototype.store = function(opts, cb) { */ Identity.prototype.obtainNetworkName = function(obj) { return obj.networkName || - obj.opts.networkName || - obj.publicKeyRing.networkName || + (obj.opts ? obj.opts.networkName : null) || + (obj.publicKeyRing ? obj.publicKeyRing.networkName :null) || obj.privateKey.networkName; }; diff --git a/js/models/Profile.js b/js/models/Profile.js index 61e01425a..a5831e5fc 100644 --- a/js/models/Profile.js +++ b/js/models/Profile.js @@ -10,34 +10,57 @@ function Profile(info, password, storage) { preconditions.checkArgument(storage); preconditions.checkArgument(storage.getItem); - this.email = info.email; + this.email = info.email; this.extra = info.extra; - this.hash = bitcore.util.sha256ripe160(this.email + this.password).toString('hex'); + this.hash = Profile.hash(this.email, password); this.storage = storage; }; +Profile.hash = function(email, password) { + return bitcore.util.sha256ripe160(email + password).toString('hex'); +}; + Profile.fromObj = function(obj, password, storage) { var o = _.clone(obj); return new Profile(obj, password, storage); }; + +Profile.prototype.key = function() { + return 'identity::' + this.hash + '_' + this.email; +}; + Profile.prototype.toObj = function() { var obj = _.clone(this); delete obj['hash']; return JSON.parse(JSON.stringify(obj)); }; +Profile.open = function(storage, cb) { + var key = this.key(); + this.storage.getGlobal(key, function(err, val) { + if (!val) return cb(new Error('PNOTFOUND: Profile not found')); + return cb(Profile.fromObj(val, password, storage)); + }); +}; -Profile.prototype.store = function(cb) { - var val = this.toObj(); - var key = 'identity::' + this.hash + '_' + this.email; +Profile.prototype.store = function(opts, cb) { + var self = this; + var val = self.toObj(); + var key = self.key(); - this.storage.setFromObj(key, val, function(err) { - log.debug('Identity stored'); - if (cb) - cb(err); + self.storage.get(key, function(val2) { + if (val2 && !opts.overwrite) { + if (cb) + return cb(new Error('PEXISTS: Profile already exist')) + } else { + self.storage.set(key, val, function(err) { + log.debug('Identity stored'); + if (cb) + cb(err); + }); + } }); }; module.exports = Profile; - diff --git a/js/models/Wallet.js b/js/models/Wallet.js index 4477ef611..696107422 100644 --- a/js/models/Wallet.js +++ b/js/models/Wallet.js @@ -876,7 +876,7 @@ Wallet.prototype.store = function(cb) { var val = this.toObj(); var key = 'wallet::' + this.id + ((val.opts && val.opts.name) ? '_' + obj.opts.name : ''); - this.storage.setFromObj(key, val, function(err) { + this.storage.set(key, val, function(err) { log.debug('Wallet stored'); if (cb) cb(err); diff --git a/test/test.Identity.js b/test/test.Identity.js index 786fa179f..a1d96055c 100644 --- a/test/test.Identity.js +++ b/test/test.Identity.js @@ -46,6 +46,8 @@ describe('Identity model', function() { profile = sinon.stub(); profile.test = sinon.stub(); + profile.store = sinon.stub(); + profile.store.yields(null); Identity._newProfile = sinon.stub().returns(profile); iden = new Identity(email, password, config); @@ -53,7 +55,7 @@ describe('Identity model', function() { afterEach(function() { - iden = undefined; + iden = storage = wallet = profile = undefined; }); @@ -91,7 +93,7 @@ describe('Identity model', function() { version: '0.0.1', }; - describe.only('#constructors', function() { + describe('#constructors', function() { describe('#new', function() { it('should create an identity', function() { var iden = new Identity(email, password, config); @@ -110,17 +112,17 @@ describe('Identity model', function() { describe('#create', function(done) { it('should call .store', function(done) { - Identity.prototype.store = sinon.stub().yields(null); Identity.create(email, password, config, function(err, iden) { should.not.exist(err); should.exist(iden.profile.test); - iden.store.getCall(0).args[0].should.deep.equal({overwrite:false}); + iden.profile.store.getCall(0).args[0].should.deep.equal({ + overwrite: false + }); done(); }); }); }); - describe('#open', function(done) { it('should call .read', function(done) { Identity.prototype.read = sinon.stub().yields(null); @@ -133,6 +135,57 @@ describe('Identity model', function() { }); }); }); + describe('#store', function() { + + it('should call .store from profile and no wallets', function(done) { + profile.store = sinon.stub().yields(null); + iden.wallets = []; + iden.store({}, function(err) { + should.not.exist(err); + profile.store.calledOnce.should.equal(true); + done(); + }); + }); + + it('should call .store from profile and wallets (2)', function(done) { + iden.profile.store = sinon.stub().yields(null); + iden.wallets = [{ + store: sinon.stub().yields(null) + }, { + store: sinon.stub().yields(null) + }]; + iden.store({}, function(err) { + should.not.exist(err); + iden.profile.store.calledOnce.should.equal(true); + iden.wallets[0].store.calledOnce.should.equal(true); + iden.wallets[1].store.calledOnce.should.equal(true); + done(); + }); + }); + }); + + describe('#obtainNetworkName', function() { + it('should return the networkname', function() { + iden.obtainNetworkName({ + networkName: 'testnet', + }).should.equal('testnet'); + iden.obtainNetworkName({ + opts: { + networkName: 'testnet' + } + }).should.equal('testnet'); + iden.obtainNetworkName({ + publicKeyRing: { + networkName: 'testnet' + } + }).should.equal('testnet'); + iden.obtainNetworkName({ + privateKey: { + networkName: 'testnet' + } + }).should.equal('testnet'); + }); + }); // TODO this is a WALLET TEST! not Wallet Factory. Move it. describe.skip('#fromObj / #toObj', function() { diff --git a/test/test.Profile.js b/test/test.Profile.js index 7d16d09fb..4baafcea6 100644 --- a/test/test.Profile.js +++ b/test/test.Profile.js @@ -18,8 +18,9 @@ describe('Profile model', function() { beforeEach(function() { storage.getItem = sinon.stub(); - storage.setFromObj = sinon.stub(); - storage.setFromObj.yields(null); + storage.set = sinon.stub(); + storage.set.yields(null); + storage.get = sinon.stub().yields(null); }); it('should fail create an instance', function() { @@ -43,15 +44,33 @@ describe('Profile model', function() { p2.should.deep.equal(p); }); - it('#store', function(done) { - var p = new Profile(opts, password, storage); - p.store(function(err) { - storage.setFromObj.getCall(0).args[1].should.deep.equal(p.toObj()); - should.not.exist(err); - done(); - }) + describe('#store', function() { + it('should call storage set', function(done) { + var p = new Profile(opts, password, storage); + p.store({}, function(err) { + storage.set.getCall(0).args[1].should.deep.equal(p.toObj()); + should.not.exist(err); + done(); + }) + }); + it('should use fail to overwrite', function(done) { + storage.get = sinon.stub().yields(123); + var p = new Profile(opts, password, storage); + p.store({}, function(err) { + err.toString().should.contain('PEXISTS'); + should.not.exist(storage.set.getCall(0)); + done(); + }) + }); + + it('should use overwrite param', function(done) { + storage.get = sinon.stub().yields(123); + var p = new Profile(opts, password, storage); + p.store({overwrite:true}, function(err) { + storage.set.getCall(0).args[1].should.deep.equal(p.toObj()); + should.not.exist(err); + done(); + }) + }); }); - - - });