user.service.ts 9.67 KB
Newer Older
Lukas Burgey's avatar
Lukas Burgey committed
1
2
import {Injectable} from '@angular/core';
import {HttpClient, HttpErrorResponse} from '@angular/common/http';
Lukas Burgey's avatar
Lukas Burgey committed
3
4
import {MatTableDataSource} from '@angular/material';

Lukas Burgey's avatar
Lukas Burgey committed
5
import {Observable} from 'rxjs/Observable';
6
import {BehaviorSubject} from 'rxjs/BehaviorSubject';
Lukas Burgey's avatar
Lukas Burgey committed
7
8

import {CookieService} from 'ngx-cookie-service';
9
10
import {StompConfig, StompRService} from '@stomp/ng2-stompjs';
import {Message} from '@stomp/stompjs';
Lukas Burgey's avatar
Lukas Burgey committed
11

Lukas Burgey's avatar
Lukas Burgey committed
12
import {SnackBarService} from './snackbar.service';
13
import {IdpService} from './idp.service';
Lukas Burgey's avatar
Lukas Burgey committed
14
import * as t from './types/types.module';
Lukas Burgey's avatar
Lukas Burgey committed
15

Lukas Burgey's avatar
Lukas Burgey committed
16
17
18

@Injectable()
export class UserService {
Lukas Burgey's avatar
Lukas Burgey committed
19
20
  private _loggedIn: boolean = false;

Lukas Burgey's avatar
Lukas Burgey committed
21
22
  private user: t.User;
  private user$ = <BehaviorSubject<t.User>> new BehaviorSubject(new Object);
23

Lukas Burgey's avatar
Lukas Burgey committed
24
  public userState: t.UserState;
Lukas Burgey's avatar
Lukas Burgey committed
25
26
27
28
  public userState$ = <BehaviorSubject<t.UserState>> new BehaviorSubject(new Object);

  private sshKeys: t.SSHKey[] = new Array<t.SSHKey>();
  private sshKeys$ = <BehaviorSubject<t.SSHKey[]>> new BehaviorSubject([]);
Lukas Burgey's avatar
Lukas Burgey committed
29

30
  public messages: string[] = [];
31
32
  // local copy of services
  public services: t.Service[] = [];
33
34
  public groupMap: Map<string, t.Service[]> = new Map();
  public groupsParsed: boolean = false;
Lukas Burgey's avatar
Lukas Burgey committed
35

36
  // TODO put in preferences cookie
Lukas Burgey's avatar
Lukas Burgey committed
37
  autoLogin = false;
38

Lukas Burgey's avatar
Lukas Burgey committed
39
40
41
42
43

  constructor(
    public cookieService: CookieService,
    public http: HttpClient,
    public snackBar: SnackBarService,
44
    public idpService: IdpService,
45
    private _stompService: StompRService,
Lukas Burgey's avatar
Lukas Burgey committed
46
  ) {
Lukas Burgey's avatar
Lukas Burgey committed
47
    this.update();
48

Lukas Burgey's avatar
Lukas Burgey committed
49

50
51
52
53
54
55
56
57
58
59
60
61
62
    // AUTO LOGIN
    this.subscribeUserState().subscribe(
      (state: t.UserState) => {
        console.log(JSON.stringify(state));

        if (!state) {
          this.idpService.subscribeIdps().subscribe(
            (idps: t.IdP[]) => {
              if (idps.length === 1 && this.autoLogin) {
                this.login(idps[0]);
              }
            }
          );
63
64
65
        }
      }
    );
66
67
68
69
70
71
72
73
74
  }

  // DATA SERVICE API
  public subscribeUserState(): Observable<t.UserState> {
    return this.userState$.asObservable();
  }

  public subscribeUser(): Observable<t.User> {
    return this.user$.asObservable();
Lukas Burgey's avatar
Lukas Burgey committed
75
76
  }

Lukas Burgey's avatar
Lukas Burgey committed
77
78
79
80
  public subscribeSSHKeys(): Observable<t.SSHKey[]> {
    return this.sshKeys$.asObservable();
  }

Lukas Burgey's avatar
Lukas Burgey committed
81
82
83
84
85
  // PRIVATE API
  private initStomp() {
    // handle with care
    let login = this.user.id
    let passcode = this.cookieService.get('sessionid');
Lukas Burgey's avatar
Lukas Burgey committed
86

Lukas Burgey's avatar
Lukas Burgey committed
87
88
    const stompConfig: StompConfig = {
      // Which server?
89
      url: 'wss://'+window.location.host+'/ws',
90

Lukas Burgey's avatar
Lukas Burgey committed
91
92
93
94
95
96
      // Headers
      // Typical keys: login, passcode, host
      headers: {
        login: 'webpage-client:' + login,
        passcode: passcode,
      },
Lukas Burgey's avatar
Lukas Burgey committed
97

Lukas Burgey's avatar
Lukas Burgey committed
98
99
100
101
102
103
      // 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
104
105
      // Typical value 15000 (15 seconds)
      reconnect_delay: 15000,
106

Lukas Burgey's avatar
Lukas Burgey committed
107
108
109
110
111
      // Will log diagnostics on console
      debug: false,
    };
    this._stompService.config = stompConfig;
    this._stompService.initAndConnect();
Lukas Burgey's avatar
Lukas Burgey committed
112
113
  }

Lukas Burgey's avatar
Lukas Burgey committed
114
115
116
  private connectLiveUpdates() {
    this.initStomp();
    let subscription = this._stompService.subscribe(
117
      '/exchange/users/' + this.user.id.toString()
Lukas Burgey's avatar
Lukas Burgey committed
118
    );
119

Lukas Burgey's avatar
Lukas Burgey committed
120
121
122
123
124
125
    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);
Lukas Burgey's avatar
Lukas Burgey committed
126
        }
