user.service.ts 9.33 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
  private _loggedIn: boolean = false;
Lukas Burgey's avatar
Lukas Burgey committed
20
  private loggedIn$ = new BehaviorSubject<boolean>(false);
Lukas Burgey's avatar
Lukas Burgey committed
21

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

Lukas Burgey's avatar
Lukas Burgey committed
25
  public userState: t.UserState;
Lukas Burgey's avatar
Lukas Burgey committed
26
27
28
29
  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
30

Lukas Burgey's avatar
Lukas Burgey committed
31
32
  private messages: string[] = [];

33
  // local copy of services
Lukas Burgey's avatar
Lukas Burgey committed
34
35
  private services: t.Service[] = [];

36
37
  public groupMap: Map<string, t.Service[]> = new Map();
  public groupsParsed: boolean = false;
Lukas Burgey's avatar
Lukas Burgey committed
38
39

  constructor(
Lukas Burgey's avatar
Lukas Burgey committed
40
41
42
43
    private cookieService: CookieService,
    private http: HttpClient,
    private snackBar: SnackBarService,
    private idpService: IdpService,
44
    private _stompService: StompRService,
Lukas Burgey's avatar
Lukas Burgey committed
45
  ) {
Lukas Burgey's avatar
Lukas Burgey committed
46
    this.update();
47
48
49
50
51
52
53
54
55
  }

  // 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
56
57
  }

Lukas Burgey's avatar
Lukas Burgey committed
58
59
60
61
  public subscribeSSHKeys(): Observable<t.SSHKey[]> {
    return this.sshKeys$.asObservable();
  }

Lukas Burgey's avatar
Lukas Burgey committed
62
63
64
65
  public subscribeLoggedIn(): Observable<boolean> {
    return this.loggedIn$.asObservable();
  }

Lukas Burgey's avatar
Lukas Burgey committed
66
67
68
69
70
  // 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
71

Lukas Burgey's avatar
Lukas Burgey committed
72
73
    const stompConfig: StompConfig = {
      // Which server?
74
      url: 'wss://'+window.location.host+'/ws',
75

Lukas Burgey's avatar
Lukas Burgey committed
76
77
78
79
80
81
      // Headers
      // Typical keys: login, passcode, host
      headers: {
        login: 'webpage-client:' + login,
        passcode: passcode,
      },
Lukas Burgey's avatar
Lukas Burgey committed
82

Lukas Burgey's avatar
Lukas Burgey committed
83
84
85
86
87
88
      // 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
89
90
      // Typical value 15000 (15 seconds)
      reconnect_delay: 15000,
91

Lukas Burgey's avatar
Lukas Burgey committed
92
93
94
95
96
      // Will log diagnostics on console
      debug: false,
    };
    this._stompService.config = stompConfig;
    this._stompService.initAndConnect();
Lukas Burgey's avatar
Lukas Burgey committed
97
98
  }

Lukas Burgey's avatar
Lukas Burgey committed
99
100
101
  private connectLiveUpdates() {
    this.initStomp();
    let subscription = this._stompService.subscribe(
102
      '/exchange/users/' + this.user.id.toString()
Lukas Burgey's avatar
Lukas Burgey committed
103
    );
104

Lukas Burgey's avatar
Lukas Burgey committed
105
106
107
108
109
110
    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
111
        }
Lukas Burgey's avatar
Lukas Burgey committed
112
113
        if (update.user_state) {
          this.updateUserState(update.user_state);
Lukas Burgey's avatar
Lukas Burgey committed
114
        }
Lukas Burgey's avatar
Lukas Burgey committed
115
116
117
      },
      (error: any) => {
        console.log(error)
118
      }
Lukas Burgey's avatar
Lukas Burgey committed
119
    );
Lukas Burgey's avatar
Lukas Burgey committed
120
  }
121

Lukas Burgey's avatar
Lukas Burgey committed
122
123
  private updateUser(newUser: t.User) {
    this.user = newUser;
124
    this.user$.next(this.user);
Lukas Burgey's avatar
Lukas Burgey committed
125
126
127

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

130
131
132
  private updateServices(newServices: t.Service[]){
    if (this.services.length !== newServices.length) {
      this.services = [];
Lukas Burgey's avatar
wip    
Lukas Burgey committed
133

134
135
      for (let service of newServices) {
        this.services.push(service);
Lukas Burgey's avatar
Lukas Burgey committed
136
      }
Lukas Burgey's avatar
wip    
Lukas Burgey committed
137
138

      for (let group of this.user.groups) {
Lukas Burgey's avatar
Lukas Burgey committed
139
        this.groupMap.set(group.name, this._getServices(group.name));
Lukas Burgey's avatar
wip    
Lukas Burgey committed
140
141
      }
      this.groupsParsed = true;
Lukas Burgey's avatar
Lukas Burgey committed
142
143
144
    }
  }

Lukas Burgey's avatar
Lukas Burgey committed
145
146
147
  private updateUserState(newState: t.UserState) {
      // did a login occur?
    let login = (!this._loggedIn && newState);
Lukas Burgey's avatar
Lukas Burgey committed
148
    // did a logout occur?
Lukas Burgey's avatar
Lukas Burgey committed
149
    let logout = (this._loggedIn && !newState);
Lukas Burgey's avatar
Lukas Burgey committed
150
151
152

    // -- Value updating --
    if (login) {
Lukas Burgey's avatar
Lukas Burgey committed
153
      this._loggedIn = true;
154
      this.snackBar.open('Logged in');
155
156


Lukas Burgey's avatar
Lukas Burgey committed
157
      this.connectLiveUpdates();
158
    }
Lukas Burgey's avatar
Lukas Burgey committed
159
    if (logout) {
160
161
      this._logout()
      return
Lukas Burgey's avatar
Lukas Burgey committed
162
163
164
    }

    this.userState = newState;
165
    this.userState$.next(this.userState);
Lukas Burgey's avatar
Lukas Burgey committed
166
167
  }

Lukas Burgey's avatar
wip    
Lukas Burgey committed
168
169
170
171
172
173
174
  private _logout() {
    this._loggedIn = false;
    this.snackBar.open('Logged out');
    this._stompService.disconnect();
    this.services = [];
    this.user = null;
    this.userState = null;
175
    this.userState$.complete();
Lukas Burgey's avatar
wip    
Lukas Burgey committed
176
177
  }

Lukas Burgey's avatar
Lukas Burgey committed
178
  private stateAPIUpdate(update: t.StateAPIResult) {
179
180
181
182
183
184
185
186
187
188
189
    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
190
    }
Lukas Burgey's avatar
Lukas Burgey committed
191
192
  }

