diff --git a/src/app/app.component.ts b/src/app/app.component.ts
index f320b3f..7f41235 100644
--- a/src/app/app.component.ts
+++ b/src/app/app.component.ts
@@ -1,6 +1,6 @@
import {Component, inject, OnInit} from '@angular/core';
-import {AuthService} from "./general/service/auth.service";
-import {ActivatedRoute, Router} from "@angular/router";
+import {AuthService} from './general/service/auth.service';
+import {ActivatedRoute, Router} from '@angular/router';
@Component({
selector: 'app-root',
@@ -14,14 +14,16 @@ export class AppComponent implements OnInit {
private auth: AuthService,
private router: Router
) {
- console.log("AppComponent.constructor")
+ console.log('AppComponent.constructor');
}
- ngOnInit() {
- if (this.auth.userSignedIn) {
- this.router.navigate(["/manager"])
- } else {
- this.router.navigate(["/login"])
- }
+ async ngOnInit() {
+ // console.log("AppComponent.ngOnInit");
+ // if (!await this.auth.checkIfUserAuthenticated()) {
+ // this.router.navigate(['/login']);
+ // }
+ // console.log("AppComponent.ngOnInit end");
}
+
+
}
diff --git a/src/app/app.module.ts b/src/app/app.module.ts
index 34a1f0e..5c8bc50 100644
--- a/src/app/app.module.ts
+++ b/src/app/app.module.ts
@@ -20,6 +20,8 @@ import { LoginHomeComponent } from './login-home/login-home.component';
import {MatGridListModule} from "@angular/material/grid-list";
import {MatCardModule} from "@angular/material/card";
import {MatButtonModule} from "@angular/material/button";
+import {DynamicScriptLoaderService} from './general/service/dynamic-script-loader.service';
+import {MatProgressBarModule} from '@angular/material/progress-bar';
@NgModule({
@@ -34,7 +36,8 @@ import {MatButtonModule} from "@angular/material/button";
HttpClientModule,
MatGridListModule,
MatCardModule,
- MatButtonModule
+ MatButtonModule,
+ MatProgressBarModule
],
declarations: [
AppComponent,
@@ -43,6 +46,7 @@ import {MatButtonModule} from "@angular/material/button";
providers: [
DiagramService,
AuthService,
+ DynamicScriptLoaderService,
LoggedInGuard,
UserPreferenceService,
GoogleDriveService,
diff --git a/src/app/data-access/service/google-drive.service.ts b/src/app/data-access/service/google-drive.service.ts
index bc00dcd..5b45127 100644
--- a/src/app/data-access/service/google-drive.service.ts
+++ b/src/app/data-access/service/google-drive.service.ts
@@ -2,6 +2,7 @@ import {Injectable} from '@angular/core';
import {AuthService} from '../../general/service/auth.service';
import {HttpClient} from '@angular/common/http';
import {DiagramMetadata} from '../model/diagram-item.model';
+import {environment} from '../../../environments/environment';
declare let gapi: any;
@@ -49,7 +50,11 @@ export class GoogleDriveService {
public async init(): Promise {
if (!this.initialized) {
- // console.log('GoogleDriveService.init');
+ console.log('GoogleDriveService.init token', this.auth.accessToken);
+ gapi.client.setToken({access_token: this.auth.accessToken});
+ gapi.client.setApiKey(environment.gapi.api_key);
+ gapi.client.load('drive', 'v3');
+
await gapi.client.load('drive', 'v3');
this.initialized = true;
}
@@ -99,7 +104,7 @@ export class GoogleDriveService {
const endpoint = 'https://www.googleapis.com/upload/drive/v3/files/' + id + '?uploadType=multipart&fields=id';
return this.http.patch(endpoint, form, {
headers: {
- Authorization: this.auth.getAuthorizationHeader()
+ Authorization: await this.auth.getAuthorizationHeader()
}
}).toPromise();
} else {
@@ -108,7 +113,7 @@ export class GoogleDriveService {
const endpoint = 'https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart&fields=id';
return this.http.post(endpoint, form, {
headers: {
- Authorization: this.auth.getAuthorizationHeader()
+ Authorization: await this.auth.getAuthorizationHeader()
}
}).toPromise();
}
diff --git a/src/app/general/service/auth.service.ts b/src/app/general/service/auth.service.ts
index 1b103ec..88d4a7c 100644
--- a/src/app/general/service/auth.service.ts
+++ b/src/app/general/service/auth.service.ts
@@ -1,137 +1,157 @@
import {EventEmitter, Injectable} from '@angular/core';
import {environment} from '../../../environments/environment';
import TokenClient = google.accounts.oauth2.TokenClient;
+import {DynamicScriptLoaderService} from './dynamic-script-loader.service';
+import {GoogleDriveService} from '../../data-access/service/google-drive.service';
+
+export type Profile = {
+ name: string,
+ email: string,
+};
+
+const AUTH_KEY = 'vect.AuthService.auth';
+declare let gapi: any;
+const GOOGLE_PROFILE_URL = `https://www.googleapis.com/oauth2/v3/userinfo`;
@Injectable()
export class AuthService {
+ public authenticatedEvent = new EventEmitter();
+
tokenClient!: TokenClient;
+ accessToken?: string;
- authInited = false;
- gapiInited = false;
- userSignedIn = false;
+ inited = false;
+ userAuthenticated = false;
- private profile: any;
- public name!: string;
- public email!: string;
- private authenticated!: EventEmitter;
+ public profile?: Profile;
- constructor() {
- this.handleAuthResponse = this.handleAuthResponse.bind(this);
+ constructor(
+ protected dynamicScriptLoader: DynamicScriptLoaderService
+ ) {
+ this.handleTokenResponse = this.handleTokenResponse.bind(this);
this.handleProfileResponse = this.handleProfileResponse.bind(this);
}
- /**
- * Callback after Google Identity Services are loaded.
- */
- googleOAuthInit() {
+ public async checkIfUserAuthenticated(): Promise {
+ console.log('AuthService.checkIfUserAuthenticated before', this.userAuthenticated);
+ if (!this.userAuthenticated) {
+ await this.init();
+ const storedAccessToken = localStorage.getItem(AUTH_KEY);
+ if (storedAccessToken) {
+ await this.requestProfile(storedAccessToken);
+ this.accessToken = storedAccessToken;
+ }
+ }
+ console.log('AuthService.checkIfUserAuthenticated after', this.userAuthenticated);
+ return this.userAuthenticated;
+ }
+
+
+ protected async init(): Promise {
+ if (!this.inited) {
+ await this.initGoogleScripts();
+ console.log('AuthService.initialize google scripts loaded');
+ this.initTokenClient();
+ }
+ }
+
+ protected initGoogleScripts(): Promise {
+ console.log('AuthService.initGoogleScripts');
+ const p1 = this.dynamicScriptLoader.loadScript('https://accounts.google.com/gsi/client');
+ const p2 = this.dynamicScriptLoader.loadScript('https://apis.google.com/js/api.js');
+ const p3 = this.dynamicScriptLoader.loadScript('https://apis.google.com/js/client:plusone.js');
+ return Promise.all([p1, p2, p3]);
+ }
+
+
+ protected initTokenClient(): void {
+ console.log('AuthService.initTokenClient');
this.tokenClient = google.accounts.oauth2.initTokenClient({
client_id: environment.gapi.client_id,
scope: environment.gapi.scope,
- callback: this.handleAuthResponse
+ callback: this.handleTokenResponse
});
- this.authInited = true;
- console.log("GoogleUtils.gisLoaded inited")
+ this.inited = true;
}
-
- async handleAuthResponse(res: any) {
+ private async handleTokenResponse(res: any): Promise {
+ console.log('AuthService.handleTokenResponse', res);
if (res.error !== undefined) {
- this.userSignedIn = false;
+ this.userAuthenticated = false;
throw (res);
}
- console.log("GoogleUtils.handleAuthClick resp", res);
- this.requestProfile(res.access_token)
-
if (res && res.access_token) {
- gapi.client.setApiKey(environment.gapi.api_key);
- gapi.client.load('drive', 'v3');
- // await gapi.client.init({
- // apiKey: environment.gapi.api_key,
- // discoveryDocs: environment.gapi.discoveryDocs,
- // });
- this.gapiInited = true;
- }
+ await this.requestProfile(res.access_token);
- }
+ // wrong location?
+ // gapi.client.setApiKey(environment.gapi.api_key);
+ // gapi.client.load('drive', 'v3');
+ this.accessToken = res.access_token;
+ localStorage.setItem(AUTH_KEY, res.access_token);
+ }
+ }
- requestProfile(accessToken: any) {
- console.log("getUserProfileData", accessToken)
- let promise = new Promise(function (resolve, reject) {
- let request = new XMLHttpRequest();
- const url = `https://www.googleapis.com/oauth2/v3/userinfo`;
- request.addEventListener("loadend", function () {
-
- const response = JSON.parse(this.responseText);
- console.log("getUserProfileData loadend response", response)
-
- if (this.status === 200) {
- resolve(response);
- } else {
- // @ts-ignore
- reject(this, response);
- }
- });
- request.open("GET", url, true);
- request.setRequestHeader('Authorization', `Bearer ${accessToken}`);
- request.send();
- });
- console.log("getUserProfileData then");
+ async requestProfile(accessToken: string): Promise {
+ console.log('AuthService.requestProfile', accessToken);
- promise.then(
- this.handleProfileResponse, function (errorMessage) {
- console.error(errorMessage);
- });
+ const res = await fetch(GOOGLE_PROFILE_URL, {
+ method: 'get',
+ headers: new Headers({
+ Authorization: `Bearer ${accessToken}`,
+ 'Content-Type': 'application/json'
+ })
+ });
+ if (res.ok) {
+ const profileResponse = await res.json();
+ await this.handleProfileResponse(profileResponse);
+ }
+ console.log('AuthService.requestProfile end');
}
- handleProfileResponse(profileResponse: any) {
- this.profile = profileResponse;
- this.email = profileResponse.email;
- this.name = profileResponse.name;
- this.userSignedIn = true;
- this.authenticated.emit(this.profile);
- console.log("getUserProfileData response", profileResponse);
+
+ private async handleProfileResponse(profileResponse: any) {
+ console.log('AuthService.handleProfileResponse response', profileResponse);
+ this.profile = {
+ name: profileResponse.name,
+ email: profileResponse.email
+ };
+ this.userAuthenticated = true;
+ console.log('AuthService.handleProfileResponse authenticatedEvent.emit', this.profile);
+ this.authenticatedEvent.emit(this.profile);
}
- /**
- * Sign in the user upon button click.
- */
- handleAuthClick() {
- const token = gapi.client.getToken()
+ handleAuthClick(): void {
+ const token = gapi.client.getToken();
if (token) {
- console.log("AuthService.handleAuthClick Skip")
+ console.log('AuthService.handleAuthClick Skip');
// Skip display of account chooser and consent dialog for an existing session.
- this.tokenClient.requestAccessToken({prompt: '', login_hint: 'Super Hint!'});
+ this.tokenClient.requestAccessToken({prompt: '', state: AUTH_KEY});
} else {
- console.log("AuthService.handleAuthClick Prompt the user to select")
+ console.log('AuthService.handleAuthClick Prompt the user to select');
// Prompt the user to select a Google Account and ask for consent to share their data
// when establishing a new session.
- this.tokenClient.requestAccessToken({prompt: 'consent'});
+ this.tokenClient.requestAccessToken({prompt: 'consent', state: AUTH_KEY});
}
}
- initialize(authenticated: EventEmitter) {
- this.authenticated = authenticated;
- this.googleOAuthInit();
- }
-
- checkIfUserAuthenticated() {
- console.log("AuthService.checkIfUserAuthenticated", this.userSignedIn)
-
- return this.userSignedIn;
+ public async getAuthorizationHeader(): Promise {
+ if (await this.checkIfUserAuthenticated()) {
+ return 'Bearer ' + this.accessToken;
+ } else {
+ throw new Error('User is not authenticated');
+ }
}
- public getAuthorizationHeader(): string {
- const token = gapi.auth.getToken();
- // @ts-ignore
- return token.token_type + ' ' + token.access_token;
+ public get allowToSignIn(): boolean {
+ return this.inited;
}
}
diff --git a/src/app/general/service/dynamic-script-loader.service.ts b/src/app/general/service/dynamic-script-loader.service.ts
new file mode 100644
index 0000000..9dc2406
--- /dev/null
+++ b/src/app/general/service/dynamic-script-loader.service.ts
@@ -0,0 +1,23 @@
+import { Injectable } from '@angular/core';
+
+@Injectable({
+ providedIn: 'root'
+})
+export class DynamicScriptLoaderService {
+
+ public loadScript(url: string): Promise {
+ return new Promise((resolve, reject) => {
+ const script = document.createElement('script');
+ script.type = 'text/javascript';
+ script.src = url;
+ script.onload = (): any => {
+ resolve();
+ };
+ script.onerror = () => {
+ reject(new Error(`Script load error for ${url}`));
+ };
+ document.head.appendChild(script);
+ });
+ }
+
+}
diff --git a/src/app/general/service/logged-in.guard.ts b/src/app/general/service/logged-in.guard.ts
index d60d525..a7920eb 100644
--- a/src/app/general/service/logged-in.guard.ts
+++ b/src/app/general/service/logged-in.guard.ts
@@ -9,13 +9,13 @@ export class LoggedInGuard implements CanActivate {
constructor(
private authService: AuthService
) {
- console.log("LoggedInGuard.constructor")
+ console.log("LoggedInGuard.constructor");
}
public async canActivate(): Promise {
- const canActivate = this.authService.checkIfUserAuthenticated()
- console.log("LoggedInGuard.canActivate", canActivate);
- return canActivate;
+ const userAuthenticated = await this.authService.checkIfUserAuthenticated();
+ console.log("LoggedInGuard.canActivate", userAuthenticated);
+ return userAuthenticated;
}
}
diff --git a/src/app/login-home/login-home.component.html b/src/app/login-home/login-home.component.html
index 2212eb5..4aec442 100644
--- a/src/app/login-home/login-home.component.html
+++ b/src/app/login-home/login-home.component.html
@@ -12,7 +12,7 @@
-
+
diff --git a/src/app/login-home/login-home.component.ts b/src/app/login-home/login-home.component.ts
index ffe601a..e6e6712 100644
--- a/src/app/login-home/login-home.component.ts
+++ b/src/app/login-home/login-home.component.ts
@@ -1,5 +1,5 @@
import {Component, EventEmitter, OnInit, Output} from '@angular/core';
-import {AuthService} from "../general/service/auth.service";
+import {AuthService, Profile} from '../general/service/auth.service';
import {ActivatedRoute, Router} from "@angular/router";
@Component({
@@ -9,33 +9,33 @@ import {ActivatedRoute, Router} from "@angular/router";
})
export class LoginHomeComponent implements OnInit {
- @Output() authenticated: EventEmitter = new EventEmitter();
+ @Output() authenticatedEvent!: EventEmitter;
constructor(
- private authService: AuthService,
+ protected authService: AuthService,
private router: Router
) {
this.userAuthenticated = this.userAuthenticated.bind(this);
- this.authenticated.subscribe({
- next: (value:any) => this.userAuthenticated(value),
- error: (err:any) => console.error('Authentication error ' , err)
+ this.authenticatedEvent = this.authService.authenticatedEvent;
+ this.authenticatedEvent.subscribe({
+ next: (value: any) => this.userAuthenticated(value),
+ error: (err: any) => console.error('Authentication error ' , err)
});
}
userAuthenticated(profile: any) {
- console.log("LoginHomeComponent.userAuthenticated", profile)
+ console.log("LoginHomeComponent.userAuthenticated", profile);
this.gotoDefault();
}
gotoDefault() {
+ console.log("LoginHomeComponent.gotoDefault");
this.router.navigate(["/manager"]);
}
- ngOnInit(): void {
+ async ngOnInit(): Promise {
console.log("LoginHomeComponent.ngOnInit")
- if (!this.authService.checkIfUserAuthenticated()) {
- this.authService.initialize(this.authenticated);
- } else {
+ if (await this.authService.checkIfUserAuthenticated()) {
this.gotoDefault();
}
}
diff --git a/src/app/manager/manager-panel/manager-panel.component.html b/src/app/manager/manager-panel/manager-panel.component.html
index 5955449..8377bd6 100644
--- a/src/app/manager/manager-panel/manager-panel.component.html
+++ b/src/app/manager/manager-panel/manager-panel.component.html
@@ -5,7 +5,7 @@
diff --git a/src/app/manager/manager-panel/manager-panel.component.ts b/src/app/manager/manager-panel/manager-panel.component.ts
index 41461cd..d388fdc 100644
--- a/src/app/manager/manager-panel/manager-panel.component.ts
+++ b/src/app/manager/manager-panel/manager-panel.component.ts
@@ -1,5 +1,5 @@
-import {Component, EventEmitter, OnInit, Output} from '@angular/core';
-import {AuthService} from '../../general/service/auth.service';
+import {Component, EventEmitter, Input, OnInit, Output} from '@angular/core';
+import {AuthService, Profile} from '../../general/service/auth.service';
import {MatDialog} from '@angular/material/dialog';
import {NewDiagramDialogComponent, NewDiagramDialogData} from '../new-diagram-dialog/new-diagram-dialog.component';
import {DiagramService} from '../../data-access/service/diagram.service';
@@ -14,20 +14,28 @@ import {DiagramItem} from '../../data-access/model/diagram-item.model';
})
export class ManagerPanelComponent implements OnInit {
+ @Input() name = '';
+
@Output() loadingEvent = new EventEmitter();
constructor(
public auth: AuthService,
protected dialog: MatDialog,
protected diagramService: DiagramService,
- private router: Router,
- protected templateService: TemplateService
+ private router: Router
) {
}
ngOnInit(): void {
+ if (this.auth.profile) {
+ this.updateProfileInfo(this.auth.profile);
+ }
}
+ updateProfileInfo(profile: Profile) {
+ console.log('ManagerPanelComponent.handleProfileUpdate');
+ this.name = profile.name;
+ }
public createNewDiagram(): void {
// console.log('ManagerPanelComponent.createNewDiagram');
diff --git a/src/index.html b/src/index.html
index 1bb6ea5..10aa13c 100644
--- a/src/index.html
+++ b/src/index.html
@@ -8,10 +8,6 @@
-
-
-
-
diff --git a/tslint.json b/tslint.json
index 277c8eb..3a0b637 100644
--- a/tslint.json
+++ b/tslint.json
@@ -11,6 +11,7 @@
]
},
"array-type": false,
+ "only-arrow-functions": false,
"arrow-return-shorthand": true,
"curly": true,
"deprecation": {
@@ -65,7 +66,7 @@
"as-needed"
],
"quotemark": [
- true,
+ false,
"single"
],
"semicolon": {
@@ -82,10 +83,7 @@
"named": "never"
}
},
- "typedef": [
- true,
- "call-signature"
- ],
+ "typedef": [],
"typedef-whitespace": {
"options": [
{