Lukas Burgey's avatar
Lukas Burgey committed
127
128
        if (update.user_state) {
          this.updateUserState(update.user_state);
Lukas Burgey's avatar
Lukas Burgey committed
129
        }
Lukas Burgey's avatar
Lukas Burgey committed
130
131
132
      },
      (error: any) => {
        console.log(error)
133
      }
Lukas Burgey's avatar
Lukas Burgey committed
134
    );
Lukas Burgey's avatar
Lukas Burgey committed
135
  }
136

Lukas Burgey's avatar
Lukas Burgey committed
137
138
  private updateUser(newUser: t.User) {
    this.user = newUser;
139
    this.user$.next(this.user);
Lukas Burgey's avatar
Lukas Burgey committed
140
141
142

    this.sshKeys = this.user.ssh_keys;
    this.sshKeys$.next(this.sshKeys);
Lukas Burgey's avatar
Lukas Burgey committed
143
144
  }

145
146
147
  private updateServices(newServices: t.Service[]){
    if (this.services.length !== newServices.length) {
      this.services = [];
Lukas Burgey's avatar
wip    
Lukas Burgey committed
148

149
150
      for (let service of newServices) {
        this.services.push(service);
Lukas Burgey's avatar
Lukas Burgey committed
151
      }
Lukas Burgey's avatar
wip    
Lukas Burgey committed
152
153

      for (let group of this.user.groups) {
Lukas Burgey's avatar
Lukas Burgey committed
154
        this.groupMap.set(group.name, this._getServices(group.name));
Lukas Burgey's avatar
wip    
Lukas Burgey committed
155
156
      }
      this.groupsParsed = true;
Lukas Burgey's avatar
Lukas Burgey committed
157
158
159
    }
  }

Lukas Burgey's avatar
Lukas Burgey committed
160
161
162
  private updateUserState(newState: t.UserState) {
      // did a login occur?
    let login = (!this._loggedIn && newState);
Lukas Burgey's avatar
Lukas Burgey committed
163
    // did a logout occur?
Lukas Burgey's avatar
Lukas Burgey committed
164
    let logout = (this._loggedIn && !newState);
Lukas Burgey's avatar
Lukas Burgey committed
165
166
167

    // -- Value updating --
    if (login) {
Lukas Burgey's avatar
Lukas Burgey committed
168
      this._loggedIn = true;
169
      this.snackBar.open('Logged in');
170
171


Lukas Burgey's avatar
Lukas Burgey committed
172
      this.connectLiveUpdates();
173
    }
Lukas Burgey's avatar
Lukas Burgey committed
174
    if (logout) {
175
176
      this._logout()
      return
Lukas Burgey's avatar
Lukas Burgey committed
177
178
179
    }

    this.userState = newState;
180
    this.userState$.next(this.userState);
Lukas Burgey's avatar
Lukas Burgey committed
181
182
  }

Lukas Burgey's avatar
wip    
Lukas Burgey committed
183
184
185
186
187
188
189
  private _logout() {
    this._loggedIn = false;
    this.snackBar.open('Logged out');
    this._stompService.disconnect();
    this.services = [];
    this.user = null;
    this.userState = null;
190
    this.userState$.complete();
Lukas Burgey's avatar
wip    
Lukas Burgey committed
191
192
  }

Lukas Burgey's avatar
Lukas Burgey committed
193
  private stateAPIUpdate(update: t.StateAPIResult) {
194
195
196
197
198
199
200
201
202
203
204
    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");
Lukas Burgey's avatar
Lukas Burgey committed
205
    }
Lukas Burgey's avatar
Lukas Burgey committed
206
207
  }

208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
  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 getDeploymentByGroup(group: t.Group): t.Deployment | undefined {
    let dep = this.userState.deployments.find(
      (d: t.Deployment) => {
        return d.group === group.id;
      }
    );
    return dep
  }


Lukas Burgey's avatar
Lukas Burgey committed
231
  // PUBLIC API
232
233
234
235
236
237
  public serviceDescription(service: t.Service): string {
    if (service.description != "") {
      return service.description;
    }
    return "No description";
  }
