import {Injectable} from '@angular/core'; import {HttpClient, HttpErrorResponse} from '@angular/common/http'; import {Observable} from 'rxjs/Observable'; import 'rxjs/add/operator/map'; import 'rxjs/add/operator/catch'; import 'rxjs/add/observable/of'; import {CookieService} from 'ngx-cookie-service'; import {MatTableDataSource} from '@angular/material'; import {SnackBarService} from './snackbar.service'; import {StompConfig, StompRService} from '@stomp/ng2-stompjs'; import {Message} from '@stomp/stompjs'; import {environment} from '../environments/environment'; import * as t from './types/types.module'; @Injectable() export class UserService { private _loggedIn: boolean = false; public user: t.User; public userState: t.UserState; public messages: string[] = []; // local copy of services public services: t.Service[] = []; public groupMap = new Map(); public groupsParsed = false; constructor( public cookieService: CookieService, public http: HttpClient, public snackBar: SnackBarService, private _stompService: StompRService, ) { this.update(); } // PRIVATE API private initStomp() { // handle with care let login = this.user.id let passcode = this.cookieService.get('sessionid'); const stompConfig: StompConfig = { // Which server? url: 'wss://hdf-portal.data.kit.edu/ws', // Headers // Typical keys: login, passcode, host headers: { login: 'webpage-client:' + login, passcode: passcode, }, // How often to heartbeat? // Interval in milliseconds, set to 0 to disable heartbeat_in: 0, // Typical value 0 - disabled heartbeat_out: 20000, // Typical value 20000 - every 20 seconds // Wait in milliseconds before attempting auto reconnect // Set to 0 to disable // Typical value 5000 (5 seconds) reconnect_delay: 5000, // Will log diagnostics on console debug: false, }; this._stompService.config = stompConfig; this._stompService.initAndConnect(); } private connectLiveUpdates() { this.initStomp(); let subscription = this._stompService.subscribe( '/exchange/update/' + this.user.id.toString() ); subscription.subscribe( (message: Message) => { let update : t.StateAPIResult = JSON.parse(message.body); if (update.error && update.error != '') { this.snackBar.open(update.error); this.messages.push(update.error); } if (update.user_state) { this.updateUserState(update.user_state); } }, (error: any) => { console.log(error) } ); } private updateUser(newUser: t.User) { this.user = newUser; } private updateServices(newServices: t.Service[]){ if (this.services.length !== newServices.length) { this.services = []; for (let service of newServices) { this.services.push(service); } for (let group of this.user.groups) { this.groupMap.set(group.name, this._getServices(group.name)); } this.groupsParsed = true; } } private _getServices(groupName: string) : t.Service[] { let services: t.Service[] = []; return this.services.filter( (service: t.Service) => { return service.groups.some( (group : t.Group) => { return group.name === groupName; } ); } ); } private updateUserState(newState: t.UserState) { // did a login occur? let login = (!this._loggedIn && newState); // did a logout occur? let logout = (this._loggedIn && !newState); // -- Value updating -- if (login) { this._loggedIn = true; this.snackBar.open('Logged in'); this.connectLiveUpdates(); } if (logout) { this._logout() return } this.userState = newState; } private _logout() { this._loggedIn = false; this.snackBar.open('Logged out'); this._stompService.disconnect(); this.services = []; this.user = null; this.userState = null; } private stateAPIUpdate(update: t.StateAPIResult) { if (update) { this.updateUser(update.user) this.updateUserState(update.user_state); this.updateServices(update.services); // report an occured error if (update.error) { this.snackBar.open(update.error); } } else { console.log("Got null update"); } } private setIdPPreference(idp: t.IdP) { this.cookieService.set(environment.idpCookieName, String(idp.id)); } // PUBLIC API public getDeployment(service: t.Service): t.Deployment { return this.userState.deployments.find( dep => { return dep.service.id === service.id; } ); } public getServices(group: t.Group): t.Service[] | undefined { return this.groupMap.get(group.name); } public getGroups(): t.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; } } ); } return [] } public userInfo(): MatTableDataSource { const userInfoList = []; for (const key in this.user.userinfo) { if (this.user.userinfo.hasOwnProperty(key)) { userInfoList.push({name: key, info: this.user.userinfo[key]}); } } return new MatTableDataSource(userInfoList); } public sshKeyTable(): MatTableDataSource { return new MatTableDataSource(this.user.ssh_keys); } public loggedIn():boolean { if (this.userState) { return true; } return false; } public update() { this.http .get('/backend/api/state') .subscribe( (data: t.StateAPIResult) => { this.stateAPIUpdate(data); }, (err: HttpErrorResponse) => { console.log('Error', err); this.snackBar.open('Error receiving data from the server'); } ); } public errorHandler(error: any): void { if (error.status === 500) { this.snackBar.open('Server Error'); } } public getIdPPreference(): Observable { let idpID = Number(this.cookieService.get(environment.idpCookieName)); return this.http.get('/backend/auth/v1/info').map( (authInfo: t.AuthInfo) => { let selected = authInfo.idps[1]; if (!idpID) { idpID = authInfo.default; } for (const idp of authInfo.idps) { if (idp.id === idpID) { selected = idp; } } return { idps: authInfo.idps, selected: selected, }; } ).catch( (error: any) => { this.errorHandler(error); return Observable.of(null); } ); } public login(idp: t.IdP) { this.setIdPPreference(idp); window.location.href = 'https://hdf-portal.data.kit.edu/backend/auth/v1/request'; } public logout() { this.http.post('/backend/auth/v1/logout', {}).subscribe( (data: t.StateAPIResult) => { this.stateAPIUpdate(data); }, (err) => { console.log(err); this._logout(); } ); } public sentQuestionnaire(stateItemID: number, answers: any) { return this.http.post('/backend/api/questionnaire?id='+String(stateItemID), answers).subscribe( (data: t.UserState) => { this.snackBar.open('Uploaded questionnaire'); this.updateUserState(data); }, (err) => { this.snackBar.open('Error uploading questionnaire'); console.log(err); this.update(); } ); } public deleteUser() { return this.http.delete('/backend/api/delete_user').subscribe( (data: {deleted: boolean}) => { if (data && data.deleted) { this._logout(); this.snackBar.open('Deleted user from server'); } }, (err) => { this.snackBar.open('Error deleting user from server'); console.log(err); this.update(); } ); } }