diff options
Diffstat (limited to 'Timeline/ClientApp/src/app/user-dialog')
6 files changed, 179 insertions, 0 deletions
diff --git a/Timeline/ClientApp/src/app/user-dialog/user-dialog.component.css b/Timeline/ClientApp/src/app/user-dialog/user-dialog.component.css new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/Timeline/ClientApp/src/app/user-dialog/user-dialog.component.css diff --git a/Timeline/ClientApp/src/app/user-dialog/user-dialog.component.html b/Timeline/ClientApp/src/app/user-dialog/user-dialog.component.html new file mode 100644 index 00000000..2c5d1879 --- /dev/null +++ b/Timeline/ClientApp/src/app/user-dialog/user-dialog.component.html @@ -0,0 +1,3 @@ +<div [ngSwitch]="state"> + <app-user-login *ngSwitchCase="'login'"></app-user-login> +</div> diff --git a/Timeline/ClientApp/src/app/user-dialog/user-dialog.component.spec.ts b/Timeline/ClientApp/src/app/user-dialog/user-dialog.component.spec.ts new file mode 100644 index 00000000..884a3710 --- /dev/null +++ b/Timeline/ClientApp/src/app/user-dialog/user-dialog.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { UserDialogComponent } from './user-dialog.component'; + +xdescribe('UserDialogComponent', () => { + let component: UserDialogComponent; + let fixture: ComponentFixture<UserDialogComponent>; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ UserDialogComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(UserDialogComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/Timeline/ClientApp/src/app/user-dialog/user-dialog.component.ts b/Timeline/ClientApp/src/app/user-dialog/user-dialog.component.ts new file mode 100644 index 00000000..1d9536c8 --- /dev/null +++ b/Timeline/ClientApp/src/app/user-dialog/user-dialog.component.ts @@ -0,0 +1,20 @@ +import { Component, OnInit } from '@angular/core'; + +@Component({ + selector: 'app-user-dialog', + templateUrl: './user-dialog.component.html', + styleUrls: ['./user-dialog.component.css'] +}) +export class UserDialogComponent implements OnInit { + + constructor() { } + + state: 'login' | 'success' = 'login'; + + ngOnInit() { + } + + login() { + + } +} diff --git a/Timeline/ClientApp/src/app/user-dialog/user.service.spec.ts b/Timeline/ClientApp/src/app/user-dialog/user.service.spec.ts new file mode 100644 index 00000000..b9221b90 --- /dev/null +++ b/Timeline/ClientApp/src/app/user-dialog/user.service.spec.ts @@ -0,0 +1,12 @@ +import { TestBed } from '@angular/core/testing'; + +import { UserService } from './user.service'; + +xdescribe('UserService', () => { + beforeEach(() => TestBed.configureTestingModule({})); + + it('should be created', () => { + const service: UserService = TestBed.get(UserService); + expect(service).toBeTruthy(); + }); +}); diff --git a/Timeline/ClientApp/src/app/user-dialog/user.service.ts b/Timeline/ClientApp/src/app/user-dialog/user.service.ts new file mode 100644 index 00000000..1afebc91 --- /dev/null +++ b/Timeline/ClientApp/src/app/user-dialog/user.service.ts @@ -0,0 +1,119 @@ +import { Injectable } from '@angular/core'; +import { HttpClient, HttpErrorResponse } from '@angular/common/http'; +import { Observable, of, throwError } from 'rxjs'; +import { map, catchError, retry } from 'rxjs/operators'; + +export interface UserCredentials { + username: string; + password: string; +} + +export interface UserInfo { + username: string; + roles: string[]; +} + +export interface CreateTokenResult { + token: string; + userInfo: UserInfo; +} + +export interface TokenValidationRequest { + token: string; +} + +export interface TokenValidationResult { + isValid: boolean; + userInfo?: UserInfo; +} + +export interface UserLoginState { + state: 'nologin' | 'invalid' | 'success'; + userInfo?: UserInfo; +} + +export class BadNetworkException extends Error { + constructor() { + super('Network is bad.'); + } +} + +export class AlreadyLoginException extends Error { + constructor() { + super('There is already a token saved. Please call validateUserLoginState first.'); + } +} + +export class BadCredentialsException extends Error { + constructor(username: string = null , password: string = null) { + super(`Username[${username}] or password[${password}] is wrong.`); + } +} + +@Injectable({ + providedIn: 'root' +}) +export class UserService { + + private token: string; + private userInfo: UserInfo; + + constructor(private httpClient: HttpClient) { } + + validateUserLoginState(): Observable<UserLoginState> { + if (this.token === undefined || this.token === null) { + return of(<UserLoginState>{ state: 'nologin' }); + } + + return this.httpClient.post<TokenValidationResult>('/api/User/ValidateToken', <TokenValidationRequest>{ token: this.token }).pipe( + retry(3), + catchError(error => { + console.error('Failed to validate token.'); + return throwError(error); + }), + map(result => { + if (result.isValid) { + this.userInfo = result.userInfo; + return <UserLoginState>{ + state: 'success', + userInfo: result.userInfo + }; + } else { + this.token = null; + this.userInfo = null; + return <UserLoginState>{ + state: 'invalid' + }; + } + }) + ); + } + + tryLogin(username: string, password: string): Observable<UserInfo> { + if (this.token) { + return throwError(new AlreadyLoginException()); + } + + return this.httpClient.post<CreateTokenResult>('/api/User/CreateToken', <UserCredentials>{ + username, password + }).pipe( + catchError((error: HttpErrorResponse) => { + if (error.error instanceof ErrorEvent) { + console.error('An error occurred when login: ' + error.error.message); + return throwError(new BadNetworkException()); + } else if (error.status === 400) { + console.error('An error occurred when login: wrong credentials.'); + return throwError(new BadCredentialsException(username, password)); + } else { + console.error('An unknown error occurred when login: ' + error); + return throwError(error); + } + }), + map(result => { + this.token = result.token; + this.userInfo = result.userInfo; + return result.userInfo; + }) + ); + } +} |