diff --git a/packages/composer-playground/e2e/tests/editor-define.spec.ts b/packages/composer-playground/e2e/tests/editor-define.spec.ts
index 20c1033ee5..f436106e7e 100644
--- a/packages/composer-playground/e2e/tests/editor-define.spec.ts
+++ b/packages/composer-playground/e2e/tests/editor-define.spec.ts
@@ -10,7 +10,6 @@ import { dragDropFile, waitForFileToExist, retrieveZipContentList } from '../uti
import * as chai from 'chai';
import * as fs from 'fs';
-import * as JSZip from 'jszip';
let should = chai.should();
@@ -18,7 +17,7 @@ describe('Editor Define', (() => {
// Navigate to Editor base page and move past welcome splash
beforeAll(() => {
- OperationsHelper.navigatePastWelcome();
+ OperationsHelper.navigatePastWelcomeAndLogin();
});
describe('On initialise', (() => {
@@ -183,7 +182,7 @@ describe('Editor Define', (() => {
// ExportBND appears to kick off processes that cause timeout in protractor
// -current work around is to refresh the page before continuing tests
// -this was previously at the start as a beforeEach, but consumes time
- OperationsHelper.navigatePastWelcome();
+ OperationsHelper.navigatePastWelcomeAndLogin();
});
}));
}));
@@ -256,7 +255,7 @@ describe('Editor Define', (() => {
});
}));
- it('should enable the addition of a script file via radio button selection', (() => {
+ fit('should enable the addition of a script file via radio button selection', (() => {
let startFiles = EditorHelper.retrieveNavigatorFileNames()
.then((names) => {
startFiles = names;
@@ -275,22 +274,27 @@ describe('Editor Define', (() => {
.then((list: any) => {
// Previous files should still exist
startFiles.forEach((element) => {
+ console.log('CAZ', list);
+ console.log('ISAAC', element);
list.includes(element).should.be.true;
});
// We should have added one file
list.length.should.be.equal(startFiles.length + 1);
+ console.log('BOB');
list.includes('Script File\nlib/script.js').should.be.true;
browser.waitForAngularEnabled(true);
});
// -deploy enabled
EditorHelper.retrieveNavigatorFileActionButtons()
.then((array: any) => {
+ console.log('CAKE');
array[1].enabled.should.be.equal(true);
});
// -active file
EditorHelper.retrieveNavigatorActiveFile()
.then((list: any) => {
list.length.should.equal(1);
+ console.log('FISH');
list.includes('Script File\nlib/script.js').should.be.true;
});
// deploy new item
diff --git a/packages/composer-playground/e2e/tests/welcome.spec.ts b/packages/composer-playground/e2e/tests/welcome.spec.ts
index 372519dd4f..f4580870d2 100644
--- a/packages/composer-playground/e2e/tests/welcome.spec.ts
+++ b/packages/composer-playground/e2e/tests/welcome.spec.ts
@@ -7,30 +7,36 @@ let should = chai.should();
describe('Welcome Splash', (() => {
- // Navigate to Editor base page
- beforeEach(() => {
- browser.get(browser.baseUrl);
- });
-
- it('should welcome the user to Composer Playground', (() => {
- let myElement = element(by.css('.welcome')).getText()
- .then((myText) => {
- myText.should.contain('Welcome to Hyperledger Composer Playground!');
+ // Navigate to Editor base page
+ beforeEach(() => {
+ return browser.get(browser.baseUrl)
+ .then(() => {
+ return browser.executeScript('window.localStorage.clear();');
+ })
+ .then(() => {
+ return browser.refresh();
+ });
});
- }));
- it('should dissappear when the user clicks cancel button', (() => {
- let myButton = element(by.id('welcome_exit')).click()
- .then(() => {
- browser.wait(ExpectedConditions.invisibilityOf(element(by.css('.welcome'))), 5000);
- });
- }));
-
- it('should dissappear when the user clicks "Let\'s Blockchain" button', (() => {
- let myButton = element(by.id('welcome_start')).click()
- .then(() => {
- browser.wait(ExpectedConditions.invisibilityOf(element(by.css('.welcome'))), 5000);
- });
- }));
+ it('should welcome the user to Composer Playground', (() => {
+ let myElement = element(by.css('.welcome')).getText()
+ .then((myText) => {
+ myText.should.contain('Welcome to Hyperledger Composer Playground!');
+ });
+ }));
+
+ it('should dissappear when the user clicks cancel button', (() => {
+ let myButton = element(by.id('welcome_exit')).click()
+ .then(() => {
+ browser.wait(ExpectedConditions.invisibilityOf(element(by.css('.welcome'))), 5000);
+ });
+ }));
+
+ it('should dissappear when the user clicks "Let\'s Blockchain" button', (() => {
+ let myButton = element(by.id('welcome_start')).click()
+ .then(() => {
+ browser.wait(ExpectedConditions.invisibilityOf(element(by.css('.welcome'))), 5000);
+ });
+ }));
}));
diff --git a/packages/composer-playground/e2e/utils/login-helper.ts b/packages/composer-playground/e2e/utils/login-helper.ts
new file mode 100644
index 0000000000..4963b4ac71
--- /dev/null
+++ b/packages/composer-playground/e2e/utils/login-helper.ts
@@ -0,0 +1,10 @@
+import { browser, element, by } from 'protractor';
+import { ExpectedConditions } from 'protractor';
+
+export class LoginHelper {
+
+ // Click login button
+ static login() {
+ return element(by.id('login-0-admin')).click();
+ }
+}
diff --git a/packages/composer-playground/e2e/utils/operations-helper.ts b/packages/composer-playground/e2e/utils/operations-helper.ts
index 96039d45aa..19e597c32e 100644
--- a/packages/composer-playground/e2e/utils/operations-helper.ts
+++ b/packages/composer-playground/e2e/utils/operations-helper.ts
@@ -1,16 +1,30 @@
import { browser, element, by } from 'protractor';
import { ExpectedConditions } from 'protractor';
+import { LoginHelper } from '../utils/login-helper.ts';
+
export class OperationsHelper {
- // Navigate to Editor base page and move past welcome splash
- static navigatePastWelcome() {
- browser.get(browser.baseUrl)
- .then(() => {
- return element(by.id('welcome_start')).click()
- .then(() => {
- return browser.wait(ExpectedConditions.invisibilityOf(element(by.css('.welcome'))), 5000);
- });
- });
- };
+ // Navigate to Editor base page and move past welcome splash and login
+ static navigatePastWelcomeAndLogin() {
+ return browser.get(browser.baseUrl)
+ .then(() => {
+ return browser.isElementPresent(element(by.css('.welcome')));
+ })
+ .then((welcomeOpen) => {
+ if (welcomeOpen) {
+ return element(by.id('welcome_start')).click()
+ .then(() => {
+ return browser.wait(ExpectedConditions.invisibilityOf(element(by.css('.welcome'))), 5000);
+ })
+ .then(() => {
+ return LoginHelper.login();
+ })
+ .then(() => {
+ return browser.wait(ExpectedConditions.invisibilityOf(element(by.tagName('login'))), 5000);
+ });
+ }
+ });
+
+ }
}
diff --git a/packages/composer-playground/src/app/app-routing.module.ts b/packages/composer-playground/src/app/app-routing.module.ts
index 45e226ddd2..da3baf2c7c 100644
--- a/packages/composer-playground/src/app/app-routing.module.ts
+++ b/packages/composer-playground/src/app/app-routing.module.ts
@@ -1,18 +1,23 @@
import { NgModule } from '@angular/core';
import { Routes, RouterModule, PreloadAllModules } from '@angular/router';
import { NoContentComponent } from './no-content';
+import { CanActivateViaLogin } from './can-activate';
+import { LoginComponent } from './login';
export const ROUTES: Routes = [
- {path: 'editor', loadChildren: 'app/editor/editor.module#EditorModule'},
- {path: 'test', loadChildren: 'app/test/test.module#TestModule'},
- {path: 'identity', loadChildren: 'app/identity/identity.module#IdentityModule'},
- {path: 'profile', loadChildren: 'app/connection-profile/connection-profile.module#ConnectionProfileModule'},
+ {path: 'editor', loadChildren: 'app/editor/editor.module#EditorModule', canActivate: [CanActivateViaLogin]},
+ {path: 'test', loadChildren: 'app/test/test.module#TestModule', canActivate: [CanActivateViaLogin]},
+ {path: 'identity', loadChildren: 'app/identity/identity.module#IdentityModule', canActivate: [CanActivateViaLogin]},
+ {path: 'profile', loadChildren: 'app/connection-profile/connection-profile.module#ConnectionProfileModule',
+ canActivate: [CanActivateViaLogin]},
+ {path: 'login', component: LoginComponent},
{path: '', redirectTo: 'editor', pathMatch: 'full'},
{path: '**', component: NoContentComponent}
];
@NgModule({
imports: [RouterModule.forRoot(ROUTES, {useHash: false, preloadingStrategy: PreloadAllModules})],
+ providers: [CanActivateViaLogin],
exports: [RouterModule]
})
diff --git a/packages/composer-playground/src/app/app.component.html b/packages/composer-playground/src/app/app.component.html
index 7e780bb912..a1169dd394 100644
--- a/packages/composer-playground/src/app/app.component.html
+++ b/packages/composer-playground/src/app/app.component.html
@@ -4,37 +4,40 @@
Hyperledger Composer Playground
-
- -
-
-
- -
-
-
-
-
+
+
+ -
+
+
+ -
+
+
+
+
+
diff --git a/packages/composer-playground/src/app/app.component.spec.ts b/packages/composer-playground/src/app/app.component.spec.ts
index a6ba18c02d..3cbf6b4380 100644
--- a/packages/composer-playground/src/app/app.component.spec.ts
+++ b/packages/composer-playground/src/app/app.component.spec.ts
@@ -54,7 +54,7 @@ class RouterStub {
set eventParams(event) {
let nav;
if (event.nav === 'end') {
- nav = new NavigationEnd(0, event.url, null);
+ nav = new NavigationEnd(0, event.url, event.urlAfterRedirects);
} else {
nav = new NavigationStart(0, event.url);
}
@@ -210,7 +210,7 @@ describe('AppComponent', () => {
]
})
- .compileComponents();
+ .compileComponents();
}));
beforeEach(async(() => {
@@ -224,11 +224,11 @@ describe('AppComponent', () => {
// find DebugElements with an attached RouterLinkStubDirective
linkDes = fixture.debugElement
- .queryAll(By.directive(MockRouterLinkDirective));
+ .queryAll(By.directive(MockRouterLinkDirective));
// get the attached link directive instances using the DebugElement injectors
links = linkDes
- .map((de) => de.injector.get(MockRouterLinkDirective) as MockRouterLinkDirective);
+ .map((de) => de.injector.get(MockRouterLinkDirective) as MockRouterLinkDirective);
}
describe('ngOnInit', () => {
@@ -289,7 +289,7 @@ describe('AppComponent', () => {
it('should open the welcome modal', () => {
let welcomeModalStub = sinon.stub(component, 'openWelcomeModal');
- routerStub.eventParams = {url: '/', nav: 'end'};
+ routerStub.eventParams = {url: '/login', nav: 'end'};
updateComponent();
@@ -338,7 +338,45 @@ describe('AppComponent', () => {
checkVersionStub.should.not.have.been.called;
welcomeModalStub.should.not.have.been.called;
+ }));
+
+ it('should show header links if logged in', fakeAsync(() => {
+ let checkVersionStub = sinon.stub(component, 'checkVersion').returns(Promise.resolve(true));
+ routerStub.eventParams = {url: '/editor', nav: 'end'};
+
+ updateComponent();
+
+ tick();
+
+ component['showHeaderLinks'].should.equal(true);
+
+ checkVersionStub.should.have.been.called;
+ }));
+
+ it('should not show header links if not logged in', fakeAsync(() => {
+ let checkVersionStub = sinon.stub(component, 'checkVersion').returns(Promise.resolve(true));
+ routerStub.eventParams = {url: '/login', nav: 'end'};
+
+ updateComponent();
+
+ tick();
+
+ component['showHeaderLinks'].should.equal(false);
+ checkVersionStub.should.have.been.called;
+ }));
+
+ it('should not show header links if redirected to login', fakeAsync(() => {
+ let checkVersionStub = sinon.stub(component, 'checkVersion').returns(Promise.resolve(true));
+ routerStub.eventParams = {url: '/editor', nav: 'end', urlAfterRedirects: '/login'};
+
+ updateComponent();
+
+ tick();
+
+ component['showHeaderLinks'].should.equal(false);
+
+ checkVersionStub.should.have.been.called;
}));
});
@@ -359,6 +397,7 @@ describe('AppComponent', () => {
it('can get RouterLinks from template', () => {
activatedRoute.testParams = {};
+ component['showHeaderLinks'] = true;
updateComponent();
@@ -372,6 +411,7 @@ describe('AppComponent', () => {
activatedRoute.testParams = {};
component['usingLocally'] = true;
+ component['showHeaderLinks'] = true;
updateComponent();
@@ -382,7 +422,16 @@ describe('AppComponent', () => {
links[3].linkParams.should.deep.equal(['profile']);
});
+ it('should not show links when not logged in', () => {
+ activatedRoute.testParams = {};
+
+ updateComponent();
+
+ links.length.should.equal(0);
+ });
+
it('can click test link in template', () => {
+ component['showHeaderLinks'] = true;
updateComponent();
const testLinkDe = linkDes[1];
@@ -397,6 +446,7 @@ describe('AppComponent', () => {
});
it('can click editor link in template', () => {
+ component['showHeaderLinks'] = true;
updateComponent();
const testLinkDe = linkDes[0];
@@ -411,6 +461,7 @@ describe('AppComponent', () => {
});
it('can click identity link in template', () => {
+ component['showHeaderLinks'] = true;
updateComponent();
const testLinkDe = linkDes[2];
@@ -425,6 +476,7 @@ describe('AppComponent', () => {
});
it('can click profile link in template', () => {
+ component['showHeaderLinks'] = true;
component['usingLocally'] = true;
updateComponent();
@@ -456,90 +508,68 @@ describe('AppComponent', () => {
errorStatusSpy = sinon.spy(mockAlertService.errorStatus$, 'next');
}));
- it('should deal with an invitation when already in wallet', fakeAsync(() => {
- mockIdentityService.setIdentity.returns(Promise.resolve());
- mockAdminService.getAdminConnection.returns(mockAdminConnection);
- mockWallet.contains.returns(Promise.resolve(true));
- mockWalletService.getWallet.returns(mockWallet);
- activatedRoute.testParams = {invitation: 'N4Igxg9gdlCmYBcCW0AKAnCAzJAbWAcgIYC2sIABAFwUgBGEdIANLZDPMmpjvpTSBIBPDNjzlWIAK4BnWOgCSAEX61hAVTmKVk2fIDK8dLASrBQw2GOmAvkA'};
-
- updateComponent();
-
- tick();
-
- mockAdminService.getAdminConnection.should.have.been.called;
- mockAdminConnection.createProfile.should.have.been.calledWith('bob', 'myProfile');
- mockConnectionProfileService.setCurrentConnectionProfile.should.have.been.calledWith('bob');
- mockWalletService.getWallet.should.have.been.calledWith('bob');
-
- mockWallet.contains.should.have.been.called; // With('myUserID');
- mockWallet.update.should.have.been.calledWith('myUserID', 'mySecret');
- mockIdentityService.setIdentity.should.have.been.calledWith('bob', 'myUserID');
+ it('should load the connection profiles when local and logged in', fakeAsync(() => {
- routerStub.navigate.should.have.been.calledWith(['/editor']);
-
- // This happens to avoid doing the window.location.reload which breaks the test and is really hard to stub
- mockAlertService.errorStatus$.next.should.have.been.called;
- }));
+ component['showHeaderLinks'] = true;
+ mockIdentityService.getCurrentIdentity.returns(Promise.resolve('bob'));
+ mockInitializationService.isWebOnly.returns(Promise.resolve(false));
+ let updateConnectionDataMock = sinon.stub(component, 'updateConnectionData').returns(Promise.resolve());
- it('should deal with an invitation when not in wallet', fakeAsync(() => {
- mockIdentityService.setIdentity.returns(Promise.resolve());
- mockAdminService.getAdminConnection.returns(mockAdminConnection);
- mockWallet.contains.returns(Promise.resolve(false));
- mockWalletService.getWallet.returns(mockWallet);
- activatedRoute.testParams = {invitation: 'N4Igxg9gdlCmYBcCW0AKAnCAzJAbWAcgIYC2sIABAFwUgBGEdIANLZDPMmpjvpTSBIBPDNjzlWIAK4BnWOgCSAEX61hAVTmKVk2fIDK8dLASrBQw2GOmAvkA'};
+ activatedRoute.testParams = {};
updateComponent();
tick();
- mockAdminService.getAdminConnection.should.have.been.called;
- mockAdminConnection.createProfile.should.have.been.calledWith('bob', 'myProfile');
- mockConnectionProfileService.setCurrentConnectionProfile.should.have.been.calledWith('bob');
- mockWalletService.getWallet.should.have.been.calledWith('bob');
+ // update now got info back about if local or not
+ updateComponent();
+
+ mockConnectionProfileService.getCurrentConnectionProfile.should.have.been.called;
+ updateConnectionDataMock.should.have.been.calledTwice;
- mockWallet.contains.should.have.been.calledWith('myUserID');
- mockWallet.add.should.have.been.calledWith('myUserID', 'mySecret');
- mockIdentityService.setIdentity.should.have.been.calledWith('bob', 'myUserID');
+ mockInitializationService.initialize.should.have.been.called;
- routerStub.navigate.should.have.been.calledWith(['/editor']);
+ component['usingLocally'].should.equal(true);
- // This happens to avoid doing the window.location.reload which breaks the test and is really hard to stub
- mockAlertService.errorStatus$.next.should.have.been.called;
+ links.length.should.equal(4);
+ links[0].linkParams.should.deep.equal(['editor']);
+ links[1].linkParams.should.deep.equal(['test']);
+ links[2].linkParams.should.deep.equal(['identity']);
+ links[3].linkParams.should.deep.equal(['profile']);
}));
- it('should deal with an invitation that errors', fakeAsync(() => {
- mockIdentityService.setIdentity.returns(Promise.resolve());
- mockAdminService.getAdminConnection.returns(mockAdminConnection);
- mockWallet.contains.returns(Promise.reject('some error'));
- mockWalletService.getWallet.returns(mockWallet);
- activatedRoute.testParams = {invitation: 'N4Igxg9gdlCmYBcCW0AKAnCAzJAbWAcgIYC2sIABAFwUgBGEdIANLZDPMmpjvpTSBIBPDNjzlWIAK4BnWOgCSAEX61hAVTmKVk2fIDK8dLASrBQw2GOmAvkA'};
+ it('should load the connection profiles when web only and logged in', fakeAsync(() => {
+
+ component['showHeaderLinks'] = true;
+ mockIdentityService.getCurrentIdentity.returns(Promise.resolve('bob'));
+ mockInitializationService.isWebOnly.returns(Promise.resolve(true));
+ let updateConnectionDataMock = sinon.stub(component, 'updateConnectionData').returns(Promise.resolve());
+
+ activatedRoute.testParams = {};
updateComponent();
tick();
- mockAdminService.getAdminConnection.should.have.been.called;
- mockAdminConnection.createProfile.should.have.been.calledWith('bob', 'myProfile');
- mockConnectionProfileService.setCurrentConnectionProfile.should.have.been.calledWith('bob');
- mockWalletService.getWallet.should.have.been.calledWith('bob');
+ // update now got info back about if local or not
+ updateComponent();
+
+ mockConnectionProfileService.getCurrentConnectionProfile.should.have.been.called;
+ updateConnectionDataMock.should.have.been.calledTwice;
- mockWallet.contains.should.have.been.calledWith('myUserID');
- mockWallet.add.should.not.have.been.called;
- mockWallet.update.should.not.have.been.called;
- mockIdentityService.setIdentity.should.not.have.been.called;
+ mockInitializationService.initialize.should.have.been.called;
- routerStub.navigate.should.not.have.been.called;
+ component['usingLocally'].should.equal(false);
- // This happens to avoid doing the window.location.reload which breaks the test and is really hard to stub
- mockAlertService.errorStatus$.next.should.have.been.called;
+ links.length.should.equal(3);
+ links[0].linkParams.should.deep.equal(['editor']);
+ links[1].linkParams.should.deep.equal(['test']);
+ links[2].linkParams.should.deep.equal(['identity']);
}));
- it('should load the connection profiles when local', fakeAsync(() => {
+ it('should load the connection profiles when local but not logged in', fakeAsync(() => {
mockIdentityService.getCurrentIdentity.returns(Promise.resolve('bob'));
mockInitializationService.isWebOnly.returns(Promise.resolve(false));
- mockBusinessNetworkConnection.ping.returns(Promise.resolve({version: 1.0, participant: 'bob'}));
- mockClientService.getBusinessNetworkConnection.returns(mockBusinessNetworkConnection);
let updateConnectionDataMock = sinon.stub(component, 'updateConnectionData').returns(Promise.resolve());
activatedRoute.testParams = {};
@@ -555,30 +585,15 @@ describe('AppComponent', () => {
updateConnectionDataMock.should.have.been.calledTwice;
mockInitializationService.initialize.should.have.been.called;
- mockClientService.getBusinessNetworkConnection.should.have.been.called;
- mockBusinessNetworkConnection.ping.should.have.been.called;
-
- mockIdentityService.getCurrentIdentity.should.have.been.called;
component['usingLocally'].should.equal(true);
- component['currentIdentity'].should.equal('bob');
- component['composerRuntimeVersion'].should.equal(1.0);
- component['participantFQI'].should.equal('bob');
- links.length.should.equal(4);
- links[0].linkParams.should.deep.equal(['editor']);
- links[1].linkParams.should.deep.equal(['test']);
- links[2].linkParams.should.deep.equal(['identity']);
- links[3].linkParams.should.deep.equal(['profile']);
+ links.length.should.equal(0);
}));
- it('should load the connection profiles but get no info from ping', fakeAsync(() => {
- component['composerRuntimeVersion'] = '1.0';
- component['participantFQI'] = 'bob';
+ it('should load the connection profiles when web only but not logged in', fakeAsync(() => {
mockIdentityService.getCurrentIdentity.returns(Promise.resolve('bob'));
mockInitializationService.isWebOnly.returns(Promise.resolve(true));
- mockBusinessNetworkConnection.ping.returns(Promise.resolve({}));
- mockClientService.getBusinessNetworkConnection.returns(mockBusinessNetworkConnection);
let updateConnectionDataMock = sinon.stub(component, 'updateConnectionData').returns(Promise.resolve());
activatedRoute.testParams = {};
@@ -587,19 +602,17 @@ describe('AppComponent', () => {
tick();
+ // update now got info back about if local or not
+ updateComponent();
+
mockConnectionProfileService.getCurrentConnectionProfile.should.have.been.called;
updateConnectionDataMock.should.have.been.calledTwice;
mockInitializationService.initialize.should.have.been.called;
- mockClientService.getBusinessNetworkConnection.should.have.been.called;
- mockBusinessNetworkConnection.ping.should.have.been.called;
-
- mockIdentityService.getCurrentIdentity.should.have.been.called;
component['usingLocally'].should.equal(false);
- component['currentIdentity'].should.equal('bob');
- component['composerRuntimeVersion'].should.equal('1.0');
- component['participantFQI'].should.equal('bob');
+
+ links.length.should.equal(0);
}));
});
@@ -971,4 +984,33 @@ describe('AppComponent', () => {
});
});
+ describe('logout', () => {
+ let mockOnBusy;
+ let mockOnError;
+ let mockQueryParamsUpdated;
+
+ beforeEach(async(() => {
+ mockOnBusy = sinon.stub(component, 'onBusyStatus');
+ mockOnError = sinon.stub(component, 'onErrorStatus');
+ mockQueryParamsUpdated = sinon.stub(component, 'queryParamsUpdated');
+
+ }));
+
+ it('should log the user out', fakeAsync(() => {
+ routerStub.navigate.returns(Promise.resolve(true));
+ activatedRoute.testParams = {};
+ updateComponent();
+
+ component.logout();
+
+ tick();
+
+ mockClientService.disconnect.should.have.been.called;
+ mockIdentityService.setCurrentIdentity.should.have.been.calledWith(null);
+ mockConnectionProfileService.setCurrentConnectionProfile.should.have.been.calledWith(null);
+ mockIdentityService.setLoggedIn.should.have.been.calledWith(false);
+ routerStub.navigate.should.have.been.calledWith(['/login']);
+ }));
+ });
+
});
diff --git a/packages/composer-playground/src/app/app.component.ts b/packages/composer-playground/src/app/app.component.ts
index d6b6609e53..338928e5b7 100644
--- a/packages/composer-playground/src/app/app.component.ts
+++ b/packages/composer-playground/src/app/app.component.ts
@@ -45,6 +45,7 @@ export class AppComponent implements OnInit, OnDestroy {
private subs: any = null;
private usingLocally = false;
+ private showHeaderLinks = false;
private composerRuntimeVersion = '';
private participantFQI = '';
@@ -82,16 +83,7 @@ export class AppComponent implements OnInit, OnDestroy {
this.onEvent(eventStatus);
}),
this.router.events.filter((e) => e instanceof NavigationEnd).subscribe((e) => {
- if (e['url'] === '/') {
- this.openWelcomeModal();
- } else {
- return this.checkVersion().then((success) => {
- if (!success) {
- this.openVersionModal();
- }
- });
- }
-
+ this.processRouteEvent(e);
})
];
}
@@ -102,97 +94,80 @@ export class AppComponent implements OnInit, OnDestroy {
});
}
- queryParamsUpdated(queryParams: Object): Promise {
- // Check for the invitation if specified.
- let invitation = queryParams['invitation'];
- if (invitation) {
- let invitationData = JSON.parse(LZString.decompressFromEncodedURIComponent(invitation));
- let connectionProfileName = invitationData.connectionProfileName;
- let connectionProfile = invitationData.connectionProfile;
- let userID = invitationData.userID;
- let userSecret = invitationData.userSecret;
- // Create the connection profile and set it as the default.
- this.adminService.getAdminConnection().createProfile(connectionProfileName, connectionProfile);
- this.connectionProfileService.setCurrentConnectionProfile(connectionProfileName);
- // Add the credentials to the wallet.
- let wallet = this.walletService.getWallet(connectionProfileName);
- return wallet.contains(userID)
- .then((exists) => {
- if (exists) {
- return wallet.update(userID, userSecret);
- } else {
- return wallet.add(userID, userSecret);
+ logout() {
+ this.clientService.disconnect();
+ this.identityService.setCurrentIdentity(null);
+ this.connectionProfileService.setCurrentConnectionProfile(null);
+ this.identityService.setLoggedIn(false);
+
+ return this.router.navigate(['/login']);
+
+ }
+
+ processRouteEvent(event): Promise {
+ let welcomePromise;
+ if (event['url'] === '/login') {
+ welcomePromise = this.openWelcomeModal();
+ } else {
+ welcomePromise = this.checkVersion().then((success) => {
+ if (!success) {
+ this.openVersionModal();
}
- })
- .then(() => {
- return this.identityService.setIdentity(connectionProfileName, userID);
- })
- .then(() => {
- return this.router.navigate(['/editor'])
- .then((result) => {
- if (result) {
- window.location.reload();
- } else {
- throw new Error('Failed to navigate to main page');
- }
- });
- })
- .catch((error) => {
- this.alertService.errorStatus$.next(error);
});
}
+ if (event['url'] === '/login' || event['urlAfterRedirects'] === '/login') {
+ this.showHeaderLinks = false;
+ } else {
+ this.showHeaderLinks = true;
+ }
+
+ return welcomePromise;
+ }
+
+ queryParamsUpdated(queryParams: Object): Promise {
// We load the connection profiles now, so we can immediately populate the menu.
this.currentConnectionProfile = this.connectionProfileService.getCurrentConnectionProfile();
return this.updateConnectionData()
- .then(() => {
- return this.initializationService.initialize();
- })
- .then(() => {
- return this.clientService.getBusinessNetworkConnection().ping();
- })
- .then((ping) => {
- this.composerRuntimeVersion = ping.version || this.composerRuntimeVersion;
- this.participantFQI = ping.participant || this.participantFQI;
- // We then load the connection profiles again, as the connect calls may have
- // created versions of the default connection profiles.
- return this.updateConnectionData();
- })
- .then(() => {
- return this.identityService.getCurrentIdentity();
- })
- .then((currentIdentity) => {
- this.currentIdentity = currentIdentity;
- return this.initializationService.isWebOnly();
- })
- .then((webOnly) => {
- if (webOnly) {
- this.usingLocally = false;
- } else {
- this.usingLocally = true;
- }
- });
+ .then(() => {
+ return this.initializationService.initialize();
+ })
+ .then(() => {
+ // We then load the connection profiles again, as the connect calls may have
+ // created versions of the default connection profiles.
+ return this.updateConnectionData();
+ })
+ .then(() => {
+ return this.initializationService.isWebOnly();
+ })
+ .then((webOnly) => {
+ if (webOnly) {
+ this.usingLocally = false;
+ } else {
+ this.usingLocally = true;
+ }
+ });
}
updateConnectionData(): Promise {
let newConnectionProfiles = [];
return this.adminService.getAdminConnection().getAllProfiles()
- .then((connectionProfiles) => {
- let keys = Object.keys(connectionProfiles).sort();
- keys.forEach((key) => {
- let connectionProfile = connectionProfiles[key];
- newConnectionProfiles.push({
- name: key,
- profile: connectionProfile,
- default: key === '$default'
+ .then((connectionProfiles) => {
+ let keys = Object.keys(connectionProfiles).sort();
+ keys.forEach((key) => {
+ let connectionProfile = connectionProfiles[key];
+ newConnectionProfiles.push({
+ name: key,
+ profile: connectionProfile,
+ default: key === '$default'
+ });
});
+ this.connectionProfiles = newConnectionProfiles;
+ return this.identityService.getCurrentIdentities();
+ })
+ .then((identities) => {
+ this.identities = identities;
});
- this.connectionProfiles = newConnectionProfiles;
- return this.identityService.getCurrentIdentities();
- })
- .then((identities) => {
- this.identities = identities;
- });
}
onBusyStatus(busyStatus) {
diff --git a/packages/composer-playground/src/app/app.module.ts b/packages/composer-playground/src/app/app.module.ts
index b71815ab1d..f6b5c4a340 100644
--- a/packages/composer-playground/src/app/app.module.ts
+++ b/packages/composer-playground/src/app/app.module.ts
@@ -20,6 +20,7 @@ import { AppState, InternalStateType } from './app.service';
import { AboutComponent } from './about';
import { BasicModalsModule } from './basic-modals/basic-models.module';
import { WelcomeComponent } from './welcome';
+import { LoginComponent } from './login';
import { NoContentComponent } from './no-content';
import { VersionCheckComponent } from './version-check';
import { ServicesModule } from './services/services.module';
@@ -57,6 +58,7 @@ type StoreType = {
declarations: [
AboutComponent,
AppComponent,
+ LoginComponent,
NoContentComponent,
VersionCheckComponent,
WelcomeComponent
@@ -77,7 +79,7 @@ type StoreType = {
providers: [ // expose our Services and Providers into Angular's dependency injection
ENV_PROVIDERS,
APP_PROVIDERS,
- {provide: APP_BASE_HREF, useValue: '/'},
+ {provide: APP_BASE_HREF, useValue: '/'}
]
})
export class AppModule {
diff --git a/packages/composer-playground/src/app/can-activate.ts b/packages/composer-playground/src/app/can-activate.ts
new file mode 100644
index 0000000000..a7b9df302b
--- /dev/null
+++ b/packages/composer-playground/src/app/can-activate.ts
@@ -0,0 +1,22 @@
+import { Injectable } from '@angular/core';
+import { CanActivate, Router } from '@angular/router';
+import { IdentityService } from './services/identity.service';
+
+@Injectable()
+export class CanActivateViaLogin implements CanActivate {
+
+ constructor(private identityService: IdentityService,
+ private router: Router) {
+
+ }
+
+ canActivate(): boolean {
+ let loggedIn = this.identityService.getLoggedIn();
+ if (loggedIn) {
+ return true;
+ } else {
+ this.router.navigate(['login']);
+ return false;
+ }
+ }
+}
diff --git a/packages/composer-playground/src/app/editor/editor.component.spec.ts b/packages/composer-playground/src/app/editor/editor.component.spec.ts
index cea95b2bc6..8063425bea 100644
--- a/packages/composer-playground/src/app/editor/editor.component.spec.ts
+++ b/packages/composer-playground/src/app/editor/editor.component.spec.ts
@@ -12,7 +12,6 @@ import { EditorComponent } from './editor.component';
import { AdminService } from '../services/admin.service';
import { ClientService } from '../services/client.service';
import { EditorService } from './editor.service';
-import { InitializationService } from '../services/initialization.service';
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
import { AlertService } from '../basic-modals/alert.service';
import { ModelFile, Script, AclFile } from 'composer-common';
@@ -50,7 +49,6 @@ describe('EditorComponent', () => {
let mockAlertService;
let mockClientService;
let mockModal;
- let mockInitializationService;
let mockModelFile;
let mockScriptFile;
let mockRuleFile;
@@ -61,7 +59,6 @@ describe('EditorComponent', () => {
mockAlertService = sinon.createStubInstance(AlertService);
mockClientService = sinon.createStubInstance(ClientService);
mockModal = sinon.createStubInstance(NgbModal);
- mockInitializationService = sinon.createStubInstance(InitializationService);
mockModelFile = sinon.createStubInstance(ModelFile);
mockScriptFile = sinon.createStubInstance(Script);
mockRuleFile = sinon.createStubInstance(AclFile);
@@ -79,7 +76,6 @@ describe('EditorComponent', () => {
{provide: ClientService, useValue: mockClientService},
{provide: NgbModal, useValue: mockModal},
{provide: AlertService, useValue: mockAlertService},
- {provide: InitializationService, useValue: mockInitializationService},
{provide: EditorService, useValue: editorService}]
});
@@ -91,7 +87,7 @@ describe('EditorComponent', () => {
let mockEditorFilesValidate;
beforeEach(() => {
- mockInitializationService.initialize.returns(Promise.resolve());
+ mockClientService.ensureConnected.returns(Promise.resolve());
mockClientService.businessNetworkChanged$ = {
takeWhile: sinon.stub().returns({
subscribe: (callback) => {
@@ -867,6 +863,7 @@ describe('EditorComponent', () => {
let mockUpdateFiles = sinon.stub(component, 'updateFiles');
mockModal.open = sinon.stub().returns({
+ componentInstance: {},
result: Promise.resolve()
});
@@ -886,6 +883,7 @@ describe('EditorComponent', () => {
component['files'] = [{readme: true}, {model: true}];
mockModal.open = sinon.stub().returns({
+ componentInstance: {},
result: Promise.resolve()
});
@@ -907,6 +905,7 @@ describe('EditorComponent', () => {
component['files'] = [{model: true}, {script: true}];
mockModal.open = sinon.stub().returns({
+ componentInstance: {},
result: Promise.resolve()
});
@@ -925,6 +924,7 @@ describe('EditorComponent', () => {
let mockUpdateFiles = sinon.stub(component, 'updateFiles');
mockModal.open = sinon.stub().returns({
+ componentInstance: {},
result: Promise.reject('some error')
});
@@ -943,6 +943,7 @@ describe('EditorComponent', () => {
let mockUpdateFiles = sinon.stub(component, 'updateFiles');
mockModal.open = sinon.stub().returns({
+ componentInstance: {},
result: Promise.reject(1)
});
@@ -1145,7 +1146,6 @@ describe('EditorComponent', () => {
it('should open add file modal and handle cancel', fakeAsync(() => {
mockModal.open = sinon.stub().returns({
componentInstance: {
- businessNetwork: {}
},
result: Promise.reject(1)
});
@@ -1163,9 +1163,7 @@ describe('EditorComponent', () => {
mockAddModel.throws('some error');
mockModal.open = sinon.stub().returns({
- componentInstance: {
- businessNetwork: {}
- },
+ componentInstance: {},
result: Promise.resolve(mockModelFile)
});
diff --git a/packages/composer-playground/src/app/editor/editor.component.ts b/packages/composer-playground/src/app/editor/editor.component.ts
index 1e2165c04b..d7c8f6b3bd 100644
--- a/packages/composer-playground/src/app/editor/editor.component.ts
+++ b/packages/composer-playground/src/app/editor/editor.component.ts
@@ -8,7 +8,6 @@ import { ReplaceComponent } from '../basic-modals/replace-confirm';
import { AdminService } from '../services/admin.service';
import { ClientService } from '../services/client.service';
-import { InitializationService } from '../services/initialization.service';
import { AlertService } from '../basic-modals/alert.service';
import { EditorService } from './editor.service';
@@ -58,7 +57,6 @@ export class EditorComponent implements OnInit, OnDestroy {
constructor(private adminService: AdminService,
private clientService: ClientService,
- private initializationService: InitializationService,
private modalService: NgbModal,
private alertService: AlertService,
private editorService: EditorService) {
@@ -66,36 +64,35 @@ export class EditorComponent implements OnInit, OnDestroy {
}
ngOnInit(): Promise {
- return this.initializationService.initialize()
- .then(() => {
- this.clientService.businessNetworkChanged$.takeWhile(() => this.alive)
- .subscribe((noError) => {
- if (this.editorFilesValidate() && noError) {
- this.noError = noError;
- this.dirty = true;
- } else {
- this.noError = false;
- }
- });
+ return this.clientService.ensureConnected().then(() => {
+ this.clientService.businessNetworkChanged$.takeWhile(() => this.alive)
+ .subscribe((noError) => {
+ if (this.editorFilesValidate() && noError) {
+ this.noError = noError;
+ this.dirty = true;
+ } else {
+ this.noError = false;
+ }
+ });
- this.clientService.namespaceChanged$.takeWhile(() => this.alive)
- .subscribe((newName) => {
- if (this.currentFile !== null) {
- this.updateFiles();
- let index = this.findFileIndex(true, newName);
- this.setCurrentFile(this.files[index]);
- }
- });
+ this.clientService.namespaceChanged$.takeWhile(() => this.alive)
+ .subscribe((newName) => {
+ if (this.currentFile !== null) {
+ this.updateFiles();
+ let index = this.findFileIndex(true, newName);
+ this.setCurrentFile(this.files[index]);
+ }
+ });
- this.updatePackageInfo();
- this.updateFiles();
+ this.updatePackageInfo();
+ this.updateFiles();
- if (this.editorService.getCurrentFile() !== null) {
- this.setCurrentFile(this.editorService.getCurrentFile());
- } else {
- this.setInitialFile();
- }
- });
+ if (this.editorService.getCurrentFile() !== null) {
+ this.setCurrentFile(this.editorService.getCurrentFile());
+ } else {
+ this.setInitialFile();
+ }
+ });
}
ngOnDestroy() {
@@ -336,7 +333,10 @@ export class EditorComponent implements OnInit, OnDestroy {
}
openImportModal() {
- this.modalService.open(ImportComponent).result.then((result) => {
+ const importModalRef = this.modalService.open(ImportComponent);
+ // only want to update here not deploy
+ importModalRef.componentInstance.deployNetwork = false;
+ importModalRef.result.then((result) => {
this.updatePackageInfo();
this.updateFiles();
if (this.files.length) {
@@ -412,7 +412,7 @@ export class EditorComponent implements OnInit, OnDestroy {
.then(() => {
this.dirty = false;
this.deploying = false;
- return this.clientService.refresh();
+ return this.clientService.refresh(this.clientService.getBusinessNetworkName());
})
.then(() => {
this.updatePackageInfo();
diff --git a/packages/composer-playground/src/app/editor/editor.service.ts b/packages/composer-playground/src/app/editor/editor.service.ts
index 0bec110cf2..13166875e0 100644
--- a/packages/composer-playground/src/app/editor/editor.service.ts
+++ b/packages/composer-playground/src/app/editor/editor.service.ts
@@ -12,5 +12,4 @@ export class EditorService {
setCurrentFile(cf: any) {
this.currentFile = cf;
}
-
}
diff --git a/packages/composer-playground/src/app/editor/import/import.component.spec.ts b/packages/composer-playground/src/app/editor/import/import.component.spec.ts
index efe43c079b..1cec422f8e 100644
--- a/packages/composer-playground/src/app/editor/import/import.component.spec.ts
+++ b/packages/composer-playground/src/app/editor/import/import.component.spec.ts
@@ -134,7 +134,7 @@ describe('ImportComponent', () => {
let onShowMock;
beforeEach(() => {
- mockClientService.ensureConnected.returns(Promise.resolve());
+ mockAdminService.connectWithoutNetwork.returns(Promise.resolve());
onShowMock = sinon.stub(component, 'onShow');
});
@@ -279,7 +279,7 @@ describe('ImportComponent', () => {
});
describe('deploy', () => {
- it('should deploy a business network from github', fakeAsync(() => {
+ it('should deploy a business network from npm', fakeAsync(() => {
let deployNpmMock = sinon.stub(component, 'deployFromNpm').returns(Promise.resolve());
@@ -305,36 +305,39 @@ describe('ImportComponent', () => {
result: Promise.resolve(true)
});
- component['currentBusinessNetwork'] = {network: 'my network'};
+ component['deployNetwork'] = true;
+ component['currentBusinessNetwork'] = {network: 'my network', getName : sinon.stub()};
mockBusinessNetworkService.deployBusinessNetwork.returns(Promise.resolve());
component.deploy();
tick();
- mockBusinessNetworkService.deployBusinessNetwork.should.have.been.calledWith({network: 'my network'});
+ mockBusinessNetworkService.deployBusinessNetwork.should.have.been.calledWith({network: 'my network', getName : sinon.match.func}, true);
component['deployInProgress'].should.equal(false);
mockActiveModal.close.should.have.been.called;
}));
- it('should handle rate limit error', fakeAsync(() => {
+ it('should update a business network from business network', fakeAsync(() => {
mockNgbModal.open = sinon.stub().returns({
- result: Promise.resolve(true),
- componentInstance: {}
+ componentInstance: {},
+ result: Promise.resolve(true)
});
- component['currentBusinessNetwork'] = {network: 'my network'};
- mockBusinessNetworkService.deployBusinessNetwork.returns(Promise.reject({message: 'API rate limit exceeded'}));
+ component['deployNetwork'] = false;
+ component['currentBusinessNetwork'] = {network: 'my network', getName : sinon.stub()};
+ mockBusinessNetworkService.deployBusinessNetwork.returns(Promise.resolve());
component.deploy();
tick();
- mockBusinessNetworkService.deployBusinessNetwork.should.have.been.calledWith({network: 'my network'});
+ mockBusinessNetworkService.deployBusinessNetwork.should.have.been.calledWith({network: 'my network', getName : sinon.match.func}, false);
+
component['deployInProgress'].should.equal(false);
- component.modalService.open.should.have.been.called;
+ mockActiveModal.close.should.have.been.called;
}));
it('should handle error', fakeAsync(() => {
@@ -344,27 +347,38 @@ describe('ImportComponent', () => {
componentInstance: {}
});
- component['currentBusinessNetwork'] = {network: 'my network'};
+ component['currentBusinessNetwork'] = {network: 'my network', getName : sinon.stub()};
mockBusinessNetworkService.deployBusinessNetwork.returns(Promise.reject({message: 'some error'}));
component.deploy();
tick();
- mockBusinessNetworkService.deployBusinessNetwork.should.have.been.calledWith({network: 'my network'});
+ mockBusinessNetworkService.deployBusinessNetwork.should.have.been.calledWith({network: 'my network', getName : sinon.match.func});
component['deployInProgress'].should.equal(false);
component.modalService.open.should.have.been.called;
}));
});
describe('deployFromNpm', () => {
- it('should deploy from npm', () => {
+ it('should get sample from npm and deploy', () => {
+ component['sampleNetworks'] = [{name: 'bob'}, {name: 'fred'}];
+ component['chosenNetwork'] = 'fred';
+ component['deployNetwork'] = true;
+
+ component.deployFromNpm();
+
+ mockBusinessNetworkService.deployChosenSample.should.have.been.calledWith({name: 'fred'}, true);
+ });
+
+ it('should get sample from npm and update', () => {
component['sampleNetworks'] = [{name: 'bob'}, {name: 'fred'}];
component['chosenNetwork'] = 'fred';
+ component['deployNetwork'] = false;
component.deployFromNpm();
- mockBusinessNetworkService.deployChosenSample.should.have.been.calledWith({name: 'fred'});
+ mockBusinessNetworkService.deployChosenSample.should.have.been.calledWith({name: 'fred'}, false);
});
it('should deploy the empty business network if chosen', () => {
diff --git a/packages/composer-playground/src/app/editor/import/import.component.ts b/packages/composer-playground/src/app/editor/import/import.component.ts
index 45e24b1f7d..64f4010ef9 100644
--- a/packages/composer-playground/src/app/editor/import/import.component.ts
+++ b/packages/composer-playground/src/app/editor/import/import.component.ts
@@ -1,4 +1,4 @@
-import { Component, OnInit } from '@angular/core';
+import { Component, OnInit, Input } from '@angular/core';
import { NgbActiveModal, NgbModal } from '@ng-bootstrap/ng-bootstrap';
import { AdminService } from '../../services/admin.service';
@@ -20,6 +20,9 @@ const fabricComposerRepository = 'composer-sample-networks';
})
export class ImportComponent implements OnInit {
+ // choose whether to deploy or update the business network
+ @Input() deployNetwork: boolean;
+
private deployInProgress: boolean = false;
private gitHubInProgress: boolean = false;
private sampleNetworks = [];
@@ -40,15 +43,15 @@ export class ImportComponent implements OnInit {
public activeModal: NgbActiveModal,
public modalService: NgbModal,
private sampleBusinessNetworkService: SampleBusinessNetworkService,
- private alertService: AlertService) {
+ private alertService: AlertService,
+ private adminService: AdminService) {
}
ngOnInit(): Promise {
- // TODO: try and do this when we close modal
this.currentBusinessNetwork = null;
- return this.clientService.ensureConnected(false)
+ return this.adminService.connectWithoutNetwork(false)
.then(() => {
this.onShow();
});
@@ -105,14 +108,15 @@ export class ImportComponent implements OnInit {
this.deployInProgress = true;
let deployPromise;
if (this.currentBusinessNetwork) {
- deployPromise = this.sampleBusinessNetworkService.deployBusinessNetwork(this.currentBusinessNetwork);
+ deployPromise = this.sampleBusinessNetworkService.deployBusinessNetwork(this.currentBusinessNetwork, this.deployNetwork);
} else {
deployPromise = this.deployFromNpm();
}
deployPromise.then(() => {
this.deployInProgress = false;
- this.activeModal.close();
+ let deployedBusinessNetwork = this.currentBusinessNetwork ? this.currentBusinessNetwork.getName() : this.chosenNetwork;
+ this.activeModal.close(deployedBusinessNetwork);
})
.catch((error) => {
this.deployInProgress = false;
@@ -174,7 +178,7 @@ export class ImportComponent implements OnInit {
};
let emptyBizNetDef = new BusinessNetworkDefinition('', '', packageJson, readme);
this.currentBusinessNetwork = emptyBizNetDef;
- return this.sampleBusinessNetworkService.deployBusinessNetwork(this.currentBusinessNetwork);
+ return this.sampleBusinessNetworkService.deployBusinessNetwork(this.currentBusinessNetwork, this.deployNetwork);
} else {
@@ -182,7 +186,7 @@ export class ImportComponent implements OnInit {
return sampleNetwork.name === this.chosenNetwork;
});
- return this.sampleBusinessNetworkService.deployChosenSample(chosenSampleNetwork);
+ return this.sampleBusinessNetworkService.deployChosenSample(chosenSampleNetwork, this.deployNetwork);
}
}
diff --git a/packages/composer-playground/src/app/identity/identity.component.spec.ts b/packages/composer-playground/src/app/identity/identity.component.spec.ts
index 29e1ef71e9..0cc97822a9 100644
--- a/packages/composer-playground/src/app/identity/identity.component.spec.ts
+++ b/packages/composer-playground/src/app/identity/identity.component.spec.ts
@@ -266,7 +266,7 @@ describe(`IdentityComponent`, () => {
component['currentIdentity'].should.equal('bob');
mockIdentityService.setCurrentIdentity.should.have.been.calledWith('bob');
- mockClientService.ensureConnected.should.have.been.calledWith(true);
+ mockClientService.ensureConnected.should.have.been.calledWith(null, true);
mockAlertService.busyStatus$.next.should.have.been.calledTwice;
}));
diff --git a/packages/composer-playground/src/app/identity/identity.component.ts b/packages/composer-playground/src/app/identity/identity.component.ts
index 71c889077c..cd7b0f5c4e 100644
--- a/packages/composer-playground/src/app/identity/identity.component.ts
+++ b/packages/composer-playground/src/app/identity/identity.component.ts
@@ -91,7 +91,7 @@ export class IdentityComponent implements OnInit {
this.currentIdentity = newIdentity;
this.alertService.busyStatus$.next({title: 'Reconnecting...', text: 'Using identity ' + this.currentIdentity});
- return this.clientService.ensureConnected(true)
+ return this.clientService.ensureConnected(null, true)
.then(() => {
this.alertService.busyStatus$.next(null);
})
diff --git a/packages/composer-playground/src/app/login/index.ts b/packages/composer-playground/src/app/login/index.ts
new file mode 100644
index 0000000000..69c16441fb
--- /dev/null
+++ b/packages/composer-playground/src/app/login/index.ts
@@ -0,0 +1 @@
+export * from './login.component';
diff --git a/packages/composer-playground/src/app/login/login.component.html b/packages/composer-playground/src/app/login/login.component.html
new file mode 100644
index 0000000000..72759eefb2
--- /dev/null
+++ b/packages/composer-playground/src/app/login/login.component.html
@@ -0,0 +1,58 @@
+
+
+
+
Identities for {{connectionProfile}}
+
+
+
+
+
+
+
+
+
+ {{identity.userId.substring(0,2)}}
+
+
+ {{identity.userId}}
+
+
+
+
+
+
+
+
BUSINESS NETWORK
+
{{identity.businessNetwork}}
+
+
+
+
+
+
+
+
+
diff --git a/packages/composer-playground/src/app/login/login.component.scss b/packages/composer-playground/src/app/login/login.component.scss
new file mode 100644
index 0000000000..13463efd87
--- /dev/null
+++ b/packages/composer-playground/src/app/login/login.component.scss
@@ -0,0 +1,125 @@
+@import '../../assets/styles/base/_colors.scss';
+@import '../../assets/styles/base/_variables.scss';
+
+login {
+ width: 100vw;
+ padding: $space-large $space-medium;
+ background-color: $fourth-highlight;
+
+ .header {
+ margin-bottom: $space-medium;
+ }
+
+ .main-view {
+ overflow-y: auto;
+ height: 80vh;
+ }
+
+ div.connection-profile:first-child {
+ margin-top: 0;
+ }
+
+ div.connection-profile {
+ margin-top: $space-large;
+
+ .connection-profile-buttons {
+ display: inline-block;
+ margin-left: $space-medium;
+ }
+
+ .identities {
+ display: flex;
+ flex-wrap: wrap;
+
+ .identity {
+ background-color: $white;
+ padding: $space-large 0 $space-smedium 0;
+ box-shadow: 3px 6px 15px 0 rgba(0, 0, 0, 0.20);
+ margin-left: $space-large;
+ margin-bottom: $space-large;
+ width: 275px;
+
+ .top-section {
+
+ padding: 0 $space-large;
+
+ & > * {
+ margin-top: $space-medium;
+ }
+
+ .userId-image {
+ background-color: $keyline-highlight;
+ border: 1px solid $keyline-highlight;
+ border-radius: 50%;
+ width: 75px;
+ height: 75px;
+ margin: 0 auto;
+ position: relative;
+
+ span {
+ position: absolute;
+ top: 26px;
+ right: 26px;
+ color: $second-highlight;
+ text-transform: uppercase;
+ }
+ }
+
+ .userId {
+ text-align: center;
+ }
+
+ .action-buttons {
+ display: flex;
+ justify-content: center;
+
+ button:first-child {
+ margin-right: $space-large;
+ }
+
+ svg {
+ fill: $second-highlight;
+ }
+ }
+ }
+
+ .bottom-section {
+
+ & > * {
+ padding: 0 $space-large;
+ text-align: center;
+ }
+
+ .business-network {
+ border-top: 1px solid $fourth-highlight;
+ text-align: center;
+ color: $secondary-text;
+ font-size: x-small;
+ padding-top: $space-medium;
+ }
+
+ .connect {
+ margin-top: $space-medium;
+ border-top: 1px solid $fourth-highlight;
+ text-align: center;
+ padding-top: $space-small;
+
+ button {
+ span {
+ color: $second-highlight;
+ margin-right: $space-smedium;
+ }
+ svg {
+ fill: $second-highlight;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ }
+
+}
+
+
diff --git a/packages/composer-playground/src/app/login/login.component.spec.ts b/packages/composer-playground/src/app/login/login.component.spec.ts
new file mode 100644
index 0000000000..0889ad4847
--- /dev/null
+++ b/packages/composer-playground/src/app/login/login.component.spec.ts
@@ -0,0 +1,153 @@
+/* tslint:disable:no-unused-variable */
+/* tslint:disable:no-unused-expression */
+/* tslint:disable:no-var-requires */
+/* tslint:disable:max-classes-per-file */
+/* tslint:disable:use-host-property-decorator*/
+/* tslint:disable:no-input-rename*/
+/* tslint:disable:member-ordering*/
+import { ComponentFixture, TestBed, fakeAsync, tick } from '@angular/core/testing';
+import { FormsModule } from '@angular/forms';
+import { IdentityService } from '../services/identity.service';
+import { ClientService } from '../services/client.service';
+import { BehaviorSubject } from 'rxjs/Rx';
+
+import { ActivatedRoute, Router, NavigationEnd, NavigationStart } from '@angular/router';
+
+import * as chai from 'chai';
+
+import * as sinon from 'sinon';
+import { ConnectionProfileService } from '../services/connectionprofile.service';
+import { AdminService } from '../services/admin.service';
+import { InitializationService } from '../services/initialization.service';
+
+import { LoginComponent } from './login.component';
+
+let should = chai.should();
+
+class RouterStub {
+
+ // Route.events is Observable
+ private subject = new BehaviorSubject(this.eventParams);
+ public events = this.subject.asObservable();
+
+ // Event parameters
+ private _eventParams;
+ get eventParams() {
+ return this._eventParams;
+ }
+
+ set eventParams(event) {
+ let nav;
+ if (event.nav === 'end') {
+ nav = new NavigationEnd(0, event.url, event.urlAfterRedirects);
+ } else {
+ nav = new NavigationStart(0, event.url);
+ }
+ this._eventParams = nav;
+ this.subject.next(nav);
+ }
+
+ // Route.snapshot.events
+ get snapshot() {
+ return {params: this.events};
+ }
+
+ navigateByUrl(url: string) {
+ return url;
+ }
+
+ navigate = sinon.stub();
+
+}
+
+describe(`LoginComponent`, () => {
+
+ let component: LoginComponent;
+ let fixture: ComponentFixture;
+
+ let mockAdminService;
+ let mockIdentityService;
+ let mockClientService;
+ let mockConnectionProfileService;
+ let mockInitializationService;
+ let routerStub;
+
+ beforeEach(() => {
+
+ mockIdentityService = sinon.createStubInstance(IdentityService);
+ mockClientService = sinon.createStubInstance(ClientService);
+ mockConnectionProfileService = sinon.createStubInstance(ConnectionProfileService);
+ mockAdminService = sinon.createStubInstance(AdminService);
+ mockInitializationService = sinon.createStubInstance(InitializationService);
+
+ routerStub = new RouterStub();
+
+ TestBed.configureTestingModule({
+ imports: [FormsModule],
+ declarations: [
+ LoginComponent
+ ],
+ providers: [
+ {provide: IdentityService, useValue: mockIdentityService},
+ {provide: ClientService, useValue: mockClientService},
+ {provide: ConnectionProfileService, useValue: mockConnectionProfileService},
+ {provide: Router, useValue: routerStub},
+ {provide: AdminService, useValue: mockAdminService},
+ {provide: InitializationService, useValue: mockInitializationService}
+ ]
+ });
+
+ fixture = TestBed.createComponent(LoginComponent);
+
+ component = fixture.componentInstance;
+ });
+
+ describe('ngOnInit', () => {
+ it('should create the component', () => {
+ component.should.be.ok;
+ });
+
+ it('should get all identities', fakeAsync(() => {
+ mockInitializationService.initialize.returns(Promise.resolve());
+ mockConnectionProfileService.getAllProfiles.returns(Promise.resolve({myProfile: {name: 'myProfile'}}));
+
+ mockIdentityService.getIdentities.returns(Promise.resolve(['bob']));
+
+ component.ngOnInit();
+
+ tick();
+
+ mockInitializationService.initialize.should.have.been.called;
+ mockConnectionProfileService.getAllProfiles.should.have.been.called;
+
+ mockIdentityService.getIdentities.should.have.been.calledWith('myProfile');
+
+ component['identities'].should.deep.equal({
+ myProfile: [{
+ userId: 'bob',
+ connectionProfile: 'myProfile',
+ businessNetwork: 'org-acme-biznet'
+ }]});
+ }));
+ });
+
+ describe('changeIdentity', () => {
+ it('should change identity', fakeAsync(() => {
+ let identity = {userId: 'bob', connectionProfile: 'myProfile'};
+ mockAdminService.list.returns(Promise.resolve(['myNetwork']));
+ mockClientService.ensureConnected.returns(Promise.resolve());
+
+ component.changeIdentity(identity);
+
+ tick();
+
+ mockConnectionProfileService.setCurrentConnectionProfile.should.have.been.calledWith('myProfile');
+ mockIdentityService.setCurrentIdentity.should.have.been.calledWith('bob');
+ mockAdminService.list.should.have.been.called;
+ mockClientService.ensureConnected.should.have.been.calledWith('myNetwork', true);
+
+ mockIdentityService.setLoggedIn.should.have.been.calledWith(true);
+ routerStub.navigate.should.have.been.calledWith(['editor']);
+ }));
+ });
+});
diff --git a/packages/composer-playground/src/app/login/login.component.ts b/packages/composer-playground/src/app/login/login.component.ts
new file mode 100644
index 0000000000..de7c489059
--- /dev/null
+++ b/packages/composer-playground/src/app/login/login.component.ts
@@ -0,0 +1,65 @@
+import { Component, OnInit } from '@angular/core';
+import { Router } from '@angular/router';
+import { IdentityService } from '../services/identity.service';
+import { AdminService } from '../services/admin.service';
+import { ConnectionProfileService } from '../services/connectionprofile.service';
+import { ClientService } from '../services/client.service';
+import { InitializationService } from '../services/initialization.service';
+
+@Component({
+ selector: 'login',
+ templateUrl: './login.component.html',
+ styleUrls: [
+ './login.component.scss'.toString()
+ ]
+})
+export class LoginComponent implements OnInit {
+
+ private identities = {};
+ private connectionProfiles = [];
+
+ constructor(private identityService: IdentityService,
+ private router: Router,
+ private adminService: AdminService,
+ private connectionProfileService: ConnectionProfileService,
+ private clientService: ClientService,
+ private initializationService: InitializationService) {
+
+ }
+
+ ngOnInit() {
+ return this.initializationService.initialize()
+ .then(() => {
+ return this.connectionProfileService.getAllProfiles();
+ })
+ .then((profiles) => {
+ this.connectionProfiles = Object.keys(profiles);
+ this.connectionProfiles.forEach((profile) => {
+ this.identities[profile] = [];
+ return this.identityService.getIdentities(profile)
+ .then((identities) => {
+ identities.forEach((identity) => {
+ this.identities[profile].push({
+ userId: identity,
+ connectionProfile: profile,
+ businessNetwork: 'org-acme-biznet'
+ });
+ });
+ });
+ });
+ });
+ }
+
+ changeIdentity(identity): Promise {
+ this.connectionProfileService.setCurrentConnectionProfile(identity.connectionProfile);
+ this.identityService.setCurrentIdentity(identity.userId);
+ return this.adminService.list()
+ .then((businessNetworks) => {
+ return this.clientService.ensureConnected(businessNetworks[0], true);
+ })
+ .then(() => {
+ this.identityService.setLoggedIn(true);
+ return this.router.navigate(['editor']);
+ });
+ }
+}
diff --git a/packages/composer-playground/src/app/services/admin.service.spec.ts b/packages/composer-playground/src/app/services/admin.service.spec.ts
index 3f246580aa..cd77ea70e5 100644
--- a/packages/composer-playground/src/app/services/admin.service.spec.ts
+++ b/packages/composer-playground/src/app/services/admin.service.spec.ts
@@ -66,131 +66,143 @@ describe('AdminService', () => {
}));
});
- describe('ensureConnected', () => {
+ describe('connect', () => {
it('should return if connected', fakeAsync(inject([AdminService], (service: AdminService) => {
service['isConnected'] = true;
- let connectSpy = sinon.spy(service, 'connect');
-
- service.ensureConnected();
+ service.connect('myNetwork');
- connectSpy.should.not.have.been.called;
+ connectionProfileMock.getCurrentConnectionProfile.should.not.have.been.called;
})));
it('should return if connecting', inject([AdminService], (service: AdminService) => {
service['connectingPromise'] = Promise.resolve();
- let connectSpy = sinon.spy(service, 'connect');
-
- service.ensureConnected();
+ service.connect('myNetwork');
- connectSpy.should.not.have.been.called;
+ connectionProfileMock.getCurrentConnectionProfile.should.not.have.been.called;
}));
- it('should connect if not connected', fakeAsync(inject([AdminService], (service: AdminService) => {
- let connectMock = sinon.stub(service, 'connect').returns(Promise.resolve());
- service.ensureConnected(false);
+ it('should connect', fakeAsync(inject([AdminService], (service: AdminService) => {
+ connectionProfileMock.getCurrentConnectionProfile.returns('my profile');
+
+ let mockGetAdminConnection = sinon.stub(service, 'getAdminConnection').returns(adminConnectionMock);
+
+ identityMock.getUserID.returns(Promise.resolve('myId'));
+ identityMock.getUserSecret.returns(Promise.resolve('myPassword'));
+
+ service.connect('myNetwork');
tick();
- connectMock.should.have.been.called;
+ connectionProfileMock.getCurrentConnectionProfile.should.have.been.called;
- service['isConnected'].should.equal(true);
- should.not.exist(service['connectingPromise']);
- })));
+ alertMock.busyStatus$.next.should.have.been.calledWith({
+ title: 'Connecting to Business Network myNetwork',
+ text: 'using connection profile my profile'
+ });
- it('should connect without id if not deployed', fakeAsync(inject([AdminService], (service: AdminService) => {
- let connectMock = sinon.stub(service, 'connect').returns(Promise.reject('error'));
- let connectWithoutMock = sinon.stub(service, 'connectWithOutID').returns(Promise.resolve());
- service['madeItToConnect'] = true;
- service.ensureConnected();
+ identityMock.getUserID.should.have.been.called;
+ identityMock.getUserSecret.should.have.been.called;
- tick();
+ mockGetAdminConnection.should.have.been.called;
- connectMock.should.have.been.called;
- connectWithoutMock.should.have.been.called;
+ adminConnectionMock.connect.should.have.been.calledWith('my profile', 'myId', 'myPassword', 'myNetwork');
service['isConnected'].should.equal(true);
- should.not.exist(service['connectingPromise']);
+ should.not.exist(service['isConnectingPromise']);
+ alertMock.busyStatus$.next.should.have.been.calledWith(null);
})));
- it('should connect without id if not deployed and handle error', fakeAsync(inject([AdminService], (service: AdminService) => {
- let connectMock = sinon.stub(service, 'connect').returns(Promise.reject('error'));
- let connectWithoutMock = sinon.stub(service, 'connectWithOutID').returns(Promise.reject('some error'));
- service['madeItToConnect'] = true;
- service.ensureConnected().then(() => {
- throw new Error('should not get here');
- })
- .catch((error) => {
- error.should.equal('some error');
- });
+ it('should connect if forced', fakeAsync(inject([AdminService], (service: AdminService) => {
+ connectionProfileMock.getCurrentConnectionProfile.returns('my profile');
- tick();
+ let mockGetAdminConnection = sinon.stub(service, 'getAdminConnection').returns(adminConnectionMock);
- alertMock.errorStatus$.next.should.have.been.called;
- connectMock.should.have.been.called;
- connectWithoutMock.should.have.been.called;
+ identityMock.getUserID.returns(Promise.resolve('myId'));
+ identityMock.getUserSecret.returns(Promise.resolve('myPassword'));
- service['isConnected'].should.equal(false);
- should.not.exist(service['connectingPromise']);
- })));
+ service['isConnected'] = true;
- it('should connect and catch error if not made it to connect', fakeAsync(inject([AdminService], (service: AdminService) => {
- let connectMock = sinon.stub(service, 'connect').returns(Promise.reject('some error'));
- service['madeItToConnect'] = false;
- service.ensureConnected().then(() => {
- throw new Error('should not have got here');
- })
- .catch((error) => {
- error.should.equal('some error');
- });
+ service.connect('myNetwork', true);
tick();
- connectMock.should.have.been.called;
- alertMock.errorStatus$.next.should.have.been.called;
- })));
+ connectionProfileMock.getCurrentConnectionProfile.should.have.been.called;
- it('should always connect when forced', fakeAsync(inject([AdminService], (service: AdminService) => {
- service['isConnected'] = true;
- let connectMock = sinon.stub(service, 'connect').returns(Promise.resolve());
- service.ensureConnected(true);
+ alertMock.busyStatus$.next.should.have.been.calledWith({
+ title: 'Connecting to Business Network myNetwork',
+ text: 'using connection profile my profile'
+ });
- tick();
+ identityMock.getUserID.should.have.been.called;
+ identityMock.getUserSecret.should.have.been.called;
+
+ mockGetAdminConnection.should.have.been.called;
- connectMock.should.have.been.called;
+ adminConnectionMock.connect.should.have.been.calledWith('my profile', 'myId', 'myPassword', 'myNetwork');
service['isConnected'].should.equal(true);
- should.not.exist(service['connectingPromise']);
+ should.not.exist(service['isConnectingPromise']);
+ alertMock.busyStatus$.next.should.have.been.calledWith(null);
})));
- });
- describe('connect', () => {
- it('should connect', fakeAsync(inject([AdminService], (service: AdminService) => {
+ it('should handle error', fakeAsync(inject([AdminService], (service: AdminService) => {
connectionProfileMock.getCurrentConnectionProfile.returns('my profile');
+ adminConnectionMock.connect.returns(Promise.reject('some error'));
let mockGetAdminConnection = sinon.stub(service, 'getAdminConnection').returns(adminConnectionMock);
identityMock.getUserID.returns(Promise.resolve('myId'));
identityMock.getUserSecret.returns(Promise.resolve('myPassword'));
- service.connect();
+ service.connect('myNetwork');
tick();
- mockGetAdminConnection.should.have.been.called;
+ connectionProfileMock.getCurrentConnectionProfile.should.have.been.called;
+
+ alertMock.busyStatus$.next.should.have.been.calledWith({
+ title: 'Connecting to Business Network myNetwork',
+ text: 'using connection profile my profile'
+ });
- service['userSecret'].should.equal('myPassword');
- service['userID'].should.equal('myId');
- service['madeItToConnect'].should.equal(true);
+ identityMock.getUserID.should.have.been.called;
+ identityMock.getUserSecret.should.have.been.called;
- adminConnectionMock.connect.should.have.been.calledWith('my profile', 'myId', 'myPassword', 'org-acme-biznet');
+ mockGetAdminConnection.should.have.been.called;
+
+ adminConnectionMock.connect.should.have.been.calledWith('my profile', 'myId', 'myPassword', 'myNetwork');
+ service['isConnected'].should.equal(false);
+ should.not.exist(service['isConnectingPromise']);
+ alertMock.errorStatus$.next.should.have.been.calledWith('some error');
+ alertMock.busyStatus$.next.should.have.been.calledWith(null);
})));
});
- describe('connectWithOutID', () => {
+ describe('connectWithOutNetwork', () => {
+ it('should return if connected', fakeAsync(inject([AdminService], (service: AdminService) => {
+ service['isConnected'] = true;
+
+ service.connectWithoutNetwork();
+
+ connectionProfileMock.getCurrentConnectionProfile.should.not.have.been.called;
+ })));
+
+ it('should return if connecting', inject([AdminService], (service: AdminService) => {
+ service['connectingPromise'] = Promise.resolve();
+
+ service.connectWithoutNetwork();
+
+ connectionProfileMock.getCurrentConnectionProfile.should.not.have.been.called;
+ }));
+
it('should connect without an id', fakeAsync(inject([AdminService], (service: AdminService) => {
+ connectionProfileMock.getCurrentConnectionProfile.returns('myProfile');
+ identityMock.getUserID.returns(Promise.resolve('myUser'));
+ identityMock.getUserSecret.returns(Promise.resolve('mySecret'));
+
let mockGetAdminConnection = sinon.stub(service, 'getAdminConnection').returns(adminConnectionMock);
adminConnectionMock.connect.returns(Promise.resolve());
@@ -200,54 +212,251 @@ describe('AdminService', () => {
adminConnectionMock.deploy.returns(Promise.resolve());
- service['userID'] = 'myUser';
- service['userSecret'] = 'mySecret';
- service['connectionProfile'] = 'myProfile';
-
- service.connectWithOutID();
+ service.connectWithoutNetwork();
tick();
+ connectionProfileMock.getCurrentConnectionProfile.should.have.been.called;
+
+ alertMock.busyStatus$.next.should.have.been.calledWith({
+ title: 'Connecting without a business network',
+ text: 'using connection profile myProfile'
+ });
+
+ identityMock.getUserID.should.have.been.called;
+ identityMock.getUserSecret.should.have.been.called;
+
mockGetAdminConnection.should.have.been.called;
- mockGenerateBusinessNetwork.should.have.been.called;
- adminConnectionMock.deploy.should.have.been.calledWith({name: 'myNetwork'});
- service['initialDeploy'].should.equal(true);
+ adminConnectionMock.connect.should.have.been.calledWith('myProfile', 'myUser', 'mySecret');
- adminConnectionMock.disconnect.should.have.been.called;
- adminConnectionMock.connect.should.have.been.calledWith('myProfile', 'myUser', 'mySecret', 'org-acme-biznet');
+ service['isConnected'].should.equal(true);
+ should.not.exist(service['isConnectingPromise']);
+ alertMock.busyStatus$.next.should.have.been.calledWith(null);
})));
- it('should connect without an id but not deploy as already deployed', fakeAsync(inject([AdminService], (service: AdminService) => {
- adminConnectionMock.connect.returns(Promise.resolve());
- adminConnectionMock.list.returns(Promise.resolve(['org-acme-biznet']));
+ it('should connect if forced', fakeAsync(inject([AdminService], (service: AdminService) => {
+ connectionProfileMock.getCurrentConnectionProfile.returns('myProfile');
+ identityMock.getUserID.returns(Promise.resolve('myUser'));
+ identityMock.getUserSecret.returns(Promise.resolve('mySecret'));
let mockGetAdminConnection = sinon.stub(service, 'getAdminConnection').returns(adminConnectionMock);
+ adminConnectionMock.connect.returns(Promise.resolve());
+ adminConnectionMock.list.returns(Promise.resolve([]));
+
let mockGenerateBusinessNetwork = sinon.stub(service, 'generateDefaultBusinessNetwork').returns({name: 'myNetwork'});
adminConnectionMock.deploy.returns(Promise.resolve());
- service['userID'] = 'myUser';
- service['userSecret'] = 'mySecret';
- service['connectionProfile'] = 'myProfile';
+ service['isConnected'] = true;
- service.connectWithOutID();
+ service.connectWithoutNetwork(true);
tick();
+ connectionProfileMock.getCurrentConnectionProfile.should.have.been.called;
+
+ alertMock.busyStatus$.next.should.have.been.calledWith({
+ title: 'Connecting without a business network',
+ text: 'using connection profile myProfile'
+ });
+
+ identityMock.getUserID.should.have.been.called;
+ identityMock.getUserSecret.should.have.been.called;
+
mockGetAdminConnection.should.have.been.called;
- mockGenerateBusinessNetwork.should.not.have.been.called;
+ adminConnectionMock.connect.should.have.been.calledWith('myProfile', 'myUser', 'mySecret');
+
+ service['isConnected'].should.equal(true);
+ should.not.exist(service['isConnectingPromise']);
+ alertMock.busyStatus$.next.should.have.been.calledWith(null);
+ })));
+
+ it('should handle error', fakeAsync(inject([AdminService], (service: AdminService) => {
+ connectionProfileMock.getCurrentConnectionProfile.returns('myProfile');
+ identityMock.getUserID.returns(Promise.resolve('myUser'));
+ identityMock.getUserSecret.returns(Promise.resolve('mySecret'));
+
+ let mockGetAdminConnection = sinon.stub(service, 'getAdminConnection').returns(adminConnectionMock);
+
+ adminConnectionMock.connect.returns(Promise.reject('some error'));
+ adminConnectionMock.list.returns(Promise.resolve([]));
+
+ let mockGenerateBusinessNetwork = sinon.stub(service, 'generateDefaultBusinessNetwork').returns({name: 'myNetwork'});
+
+ adminConnectionMock.deploy.returns(Promise.resolve());
+
+ service.connectWithoutNetwork();
+
+ tick();
+
+ connectionProfileMock.getCurrentConnectionProfile.should.have.been.called;
+
+ alertMock.busyStatus$.next.should.have.been.calledWith({
+ title: 'Connecting without a business network',
+ text: 'using connection profile myProfile'
+ });
+
+ identityMock.getUserID.should.have.been.called;
+ identityMock.getUserSecret.should.have.been.called;
+
+ mockGetAdminConnection.should.have.been.called;
+
+ adminConnectionMock.connect.should.have.been.calledWith('myProfile', 'myUser', 'mySecret');
+
+ service['isConnected'].should.equal(false);
+ should.not.exist(service['isConnectingPromise']);
+ alertMock.errorStatus$.next.should.have.been.calledWith('some error');
+ alertMock.busyStatus$.next.should.have.been.calledWith(null);
+ })));
+ });
+
+ describe('createNewBusinessNetwork', () => {
+ it('should create a new business network', fakeAsync(inject([AdminService], (service: AdminService) => {
+
+ let stubList = sinon.stub(service, 'list').returns(Promise.resolve(['anotherNetwork']));
+ connectionProfileMock.getCurrentConnectionProfile.returns('myProfile');
+ identityMock.getUserID.returns(Promise.resolve('myUser'));
+ identityMock.getUserSecret.returns(Promise.resolve('mySecret'));
+
+ let mockGetAdminConnection = sinon.stub(service, 'getAdminConnection').returns(adminConnectionMock);
+
+ adminConnectionMock.connect.returns(Promise.resolve());
+ adminConnectionMock.deploy.returns(Promise.resolve());
+
+ let stubGenerateBusinessNetwork = sinon.stub(service, 'generateDefaultBusinessNetwork').returns({name: 'myNetwork'});
+
+ service.createNewBusinessNetwork('myNetwork', 'myDescription');
+
+ tick();
+
+ alertMock.busyStatus$.next.should.have.been.calledWith({
+ title: 'Checking Business Network',
+ text: 'checking if myNetwork exists'
+ });
+
+ stubList.should.have.been.called;
+
+ alertMock.busyStatus$.next.should.have.been.calledWith({
+ title: 'Creating Business Network',
+ text: 'creating business network myNetwork'
+ });
+
+ connectionProfileMock.getCurrentConnectionProfile.should.have.been.called;
+
+ identityMock.getUserID.should.have.been.called;
+ identityMock.getUserSecret.should.have.been.called;
+
+ adminConnectionMock.connect.should.have.been.calledWith('myProfile', 'myUser', 'mySecret');
+
+ stubGenerateBusinessNetwork.should.have.been.calledWith('myNetwork', 'myDescription');
+
+ adminConnectionMock.deploy.should.have.been.calledWith({name: 'myNetwork'});
adminConnectionMock.disconnect.should.have.been.called;
- adminConnectionMock.connect.should.have.been.calledWith('myProfile', 'myUser', 'mySecret', 'org-acme-biznet');
+
+ alertMock.busyStatus$.next.should.have.been.calledWith({
+ title: 'Connecting to Business Network myNetwork',
+ text: 'using connection profile, connectionProfile'
+ });
+
+ adminConnectionMock.connect.should.have.been.calledWith('myProfile', 'myUser', 'mySecret', 'myNetwork');
+
+ alertMock.busyStatus$.next.should.have.been.calledWith(null);
+ })));
+
+ it('should not create if name already exists', fakeAsync(inject([AdminService], (service: AdminService) => {
+
+ let stubList = sinon.stub(service, 'list').returns(Promise.resolve(['myNetwork']));
+
+ let mockGetAdminConnection = sinon.stub(service, 'getAdminConnection').returns(adminConnectionMock);
+
+ adminConnectionMock.connect.returns(Promise.resolve());
+ adminConnectionMock.deploy.returns(Promise.resolve());
+
+ let stubGenerateBusinessNetwork = sinon.stub(service, 'generateDefaultBusinessNetwork').returns({name: 'myNetwork'});
+
+ service.createNewBusinessNetwork('myNetwork', 'myDescription')
+ .then(() => {
+ throw new Error('should not have got here');
+ })
+ .catch((error) => {
+ error.message.should.equal('businessNetwork with name myNetwork already exists');
+ });
+
+ tick();
+
+ alertMock.busyStatus$.next.should.have.been.calledWith({
+ title: 'Checking Business Network',
+ text: 'checking if myNetwork exists'
+ });
+
+ stubList.should.have.been.called;
+
+ connectionProfileMock.getCurrentConnectionProfile.should.not.have.been.called;
+
+ identityMock.getUserID.should.not.have.been.called;
+ identityMock.getUserSecret.should.not.have.been.called;
+
+ adminConnectionMock.connect.should.not.have.been.called;
+
+ stubGenerateBusinessNetwork.should.not.have.been.called;
+
+ adminConnectionMock.deploy.should.not.have.been.called;
+
+ adminConnectionMock.disconnect.should.not.have.been.called;
+
+ alertMock.busyStatus$.next.should.have.been.calledWith(null);
})));
+
+ it('should handle error', fakeAsync(inject([AdminService], (service: AdminService) => {
+
+ let stubList = sinon.stub(service, 'list').returns(Promise.reject(new Error('some error')));
+
+ let mockGetAdminConnection = sinon.stub(service, 'getAdminConnection').returns(adminConnectionMock);
+
+ adminConnectionMock.connect.returns(Promise.resolve());
+ adminConnectionMock.deploy.returns(Promise.resolve());
+
+ let stubGenerateBusinessNetwork = sinon.stub(service, 'generateDefaultBusinessNetwork').returns({name: 'myNetwork'});
+
+ service.createNewBusinessNetwork('myNetwork', 'myDescription');
+
+ tick();
+
+ alertMock.busyStatus$.next.should.have.been.calledWith({
+ title: 'Checking Business Network',
+ text: 'checking if myNetwork exists'
+ });
+
+ stubList.should.have.been.called;
+
+ connectionProfileMock.getCurrentConnectionProfile.should.not.have.been.called;
+
+ identityMock.getUserID.should.not.have.been.called;
+ identityMock.getUserSecret.should.not.have.been.called;
+
+ adminConnectionMock.connect.should.not.have.been.called;
+
+ stubGenerateBusinessNetwork.should.not.have.been.called;
+
+ adminConnectionMock.deploy.should.not.have.been.called;
+
+ adminConnectionMock.disconnect.should.not.have.been.called;
+
+ alertMock.busyStatus$.next.should.have.been.calledWith(null);
+
+ alertMock.errorStatus$.next.should.have.been.called;
+ })));
+
});
describe('deploy', () => {
it('should deploy a business network', fakeAsync(inject([AdminService], (service: AdminService) => {
- let connectedMock = sinon.stub(service, 'ensureConnected').returns(Promise.resolve());
+ let connectedMock = sinon.stub(service, 'connect').returns(Promise.resolve());
+ businessNetworkDefMock.getName.returns('myNetwork');
service['adminConnection'] = adminConnectionMock;
@@ -255,22 +464,19 @@ describe('AdminService', () => {
tick();
- connectedMock.should.have.been.called;
+ connectedMock.should.have.been.calledWith('myNetwork');
adminConnectionMock.deploy.should.have.been.calledWith(businessNetworkDefMock);
})));
});
describe('update', () => {
it('should update a business network', fakeAsync(inject([AdminService], (service: AdminService) => {
- let connectedMock = sinon.stub(service, 'ensureConnected').returns(Promise.resolve());
-
service['adminConnection'] = adminConnectionMock;
service.update(businessNetworkDefMock);
tick();
- connectedMock.should.have.been.called;
adminConnectionMock.update.should.have.been.calledWith(businessNetworkDefMock);
})));
});
@@ -284,4 +490,47 @@ describe('AdminService', () => {
service['initialDeploy'].should.equal(false);
}));
});
+
+ describe('list', () => {
+ it('should list the business networks', fakeAsync(inject([AdminService], (service: AdminService) => {
+ connectionProfileMock.getCurrentConnectionProfile.returns('myProfile');
+ identityMock.getUserID.returns(Promise.resolve('myUserId'));
+ identityMock.getUserSecret.returns(Promise.resolve('mySecret'));
+
+ let mockGetAdminConnection = sinon.stub(service, 'getAdminConnection').returns(adminConnectionMock);
+
+ adminConnectionMock.connect.returns(Promise.resolve());
+ adminConnectionMock.list.returns(Promise.resolve(['myNetwork']));
+
+ let disconnectStub = sinon.stub(service, 'disconnect');
+
+ service.list().then((networks) => {
+ networks.should.deep.equal(['myNetwork']);
+ });
+
+ tick();
+
+ connectionProfileMock.getCurrentConnectionProfile.should.have.been.called;
+ identityMock.getUserID.should.have.been.called;
+ identityMock.getUserSecret.should.have.been.called;
+
+ adminConnectionMock.connect.should.have.been.calledWith('myProfile', 'myUserId', 'mySecret');
+ adminConnectionMock.list.should.have.been.called;
+
+ disconnectStub.should.have.been.called;
+ })));
+ });
+
+ describe('disconnect', () => {
+ it('should disconnect', inject([AdminService], (service: AdminService) => {
+ service['isConnected'] = true;
+
+ let mockGetAdminConnection = sinon.stub(service, 'getAdminConnection').returns(adminConnectionMock);
+
+ service.disconnect();
+
+ service['isConnected'].should.equal(false);
+ adminConnectionMock.disconnect.should.have.been.called;
+ }));
+ });
});
diff --git a/packages/composer-playground/src/app/services/admin.service.ts b/packages/composer-playground/src/app/services/admin.service.ts
index 56dad51466..c2eda8483c 100644
--- a/packages/composer-playground/src/app/services/admin.service.ts
+++ b/packages/composer-playground/src/app/services/admin.service.ts
@@ -1,5 +1,4 @@
import { Injectable } from '@angular/core';
-import { BehaviorSubject, Subject } from 'rxjs/Rx';
import { ConnectionProfileService } from './connectionprofile.service';
import { IdentityService } from './identity.service';
import { AlertService } from '../basic-modals/alert.service';
@@ -11,15 +10,11 @@ import WebConnectionManager = require('composer-connector-web');
@Injectable()
export class AdminService {
private adminConnection: AdminConnection = null;
+
private isConnected: boolean = false;
private connectingPromise: Promise = null;
- private initialDeploy: boolean = false;
- private madeItToConnect = false;
- private connectionProfile;
- private userID;
- private userSecret;
- private deployed = false;
+ private initialDeploy: boolean = false;
constructor(private connectionProfileService: ConnectionProfileService,
private identityService: IdentityService,
@@ -40,7 +35,7 @@ export class AdminService {
ConnectionProfileManager.registerConnectionManager('web', WebConnectionManager);
}
- getAdminConnection() {
+ getAdminConnection(): AdminConnection {
if (!this.adminConnection) {
this.adminConnection = new AdminConnection();
}
@@ -48,7 +43,7 @@ export class AdminService {
return this.adminConnection;
}
- public ensureConnected(force: boolean = false): Promise {
+ connect(businessNetworkName: string, force = false): Promise {
if (this.isConnected && !force) {
return Promise.resolve();
} else if (this.connectingPromise) {
@@ -56,96 +51,185 @@ export class AdminService {
}
console.log('Establishing admin connection ...');
- this.connectingPromise = Promise.resolve()
- .then(() => {
- return this.connect();
- })
- .catch((error) => {
- // If we didn't make it to connect, then the business network is probably not deployed.
- // Try again with a admin connection with no business network specified so we can deploy it.
- if (!this.madeItToConnect) {
- throw error;
- }
- return this.connectWithOutID();
+ let connectionProfile = this.connectionProfileService.getCurrentConnectionProfile();
+
+ this.alertService.busyStatus$.next({
+ title: 'Connecting to Business Network ' + businessNetworkName,
+ text: 'using connection profile ' + connectionProfile
+ });
+
+ let userID;
+ this.connectingPromise = this.identityService.getUserID()
+ .then((userId) => {
+ userID = userId;
+ return this.identityService.getUserSecret();
+ })
+ .then((userSecret) => {
+ console.log('Connecting to business network %s with connection profile %s with id %s', businessNetworkName, connectionProfile, userID);
+ return this.getAdminConnection().connect(connectionProfile, userID, userSecret, businessNetworkName);
})
.then(() => {
- console.log('Connected');
this.isConnected = true;
this.connectingPromise = null;
+ this.alertService.busyStatus$.next(null);
})
.catch((error) => {
- this.alertService.errorStatus$.next(`Failed to connect: ${error}`);
- this.isConnected = false;
this.connectingPromise = null;
- throw error;
+ this.alertService.busyStatus$.next(null);
+ this.alertService.errorStatus$.next(error);
});
+
return this.connectingPromise;
}
- connect(): Promise {
- this.connectionProfile = this.connectionProfileService.getCurrentConnectionProfile();
- console.log('Connecting to connection profile (w/ business network ID)', this.connectionProfile);
- return this.identityService.getUserID()
+ connectWithoutNetwork(force = false) {
+ if (this.isConnected && !force) {
+ return Promise.resolve();
+ } else if (this.connectingPromise) {
+ return this.connectingPromise;
+ }
+
+ console.log('Establishing admin connection ...');
+
+ let connectionProfile = this.connectionProfileService.getCurrentConnectionProfile();
+
+ this.alertService.busyStatus$.next({
+ title: 'Connecting without a business network',
+ text: 'using connection profile ' + connectionProfile
+ });
+
+ let userID;
+ this.connectingPromise = this.identityService.getUserID()
.then((userId) => {
- this.userID = userId;
+ userID = userId;
return this.identityService.getUserSecret();
})
.then((userSecret) => {
- this.userSecret = userSecret;
- this.madeItToConnect = true;
- return this.getAdminConnection().connect(this.connectionProfile, this.userID, this.userSecret, 'org-acme-biznet');
+ console.log('Connecting with connection profile %s with id %s', connectionProfile, userID);
+ return this.getAdminConnection().connect(connectionProfile, userID, userSecret);
+ })
+ .then(() => {
+ this.isConnected = true;
+ this.connectingPromise = null;
+ this.alertService.busyStatus$.next(null);
+ })
+ .catch((error) => {
+ this.connectingPromise = null;
+ this.alertService.busyStatus$.next(null);
+ this.alertService.errorStatus$.next(error);
});
+
+ return this.connectingPromise;
+
}
- connectWithOutID(): Promise {
- console.log('Connecting to connection profile (w/o business network ID)', this.connectionProfile);
- return this.getAdminConnection().connect(this.connectionProfile, this.userID, this.userSecret)
- .then(() => {
- return this.getAdminConnection().list();
- })
+ public createNewBusinessNetwork(name: string, description: string): Promise {
+ this.alertService.busyStatus$.next({
+ title: 'Checking Business Network',
+ text: 'checking if ' + name + ' exists'
+ });
+
+ let userSecret;
+ let connectionProfile;
+ let userId;
+ return this.list()
.then((businessNetworks) => {
- console.log('Got business networks', businessNetworks);
- this.deployed = businessNetworks.some((businessNetwork) => {
- return businessNetwork === 'org-acme-biznet';
+ // check if business network already exists
+ let deployed = businessNetworks.some((businessNetwork) => {
+ return businessNetwork === name;
});
- if (!this.deployed) {
- this.alertService.busyStatus$.next({
- title: 'Creating Business Network',
- text: 'creating business network org-acme-biznet'
- });
- let businessNetworkDefinition = this.generateDefaultBusinessNetwork();
- return this.getAdminConnection().deploy(businessNetworkDefinition)
- .then(() => {
- this.initialDeploy = true;
- });
+ if (deployed) {
+ this.initialDeploy = false;
+ this.alertService.busyStatus$.next(null);
+ throw Error('businessNetwork with name ' + name + ' already exists');
}
+
+ this.alertService.busyStatus$.next({
+ title: 'Creating Business Network',
+ text: 'creating business network ' + name
+ });
+ connectionProfile = this.connectionProfileService.getCurrentConnectionProfile();
+ return this.identityService.getUserID();
+ })
+ .then((userID) => {
+ userId = userID;
+ return this.identityService.getUserSecret();
+ })
+ .then((secret) => {
+ userSecret = secret;
+ return this.getAdminConnection().connect(connectionProfile, userId, userSecret);
})
.then(() => {
+ let businessNetworkDefinition = this.generateDefaultBusinessNetwork(name, description);
+ return this.getAdminConnection().deploy(businessNetworkDefinition);
+ })
+ .then(() => {
+ this.initialDeploy = true;
return this.getAdminConnection().disconnect();
})
.then(() => {
- console.log('Connecting to connection profile (w/ business network ID)', this.connectionProfile);
- return this.getAdminConnection().connect(this.connectionProfile, this.userID, this.userSecret, 'org-acme-biznet');
- });
- }
+ this.alertService.busyStatus$.next({
+ title: 'Connecting to Business Network ' + name,
+ text: 'using connection profile, connectionProfile'
+ });
- public deploy(businessNetworkDefinition: BusinessNetworkDefinition): Promise {
- return this.ensureConnected()
+ console.log('Connecting to business network %s with connection profile %s with id %s', name, connectionProfile, userId);
+ return this.getAdminConnection().connect(connectionProfile, userId, userSecret, name);
+ })
.then(() => {
- return this.adminConnection.deploy(businessNetworkDefinition);
+ this.alertService.busyStatus$.next(null);
+ })
+ .catch((error) => {
+ this.alertService.busyStatus$.next(null);
+ if (error.message.startsWith('businessNetwork with name')) {
+ throw error;
+ } else {
+ this.alertService.errorStatus$.next(error);
+ }
});
}
- public update(businessNetworkDefinition: BusinessNetworkDefinition): Promise {
- return this.ensureConnected()
+ public list(): Promise {
+ let connectionProfile = this.connectionProfileService.getCurrentConnectionProfile();
+ let userId;
+ let userSecret;
+ return this.identityService.getUserID()
+ .then((userID) => {
+ userId = userID;
+ return this.identityService.getUserSecret();
+ })
+ .then((secret) => {
+ userSecret = secret;
+ return this.getAdminConnection().connect(connectionProfile, userId, userSecret);
+ })
.then(() => {
- return this.adminConnection.update(businessNetworkDefinition);
+ return this.getAdminConnection().list();
+ })
+ .then((businessNetworks) => {
+ this.disconnect();
+ return businessNetworks;
});
}
- generateDefaultBusinessNetwork(): BusinessNetworkDefinition {
- let businessNetworkDefinition = new BusinessNetworkDefinition('org-acme-biznet@0.0.1', 'Acme Business Network');
+ public disconnect(): void {
+ this.isConnected = false;
+ this.getAdminConnection().disconnect();
+ }
+
+ public deploy(businessNetworkDefinition: BusinessNetworkDefinition): Promise {
+ return this.connect(businessNetworkDefinition.getName()).then(() => {
+ return this.getAdminConnection().deploy(businessNetworkDefinition);
+ });
+
+ }
+
+ public update(businessNetworkDefinition: BusinessNetworkDefinition): Promise {
+ return this.getAdminConnection().update(businessNetworkDefinition);
+ }
+
+ generateDefaultBusinessNetwork(name: string, description: string): BusinessNetworkDefinition {
+ let businessNetworkDefinition = new BusinessNetworkDefinition(name + '@0.0.1', description);
return businessNetworkDefinition;
}
diff --git a/packages/composer-playground/src/app/services/client.service.spec.ts b/packages/composer-playground/src/app/services/client.service.spec.ts
index 8af39d2509..a4b614aa1b 100644
--- a/packages/composer-playground/src/app/services/client.service.spec.ts
+++ b/packages/composer-playground/src/app/services/client.service.spec.ts
@@ -17,6 +17,7 @@ import { BusinessNetworkDefinition, ModelFile, Script, AclFile } from 'composer-
import { ConnectionProfileService } from './connectionprofile.service';
import { BusinessNetworkConnection } from 'composer-client';
import { IdentityService } from './identity.service';
+import { LocalStorageService } from 'angular-2-local-storage';
describe('ClientService', () => {
@@ -31,6 +32,7 @@ describe('ClientService', () => {
let modelFileMock;
let scriptFileMock;
let aclFileMock;
+ let mockLocalStorage;
beforeEach(() => {
sandbox = sinon.sandbox.create();
@@ -44,6 +46,7 @@ describe('ClientService', () => {
modelFileMock = sinon.createStubInstance(ModelFile);
scriptFileMock = sinon.createStubInstance(Script);
aclFileMock = sinon.createStubInstance(AclFile);
+ mockLocalStorage = sinon.createStubInstance(LocalStorageService);
alertMock.errorStatus$ = {next: sinon.stub()};
alertMock.busyStatus$ = {next: sinon.stub()};
@@ -53,7 +56,8 @@ describe('ClientService', () => {
{provide: AdminService, useValue: adminMock},
{provide: AlertService, useValue: alertMock},
{provide: ConnectionProfileService, useValue: connectionProfileMock},
- {provide: IdentityService, useValue: identityMock}]
+ {provide: IdentityService, useValue: identityMock},
+ {provide: LocalStorageService, useValue: mockLocalStorage}]
});
});
@@ -705,9 +709,9 @@ describe('ClientService', () => {
it('should return if connected when not forced', fakeAsync(inject([ClientService], (service: ClientService) => {
service['isConnected'] = true;
- service.ensureConnected(false);
+ service.ensureConnected();
- connectionProfileMock.getCurrentConnectionProfile.should.not.have.been.called;
+ identityMock.getUserID.should.not.have.been.called;
})));
it('should return if connecting', fakeAsync(inject([ClientService], (service: ClientService) => {
@@ -715,76 +719,132 @@ describe('ClientService', () => {
service.ensureConnected();
- connectionProfileMock.getCurrentConnectionProfile.should.not.have.been.called;
+ identityMock.getUserID.should.not.have.been.called;
})));
- it('should connect if not connected and deploy sample', fakeAsync(inject([ClientService], (service: ClientService) => {
+ it('should connect if not connected', fakeAsync(inject([ClientService], (service: ClientService) => {
+
+ identityMock.getUserID.returns(Promise.resolve('myId'));
+
connectionProfileMock.getCurrentConnectionProfile.returns('myProfile');
- adminMock.ensureConnected.returns(Promise.resolve());
+ adminMock.connect.returns(Promise.resolve());
let refreshMock = sinon.stub(service, 'refresh').returns(Promise.resolve());
+ let setBusinessNetworkMock = sinon.stub(service, 'setSavedBusinessNetworkName');
- adminMock.isInitialDeploy.returns(true);
+ let businessNetworkNameMock = sinon.stub(service, 'getBusinessNetworkName').returns('myNetwork');
- let deployInitialSample = sinon.stub(service, 'deployInitialSample');
-
- service.ensureConnected(false);
+ service.ensureConnected(null, false);
tick();
+ identityMock.getUserID.should.have.been.called;
+
connectionProfileMock.getCurrentConnectionProfile.should.have.been.called;
- adminMock.ensureConnected.should.have.been.calledWith(false);
- refreshMock.should.have.been.called;
alertMock.busyStatus$.next.should.have.been.calledTwice;
alertMock.busyStatus$.next.firstCall.should.have.been.calledWith({
title: 'Establishing connection',
text: 'Using the connection profile myProfile'
});
+ adminMock.connect.should.have.been.calledWith('myNetwork', false);
+
+ refreshMock.should.have.been.calledWith('myNetwork');
+
alertMock.busyStatus$.next.secondCall.should.have.been.calledWith(null);
+ setBusinessNetworkMock.should.have.been.calledWith('myId');
+
service['isConnected'].should.equal(true);
should.not.exist(service['connectingPromise']);
+ })));
+
+ it('should connect if not connected to specified business network', fakeAsync(inject([ClientService], (service: ClientService) => {
+
+ identityMock.getUserID.returns(Promise.resolve('myId'));
+
+ connectionProfileMock.getCurrentConnectionProfile.returns('myProfile');
+ adminMock.connect.returns(Promise.resolve());
+ let refreshMock = sinon.stub(service, 'refresh').returns(Promise.resolve());
+ let setBusinessNetworkMock = sinon.stub(service, 'setSavedBusinessNetworkName');
+
+ let businessNetworkNameMock = sinon.stub(service, 'getBusinessNetworkName');
+
+ service.ensureConnected('myNetwork', false);
+
+ tick();
+
+ identityMock.getUserID.should.have.been.called;
+
+ connectionProfileMock.getCurrentConnectionProfile.should.have.been.called;
+
+ alertMock.busyStatus$.next.should.have.been.calledTwice;
+ alertMock.busyStatus$.next.firstCall.should.have.been.calledWith({
+ title: 'Establishing connection',
+ text: 'Using the connection profile myProfile'
+ });
- deployInitialSample.should.have.been.called;
+ adminMock.connect.should.have.been.calledWith('myNetwork', false);
+
+ refreshMock.should.have.been.calledWith('myNetwork');
+
+ alertMock.busyStatus$.next.secondCall.should.have.been.calledWith(null);
+
+ setBusinessNetworkMock.should.have.been.called;
+
+ businessNetworkNameMock.should.not.have.been.called;
+
+ service['isConnected'].should.equal(true);
+ should.not.exist(service['connectingPromise']);
})));
- it('should connect if not connected and not deploy sample if already deployed', fakeAsync(inject([ClientService], (service: ClientService) => {
+ it('should connect if not connected with business network from local storage', fakeAsync(inject([ClientService], (service: ClientService) => {
+
+ identityMock.getUserID.returns(Promise.resolve('myId'));
+
connectionProfileMock.getCurrentConnectionProfile.returns('myProfile');
- adminMock.ensureConnected.returns(Promise.resolve());
+ adminMock.connect.returns(Promise.resolve());
let refreshMock = sinon.stub(service, 'refresh').returns(Promise.resolve());
- adminMock.isInitialDeploy.returns(false);
+ let setBusinessNetworkMock = sinon.stub(service, 'setSavedBusinessNetworkName');
+ let getBusinessNetworkMock = sinon.stub(service, 'getSavedBusinessNetworkName').returns('myNetwork');
- let deployInitialSample = sinon.stub(service, 'deployInitialSample');
+ let businessNetworkNameMock = sinon.stub(service, 'getBusinessNetworkName').throws();
- service.ensureConnected(false);
+ service.ensureConnected(null, false);
tick();
+ identityMock.getUserID.should.have.been.called;
+
connectionProfileMock.getCurrentConnectionProfile.should.have.been.called;
- adminMock.ensureConnected.should.have.been.calledWith(false);
- refreshMock.should.have.been.called;
alertMock.busyStatus$.next.should.have.been.calledTwice;
alertMock.busyStatus$.next.firstCall.should.have.been.calledWith({
title: 'Establishing connection',
text: 'Using the connection profile myProfile'
});
+ getBusinessNetworkMock.should.have.been.calledWith('myId');
+
+ adminMock.connect.should.have.been.calledWith('myNetwork', false);
+
+ refreshMock.should.have.been.calledWith('myNetwork');
+
alertMock.busyStatus$.next.secondCall.should.have.been.calledWith(null);
+ setBusinessNetworkMock.should.have.been.calledWith('myId');
+
service['isConnected'].should.equal(true);
should.not.exist(service['connectingPromise']);
-
- deployInitialSample.should.not.have.been.called;
})));
it('should send alert if error thrown', fakeAsync(inject([ClientService], (service: ClientService) => {
- adminMock.ensureConnected.returns(Promise.resolve());
+ identityMock.getUserID.returns(Promise.resolve('myId'));
+ adminMock.connect.returns(Promise.resolve());
let refreshMock = sinon.stub(service, 'refresh').returns(Promise.reject('forced error'));
- service.ensureConnected(false)
+ service.ensureConnected('myNetwork', false)
.then(() => {
throw new Error('should not get here');
})
@@ -796,11 +856,12 @@ describe('ClientService', () => {
})));
it('should set connection variables if error thrown', fakeAsync(inject([ClientService], (service: ClientService) => {
- adminMock.ensureConnected.returns(Promise.resolve());
+ identityMock.getUserID.returns(Promise.resolve('myId'));
+ adminMock.connect.returns(Promise.resolve());
let refreshMock = sinon.stub(service, 'refresh').returns(Promise.reject('forced error'));
alertMock.errorStatus$ = {next: sinon.stub()};
- service.ensureConnected(false)
+ service.ensureConnected('myNetwork', false)
.then(() => {
throw new Error('should not get here');
})
@@ -819,15 +880,16 @@ describe('ClientService', () => {
let businessNetworkConnectionMock = sinon.stub(service, 'getBusinessNetworkConnection').returns(businessNetworkConMock);
connectionProfileMock.getCurrentConnectionProfile.returns('myProfile');
businessNetworkConMock.disconnect.returns(Promise.resolve());
- identityMock.getUserID.returns(Promise.resolve());
- identityMock.getUserSecret.returns(Promise.resolve());
+ identityMock.getUserID.returns(Promise.resolve('myUser'));
+ identityMock.getUserSecret.returns(Promise.resolve('mySecret'));
- service.refresh();
+ service.refresh('myNetwork');
tick();
businessNetworkConMock.disconnect.should.have.been.calledOnce;
businessNetworkConMock.connect.should.have.been.calledOnce;
+ businessNetworkConMock.connect.should.have.been.calledWith('myProfile', 'myNetwork', 'myUser', 'mySecret');
alertMock.busyStatus$.next.should.have.been.calledWith({
title: 'Refreshing Connection',
text: 'refreshing the connection to myProfile'
@@ -853,12 +915,56 @@ describe('ClientService', () => {
describe('it should deployInitial sample', () => {
it('should deploy the initial sample', fakeAsync(inject([ClientService], (service: ClientService) => {
- alertMock.busyStatus$ = {next: sinon.stub()};
+ let resetMock = sinon.stub(service, 'reset');
+
+ adminMock.createNewBusinessNetwork.returns(Promise.resolve());
+ adminMock.isInitialDeploy.returns(true);
+
+ let businessNetworkMock = sinon.stub(service, 'getBusinessNetworkConnection').returns(businessNetworkConMock);
+ let businessNetworkFromArchiveMock = sandbox.stub(BusinessNetworkDefinition, 'fromArchive').returns(Promise.resolve({
+ name: 'bob',
+ getName: sinon.stub().returns('myNetwork'),
+ getDescription: sinon.stub().returns('myDescription')
+ }));
+
+ service.deployInitialSample();
- let refreshMock = sinon.stub(service, 'refresh');
+ alertMock.busyStatus$.next.should.have.been.calledWith({
+ title: 'Deploying Business Network',
+ text: 'deploying sample business network'
+ });
+
+ tick();
+
+ businessNetworkFromArchiveMock.should.have.been.called;
+
+ adminMock.createNewBusinessNetwork.should.have.been.calledWith('myNetwork', 'myDescription');
+
+ adminMock.isInitialDeploy.should.have.been.called;
+
+ adminMock.update.should.have.been.calledWith({
+ name: 'bob',
+ getName: sinon.match.func,
+ getDescription: sinon.match.func
+ });
+ resetMock.should.have.been.called;
+
+ businessNetworkConMock.disconnect.should.have.been.called;
+ businessNetworkConMock.connect.should.have.been.calledWith('$default', 'myNetwork', 'admin', 'adminpw');
+ })));
+
+ it('should not deploy if already deployed', fakeAsync(inject([ClientService], (service: ClientService) => {
let resetMock = sinon.stub(service, 'reset');
- let businessNetworkFromArchiveMock = sandbox.stub(BusinessNetworkDefinition, 'fromArchive').returns(Promise.resolve({name: 'bob'}));
+ adminMock.createNewBusinessNetwork.returns(Promise.reject({message: 'businessNetwork with name myNetwork already exists'}));
+ adminMock.isInitialDeploy.returns(false);
+
+ let businessNetworkMock = sinon.stub(service, 'getBusinessNetworkConnection').returns(businessNetworkConMock);
+ let businessNetworkFromArchiveMock = sandbox.stub(BusinessNetworkDefinition, 'fromArchive').returns(Promise.resolve({
+ name: 'bob',
+ getName: sinon.stub().returns('myNetwork'),
+ getDescription: sinon.stub().returns('myDescription')
+ }));
service.deployInitialSample();
@@ -871,9 +977,52 @@ describe('ClientService', () => {
businessNetworkFromArchiveMock.should.have.been.called;
- adminMock.update.should.have.been.calledWith({name: 'bob'});
- refreshMock.should.have.been.called;
+ adminMock.createNewBusinessNetwork.should.have.been.calledWith('myNetwork', 'myDescription');
+
+ adminMock.isInitialDeploy.should.have.been.called;
+
+ adminMock.update.should.not.have.been.called;
resetMock.should.have.been.called;
+
+ businessNetworkConMock.disconnect.should.have.been.called;
+ businessNetworkConMock.connect.should.have.been.calledWith('$default', 'myNetwork', 'admin', 'adminpw');
+ })));
+
+ it('should handle error', fakeAsync(inject([ClientService], (service: ClientService) => {
+ let resetMock = sinon.stub(service, 'reset');
+
+ adminMock.createNewBusinessNetwork.returns(Promise.reject('some error'));
+ adminMock.isInitialDeploy.returns(true);
+
+ let businessNetworkMock = sinon.stub(service, 'getBusinessNetworkConnection').returns(businessNetworkConMock);
+ let businessNetworkFromArchiveMock = sandbox.stub(BusinessNetworkDefinition, 'fromArchive').returns(Promise.resolve({
+ name: 'bob',
+ getName: sinon.stub().returns('myNetwork'),
+ getDescription: sinon.stub().returns('myDescription')
+ }));
+
+ service.deployInitialSample()
+ .then(() => {
+ throw new Error('should not have got here');
+ })
+ .catch((error) => {
+ error.should.equal('some error');
+ });
+
+ alertMock.busyStatus$.next.should.have.been.calledWith({
+ title: 'Deploying Business Network',
+ text: 'deploying sample business network'
+ });
+
+ tick();
+
+ businessNetworkFromArchiveMock.should.have.been.called;
+
+ adminMock.createNewBusinessNetwork.should.have.been.calledWith('myNetwork', 'myDescription');
+
+ adminMock.isInitialDeploy.should.not.have.been.called;
+
+ alertMock.busyStatus$.next.should.have.been.calledWith(null);
})));
});
@@ -934,6 +1083,34 @@ describe('ClientService', () => {
})));
});
+ describe('disconnect', () => {
+ it('should disconnect', inject([ClientService], (service: ClientService) => {
+ let businessNetworkMock = sinon.stub(service, 'getBusinessNetworkConnection').returns(businessNetworkConMock);
+ service.disconnect();
+
+ service['isConnected'].should.equal(false);
+ adminMock.disconnect.should.have.been.called;
+ businessNetworkConMock.disconnect.should.have.been.called;
+ }));
+ });
+
+ describe('getSavedBusinessNetworkName', () => {
+ it('should get saved the business network name', inject([ClientService], (service: ClientService) => {
+ service['getSavedBusinessNetworkName']('bob');
+
+ mockLocalStorage.get.should.have.been.calledWith('currentBusinessNetwork:bob');
+ }));
+ });
+
+ describe('setSavedBusinessNetworkName', () => {
+ it('should save the business network name', inject([ClientService], (service: ClientService) => {
+ let businessNetworkMock = sinon.stub(service, 'getBusinessNetworkName').returns('myNetwork');
+ service['setSavedBusinessNetworkName']('bob');
+
+ mockLocalStorage.set.should.have.been.calledWith('currentBusinessNetwork:bob', 'myNetwork');
+ }));
+ });
+
describe('createNewBusinessNetwork', () => {
it('should alert on failure', inject([ClientService], (service: ClientService) => {
// Set up mocks
diff --git a/packages/composer-playground/src/app/services/client.service.ts b/packages/composer-playground/src/app/services/client.service.ts
index 43a33a77fc..a111231084 100644
--- a/packages/composer-playground/src/app/services/client.service.ts
+++ b/packages/composer-playground/src/app/services/client.service.ts
@@ -1,5 +1,6 @@
import { Injectable } from '@angular/core';
import { BehaviorSubject, Subject } from 'rxjs/Rx';
+import { LocalStorageService } from 'angular-2-local-storage';
import { AdminService } from './admin.service';
import { ConnectionProfileService } from './connectionprofile.service';
@@ -26,7 +27,8 @@ export class ClientService {
constructor(private adminService: AdminService,
private connectionProfileService: ConnectionProfileService,
private identityService: IdentityService,
- private alertService: AlertService) {
+ private alertService: AlertService,
+ private localStorageService: LocalStorageService) {
}
// horrible hack for tests
@@ -218,33 +220,48 @@ export class ClientService {
this.createNewBusinessNetwork(name, version, description, packageJson, readme);
}
- ensureConnected(force: boolean = true): Promise {
+ ensureConnected(name: string = null, force: boolean = false): Promise {
if (this.isConnected && !force) {
return Promise.resolve();
} else if (this.connectingPromise) {
return this.connectingPromise;
}
- let connectionProfile = this.connectionProfileService.getCurrentConnectionProfile();
- this.alertService.busyStatus$.next({
- title: 'Establishing connection',
- text: 'Using the connection profile ' + connectionProfile
- });
- console.log('Connecting to connection profile', connectionProfile);
- this.connectingPromise = this.adminService.ensureConnected(force)
+
+ let businessNetworkName: string;
+ let userId;
+ this.connectingPromise = this.identityService.getUserID()
+ .then((userID) => {
+ userId = userID;
+ if (!name) {
+ try {
+ businessNetworkName = this.getBusinessNetworkName();
+ } catch (error) {
+ console.log('business network name not set yet so using from local storage');
+ } finally {
+ if (!businessNetworkName) {
+ businessNetworkName = this.getSavedBusinessNetworkName(userId);
+ }
+ }
+ } else {
+ businessNetworkName = name;
+ }
+
+ let connectionProfile = this.connectionProfileService.getCurrentConnectionProfile();
+ this.alertService.busyStatus$.next({
+ title: 'Establishing connection',
+ text: 'Using the connection profile ' + connectionProfile
+ });
+ console.log('Connecting to connection profile', connectionProfile);
+ return this.adminService.connect(businessNetworkName, force);
+ })
.then(() => {
- return this.refresh();
+ return this.refresh(businessNetworkName);
})
.then(() => {
console.log('connected');
this.isConnected = true;
this.connectingPromise = null;
- })
- .then(() => {
- if (this.adminService.isInitialDeploy()) {
- return this.deployInitialSample();
- }
- })
- .then(() => {
+ this.setSavedBusinessNetworkName(userId);
this.alertService.busyStatus$.next(null);
})
.catch((error) => {
@@ -258,14 +275,11 @@ export class ClientService {
}
reset(): Promise {
- return this.ensureConnected()
- .then(() => {
- // TODO: hack hack hack, this should be in the admin API.
- return Util.invokeChainCode(( (this.getBusinessNetworkConnection())).securityContext, 'resetBusinessNetwork', []);
- });
+ // TODO: hack hack hack, this should be in the admin API.
+ return Util.invokeChainCode(( (this.getBusinessNetworkConnection())).securityContext, 'resetBusinessNetwork', []);
}
- refresh(): Promise {
+ refresh(businessNetworkName): Promise {
this.currentBusinessNetwork = null;
let connectionProfile = this.connectionProfileService.getCurrentConnectionProfile();
this.alertService.busyStatus$.next({
@@ -282,10 +296,16 @@ export class ClientService {
return this.identityService.getUserSecret();
})
.then((userSecret) => {
- return this.getBusinessNetworkConnection().connect(connectionProfile, 'org-acme-biznet', userID, userSecret);
+ return this.getBusinessNetworkConnection().connect(connectionProfile, businessNetworkName, userID, userSecret);
});
}
+ public disconnect() {
+ this.isConnected = false;
+ this.adminService.disconnect();
+ return this.getBusinessNetworkConnection().disconnect();
+ }
+
public getBusinessNetworkFromArchive(buffer): Promise {
return BusinessNetworkDefinition.fromArchive(buffer);
}
@@ -296,12 +316,28 @@ export class ClientService {
text: 'deploying sample business network'
});
+ let businessNetwork: BusinessNetworkDefinition;
return BusinessNetworkDefinition.fromArchive(sampleBusinessNetworkArchive)
.then((sampleBusinessNetworkDefinition) => {
- return this.adminService.update(sampleBusinessNetworkDefinition);
+ businessNetwork = sampleBusinessNetworkDefinition;
+ return this.adminService.createNewBusinessNetwork(businessNetwork.getName(), businessNetwork.getDescription())
+ .catch((error) => {
+ // if it already exists we just carry on otherwise we need to throw the error that happened
+ if (error.message !== 'businessNetwork with name ' + businessNetwork.getName() + ' already exists') {
+ throw error;
+ }
+ });
})
.then(() => {
- return this.refresh();
+ if (this.adminService.isInitialDeploy()) {
+ return this.adminService.update(businessNetwork);
+ }
+ })
+ .then(() => {
+ return this.getBusinessNetworkConnection().disconnect();
+ })
+ .then(() => {
+ return this.getBusinessNetworkConnection().connect('$default', businessNetwork.getName(), 'admin', 'adminpw');
})
.then(() => {
return this.reset();
@@ -367,4 +403,14 @@ export class ClientService {
return !model.isSystemModelFile();
});
}
+
+ private getSavedBusinessNetworkName(identity: string): string {
+ let key = `currentBusinessNetwork:${identity}`;
+ return this.localStorageService.get(key);
+ }
+
+ private setSavedBusinessNetworkName(identity: string): void {
+ let key = `currentBusinessNetwork:${identity}`;
+ this.localStorageService.set(key, this.getBusinessNetworkName());
+ }
}
diff --git a/packages/composer-playground/src/app/services/identity.service.ts b/packages/composer-playground/src/app/services/identity.service.ts
index e9deb5dac8..8c54fa6dae 100644
--- a/packages/composer-playground/src/app/services/identity.service.ts
+++ b/packages/composer-playground/src/app/services/identity.service.ts
@@ -55,17 +55,13 @@ export class IdentityService {
let key = `currentIdentity:${connectionProfile}`;
let result = this.localStorageService.get(key);
return this.getIdentities(connectionProfile)
- .then((identities) => {
- if (identities.indexOf(result) > -1) {
- return result;
- } else if (identities.length > 0) {
- result = identities[0];
- this.setIdentity(connectionProfile, result);
- return result;
- } else {
- return null;
- }
- });
+ .then((identities) => {
+ if (identities.indexOf(result) > -1) {
+ return result;
+ } else {
+ return null;
+ }
+ });
}
setCurrentIdentity(identity: string) {
@@ -93,4 +89,13 @@ export class IdentityService {
});
}
+ setLoggedIn(loggedIn: boolean) {
+ let key = `loggedIn`;
+ this.localStorageService.set(key, loggedIn);
+ }
+
+ getLoggedIn() {
+ let key = `loggedIn`;
+ return this.localStorageService.get(key);
+ }
}
diff --git a/packages/composer-playground/src/app/services/initialization.service.spec.ts b/packages/composer-playground/src/app/services/initialization.service.spec.ts
index fd1fe68410..6493f0f5c4 100644
--- a/packages/composer-playground/src/app/services/initialization.service.spec.ts
+++ b/packages/composer-playground/src/app/services/initialization.service.spec.ts
@@ -20,6 +20,7 @@ import { WalletService } from './wallet.service';
import { FileWallet } from 'composer-common';
import * as sinon from 'sinon';
+import { IdentityService } from './identity.service';
describe('InitializationService', () => {
@@ -27,6 +28,7 @@ describe('InitializationService', () => {
let mockAlertService;
let mockConnectionProfileService;
let mockWalletService;
+ let mockIdentityService;
beforeEach(() => {
@@ -34,6 +36,7 @@ describe('InitializationService', () => {
mockAlertService = sinon.createStubInstance(AlertService);
mockConnectionProfileService = sinon.createStubInstance(ConnectionProfileService);
mockWalletService = sinon.createStubInstance(WalletService);
+ mockIdentityService = sinon.createStubInstance(IdentityService);
TestBed.configureTestingModule({
imports: [HttpModule],
@@ -42,6 +45,7 @@ describe('InitializationService', () => {
{provide: ClientService, useValue: mockClientService},
{provide: AlertService, useValue: mockAlertService},
{provide: ConnectionProfileService, useValue: mockConnectionProfileService},
+ {provide: IdentityService, useValue: mockIdentityService},
{provide: WalletService, useValue: mockWalletService},
{provide: XHRBackend, useClass: MockBackend}
]
@@ -67,6 +71,8 @@ describe('InitializationService', () => {
})));
it('should initialize and deploy sample', fakeAsync(inject([InitializationService], (service: InitializationService) => {
+ let mockCreateSample = sinon.stub(service, 'deployInitialSample');
+ mockCreateSample.returns(Promise.resolve());
let stubLoadConfig = sinon.stub(service, 'loadConfig');
stubLoadConfig.returns(Promise.resolve({}));
@@ -80,6 +86,8 @@ describe('InitializationService', () => {
mockAlertService.busyStatus$ = {next: sinon.stub()};
+ mockIdentityService.getLoggedIn.returns(false);
+
service.initialize();
tick();
@@ -87,11 +95,13 @@ describe('InitializationService', () => {
stubCreateInitialProfiles.should.be.called;
stubCreateInitialIdentities.should.be.called;
- mockConnectionProfileService.setCurrentConnectionProfile.should.not.have.been.called;
- mockClientService.ensureConnected.should.be.called;
+ mockConnectionProfileService.setCurrentConnectionProfile.should.have.been.called;
+ mockCreateSample.should.be.called;
})));
- it('should initialize and continue if sample is already deployed', fakeAsync(inject([InitializationService], (service: InitializationService) => {
+ it('should initialize and not deploy sample as logged in', fakeAsync(inject([InitializationService], (service: InitializationService) => {
+ let mockCreateSample = sinon.stub(service, 'deployInitialSample');
+ mockCreateSample.returns(Promise.resolve());
let stubLoadConfig = sinon.stub(service, 'loadConfig');
stubLoadConfig.returns(Promise.resolve({}));
@@ -104,32 +114,8 @@ describe('InitializationService', () => {
mockClientService.ensureConnected.returns(Promise.resolve());
mockAlertService.busyStatus$ = {next: sinon.stub()};
- mockAlertService.errorStatus$ = {next: sinon.stub()};
-
- service.initialize();
-
- tick();
-
- stubLoadConfig.should.be.called;
- stubCreateInitialProfiles.should.be.called;
- stubCreateInitialIdentities.should.be.called;
- mockConnectionProfileService.setCurrentConnectionProfile.should.not.have.been.called;
- mockClientService.ensureConnected.should.be.called;
- })));
- it('should connect to profile specified in config', fakeAsync(inject([InitializationService], (service: InitializationService) => {
- let stubLoadConfig = sinon.stub(service, 'loadConfig');
- stubLoadConfig.returns(Promise.resolve({defaultConnectionProfile: 'myProfile'}));
-
- let stubCreateInitialProfiles = sinon.stub(service, 'createInitialProfiles');
- stubCreateInitialProfiles.returns(Promise.resolve());
-
- let stubCreateInitialIdentities = sinon.stub(service, 'createInitialIdentities');
- stubCreateInitialIdentities.returns(Promise.resolve());
-
- mockClientService.ensureConnected.returns(Promise.resolve());
-
- mockAlertService.busyStatus$ = {next: sinon.stub()};
+ mockIdentityService.getLoggedIn.returns(true);
service.initialize();
@@ -138,8 +124,8 @@ describe('InitializationService', () => {
stubCreateInitialProfiles.should.be.called;
stubCreateInitialIdentities.should.be.called;
- mockConnectionProfileService.setCurrentConnectionProfile.should.have.been.calledWith('myProfile');
- mockClientService.ensureConnected.should.be.called;
+ mockConnectionProfileService.setCurrentConnectionProfile.should.not.have.been.called;
+ mockCreateSample.should.not.have.been.called;
})));
it('should handle errors and revert to uninitialized state', fakeAsync(inject([InitializationService], (service: InitializationService) => {
@@ -275,4 +261,14 @@ describe('InitializationService', () => {
result.should.equal(true);
})));
});
+
+ describe('deployInitialSample', () => {
+ it('should deploy the initial sample', fakeAsync(inject([InitializationService], (service: InitializationService) => {
+ service.deployInitialSample();
+
+ tick();
+
+ mockClientService.deployInitialSample.should.have.been.called;
+ })));
+ });
});
diff --git a/packages/composer-playground/src/app/services/initialization.service.ts b/packages/composer-playground/src/app/services/initialization.service.ts
index f524c9081c..e845c936e7 100644
--- a/packages/composer-playground/src/app/services/initialization.service.ts
+++ b/packages/composer-playground/src/app/services/initialization.service.ts
@@ -5,6 +5,7 @@ import { ClientService } from './client.service';
import { AlertService } from '../basic-modals/alert.service';
import { ConnectionProfileService } from './connectionprofile.service';
import { WalletService } from './wallet.service';
+import { IdentityService } from './identity.service';
@Injectable()
export class InitializationService {
@@ -18,6 +19,7 @@ export class InitializationService {
private alertService: AlertService,
private connectionProfileService: ConnectionProfileService,
private walletService: WalletService,
+ private identityService: IdentityService,
private http: Http) {
}
@@ -40,10 +42,12 @@ export class InitializationService {
return this.createInitialIdentities();
})
.then(() => {
- if (this.config && this.config.defaultConnectionProfile) {
- this.connectionProfileService.setCurrentConnectionProfile(this.config.defaultConnectionProfile);
+ // only need to check about initial sample if not logged in
+ if (!this.identityService.getLoggedIn()) {
+ this.connectionProfileService.setCurrentConnectionProfile('$default');
+ this.identityService.setCurrentIdentity('admin');
+ return this.deployInitialSample();
}
- return this.clientService.ensureConnected();
})
.then(() => {
this.initialized = true;
@@ -112,6 +116,10 @@ export class InitializationService {
}, Promise.resolve());
}
+ deployInitialSample() {
+ return this.clientService.deployInitialSample();
+ }
+
isWebOnly(): boolean {
if (!this.config) {
return false;
diff --git a/packages/composer-playground/src/app/services/samplebusinessnetwork.service.spec.ts b/packages/composer-playground/src/app/services/samplebusinessnetwork.service.spec.ts
index f603bd93bc..12366399b1 100644
--- a/packages/composer-playground/src/app/services/samplebusinessnetwork.service.spec.ts
+++ b/packages/composer-playground/src/app/services/samplebusinessnetwork.service.spec.ts
@@ -99,12 +99,31 @@ describe('SampleBusinessNetworkService', () => {
})));
});
- service.deployChosenSample({name: 'bob'});
+ service.deployChosenSample({name: 'bob'}, true);
tick();
businessNetworkFromArchiveMock.should.have.been.called;
- mockDeployNetwork.should.have.been.calledWith({name: 'myNetwork'});
+ mockDeployNetwork.should.have.been.calledWith({name: 'myNetwork'}, true);
+
+ })));
+
+ it('should update the chosen sample', fakeAsync(inject([SampleBusinessNetworkService, XHRBackend], (service: SampleBusinessNetworkService, mockBackend) => {
+ let mockDeployNetwork = sinon.stub(service, 'deployBusinessNetwork');
+ let businessNetworkFromArchiveMock = sandbox.stub(BusinessNetworkDefinition, 'fromArchive').returns(Promise.resolve({name: 'myNetwork'}));
+
+ mockBackend.connections.subscribe((connection) => {
+ connection.mockRespond(new Response(new ResponseOptions({
+ body: '1234'
+ })));
+ });
+
+ service.deployChosenSample({name: 'bob'}, false);
+
+ tick();
+
+ businessNetworkFromArchiveMock.should.have.been.called;
+ mockDeployNetwork.should.have.been.calledWith({name: 'myNetwork'}, false);
})));
@@ -116,7 +135,7 @@ describe('SampleBusinessNetworkService', () => {
connection.mockError(new Error('some error'));
});
- service.deployChosenSample({name: 'bob'})
+ service.deployChosenSample({name: 'bob'}, true)
.then(() => {
throw('should not get here');
})
@@ -133,15 +152,54 @@ describe('SampleBusinessNetworkService', () => {
describe('deployBusinessNetwork', () => {
it('should deploy the business network definition', fakeAsync(inject([SampleBusinessNetworkService], (service: SampleBusinessNetworkService) => {
+ adminMock.deploy.returns(Promise.resolve());
+ clientMock.refresh.returns(Promise.resolve());
+
+ alertMock.busyStatus$ = {next: sinon.stub()};
+
+ service.deployBusinessNetwork(businessNetworkMock, true);
+
+ tick();
+
+ adminMock.deploy.should.have.been.called;
+ clientMock.refresh.should.have.been.called;
+ clientMock.reset.should.have.been.called;
+ alertMock.busyStatus$.next.should.have.been.calledWith(null);
+ })));
+
+ it('should update the business network definition', fakeAsync(inject([SampleBusinessNetworkService], (service: SampleBusinessNetworkService) => {
+
adminMock.update.returns(Promise.resolve());
clientMock.refresh.returns(Promise.resolve());
+ clientMock.getBusinessNetworkName.returns('myNetwork');
+
+ let modalManagerMock = {addModelFiles: sinon.stub(), getModelFiles: sinon.stub().returns(['model'])};
+ let scriptManagerMock = {getScripts: sinon.stub().returns(['script']), addScript: sinon.stub()};
+ let aclManagerMock = {getAclFile: sinon.stub().returns('acl'), setAclFile: sinon.stub()};
+ let metaData = {getPackageJson: sinon.stub().returns({}), getREADME: sinon.stub()};
+
+ businessNetworkMock.getModelManager.returns(modalManagerMock);
+ businessNetworkMock.getScriptManager.returns(scriptManagerMock);
+ businessNetworkMock.getAclManager.returns(aclManagerMock);
+ businessNetworkMock.getMetadata.returns(metaData);
+
+ let mockCreateBN = sinon.stub(service, 'createNewBusinessDefinition').returns(businessNetworkMock);
alertMock.busyStatus$ = {next: sinon.stub()};
- service.deployBusinessNetwork(businessNetworkMock);
+ service.deployBusinessNetwork(businessNetworkMock, false);
tick();
+ metaData.getREADME.should.have.been.called;
+ metaData.getPackageJson.should.have.been.called;
+ mockCreateBN.should.have.been.called;
+ clientMock.filterModelFiles.should.have.been.called;
+
+ modalManagerMock.addModelFiles.should.have.been.called;
+ scriptManagerMock.addScript.should.have.been.called;
+ aclManagerMock.setAclFile.should.have.been.called;
+
adminMock.update.should.have.been.called;
clientMock.refresh.should.have.been.called;
clientMock.reset.should.have.been.called;
@@ -149,11 +207,11 @@ describe('SampleBusinessNetworkService', () => {
})));
it('should handle error', fakeAsync(inject([SampleBusinessNetworkService], (service: SampleBusinessNetworkService) => {
- adminMock.update.returns(Promise.reject('some error'));
+ adminMock.deploy.returns(Promise.reject('some error'));
alertMock.busyStatus$ = {next: sinon.stub()};
- service.deployBusinessNetwork(businessNetworkMock).then(() => {
+ service.deployBusinessNetwork(businessNetworkMock, true).then(() => {
throw('should not get here');
})
.catch((error) => {
diff --git a/packages/composer-playground/src/app/services/samplebusinessnetwork.service.ts b/packages/composer-playground/src/app/services/samplebusinessnetwork.service.ts
index 3b3564e64b..c9f4afe870 100644
--- a/packages/composer-playground/src/app/services/samplebusinessnetwork.service.ts
+++ b/packages/composer-playground/src/app/services/samplebusinessnetwork.service.ts
@@ -15,6 +15,10 @@ export class SampleBusinessNetworkService {
private http: Http) {
}
+ createNewBusinessDefinition(name, description, packageJson, readme) {
+ return new BusinessNetworkDefinition(name, description, packageJson, readme);
+ }
+
public getSampleList() {
return this.http.get(PLAYGROUND_API + '/api/getSampleList')
.toPromise()
@@ -26,7 +30,7 @@ export class SampleBusinessNetworkService {
});
}
- public deployChosenSample(chosenNetwork: object): Promise {
+ public deployChosenSample(chosenNetwork: object, deployNetwork: boolean): Promise {
let params: URLSearchParams = new URLSearchParams();
let paramNames = Object.keys(chosenNetwork);
@@ -44,17 +48,43 @@ export class SampleBusinessNetworkService {
return BusinessNetworkDefinition.fromArchive(( response)._body);
})
.then((businessNetwork) => {
- return this.deployBusinessNetwork(businessNetwork);
+ return this.deployBusinessNetwork(businessNetwork, deployNetwork);
})
.catch((error) => {
throw(error);
});
}
- public deployBusinessNetwork(businessNetworkDefinition: BusinessNetworkDefinition): Promise {
- return this.adminService.update(businessNetworkDefinition)
+ public deployBusinessNetwork(businessNetworkDefinition: BusinessNetworkDefinition, deployNetwork: boolean): Promise {
+ let deployPromise;
+
+ if (deployNetwork) {
+ deployPromise = this.adminService.deploy(businessNetworkDefinition);
+ } else {
+ let currentBusinessNetworkName = this.clientService.getBusinessNetworkName();
+
+ let packageJson = businessNetworkDefinition.getMetadata().getPackageJson();
+ packageJson.name = currentBusinessNetworkName;
+
+ let newNetwork = this.createNewBusinessDefinition(currentBusinessNetworkName, businessNetworkDefinition.getDescription(), packageJson, businessNetworkDefinition.getMetadata().getREADME());
+
+ let modelFiles = this.clientService.filterModelFiles(businessNetworkDefinition.getModelManager().getModelFiles());
+
+ newNetwork.getModelManager().addModelFiles(modelFiles);
+ businessNetworkDefinition.getScriptManager().getScripts().forEach((script) => {
+ newNetwork.getScriptManager().addScript(script);
+ });
+
+ if (businessNetworkDefinition.getAclManager().getAclFile()) {
+ newNetwork.getAclManager().setAclFile(businessNetworkDefinition.getAclManager().getAclFile());
+ }
+
+ deployPromise = this.adminService.update(newNetwork);
+ }
+
+ return deployPromise
.then(() => {
- return this.clientService.refresh();
+ return this.clientService.refresh(businessNetworkDefinition.getName());
})
.then(() => {
return this.clientService.reset();
diff --git a/packages/composer-playground/src/app/test/switch-identity/switch-identity.component.spec.ts b/packages/composer-playground/src/app/test/switch-identity/switch-identity.component.spec.ts
index 3364b1ae7c..09b1c0b7a5 100644
--- a/packages/composer-playground/src/app/test/switch-identity/switch-identity.component.spec.ts
+++ b/packages/composer-playground/src/app/test/switch-identity/switch-identity.component.spec.ts
@@ -108,7 +108,7 @@ describe('SwitchIdentityComponent', () => {
mockConnectionProfileService.setCurrentConnectionProfile.should.have.been.calledWith('myProfile');
mockIdentityService.setCurrentIdentity.should.have.been.calledWith('bob');
- mockClientService.ensureConnected.should.have.been.calledWith(true);
+ mockClientService.ensureConnected.should.have.been.calledWith(null, true);
component['switchInProgress'].should.equal(false);
mockActiveModal.close.should.have.been.called;
@@ -141,7 +141,7 @@ describe('SwitchIdentityComponent', () => {
mockConnectionProfileService.setCurrentConnectionProfile.should.have.been.calledWith('myProfile');
mockIdentityService.setCurrentIdentity.should.have.been.calledWith('bob');
- mockClientService.ensureConnected.should.have.been.calledWith(true);
+ mockClientService.ensureConnected.should.have.been.calledWith(null, true);
component['switchInProgress'].should.equal(false);
mockActiveModal.close.should.have.been.called;
@@ -174,7 +174,7 @@ describe('SwitchIdentityComponent', () => {
mockConnectionProfileService.setCurrentConnectionProfile.should.have.been.calledWith('myProfile');
mockIdentityService.setCurrentIdentity.should.have.been.calledWith('bob');
- mockClientService.ensureConnected.should.have.been.calledWith(true);
+ mockClientService.ensureConnected.should.have.been.calledWith(null, true);
component['switchInProgress'].should.equal(false);
mockActiveModal.close.should.have.been.called;
@@ -193,7 +193,7 @@ describe('SwitchIdentityComponent', () => {
tick();
- mockClientService.ensureConnected.should.have.been.calledWith(true);
+ mockClientService.ensureConnected.should.have.been.calledWith(null, true);
component['switchInProgress'].should.equal(false);
mockActiveModal.dismiss.should.have.been.called;
diff --git a/packages/composer-playground/src/app/test/switch-identity/switch-identity.component.ts b/packages/composer-playground/src/app/test/switch-identity/switch-identity.component.ts
index d88dbb7ad3..c7a2d4a40b 100644
--- a/packages/composer-playground/src/app/test/switch-identity/switch-identity.component.ts
+++ b/packages/composer-playground/src/app/test/switch-identity/switch-identity.component.ts
@@ -73,7 +73,7 @@ export class SwitchIdentityComponent implements OnInit {
this.connectionProfileService.setCurrentConnectionProfile(this.connectionProfileName);
this.identityService.setCurrentIdentity(chosenUser);
- return this.clientService.ensureConnected(true);
+ return this.clientService.ensureConnected(null, true);
})
.then(() => {
this.switchInProgress = false;
diff --git a/packages/composer-playground/src/app/test/test.component.spec.ts b/packages/composer-playground/src/app/test/test.component.spec.ts
index aeccb6e3e3..c01e5d6887 100644
--- a/packages/composer-playground/src/app/test/test.component.spec.ts
+++ b/packages/composer-playground/src/app/test/test.component.spec.ts
@@ -6,7 +6,6 @@ import { ComponentFixture, TestBed, fakeAsync, tick } from '@angular/core/testin
import { Directive, Input } from '@angular/core';
import { TestComponent } from './test.component';
import { ClientService } from '../services/client.service';
-import { InitializationService } from '../services/initialization.service';
import { TransactionService } from '../services/transaction.service';
import { AlertService } from '../basic-modals/alert.service';
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
@@ -35,7 +34,6 @@ describe('TestComponent', () => {
let fixture: ComponentFixture;
let mockClientService;
- let mockInitializationService;
let mockAlertService;
let mockTransactionService;
let mockModal;
@@ -48,7 +46,6 @@ describe('TestComponent', () => {
sandbox = sinon.sandbox.create();
mockClientService = sinon.createStubInstance(ClientService);
- mockInitializationService = sinon.createStubInstance(InitializationService);
mockAlertService = sinon.createStubInstance(AlertService);
mockModal = sinon.createStubInstance(NgbModal);
mockBusinessNetworkConnection = sinon.createStubInstance(BusinessNetworkConnection);
@@ -62,7 +59,6 @@ describe('TestComponent', () => {
declarations: [TestComponent, MockRegistryDirective],
providers: [
{provide: NgbModal, useValue: mockModal},
- {provide: InitializationService, useValue: mockInitializationService},
{provide: AlertService, useValue: mockAlertService},
{provide: ClientService, useValue: mockClientService},
{provide: TransactionService, useValue: mockTransactionService}
@@ -87,7 +83,7 @@ describe('TestComponent', () => {
});
it('should load all the registries', fakeAsync(() => {
- mockInitializationService.initialize.returns(Promise.resolve());
+ mockClientService.ensureConnected.returns(Promise.resolve());
mockBusinessNetworkConnection.getAllAssetRegistries.returns(Promise.resolve([{id: 'asset.fred'}, {id: 'asset.bob'}]));
mockBusinessNetworkConnection.getAllParticipantRegistries.returns(Promise.resolve([{id: 'participant.fred'}, {id: 'participant.bob'}]));
@@ -121,7 +117,7 @@ describe('TestComponent', () => {
}));
it('should set chosen registry to first asset one if no participant registries', fakeAsync(() => {
- mockInitializationService.initialize.returns(Promise.resolve());
+ mockClientService.ensureConnected.returns(Promise.resolve());
mockBusinessNetworkConnection.getAllAssetRegistries.returns(Promise.resolve([{id: 'asset.fred'}, {id: 'asset.bob'}]));
mockBusinessNetworkConnection.getAllParticipantRegistries.returns(Promise.resolve([]));
@@ -152,7 +148,7 @@ describe('TestComponent', () => {
}));
it('should set chosen registry to transaction registry if no asset or participant registries', fakeAsync(() => {
- mockInitializationService.initialize.returns(Promise.resolve());
+ mockClientService.ensureConnected.returns(Promise.resolve());
mockBusinessNetworkConnection.getAllAssetRegistries.returns(Promise.resolve([]));
mockBusinessNetworkConnection.getAllParticipantRegistries.returns(Promise.resolve([]));
@@ -180,8 +176,7 @@ describe('TestComponent', () => {
}));
it('should handle error', fakeAsync(() => {
- mockInitializationService.initialize.returns(Promise.reject('some error'));
- mockClientService.getBusinessNetworkConnection.returns(mockBusinessNetworkConnection);
+ mockClientService.ensureConnected.returns(Promise.reject('some error'));
mockAlertService.errorStatus$ = {next: sinon.stub()};
diff --git a/packages/composer-playground/src/app/test/test.component.ts b/packages/composer-playground/src/app/test/test.component.ts
index 9a8bcd1e34..d14f6ce9d3 100644
--- a/packages/composer-playground/src/app/test/test.component.ts
+++ b/packages/composer-playground/src/app/test/test.component.ts
@@ -1,8 +1,6 @@
-
import { Component, OnInit, OnDestroy } from '@angular/core';
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
import { ClientService } from '../services/client.service';
-import { InitializationService } from '../services/initialization.service';
import { AlertService } from '../basic-modals/alert.service';
import { TransactionComponent } from './transaction/transaction.component';
import { TransactionService } from '../services/transaction.service';
@@ -25,55 +23,54 @@ export class TestComponent implements OnInit, OnDestroy {
private eventsTriggered = [];
constructor(private clientService: ClientService,
- private initializationService: InitializationService,
private alertService: AlertService,
private transactionService: TransactionService,
private modalService: NgbModal) {
}
ngOnInit(): Promise {
- this.initializeEventListener();
- return this.initializationService.initialize()
+ return this.clientService.ensureConnected()
.then(() => {
- return this.clientService.getBusinessNetworkConnection().getAllAssetRegistries();
- })
- .then((assetRegistries) => {
- assetRegistries.forEach((assetRegistry) => {
- let index = assetRegistry.id.lastIndexOf('.');
- let displayName = assetRegistry.id.substring(index + 1);
- assetRegistry.displayName = displayName;
- });
-
- this.assetRegistries = assetRegistries.sort((a, b) => {
- return a.id.localeCompare(b.id);
- });
-
- return this.clientService.getBusinessNetworkConnection().getAllParticipantRegistries();
- })
- .then((participantRegistries) => {
- participantRegistries.forEach((participantRegistry) => {
- let index = participantRegistry.id.lastIndexOf('.');
- let displayName = participantRegistry.id.substring(index + 1);
- participantRegistry.displayName = displayName;
- });
-
- this.participantRegistries = participantRegistries.sort((a, b) => {
- return a.id.localeCompare(b.id);
- });
-
- return this.clientService.getBusinessNetworkConnection().getTransactionRegistry();
- })
- .then((transactionRegistry) => {
- this.transactionRegistry = transactionRegistry;
-
- // set the default registry selection
- if (this.participantRegistries.length !== 0) {
- this.chosenRegistry = this.participantRegistries[0];
- } else if (this.assetRegistries.length !== 0) {
- this.chosenRegistry = this.assetRegistries[0];
- } else {
- this.chosenRegistry = this.transactionRegistry;
- }
+ this.initializeEventListener();
+ return this.clientService.getBusinessNetworkConnection().getAllAssetRegistries()
+ .then((assetRegistries) => {
+ assetRegistries.forEach((assetRegistry) => {
+ let index = assetRegistry.id.lastIndexOf('.');
+ let displayName = assetRegistry.id.substring(index + 1);
+ assetRegistry.displayName = displayName;
+ });
+
+ this.assetRegistries = assetRegistries.sort((a, b) => {
+ return a.id.localeCompare(b.id);
+ });
+
+ return this.clientService.getBusinessNetworkConnection().getAllParticipantRegistries();
+ })
+ .then((participantRegistries) => {
+ participantRegistries.forEach((participantRegistry) => {
+ let index = participantRegistry.id.lastIndexOf('.');
+ let displayName = participantRegistry.id.substring(index + 1);
+ participantRegistry.displayName = displayName;
+ });
+
+ this.participantRegistries = participantRegistries.sort((a, b) => {
+ return a.id.localeCompare(b.id);
+ });
+
+ return this.clientService.getBusinessNetworkConnection().getTransactionRegistry();
+ })
+ .then((transactionRegistry) => {
+ this.transactionRegistry = transactionRegistry;
+
+ // set the default registry selection
+ if (this.participantRegistries.length !== 0) {
+ this.chosenRegistry = this.participantRegistries[0];
+ } else if (this.assetRegistries.length !== 0) {
+ this.chosenRegistry = this.assetRegistries[0];
+ } else {
+ this.chosenRegistry = this.transactionRegistry;
+ }
+ });
})
.catch((error) => {
this.alertService.errorStatus$.next(error);
@@ -90,7 +87,6 @@ export class TestComponent implements OnInit, OnDestroy {
submitTransaction() {
const modalRef = this.modalService.open(TransactionComponent);
-
modalRef.result.then((transaction) => {
// refresh current resource list
if (this.chosenRegistry === this.transactionRegistry) {