193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
  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
215
  // PUBLIC API
Lukas Burgey's avatar
Lukas Burgey committed
216
217
218
219
220
221
222
223
224
225
226
227
228
229
  public loggedIn(): boolean {
    if (this.userState) {
      return true;
    }
    return false;
  }

  public update(): void {
    this.http.get('/backend/api/state').subscribe(
      (data: t.StateAPIResult) => this.stateAPIUpdate(data),
      (err: any) => this.errorLogger(err, 'receiving data from the server')
    );
  }

230
231
232
233
234
235
  public serviceDescription(service: t.Service): string {
    if (service.description != "") {
      return service.description;
    }
    return "No description";
  }
Lukas Burgey's avatar
Lukas Burgey committed
236

237
  public getDeployment(service: t.Service): t.Deployment {
Lukas Burgey's avatar
Lukas Burgey committed
238
    return this.userState.deployments.find(
Lukas Burgey's avatar
Lukas Burgey committed
239
      dep => dep.service && dep.service.id === service.id
Lukas Burgey's avatar
Lukas Burgey committed
240
241
    );
  }
Lukas Burgey's avatar
wip    
Lukas Burgey committed
242

243
244
245
246
247
  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
248
    return s
Lukas Burgey's avatar
wip    
Lukas Burgey committed
249
250
  }

Lukas Burgey's avatar
Lukas Burgey committed
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
  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
268
269
270
271
272
273
274
275
276
277
278
279
280
281
  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);
  }

Lukas Burgey's avatar
Lukas Burgey committed
282
  public errorLogger(error: any, msg?: string): void {
283
    console.log(error);
Lukas Burgey's avatar
Lukas Burgey committed
284
285
286
287
288
    if (msg) {
      this.snackBar.open('Error: '+msg);
    } else {
      this.snackBar.open('Error');
    }
Lukas Burgey's avatar
Lukas Burgey committed
289
290
291
  }

  public login(idp: t.IdP) {
292
    this.idpService.setIdPPreference(idp);
293
294
295
296

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

Lukas Burgey's avatar
Lukas Burgey committed
299
  public logout() {
300
    this.http.post('/backend/auth/v1/logout', {}).subscribe(
301
      (data: t.StateAPIResult) => this.stateAPIUpdate(data),
Lukas Burgey's avatar
Lukas Burgey committed
302
303
      (err: any) => {
        this.errorLogger(err);
304
        this._logout();
305
306
307
308
      }
    );
  }

309
  public sentQuestionnaire(stateItemID: number, answers: Object) {
310
    return this.http.post('/backend/api/questionnaire?id='+String(stateItemID), answers).subscribe(
Lukas Burgey's avatar
Lukas Burgey committed
311
      (data: t.UserState) => {
Lukas Burgey's avatar
Lukas Burgey committed
312
        this.snackBar.open('Uploaded questionnaire');
Lukas Burgey's avatar
Lukas Burgey committed
313
        this.updateUserState(data);
Lukas Burgey's avatar
Lukas Burgey committed
314
315
316
317
      },
      (err) => {
        this.snackBar.open('Error uploading questionnaire');
        console.log(err);
Lukas Burgey's avatar
Lukas Burgey committed
318
        this.update();
Lukas Burgey's avatar
Lukas Burgey committed
319
320
321
322
      }
    );
  }

Lukas Burgey's avatar
Lukas Burgey committed
323
  public deleteUser() {
Lukas Burgey's avatar
Lukas Burgey committed
324
325
326
327
328
329
    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
330
331
332
333
      },
      (err) => {
        this.snackBar.open('Error deleting user from server');
        console.log(err);
Lukas Burgey's avatar
Lukas Burgey committed
334
        this.update();
Lukas Burgey's avatar
Lukas Burgey committed
335
336
337
      }
    );
  }
Lukas Burgey's avatar
Lukas Burgey committed
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368

  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
369
}