Overlay until log status received
This commit is contained in:
@@ -0,0 +1,24 @@
|
||||
.overlay {
|
||||
position: fixed;
|
||||
background-color: firebrick;
|
||||
left: 0;
|
||||
right: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.logo {
|
||||
width: 50%;
|
||||
padding-top: 100px;
|
||||
}
|
||||
|
||||
.spinner-container {
|
||||
height: 360px;
|
||||
width: 390px;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
.spinner-container mat-spinner {
|
||||
margin: 130px auto 0 auto;
|
||||
}
|
||||
|
||||
@@ -4,8 +4,11 @@
|
||||
<div class="row">
|
||||
<router-outlet></router-outlet>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<router-outlet name="aux"></router-outlet>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div *ngIf="showOverlay" class="overlay">
|
||||
<img class="logo" src="/assets/img/logo.png" />
|
||||
<div class="spinner-container">
|
||||
<mat-spinner></mat-spinner>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,35 +1,21 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { OAuthService, NullValidationHandler } from 'angular-oauth2-oidc';
|
||||
import { Router } from '@angular/router';
|
||||
import { filter } from 'rxjs/operators';
|
||||
import { authConfig } from './auth.config';
|
||||
import { useHash } from '../flags';
|
||||
import { Component, ElementRef, OnInit, ViewChild } from '@angular/core';
|
||||
import { AuthService } from './services/auth.service';
|
||||
|
||||
@Component({
|
||||
// tslint:disable-next-line:component-selector
|
||||
selector: 'app-root',
|
||||
templateUrl: './app.component.html',
|
||||
styleUrls: ['./app.component.css'],
|
||||
})
|
||||
export class AppComponent {
|
||||
constructor(private router: Router, private oauthService: OAuthService) {
|
||||
this.configureCodeFlow();
|
||||
export class AppComponent implements OnInit {
|
||||
showOverlay = true;
|
||||
|
||||
// Automatically load user profile
|
||||
this.oauthService.events
|
||||
.pipe(filter((e) => e.type === 'token_received'))
|
||||
.subscribe((_) => {
|
||||
console.log('state', this.oauthService.state);
|
||||
this.oauthService.loadUserProfile();
|
||||
});
|
||||
}
|
||||
constructor(
|
||||
private authService: AuthService
|
||||
) { }
|
||||
|
||||
private configureCodeFlow(): void {
|
||||
this.oauthService.configure(authConfig);
|
||||
this.oauthService.loadDiscoveryDocumentAndTryLogin().then((_) => {
|
||||
if (useHash) {
|
||||
this.router.navigate(['/']);
|
||||
}
|
||||
});
|
||||
this.oauthService.setupAutomaticSilentRefresh();
|
||||
async ngOnInit(): Promise<void> {
|
||||
await this.authService.isLogged;
|
||||
this.showOverlay = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,15 @@
|
||||
<button *ngIf="logged" mat-raised-button class="btn btn-default" (click)="newTravel()">New travel</button>
|
||||
<button *ngIf="isLogged" mat-raised-button class="btn btn-default" (click)="newTravel()">New travel</button>
|
||||
|
||||
<mat-card>
|
||||
<mat-card-title>My travels</mat-card-title>
|
||||
<app-list *ngIf="logged" (rowClick)="travelClicked($event)" [displayedColumns]="displayedColumns"
|
||||
<div *ngIf="isLogged | async; then thenBlock; else elseBlock"></div>
|
||||
<ng-template #thenBlock>
|
||||
<app-list (rowClick)="travelClicked($event)" [displayedColumns]="displayedColumns"
|
||||
[apiCall]="myTravelsApiCall"></app-list>
|
||||
<mat-card-content *ngIf="!logged">Logueate para ver tus viajes</mat-card-content>
|
||||
</ng-template>
|
||||
<ng-template #elseBlock>
|
||||
<mat-card-content>Logueate para ver tus viajes</mat-card-content>
|
||||
</ng-template>
|
||||
</mat-card>
|
||||
|
||||
<mat-card>
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { OAuthService } from 'angular-oauth2-oidc';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { ApiService } from '../../services/api.service';
|
||||
import { Router } from '@angular/router';
|
||||
import { AuthService } from 'src/app/services/auth.service';
|
||||
import { Travel } from '../../entities/travel';
|
||||
import { ApiService } from '../../services/api.service';
|
||||
|
||||
@Component({
|
||||
templateUrl: './home.component.html',
|
||||
@@ -26,16 +26,16 @@ export class HomeComponent implements OnInit {
|
||||
myTravelsApiCall = this.apiService.getMyTravels;
|
||||
|
||||
constructor(
|
||||
private route: ActivatedRoute,
|
||||
// private route: ActivatedRoute,
|
||||
private router: Router,
|
||||
private oauthService: OAuthService,
|
||||
private authService: AuthService,
|
||||
private apiService: ApiService
|
||||
) {}
|
||||
) { }
|
||||
|
||||
ngOnInit(): void {
|
||||
this.route.params.subscribe((p) => {
|
||||
this.login = p['login'];
|
||||
});
|
||||
// this.route.params.subscribe((p) => {
|
||||
// this.login = p['login'];
|
||||
// });
|
||||
}
|
||||
|
||||
newTravel(): void {
|
||||
@@ -47,12 +47,8 @@ export class HomeComponent implements OnInit {
|
||||
this.router.navigateByUrl('/travel/' + travel.id);
|
||||
}
|
||||
|
||||
loadUserProfile(): void {
|
||||
this.oauthService.loadUserProfile().then((userProfile) => (this.userProfile = userProfile));
|
||||
}
|
||||
|
||||
get logged(): boolean {
|
||||
return this.oauthService.getIdentityClaims() != null;
|
||||
// return this.oauthService.hasValidIdToken() && this.oauthService.hasValidAccessToken();
|
||||
get isLogged(): Promise<boolean> {
|
||||
return this.authService.isLogged;
|
||||
// return this.authService.isLogged();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import { Travel, TravelId } from '../entities/travel';
|
||||
import { PUBLIC_API_URL, TRAVEL_API_URL, USER_API_URL } from '../app.config';
|
||||
import { ListDto } from '../entities/list-dto';
|
||||
import { User } from '../entities/user';
|
||||
import { AuthService } from './auth.service';
|
||||
|
||||
export type ApiCall<T> = (params?: { [param: string]: any }) => (Observable<ApiResponse<ListDto<T>>>);
|
||||
|
||||
@@ -14,7 +15,10 @@ export type ApiCall<T> = (params?: { [param: string]: any }) => (Observable<ApiR
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class ApiService {
|
||||
constructor(private http: HttpClient) { }
|
||||
constructor(
|
||||
private authService: AuthService,
|
||||
private http: HttpClient
|
||||
) { }
|
||||
|
||||
// Las llamadas al API son arrow-functions para capturar el parámetro this en la definición
|
||||
// y no en la ejecución.
|
||||
@@ -63,11 +67,32 @@ export class ApiService {
|
||||
this.http.get<ApiResponse<T>>(url, { params });
|
||||
|
||||
return response$.pipe(
|
||||
retry(0), // retry a failed request up to 3 times
|
||||
catchError(this.handleError) // then handle the error
|
||||
);
|
||||
retry(0), // retry a failed request up to 3 times
|
||||
catchError(this.handleError) // then handle the error
|
||||
);
|
||||
}
|
||||
|
||||
// private callProtectedApi<T>(
|
||||
// url: string,
|
||||
// params?: { [param: string]: any },
|
||||
// body?: any
|
||||
// ): Observable<ApiResponse<T>> {
|
||||
// const observable = new Observable<ApiResponse<T>>(observer => {
|
||||
// this.authService.configurePromise.then(logged => {
|
||||
// if (logged) {
|
||||
// this.callApi<T>(url, params, body).subscribe(res => {
|
||||
// observer.next(res);
|
||||
// });
|
||||
// }
|
||||
// else {
|
||||
// console.error('callProtectedApi: NOT LOGGED');
|
||||
// observer.error('NOT LOGGED');
|
||||
// }
|
||||
// });
|
||||
// });
|
||||
// return observable;
|
||||
// }
|
||||
|
||||
private handleError(error: HttpErrorResponse): Observable<never> {
|
||||
if (error.error instanceof ErrorEvent) {
|
||||
// A client-side or network error occurred. Handle it accordingly.
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { OAuthService } from 'angular-oauth2-oidc';
|
||||
import { authConfig } from '../auth.config';
|
||||
import { Travel } from '../entities/travel';
|
||||
import { User } from '../entities/user';
|
||||
|
||||
@@ -7,8 +8,26 @@ import { User } from '../entities/user';
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class AuthService {
|
||||
private configurePromise = null;
|
||||
|
||||
constructor(private oauthService: OAuthService) { }
|
||||
constructor(
|
||||
private oauthService: OAuthService
|
||||
) { }
|
||||
|
||||
get isLogged(): Promise<boolean> {
|
||||
if (this.configurePromise == null) {
|
||||
this.configurePromise = this.configureAndTryLogin();
|
||||
}
|
||||
return this.configurePromise;
|
||||
}
|
||||
|
||||
login(): void {
|
||||
this.oauthService.initLoginFlow();
|
||||
}
|
||||
|
||||
logout(): void {
|
||||
this.oauthService.revokeTokenAndLogout();
|
||||
}
|
||||
|
||||
currentUser(): User {
|
||||
const claims = this.oauthService.getIdentityClaims();
|
||||
@@ -16,6 +35,9 @@ export class AuthService {
|
||||
}
|
||||
|
||||
canEditTravel(travel: Travel): boolean {
|
||||
if (travel == null) {
|
||||
return false;
|
||||
}
|
||||
const user = this.currentUser();
|
||||
if (user == null) {
|
||||
return false;
|
||||
@@ -23,4 +45,47 @@ export class AuthService {
|
||||
|
||||
return user.admin || (user.id === travel.driverInfo.id);
|
||||
}
|
||||
|
||||
private async configureAndTryLogin(): Promise<boolean> {
|
||||
this.oauthService.configure(authConfig);
|
||||
this.oauthService.setupAutomaticSilentRefresh();
|
||||
|
||||
return new Promise((resolve) => {
|
||||
this.oauthService.loadDiscoveryDocumentAndTryLogin().then((_) => {
|
||||
if (this.oauthService.getIdentityClaims() != null) {
|
||||
if (this.oauthService.hasValidIdToken() && this.oauthService.hasValidAccessToken()) {
|
||||
console.log('NO NEED FOR TOKEN REFRESH');
|
||||
resolve(true);
|
||||
}
|
||||
else {
|
||||
this.oauthService.refreshToken().then(() => {
|
||||
console.log('TOKEN REFRESHED');
|
||||
resolve(true);
|
||||
}).catch(e => {
|
||||
console.error('ERROR REFRESHING TOKEN');
|
||||
console.error(e);
|
||||
resolve(false);
|
||||
});
|
||||
}
|
||||
}
|
||||
else {
|
||||
console.error('NOT LOGGED!');
|
||||
resolve(false);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Automatically load user profile
|
||||
// this.oauthService.events
|
||||
// .pipe(filter((e) => e.type === 'token_received'))
|
||||
// .subscribe((_) => {
|
||||
// console.log('state', this.oauthService.state);
|
||||
// this.oauthService.loadUserProfile();
|
||||
|
||||
// this.apiService.getUser().subscribe(user => {
|
||||
// console.log('USER');
|
||||
// console.log(user);
|
||||
// });
|
||||
// });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<img width="100%" src="/assets/img/logo.png" />
|
||||
</mat-grid-tile>
|
||||
<mat-grid-tile colspan="1" rowspan="2">
|
||||
<div *ngIf="logged; then thenBlock; else elseBlock"></div>
|
||||
<div *ngIf="isLogged | async; then thenBlock; else elseBlock"></div>
|
||||
<ng-template #thenBlock>
|
||||
{{ name }}
|
||||
<button mat-raised-button class="btn btn-default" (click)="logout()">Logout</button>
|
||||
|
||||
@@ -1,57 +1,29 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { OAuthService } from 'angular-oauth2-oidc';
|
||||
import { ApiService } from 'src/app/services/api.service';
|
||||
import { authConfig } from '../../auth.config';
|
||||
import { Component } from '@angular/core';
|
||||
import { AuthService } from 'src/app/services/auth.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-header',
|
||||
templateUrl: './header.component.html',
|
||||
styleUrls: ['./header.component.css'],
|
||||
})
|
||||
export class HeaderComponent implements OnInit {
|
||||
export class HeaderComponent {
|
||||
constructor(
|
||||
private oauthService: OAuthService,
|
||||
private apiService: ApiService
|
||||
private authService: AuthService
|
||||
) { }
|
||||
|
||||
ngOnInit(): void {
|
||||
console.log('INIT logged=' + String(this.logged));
|
||||
this.oauthService.configure(authConfig);
|
||||
this.oauthService.loadDiscoveryDocumentAndTryLogin().then(success => {
|
||||
console.log('Autologin success=' + success + ' logged=' + String(this.logged));
|
||||
console.log('USER autologin');
|
||||
if (this.logged) {
|
||||
this.apiService.getUser().subscribe(user => {
|
||||
console.log(user);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async login(): Promise<void> {
|
||||
this.oauthService.loadDiscoveryDocumentAndLogin().then(success => {
|
||||
console.log('USER login');
|
||||
if (this.logged) {
|
||||
this.apiService.getUser().subscribe(user => {
|
||||
console.log(user);
|
||||
});
|
||||
}
|
||||
});
|
||||
this.authService.login();
|
||||
}
|
||||
|
||||
logout(): void {
|
||||
this.oauthService.revokeTokenAndLogout();
|
||||
this.authService.logout();
|
||||
}
|
||||
|
||||
get logged(): boolean {
|
||||
return this.oauthService.getIdentityClaims() != null;
|
||||
get isLogged(): Promise<boolean> {
|
||||
return this.authService.isLogged;
|
||||
}
|
||||
|
||||
get name(): any {
|
||||
const claims = this.oauthService.getIdentityClaims();
|
||||
if (!claims) {
|
||||
return null;
|
||||
}
|
||||
return claims['name'];
|
||||
get name(): string {
|
||||
return this.authService.currentUser()?.name;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ import { ListDataSource } from './list.datasource';
|
||||
@Component({
|
||||
selector: 'app-list',
|
||||
templateUrl: './list.component.html',
|
||||
styleUrls: ['./list.component.css'],
|
||||
styleUrls: ['./list.component.css']
|
||||
})
|
||||
export class ListComponent<T> implements OnInit, AfterViewInit {
|
||||
dataSource: ListDataSource<T>;
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { CollectionViewer, DataSource } from '@angular/cdk/collections';
|
||||
import { Observable, BehaviorSubject, of, throwError } from 'rxjs';
|
||||
import { BehaviorSubject, Observable, throwError } from 'rxjs';
|
||||
import { catchError, finalize } from 'rxjs/operators';
|
||||
import { ApiResponse } from '../../entities/api-response';
|
||||
import { ListDto } from '../../entities/list-dto';
|
||||
import { ApiCall, ApiService } from '../../services/api.service';
|
||||
import { ApiCall } from '../../services/api.service';
|
||||
|
||||
export class ListDataSource<T> implements DataSource<T> {
|
||||
private listSubject = new BehaviorSubject<T[]>([]);
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
// Use HashLocationStrategy for routing?
|
||||
export const useHash = false;
|
||||
|
||||
// Set this to true, to use silent refresh; otherwise the example
|
||||
// uses the refresh_token via an AJAX coll to get new tokens.
|
||||
export const useSilentRefreshForCodeFlow = false;
|
||||
export const useSilentRefreshForCodeFlow = true;
|
||||
|
||||
Reference in New Issue
Block a user