diff --git a/.angular-cli.json b/.angular-cli.json index 5d35d54f9..a446cd5b7 100644 --- a/.angular-cli.json +++ b/.angular-cli.json @@ -10,6 +10,7 @@ "assets": [ "assets", "favicon-96x96.png", + "app.config.json", { "glob": "**/*", "input": "../node_modules/ng2-alfresco-core/bundles/assets", "output": "./assets/" }, { "glob": "**/*", "input": "../node_modules/ng2-alfresco-datatable/bundles/assets", "output": "./assets/" }, diff --git a/package.json b/package.json index a81acdfd6..1ad3470f6 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,7 @@ "@angular/material": "2.0.0-beta.10", "@angular/platform-browser": "4.3.6", "@angular/platform-browser-dynamic": "4.3.6", - "@angular/router": "~3.1.1", + "@angular/router": "4.3.6", "@ngx-translate/core": "7.0.0", "alfresco-js-api": "1.9.0", "core-js": "^2.4.1", diff --git a/src/app.config.json b/src/app.config.json new file mode 100644 index 000000000..38f5a8381 --- /dev/null +++ b/src/app.config.json @@ -0,0 +1,18 @@ +{ + "ecmHost": "http://{hostname}:{port}/ecm", + "application": { + "name": "Alfresco Example Content Application", + "build": "1234" + }, + "document-list": { + "supportedPageSizes": [25, 50, 100] + }, + "files": { + "excluded": [ + ".DS_Store", + "desktop.ini", + "thumbs.db", + ".git" + ] + } +} diff --git a/src/app/app.component.html b/src/app/app.component.html index 46d517b68..0680b43f9 100644 --- a/src/app/app.component.html +++ b/src/app/app.component.html @@ -1,20 +1 @@ - -
-

- Welcome to {{title}}! -

- -
-

Here are some links to help you start:

- - + diff --git a/src/app/app.component.ts b/src/app/app.component.ts index 7d943bc90..82c93e10f 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -1,10 +1,60 @@ -import { Component } from '@angular/core'; +/*! + * @license + * Copyright 2017 Alfresco Software, Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Component, OnInit } from '@angular/core'; +import { Router, ActivatedRoute, NavigationEnd } from '@angular/router'; +import { TranslationService, PageTitleService } from 'ng2-alfresco-core'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.scss'] }) -export class AppComponent { - title = 'app'; +export class AppComponent implements OnInit { + constructor( + private route: ActivatedRoute, + private router: Router, + private pageTitle: PageTitleService, + private translateService: TranslationService) { + } + + ngOnInit() { + const { router, pageTitle, route, translateService } = this; + + router + .events + .filter(event => event instanceof NavigationEnd) + .subscribe(() => { + let currentRoute = route.root; + + while (currentRoute.firstChild) { + currentRoute = currentRoute.firstChild; + } + + const snapshot: any = currentRoute.snapshot || {}; + const data: any = snapshot.data || {}; + + if (data.i18nTitle) { + translateService.get(data.i18nTitle).subscribe(title => { + pageTitle.setTitle(title); + }); + } else { + pageTitle.setTitle(data.title || ''); + } + }); + } } diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 8a86c93b3..da472df9c 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -1,17 +1,25 @@ import { BrowserModule } from '@angular/platform-browser'; import { NgModule } from '@angular/core'; +import { RouterModule } from '@angular/router'; import { AdfModule } from './adf.module'; import { AppComponent } from './app.component'; +import { APP_ROUTES } from './app.routes'; + +import { LoginComponent } from './components/login/login.component'; @NgModule({ - declarations: [ - AppComponent - ], imports: [ BrowserModule, + RouterModule.forRoot(APP_ROUTES, { + enableTracing: true + }), AdfModule ], + declarations: [ + AppComponent, + LoginComponent + ], providers: [], bootstrap: [AppComponent] }) diff --git a/src/app/app.routes.ts b/src/app/app.routes.ts new file mode 100644 index 000000000..7c65b7533 --- /dev/null +++ b/src/app/app.routes.ts @@ -0,0 +1,35 @@ +/*! + * @license + * Copyright 2017 Alfresco Software, Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Routes } from '@angular/router'; + +import { LoginComponent } from './components/login/login.component'; + +export const APP_ROUTES: Routes = [ + { + path: '**', + redirectTo: '/login', + pathMatch: 'full' + }, + { + path: 'login', + component: LoginComponent, + data: { + title: 'Sign in' + } + } +]; diff --git a/src/app/components/login/login.component.html b/src/app/components/login/login.component.html new file mode 100644 index 000000000..c545e59f7 --- /dev/null +++ b/src/app/components/login/login.component.html @@ -0,0 +1,8 @@ + + diff --git a/src/app/components/login/login.component.spec.ts b/src/app/components/login/login.component.spec.ts new file mode 100644 index 000000000..1580b1e82 --- /dev/null +++ b/src/app/components/login/login.component.spec.ts @@ -0,0 +1,144 @@ +/*! + * @license + * Copyright 2017 Alfresco Software, Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { RouterTestingModule } from '@angular/router/testing'; +import { Router, ActivatedRoute } from '@angular/router'; +import { TestBed, async } from '@angular/core/testing'; +import { Observable } from 'rxjs/Rx'; +import { AlfrescoAuthenticationService, UserPreferencesService } from 'ng2-alfresco-core'; +import { LoginModule } from 'ng2-alfresco-login'; + +import { LoginComponent } from './login.component'; + +describe('LoginComponent', () => { + let router: Router; + let route: ActivatedRoute; + let authService: AlfrescoAuthenticationService; + let userPrefService: UserPreferencesService; + + class TestConfig { + private testBed; + private componentInstance; + private fixture; + + constructor(config: any = {}) { + const routerProvider = { + provide: Router, + useValue: { + navigateByUrl: jasmine.createSpy('navigateByUrl'), + navigate: jasmine.createSpy('navigate') + } + }; + + const authProvider = { + provide: AlfrescoAuthenticationService, + useValue: { + isEcmLoggedIn: jasmine.createSpy('navigateByUrl') + .and.returnValue(config.isEcmLoggedIn || false) + } + }; + + const preferencesProvider = { + provide: UserPreferencesService, + useValue: { + setStoragePrefix: jasmine.createSpy('setStoragePrefix') + } + }; + + this.testBed = TestBed.configureTestingModule({ + imports: [ + RouterTestingModule, + LoginModule + ], + declarations: [ + LoginComponent + ], + providers: [ + routerProvider, + authProvider, + preferencesProvider, + { + provide: ActivatedRoute, + useValue: { + params: Observable.of({ redirect: config.redirect }) + } + } + ] + }); + + this.fixture = TestBed.createComponent(LoginComponent); + this.componentInstance = this.fixture.componentInstance; + this.fixture.detectChanges(); + } + + get userPrefService() { + return TestBed.get(UserPreferencesService); + } + + get authService() { + return TestBed.get(AlfrescoAuthenticationService); + } + + get routerService() { + return TestBed.get(Router); + } + + get component() { + return this.componentInstance; + } + } + + it('load app when user is already logged in', () => { + const testConfig = new TestConfig({ + isEcmLoggedIn: true + }); + + expect(testConfig.routerService.navigateByUrl).toHaveBeenCalled(); + }); + + it('requires user to be logged in', () => { + const testConfig = new TestConfig({ + isEcmLoggedIn: false, + redirect: '/personal-files' + }); + + expect(testConfig.routerService.navigate).toHaveBeenCalledWith(['/login', {}]); + }); + + describe('onLoginSuccess()', () => { + let testConfig; + + beforeEach(() => { + testConfig = new TestConfig({ + isEcmLoggedIn: false, + redirect: 'somewhere-over-the-rainbow' + }); + }); + + it('redirects on success', () => { + testConfig.component.onLoginSuccess(); + + expect(testConfig.routerService.navigateByUrl).toHaveBeenCalledWith('somewhere-over-the-rainbow'); + }); + + it('sets user preference store prefix', () => { + testConfig.component.onLoginSuccess({ username: 'bogus' }); + + expect(testConfig.userPrefService.setStoragePrefix).toHaveBeenCalledWith('bogus'); + }); + }); +}); diff --git a/src/app/components/login/login.component.ts b/src/app/components/login/login.component.ts new file mode 100644 index 000000000..bd0713c51 --- /dev/null +++ b/src/app/components/login/login.component.ts @@ -0,0 +1,69 @@ +/*! + * @license + * Copyright 2017 Alfresco Software, Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Component } from '@angular/core'; +import { Router, ActivatedRoute } from '@angular/router'; +import { Validators } from '@angular/forms'; + +import { AlfrescoAuthenticationService, UserPreferencesService } from 'ng2-alfresco-core'; + +const skipRedirectUrls: string[] = [ + '/logout', + '/personal-files' +]; + +@Component({ + templateUrl: './login.component.html' +}) +export class LoginComponent { + + private redirectUrl = ''; + + constructor( + private router: Router, + private route: ActivatedRoute, + private auth: AlfrescoAuthenticationService, + private userPreferences: UserPreferencesService + ) { + if (auth.isEcmLoggedIn()) { + this.redirect(); + } + + route.params.subscribe((params: any) => { + if (skipRedirectUrls.indexOf(params.redirect) > -1) { + const remainingParams = Object.assign({}, params); + + delete remainingParams.redirect; + + router.navigate(['/login', remainingParams]); + } + + this.redirectUrl = params.redirect; + }); + } + + redirect() { + this.router.navigateByUrl(this.redirectUrl || ''); + } + + onLoginSuccess(data) { + if (data && data.username) { + this.userPreferences.setStoragePrefix(data.username); + } + this.redirect(); + } +} diff --git a/yarn.lock b/yarn.lock index 5aeddac5d..7105a9694 100644 --- a/yarn.lock +++ b/yarn.lock @@ -164,10 +164,6 @@ dependencies: tslib "^1.7.1" -"@angular/router@~3.1.1": - version "3.1.2" - resolved "https://registry.yarnpkg.com/@angular/router/-/router-3.1.2.tgz#1046c943ace795027e2e5057df8c897da968fcd6" - "@angular/tsc-wrapped@4.3.6": version "4.3.6" resolved "https://registry.yarnpkg.com/@angular/tsc-wrapped/-/tsc-wrapped-4.3.6.tgz#1aa66e0ab2c4799a4ad14b675e13953aa5fcd436"