238
  public getDeployment(service: t.Service): t.Deployment {
Lukas Burgey's avatar
Lukas Burgey committed
239
240
    return this.userState.deployments.find(
      dep => {
241
242
243
244
        if (dep.service) {
          return dep.service.id === service.id;
        }
        return false
Lukas Burgey's avatar
Lukas Burgey committed
245
246
247
      }
    );
  }
Lukas Burgey's avatar
wip    
Lukas Burgey committed
248

249
250
251
252
253
  public getServices(group: t.Group): t.Service[] {
    let s = this.groupMap.get(group.name);
    if (s == undefined) {
      return []
    }
Lukas Burgey's avatar
Lukas Burgey committed
254
    return s
Lukas Burgey's avatar
wip    
Lukas Burgey committed
255
256
  }

Lukas Burgey's avatar
Lukas Burgey committed
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
  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 []
  }

Lukas Burgey's avatar
Lukas Burgey committed
274
275
276
277
278
279
280
281
282
283
284
285
286
287
  public userInfo(): MatTableDataSource<any> {
      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<any> {
      return new MatTableDataSource(this.user.ssh_keys);
  }

288
  public loggedIn(): boolean {
Lukas Burgey's avatar
Lukas Burgey committed
289
290
291
292
293
294
    if (this.userState) {
      return true;
    }
    return false;
  }

295
296
  public update(): void {
    this.http.get('/backend/api/state').subscribe(
Lukas Burgey's avatar
Lukas Burgey committed
297
      (data: t.StateAPIResult) => this.stateAPIUpdate(data),
298
299
300
301
302
      (err: HttpErrorResponse) => {
        console.log('Error', err);
        this.snackBar.open('Error receiving data from the server');
      }
    );
Lukas Burgey's avatar
Lukas Burgey committed
303
304
  }

Lukas Burgey's avatar
Lukas Burgey committed
305
  public errorHandler(error: any): void {
306
307
    console.log(error);
    this.snackBar.open('Error');
Lukas Burgey's avatar
Lukas Burgey committed
308
309
310
  }

  public login(idp: t.IdP) {
311
    this.idpService.setIdPPreference(idp);
312
313
314
315

    if (!this.loggedIn()) {
      window.location.href = '/backend/auth/v1/request';
    }
316
317
  }

Lukas Burgey's avatar
Lukas Burgey committed
318
  public logout() {
319
    this.http.post('/backend/auth/v1/logout', {}).subscribe(
320
      (data: t.StateAPIResult) => this.stateAPIUpdate(data),
Lukas Burgey's avatar
Lukas Burgey committed
321
      (err) => {
322
        this.errorHandler(err);
323
        this._logout();
324
325
326
327
      }
    );
  }

328
  public sentQuestionnaire(stateItemID: number, answers: Object) {
329
    return this.http.post('/backend/api/questionnaire?id='+String(stateItemID), answers).subscribe(
Lukas Burgey's avatar
Lukas Burgey committed
330
      (data: t.UserState) => {
Lukas Burgey's avatar
Lukas Burgey committed
331
        this.snackBar.open('Uploaded questionnaire');
Lukas Burgey's avatar
Lukas Burgey committed
332
        this.updateUserState(data);
Lukas Burgey's avatar
Lukas Burgey committed
333
334
335
336
      },
      (err) => {
        this.snackBar.open('Error uploading questionnaire');
        console.log(err);
Lukas Burgey's avatar
Lukas Burgey committed
337
        this.update();
Lukas Burgey's avatar
Lukas Burgey committed
338
339
340
341
      }
    );
  }

Lukas Burgey's avatar
Lukas Burgey committed
342
  public deleteUser() {
Lukas Burgey's avatar
Lukas Burgey committed
343
344
345
346
347
348
    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');
        }
Lukas Burgey's avatar
Lukas Burgey committed
349
350
351
352
      },
      (err) => {
        this.snackBar.open('Error deleting user from server');
        console.log(err);
Lukas Burgey's avatar
Lukas Burgey committed
353
        this.update();
Lukas Burgey's avatar
Lukas Burgey committed
354
355
356
      }
    );
  }
Lukas Burgey's avatar
Lukas Burgey committed
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387

  public uploadSshKey(key: t.NewSSHKey) {
    console.log('uploading key:', key);
    const body = {
      'type': 'add',
      'key': key,
    };
    return this.http.post('/backend/api/sshkey', body).subscribe(
      (newKey: t.SSHKey) => {
        this.sshKeys.push(newKey);
        this.sshKeys$.next(this.sshKeys);
      }
    );
  }

  public removeSshKey(key: t.SSHKey) {
    console.log('deleting key:', key);
    return this.http.post('/backend/api/sshkey', {
      'type': 'remove',
      'id': key.id,
    }).subscribe(
      (data: {deleted: boolean}) => {
        if (data && data.deleted) {
          this.sshKeys = this.sshKeys.filter(
            k => key.id != k.id
          );
          this.sshKeys$.next(this.sshKeys);
        }
      }
    );
  }
Lukas Burgey's avatar
Lukas Burgey committed
388
}