Skip to content
This repository was archived by the owner on Oct 26, 2024. It is now read-only.

Commit 0d55b01

Browse files
committed
refactor(select-union): extract to separate component
1 parent bf14955 commit 0d55b01

23 files changed

+385
-222
lines changed

src/_constants/unions.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import {InjectionToken} from '@angular/core';
2+
3+
export const unions: UnionMap = {
4+
mydata: {key: 'mydata', name: 'My Data', url: 'https://mydata.webtree.org/applyToken'},
5+
imprint: {key: 'imprint', name: 'Imprint', url: 'https://imprint.webtree.org/applyToken'}
6+
};
7+
8+
export interface Union {
9+
key: string;
10+
name: string;
11+
url: string;
12+
}
13+
14+
export type UnionMap = Record<string, Union>;
15+
16+
export const UNIONS_TOKEN = new InjectionToken<UnionMap>('unions');

src/_helpers/login.guard.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import {Injectable} from '@angular/core';
2+
import {ActivatedRouteSnapshot, CanActivate, RouterStateSnapshot} from '@angular/router';
3+
import {Observable} from 'rxjs';
4+
import {map} from 'rxjs/operators';
5+
import {AuthenticationService} from '../_services/authentication.service';
6+
import {TokenService} from '../_services/token.service';
7+
8+
@Injectable({providedIn: 'root'})
9+
export class LoginGuard implements CanActivate {
10+
constructor(
11+
private tokenService: TokenService,
12+
private authenticationService: AuthenticationService,
13+
) {
14+
}
15+
16+
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> | boolean {
17+
if (!this.tokenService.tokenExists()) {
18+
return true;
19+
}
20+
21+
return this.tokenService.isTokenValid().pipe(
22+
map(isValid => {
23+
if (isValid) {
24+
return !this.authenticationService.redirectToUnionIfNeeded(route);
25+
}
26+
return true;
27+
})
28+
);
29+
}
30+
}

src/_models/index.ts

Lines changed: 0 additions & 1 deletion
This file was deleted.

src/_services/alert.service.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import {Injectable} from '@angular/core';
22
import {MatSnackBar} from '@angular/material';
33

