Commit 8f062f2b authored by Lukas Burgey's avatar Lukas Burgey
Browse files

Rework user data service

parent 8cb27251
<div class="body" class="mat-typography" class="body" >
<div *ngIf="userService.subscribeLoggedIn() | async">
<div *ngIf="(userService.subscribeUser() | async) as user">
<mat-tab-group>
<mat-tab label="Your VOs">
<div class="mat-typography" class="body">
<h2>Your Virtual Organisations</h2>
<div *ngIf="(userService.subscribeSpecific(userService.groupSelector) | async) as groups; else noGroups">
<mat-accordion *ngIf="groups.length > 0; else noGroups">
<div>
<mat-accordion *ngIf="(userService.subscribeGroups() | async) as groups">
<app-vo-data *ngFor="let group of groups" [group]="group"></app-vo-data>
</mat-accordion>
<ng-template #noGroups>
<p>
You are not member in any Virtual Organisations.
</p>
</ng-template>
</div>
<ng-template #noGroups>
<p>
You are not member in any Virtual Organisations.
</p>
</ng-template>
</div>
</mat-tab>
<!--
......
......@@ -4,22 +4,20 @@
Federated User Credential Deployment Portal
</h1>
<div class="header-bar">
<div *ngIf="(userService.subscribeLoggedIn() | async); else notLoggedIn">
<span *ngIf="(userService.subscribeUser() | async) as user">
<button mat-button mat-icon-button (click)="dialog.openAccount()">
<mat-icon>settings</mat-icon>
</button>
<button *ngIf="user.profile_name != undefined" mat-button (click)="dialog.openProfile(user)">
{{ user.profile_name }}
</button>
<button *ngIf="user.profile_name == undefined" mat-button (click)="dialog.openProfile(user)">
Profile
</button>
<button mat-raised-button color="accent" (click)="userService.logout()">
Logout
</button>
</span>
</div>
<span *ngIf="(userService.subscribeUser() | async) as user; else notLoggedIn">
<button mat-button mat-icon-button (click)="dialog.openAccount()">
<mat-icon>settings</mat-icon>
</button>
<button *ngIf="user.profile_name != undefined" mat-button (click)="dialog.openProfile(user)">
{{ user.profile_name }}
</button>
<button *ngIf="user.profile_name == undefined" mat-button (click)="dialog.openProfile(user)">
Profile
</button>
<button mat-raised-button color="accent" (click)="userService.logout()">
Logout
</button>
</span>
<ng-template #notLoggedIn>
<span>
<form (ngSubmit)="userService.login(selectedIdP)" #loginForm="ngForm">
......
import {Injectable} from '@angular/core';
import {HttpClient, HttpErrorResponse} from '@angular/common/http';
import {MatTableDataSource} from '@angular/material';
import { Injectable } from '@angular/core';
import { HttpClient, HttpErrorResponse } from '@angular/common/http';
import {Observable} from 'rxjs/Observable';
import {BehaviorSubject} from 'rxjs/BehaviorSubject';
import {Subject} from 'rxjs/Subject';
import { Observable } from 'rxjs/Observable';
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
import {CookieService} from 'ngx-cookie-service';
import {StompConfig, StompRService} from '@stomp/ng2-stompjs';
import {Message} from '@stomp/stompjs';
import { CookieService } from 'ngx-cookie-service';
import { StompConfig, StompRService } from '@stomp/ng2-stompjs';
import { Message } from '@stomp/stompjs';
import { SnackBarService } from './snackbar.service';
import { IdpService } from './idp.service';
import {SnackBarService} from './snackbar.service';
import {IdpService} from './idp.service';
// import * as t from './types/types.module';
import { User, Update, State, Deployment, SSHKey, NewSSHKey, Group, IdP, Service } from './types/types.module';
......@@ -20,18 +18,17 @@ import { User, Update, State, Deployment, SSHKey, NewSSHKey, Group, IdP, Service
export class UserService {
private initialized = false;
private loggedIn: boolean = false;
private loggedIn$ = new BehaviorSubject<boolean>(false);
private user: User;
private user$ = <BehaviorSubject<User>> new BehaviorSubject(undefined);
private user$: BehaviorSubject<User>;
private sshKeys: SSHKey[] = new Array<SSHKey>();
private sshKeys$ = new BehaviorSubject<SSHKey[]>(this.sshKeys);
private sshKeys$ = new BehaviorSubject<SSHKey[]>([]);
private deployments: Map<number, Deployment> = new Map([]);
private deployments$ = <BehaviorSubject<Deployment[]>> new BehaviorSubject([]);
private deployments$ = new BehaviorSubject<Deployment[]>([]);
public groupSelector = (user: User) => user ? user.groups ? user.groups : [] : [];
public groupSelector = (user: User) => user ? user.groups : [];
public serviceSelector = (user: User) => user ? user.services ? user.services : [] : [];
constructor(
......@@ -39,24 +36,44 @@ export class UserService {
private http: HttpClient,
private snackBar: SnackBarService,
private idpService: IdpService,
private _stompService: StompRService,
private stompService: StompRService,
) {
this.user$ = new BehaviorSubject(null);
this.connect();
}
// PRIVATE API
private disconnect(): void {
this.loggedIn = false;
this.sshKeys$.complete();
this.loggedIn$.next(this.loggedIn);
}
private connect(): void {
this.fetch();
this.subscribeUser().subscribe(
(newUser: User) => {
// update users
if (newUser != undefined) {
console.log(newUser);
if (newUser == undefined || newUser == null) {
// LOGGED OUT
// show the logout to the user
if (this.loggedIn) {
this.snackBar.open('Logged out');
// purge all values
this.stompService.disconnect();
this.user = undefined;
this.deployments = new Map([]);
this.deployments$.next([]);
this.sshKeys = [];
this.sshKeys$.next([]);
}
this.loggedIn = false;
} else {
// LOGGED IN
// show the login to the user
if (!this.loggedIn) {
this.snackBar.open('Logged in');
}
if (newUser.id) {
this.connectLiveUpdates(newUser.id);
......@@ -74,40 +91,13 @@ export class UserService {
this.deployments$.next(Array.from(this.deployments.values()));
}
}
},
this.logErrorAndFetch,
() => console.log('user$ is complete'),
);
this.subscribeLoggedIn().subscribe(
(loggedIn: boolean) => {
if (loggedIn) {
if (!this.initialized) {
this.snackBar.open('Logged in');
}
this.loggedIn = true;
this.initialized = true;
}
if (!loggedIn && this.initialized) {
console.log('Logging out');
this._stompService.disconnect();
this.user$.complete();
this.deployments$.complete();
this.sshKeys$.complete();
this.snackBar.open('Logged out');
}
},
this.logErrorAndFetch,
() => console.log('loggedIn$ completed'),
this.handleError(true),
() => console.log('user$ is complete'),
);
// start pulling updates
this.fetch();
}
private connectLiveUpdates(userID: number): void {
......@@ -138,10 +128,10 @@ export class UserService {
// Will log diagnostics on console
debug: false,
};
this._stompService.config = stompConfig;
this._stompService.initAndConnect();
this.stompService.config = stompConfig;
this.stompService.initAndConnect();
let subscription = this._stompService.subscribe(
let subscription = this.stompService.subscribe(
'/exchange/users/' + userID.toString()
);
......@@ -163,10 +153,14 @@ export class UserService {
);
}
private updateState(update: State) {
console.log('updateState:', update);
private updateDeployment(dep: Deployment): void {
if (dep) {
this.deployments.set(dep.id, dep);
this.deployments$.next(Array.from(this.deployments.values()));
}
}
private updateState(update: State): void {
if (update) {
// report an occured error
if (update.error) {
......@@ -174,87 +168,46 @@ export class UserService {
this.snackBar.open(update.error);
}
// did a login occur?
let login = (!this.loggedIn && update.user);
// did a logout occur?
let logout = (this.loggedIn && !update.user);
// -- Value updating --
if (logout) {
this.loggedIn = false;
this.loggedIn$.next(this.loggedIn);
return
}
if (login) {
this.loggedIn = true;
this.loggedIn$.next(this.loggedIn);
}
if (update.user) {
this.user = update.user;
this.user$.next(this.user);
}
this.user = update.user;
this.user$.next(this.user);
} else {
this.disconnect();
return
this.user$.next(undefined);
}
}
private fetch(): void {
this.http.get('/backend/api/state').subscribe(
this.http.get<State>('/backend/api/state').subscribe(
(state: State) => this.updateState(state),
(err: any) => {
console.log('Error in fetch:', err);
this.snackBar.open('Error. Retry sometime later');
}
this.handleError(false, 'Error fetching state. Try again later'),
);
}
private updateDeployment(dep: Deployment): void {
if (dep) {
this.deployments.set(dep.id, dep);
this.deployments$.next(Array.from(this.deployments.values()));
}
}
private handleError(fetch: boolean, msg?: string) {
return (error: any) => {
if (error.status == 403) {
this.login();
return
}
// PUBLIC API
public serviceDescription(service: Service): string {
if (service.description != "") {
return service.description;
if (msg) {
this.snackBar.open(msg);
}
console.log('fetch:', error);
if (fetch) {
this.fetch();
}
}
return "No description";
}
public getGroups(): Group[] {
if (this.user.groups) {
return this.user.groups.sort(
function(a,b) {
if (a.name < b.name) {
return -1;
} else if (a.name > b.name) {
return 1;
} else if (a.name === b.name) {
return 0;
}
}
);
private catchError(fetch: boolean, msg?: string) {
return (error: any) => {
this.handleError(fetch, msg)(error);
return Observable.throw(error);
}
return []
}
public getDeployment(service: Service): Deployment {
return this.user.deployments.find(
dep => dep.service && dep.service.id === service.id
);
}
public getServices(group: Group): Service[] {
// TODO implement
//
return []
}
public logErrorAndFetch(error: any) {
private logErrorAndFetch(error: any) {
if (error.status === 403) {
this.login();
}
......@@ -265,6 +218,14 @@ export class UserService {
return Observable.throw(error);
}
// PUBLIC API
public serviceDescription(service: Service): string {
if (service.description != "") {
return service.description;
}
return "No description";
}
public login(idp?: IdP): void {
if (idp) {
this.idpService.setIdPPreference(idp);
......@@ -273,21 +234,16 @@ export class UserService {
window.location.href = '/backend/auth/v1/request';
}
public logout() {
this.http.post('/backend/auth/v1/logout', {}).subscribe(
public logout(): void {
this.http.post<State>('/backend/auth/v1/logout', {}).subscribe(
(state: State) => this.updateState(state),
this.logErrorAndFetch,
);
}
public sentQuestionnaire(stateItemID: number, answers: Object) {
return this.http.post('/backend/api/questionnaire?id='+String(stateItemID), answers).subscribe(
(data: Deployment) => {
this.snackBar.open('Uploaded questionnaire');
/* TODO fix
this.userUserUpdate(data);
*/
},
return this.http.post<Deployment>('/backend/api/questionnaire?id='+String(stateItemID), answers).subscribe(
(dep: Deployment) => this.updateDeployment(dep),
this.logErrorAndFetch,
);
}
......@@ -296,7 +252,7 @@ export class UserService {
return this.http.delete('/backend/api/delete_user').subscribe(
(data: {deleted: boolean}) => {
if (data && data.deleted) {
this.disconnect();
this.user$.next(undefined);
this.snackBar.open('Deleted user from server');
}
},
......@@ -305,12 +261,12 @@ export class UserService {
}
public uploadSshKey(key: NewSSHKey) {
console.log('uploading key:', key);
console.log('Uploading key:', key);
const body = {
'type': 'add',
'key': key,
};
return this.http.post('/backend/api/sshkey', body).subscribe(
return this.http.post<SSHKey>('/backend/api/sshkey', body).subscribe(
(newKey: SSHKey) => {
this.sshKeys.push(newKey);
this.sshKeys$.next(this.sshKeys);
......@@ -320,7 +276,7 @@ export class UserService {
}
public removeSshKey(key: SSHKey) {
console.log('deleting key:', key);
console.log('Deleting key:', key);
return this.http.post('/backend/api/sshkey', {
'type': 'remove',
'id': key.id,
......@@ -343,18 +299,18 @@ export class UserService {
'group': group.id,
};
return this.http.post<Deployment>('/backend/api/deployments', body).catch(
this.logErrorAndFetch,
this.catchError(true, "Error changing deployment"),
);
}
// DATA SERVICE API
//
public subscribeSSHKeys(): Observable<SSHKey[]> {
return this.sshKeys$.asObservable();
public subscribeSpecific<T>(selector: (user: User) => T): Observable<T> {
return this.subscribeUser().map(selector);
}
public subscribeLoggedIn(): Observable<boolean> {
return this.loggedIn$.asObservable();
public subscribeSSHKeys(): Observable<SSHKey[]> {
return this.sshKeys$.asObservable();
}
public subscribeUser(): Observable<User> {
......@@ -365,10 +321,12 @@ export class UserService {
return this.deployments$.asObservable();
}
public subscribeSpecific<T>(selector: (user: User) => T): Observable<T> {
return this.subscribeUser().map(selector);
public subscribeGroups(): Observable<Group[]> {
let groupSelector = (user: User) => user ? user.groups : [];
return this.subscribeSpecific<Group[]>(groupSelector);
}
public subscribeServiceDeployment(service: Service): Observable<Deployment> {
return this.subscribeDeployments().map(
(deployments: Deployment[]) => {
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment