import { Injectable } from '@angular/core'; import { HttpClient } from '@angular/common/http'; import { Observable, Subject, throwError as _throw } from 'rxjs'; import { catchError } from 'rxjs/operators'; import { ConfigService } from '@arrow/bom/config'; import { MessageBusService } from '../message-bus/message-bus.service'; import { LoggerService } from '@arrow/bom/logger'; import * as cookie from '../util/cookie'; import { User } from './user.model'; /** * deprecated This service will be replaced by UserService2 in the near future * this was set deprecated in 16/5/20, still is being used. Needs to be reviseted as user.service2 still doesnt have * most of the methods or logic. New code MUST go to userService2 */ @Injectable() export class UserService { private readonly LOCAL_STORAGE_KEY: string = 'BomHistoryViewDates'; // private readonly FRESH_AUTH_TIME: number = 1000; private _isAuthReady: Subject = new Subject(); private isAuthFresh: boolean = false; private isWaitingOnAuthCall: boolean = false; public isAnonymous: boolean = true; public email: string; public canArrowReel: boolean; constructor( private http: HttpClient, private config: ConfigService, private _messageBus: MessageBusService, private log: LoggerService ) { this.requestFreshAuth(); } /** * This method should be called after subscribing to `isReady()` */ requestFreshAuth() { // If for some reason another request for authentication is if (this.isWaitingOnAuthCall) { return; } if (!this.isAuthFresh) { this.isWaitingOnAuthCall = true; this.http.get(this.getUserIdentityUrl(), { withCredentials: true }).subscribe( (response: any) => { // A 503 statusCode means the BOM API is in "maintenance mode" // we should not make anymore requests. We return here early // so that the rest of the application will "hang" on purpose. // This means sockets will never connect. // Note: this is not a 503 HTTP error. It's a status code set // in the response body if (response.status.statusCode === 503) { return; } // If 'MyArrow' the response for unauthenticated is different if ( this.config.getTarget() === 'myarrow' && response.status.statusCode === 401 ) { this.isAnonymous = true; // TODO something else? If a user is not autorized, they will not be allowed to use the tool } else if (response.status.statusCode === 200) { this.isAnonymous = !response.payload.isAuth; this.email = response.payload.email; this.canArrowReel = response.payload.arrowReel; } else { const errMsg = `Unexpected status code "${response.status.statusCode}" received from "authenticated" call`; this.log.warn(errMsg); throw _throw(errMsg); } this.isAuthFresh = true; this.isWaitingOnAuthCall = false; this._isAuthReady.next(); // Consider auth "stale" after specified period // removed because was producing errors on the bom list loading // if needed add again but consider that will requiere a fix for the bom management component // check BM-6813 for more details // setTimeout(() => { this.isAuthFresh = false; // }, this.FRESH_AUTH_TIME); }, (error: any) => this.handleError(error) ); } else { this._isAuthReady.next(); } } //TODO: Remove this flag after successful testing. private getUserIdentityUrl(){ const coreVersion: boolean = true; const url = coreVersion ? `${this.config.apiCoreUrl}/api/users/@current/identity` : `${this.config.apiUrl}/user/authenticated`; return url; } private handleError(error: any): any { this._messageBus.to('ch:loader', { payload: true }); this.isWaitingOnAuthCall = false; this.isAuthFresh = false; this.log.warn(error); // Commented because it seems like no one is observing this error anyways. // error is handled here so probably no need for this line. return _throw(error.error || 'Server error'); } public isReady(): Observable { return this._isAuthReady; } public getData() { return ( this.http .get(this.getUserIdentityUrl(), { withCredentials: true }) // .map(response => response.json()) // .catch(error => this.handleError(error)); .pipe(catchError(error => this.handleError(error))) ); } // /** // * Check if user is logged in // * @returns {boolean} // */ public isLoggedIn() { return cookie.getCookie('.ASPXAUTH.arrow'); } private getStorageBomHistoryLastViewed() { // Sample object structure: [ {bomId: '123', date: 5738383} ... ] const datesString = localStorage.getItem(this.LOCAL_STORAGE_KEY); let dates: any[] = []; // If no storage object, create it if (!datesString) { localStorage.setItem(this.LOCAL_STORAGE_KEY, '[]'); } else { // If storage object - try parsing it in case someone manually edited it try { dates = JSON.parse(datesString); } catch (e) { localStorage.setItem(this.LOCAL_STORAGE_KEY, '[]'); } } return dates; } /** * Updates the "last viewed" date for a given BOM id * @param bomId */ updateBomHistoryLastViewed(bomId: string): void { const dates = this.getStorageBomHistoryLastViewed(); const matched = dates.find(date => date.bomId === bomId); if (matched) { matched.date = Date.now(); } else { dates.push({ bomId, date: Date.now() }); } localStorage.setItem(this.LOCAL_STORAGE_KEY, JSON.stringify(dates)); } /** * Retrieves the "last viewed" date for a given BOM id * @param bomId */ getBomHistoryLastViewed(bomId: string): number { const dates = this.getStorageBomHistoryLastViewed(); const matched = dates.find(date => date.bomId === bomId); if (matched) { return matched.date; } else { return 0; } } /** * Makes an HTTP request to find out how many changes have been * made for a given BOM since the last time this BOM was viewed * @param bomId */ getBomChangesSinceHistoryLastViewed(bomId: string): Observable { let date = new Date(this.getBomHistoryLastViewed(bomId)).toUTCString(); date = encodeURIComponent(date); return ( this.http .get(`${this.config.apiUrl}/${bomId}/changelog/since?d=${date}`, { withCredentials: true }) // .map(response => Number(response.json().payload)) .pipe(catchError(error => this.handleError(error))) ); } public getUserCollegues(): Observable { const url = `${this.config.apiUrl}/user/collegues`; return >this.http.get(url); } }