4-
@Injectable()
4+
@Injectable({ providedIn: 'root'})
55
export class AlertService {
66

77
constructor(private snackBar: MatSnackBar) {
Lines changed: 50 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,67 @@
1-
import {Injectable} from '@angular/core';
2-
import 'rxjs/add/operator/map';
1+
import {HttpClient, HttpErrorResponse} from '@angular/common/http';
2+
import {Inject, Injectable} from '@angular/core';
3+
import {Observable, of} from 'rxjs';
4+
import {catchError, map} from 'rxjs/operators';
35
import {TokenService} from './token.service';
4-
import {HttpClient} from '@angular/common/http';
56
import {environment} from '../environments/environment';
6-
import {User} from '../_models';
7+
import {User} from '../_models/User';
8+
import {AlertService} from './alert.service';
9+
import {ActivatedRouteSnapshot} from '@angular/router';
10+
import {Union, UnionMap, UNIONS_TOKEN} from '../_constants/unions';
11+
import {DOCUMENT} from '@angular/common';
712

8-
@Injectable()
13+
@Injectable({providedIn: 'root'})
914
export class AuthenticationService {
1015
constructor(private http: HttpClient,
11-
private tokenService: TokenService) {
16+
private alertService: AlertService,
17+
private tokenService: TokenService,
18+
@Inject(UNIONS_TOKEN) private unions: UnionMap,
19+
@Inject(DOCUMENT) private document: Document,
20+
) {
1221
}
1322

14-
login(user: User) {
15-
return this.http.post(environment.backendUrl + 'token/new', user, {responseType: 'text'});
23+
login(user: User): Observable<string | null> {
24+
return this.http.post<{ token: string }>(environment.backendUrl + 'token/new', user)
25+
.pipe(
26+
map(res => {
27+
if ('token' in res) {
28+
return res.token;
29+
}
30+
return null;
31+
}),
32+
catchError((error: HttpErrorResponse) => {
33+
console.log(error);
34+
if (error.status === 401) {
35+
this.alertService.error(error.error);
36+
return of(null);
37+
}
38+
})
39+
);
1640
}
1741

1842
logout() {
1943
this.tokenService.removeToken();
2044
}
2145

22-
async isAuthorized(): Promise<boolean> {
23-
if (!this.tokenService.tokenExists()) {
24-
return Promise.resolve(this.tokenService.tokenExists());
25-
}
46+
redirectToUnionIfNeeded(route: ActivatedRouteSnapshot): boolean {
47+
const returnUnion = route.queryParamMap.get('returnUnion');
2648

27-
return this.http.post(environment.backendUrl + 'checkToken', this.tokenService.getToken())
28-
.toPromise()
29-
.then(() => {
49+
if (typeof returnUnion === 'string') {
50+
if (returnUnion in this.unions) {
51+
this.redirectToUnion(this.unions[returnUnion]);
3052
return true;
31-
}).catch((err) => {
32-
if (err.status !== 401) {
33-
console.error(err);
34-
}
35-
this.tokenService.removeToken();
36-
return false;
37-
});
53+
} else {
54+
this.alertService.error(`Unknown union: ${returnUnion}`);
55+
}
56+
}
57+
58+
return false;
59+
}
60+
61+
redirectToUnion({url}: Union): void {
62+
const token = this.tokenService.getToken();
63+
const tokenizedUrl = `${url}#token=${token}`;
64+
65+
this.document.location.href = tokenizedUrl;
3866
}
3967
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import {TestBed} from '@angular/core/testing';
2+
3+
import {BrowserStorageService} from './browser-storage.service';
4+
5+
describe('BrowserStorageServiceService', () => {
6+
beforeEach(() => TestBed.configureTestingModule({}));
7+
8+
it('should be created', () => {
9+
const service: BrowserStorageService = TestBed.get(BrowserStorageService);
10+
expect(service).toBeTruthy();
11+
});
12+
});
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import { Inject, Injectable, InjectionToken } from '@angular/core';
2+
3+
export const BROWSER_STORAGE = new InjectionToken<Storage>('Browser Storage', {
4+
providedIn: 'root',
5+
factory: () => localStorage
6+
});
7+
8+
@Injectable({
9+
providedIn: 'root'
10+
})
11+
export class BrowserStorageService {
12+
constructor(@Inject(BROWSER_STORAGE) public storage: Storage) {}
13+
14+
get(key: string) {
15+
return this.storage.getItem(key);
16+
}
17+
18+
set(key: string, value: string) {
19+
return this.storage.setItem(key, value);
20+
}
21+
22+
remove(key: string) {
23+
return this.storage.removeItem(key);
24+
}
25+
26+
clear() {
27+
this.storage.clear();
28+
}
29+
}

src/_services/index.ts

Lines changed: 0 additions & 4 deletions
This file was deleted.

src/_services/token.service.ts

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,45 @@
11
import {Injectable} from '@angular/core';
2+
import {Observable, of} from 'rxjs';
3+
import {environment} from '../environments/environment';
4+
import {catchError, mapTo} from 'rxjs/operators';
5+
import {HttpClient, HttpErrorResponse} from '@angular/common/http';
6+
import {BrowserStorageService} from './browser-storage.service';
27

3-
@Injectable()
8+
@Injectable({providedIn: 'root'})
49
export class TokenService {
510
private tokenName = 'token';
611

12+
constructor(private http: HttpClient,
13+
private storage: BrowserStorageService) {
14+
}
15+
716
tokenExists(): boolean {
817
return !!this.getToken();
918
}
1019

1120
getToken(): string {
12-
return localStorage.getItem(this.tokenName);
21+
return this.storage.get(this.tokenName);
1322
}
1423

1524
saveToken(token: string) {
16-
localStorage.setItem(this.tokenName, token);
25+
this.storage.set(this.tokenName, token);
1726
}
1827

1928
removeToken(): void {
20-
localStorage.removeItem('token');
29+
this.storage.remove('token');
30+
}
31+
32+
isTokenValid(): Observable<boolean> {
33+
return this.http.post(environment.backendUrl + 'checkToken', this.getToken())
34+
.pipe(
35+
mapTo(true),
36+
catchError((err: HttpErrorResponse) => {
37+
if (err.status !== 401) {
38+
console.error(err);
39+
}
40+
this.removeToken();
41+
return of(false);
42+
})
43+
);
2144
}
2245
}

src/_services/user.service.ts

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,29 @@
11
import {Injectable} from '@angular/core';
22

3-
import {User} from '../_models';
4-
import {HttpClient} from '@angular/common/http';
3+
import {User} from '../_models/User';
4+
import {HttpClient, HttpErrorResponse} from '@angular/common/http';
55
import {Observable} from 'rxjs/Observable';
66
import {environment} from '../environments/environment';
7+
import {catchError} from 'rxjs/operators';
8+
import {of, throwError} from 'rxjs';
79

8-
@Injectable()
10+
@Injectable({providedIn: 'root'})
911
export class UserService {
1012
constructor(private http: HttpClient) {
1113
}
1214

13-
create(user: User): Observable<User> {
15+
create(user: User): Observable<User | null> {
1416
const url = environment.backendUrl + 'user/register';
15-
return this.http.post<User>(url, user);
17+
18+
return this.http.post<User | null>(url, user).pipe(
19+
catchError((error: HttpErrorResponse) => {
20+
console.error(error);
21+
if (error.status === 400) {
22+
return of(null);
23+
} else {
24+
return throwError(error);
25+
}
26+
})
27+
);
1628
}
1729
}

0 commit comments

Comments
 (0)