Created
March 30, 2017 08:53
-
-
Save fildidi/dc1e71126a959376805ff3d34cf29a00 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import {Injectable, Inject} from '@angular/core'; | |
| import { | |
| Http, | |
| Headers, | |
| Response, | |
| BrowserXhr, | |
| RequestOptions, | |
| RequestOptionsArgs, | |
| RequestMethod, | |
| Request | |
| } from '@angular/http'; | |
| import {Observable} from 'rxjs/Observable'; | |
| import {Observer} from 'rxjs/Observer'; | |
| import {Subject} from 'rxjs/Subject'; | |
| import 'rxjs/add/observable/throw'; | |
| import 'rxjs/add/observable/fromPromise'; | |
| import 'rxjs/add/operator/map'; | |
| import 'rxjs/add/operator/mergeMap'; | |
| import 'rxjs/add/operator/toPromise'; | |
| import 'rxjs/add/operator/catch'; | |
| import 'rxjs/add/operator/finally'; | |
| import {ResponseOptions} from "@angular/http"; | |
| import {API_ENDPOINTS, IApiEndpoints} from "../config/API_ENDPOINTS.config"; | |
| import {APPLICATION_SETTINGS, IApplicationSettings} from "../config/APPLICATION_SETTINGS.config"; | |
| import {BehaviorSubject} from "rxjs"; | |
| import {User} from '../authentication/user.model'; | |
| // Annoying that these arent exposed in Angular since we need to adda a Progress Response Type (to track upload progress) | |
| enum ResponseType { | |
| Basic = 0, | |
| Cors = 1, | |
| Default = 2, | |
| Error = 3, | |
| Opaque = 4, | |
| Progress = 5 | |
| } | |
| @Injectable() | |
| export class AuthHttpService { | |
| private STORAGE_IDENTIFIER: string; | |
| public TOKEN: any; | |
| private _currentUser: BehaviorSubject<any>; | |
| public currentUser: Observable<any>; | |
| constructor(@Inject(API_ENDPOINTS) private endpoints: IApiEndpoints, | |
| @Inject(APPLICATION_SETTINGS) private appSettings: IApplicationSettings, | |
| private http: Http, | |
| private browserXhr: BrowserXhr) { | |
| this.STORAGE_IDENTIFIER = appSettings.storageIdentifier + 'AUTH'; | |
| this._currentUser = new BehaviorSubject<any>(null); | |
| this.currentUser = this._currentUser.asObservable(); | |
| } | |
| public get(url: string, options?: RequestOptionsArgs): Observable<Response> { | |
| return this.requestHelper({body: '', method: RequestMethod.Get, url: url}, options); | |
| } | |
| public post(url: string, body: any, options?: RequestOptionsArgs): Observable<Response> { | |
| return this.requestHelper({body: body, method: RequestMethod.Post, url: url}, options); | |
| } | |
| public put(url: string, body: any, options?: RequestOptionsArgs): Observable<Response> { | |
| return this.requestHelper({body: body, method: RequestMethod.Put, url: url}, options); | |
| } | |
| public delete(url: string, options?: RequestOptionsArgs): Observable<Response> { | |
| return this.requestHelper({body: '', method: RequestMethod.Delete, url: url}, options); | |
| } | |
| public patch(url: string, body: any, options?: RequestOptionsArgs): Observable<Response> { | |
| return this.requestHelper({body: body, method: RequestMethod.Patch, url: url}, options); | |
| } | |
| public upload(url: string, body: any, options?: RequestOptionsArgs, forceMethod?: string): Observable<Response> { | |
| return new Observable<Response>((responseObserver: Observer<Response>) => { | |
| const _xhr: XMLHttpRequest = this.browserXhr.build(); | |
| const method = forceMethod || 'POST'; | |
| _xhr.open(method, url); | |
| const onLoad = () => { | |
| const headers: Headers = Headers.fromResponseHeaderString(_xhr.getAllResponseHeaders()); | |
| const responseUrl: string = this.getResponseURL(_xhr) || url; | |
| let responseOptions = new ResponseOptions({ | |
| body: _xhr.response, | |
| status: _xhr.status, | |
| headers: headers, | |
| type: ResponseType.Default, | |
| statusText: _xhr.statusText || 'OK', | |
| url: responseUrl | |
| }); | |
| let response = new Response(responseOptions); | |
| response.ok = (_xhr.status >= 200 && _xhr.status < 300); | |
| if (response.ok) { | |
| responseObserver.next(response); | |
| responseObserver.complete(); | |
| return; | |
| } | |
| responseObserver.error(response); | |
| }; | |
| const onError = (err: ErrorEvent) => { | |
| let responseOptions = new ResponseOptions({ | |
| body: err, | |
| type: ResponseType.Error, | |
| status: _xhr.status, | |
| statusText: _xhr.statusText | |
| }); | |
| responseObserver.error(new Response(responseOptions)); | |
| }; | |
| const onProgress = (progress: ProgressEvent) => { | |
| const percentageComplete = Math.round(progress.loaded / progress.total * 100); | |
| let responseOptions = new ResponseOptions({ | |
| body: percentageComplete, | |
| type: ResponseType.Progress, | |
| status: _xhr.status, | |
| statusText: _xhr.statusText | |
| }); | |
| // For the callee of the .uploadFile method | |
| responseObserver.next(new Response(responseOptions)); | |
| }; | |
| //to be refactored!!!!! | |
| // let reqOptions = this.addAuthHeader(options, token); | |
| // reqOptions.headers.forEach((values, name) => { | |
| // _xhr.setRequestHeader(name, values.join(',')); | |
| // }); | |
| _xhr.addEventListener('load', onLoad); | |
| _xhr.addEventListener('error', onError); | |
| _xhr.upload.addEventListener('progress', onProgress); | |
| _xhr.send(body); | |
| return () => { | |
| _xhr.removeEventListener('load', onLoad); | |
| _xhr.removeEventListener('error', onError); | |
| _xhr.upload.removeEventListener('progress', onProgress); | |
| _xhr.abort(); | |
| } | |
| }); | |
| } | |
| private request(request: Request): Observable<Response> { | |
| return Observable.fromPromise(this.tokenGetter()).mergeMap((token: string) => { | |
| request.headers.set('Authorization', 'Bearer ' + token); | |
| return this.http.request(request); | |
| }); | |
| } | |
| private tokenGetter(): Promise<string> { | |
| return new Promise((resolve, reject) => { | |
| let token = localStorage.getItem(this.STORAGE_IDENTIFIER + '_TOKEN'); | |
| let decodedToken; | |
| let decodedTokenToDate; | |
| if (token) { | |
| //decode the token | |
| let base64Url = token.split('.')[1]; | |
| let base64 = base64Url.replace('-', '+').replace('_', '/'); | |
| decodedToken = JSON.parse(window.atob(base64)); | |
| console.log('base64', decodedToken) | |
| decodedTokenToDate = decodedToken.exp * 1000; | |
| } | |
| console.log('rett'); | |
| if (decodedTokenToDate < new Date()) { | |
| console.log('its invalid') | |
| let additionalHeaders = new Headers(); | |
| additionalHeaders.append('Authorization', 'Bearer ' + token); | |
| additionalHeaders.append('N-Meta', 'web;development'); | |
| let requestOptions = new RequestOptions(); | |
| requestOptions.headers = additionalHeaders; | |
| console.log('inside refresh token'); | |
| let tokenUpdateUrl = [ | |
| this.endpoints.root.production, | |
| this.endpoints.usersProperties.refreshToken | |
| ].join('/'); | |
| this.http.patch(tokenUpdateUrl, null, requestOptions) | |
| .subscribe( | |
| response => { | |
| let body = response.json(); | |
| localStorage.setItem(this.STORAGE_IDENTIFIER + '_TOKEN', body.token); | |
| resolve(body.token); | |
| } | |
| ) | |
| } else { | |
| //resolve the promise by senind the token | |
| resolve(token); | |
| } | |
| }) | |
| } | |
| private requestHelper(requestArgs: RequestOptionsArgs, additionalOptions?: RequestOptionsArgs): Observable<Response> { | |
| let options = new RequestOptions(requestArgs); | |
| if (additionalOptions) { | |
| options = options.merge(additionalOptions); | |
| } | |
| console.log(options); | |
| if (!options.headers) { | |
| options.headers = new Headers(); | |
| } | |
| if (!options.headers.has('N-Meta')) { | |
| options.headers.append('N-Meta', 'web;development'); | |
| } | |
| return this.request(new Request(options)); | |
| } | |
| // More "hidden" gems in the Http files in Angular ... They really dont want to make it easy :( | |
| private getResponseURL(xhr: any): string { | |
| if ('responseURL' in xhr) { | |
| return xhr.responseURL; | |
| } | |
| if (/^X-Request-URL:/m.test(xhr.getAllResponseHeaders())) { | |
| return xhr.getResponseHeader('X-Request-URL'); | |
| } | |
| return; | |
| } | |
| /** | |
| * Check if the user is authenticated based on their auth token being present in Storage | |
| * @returns {Promise<boolean>|PromiseLike<boolean>} | |
| */ | |
| isAuthenticated() { | |
| const token = localStorage.getItem(this.STORAGE_IDENTIFIER + '_TOKEN'); | |
| return !!token; | |
| } | |
| /** | |
| * Helper method for updating user and authentication state | |
| * @param data | |
| * @returns {Observable<T>} | |
| * @private | |
| */ | |
| private _setUser(data) { | |
| let user = Object.assign(new User(), data); | |
| this._currentUser.next(user); | |
| localStorage.setItem(this.STORAGE_IDENTIFIER + '_TOKEN', user.token); | |
| } | |
| /** | |
| * | |
| * @returns {Observable<R>} | |
| */ | |
| me(): Observable<any> { | |
| let url = [ | |
| this.endpoints.root.production, | |
| this.endpoints.usersProperties.me | |
| ].join('/'); | |
| return this.get(url) | |
| .map(response => { | |
| let body = response.json(); | |
| this._setUser(body); | |
| return body; | |
| }) | |
| // .catch(this._handleError.bind(this)); | |
| } | |
| /** | |
| * Login | |
| * | |
| * @param email {string} | |
| * @param password {string} | |
| * @returns {Observable<R>} | |
| */ | |
| login(email: string, password: string): Observable<any> { | |
| let url = [ | |
| this.endpoints.root.production, | |
| this.endpoints.usersProperties.login | |
| ].join('/'); | |
| let payload = { | |
| email: email, | |
| password: password, | |
| }; | |
| return this.post(url, payload) | |
| .map(response => { | |
| let body = response.json(); | |
| console.log(body); | |
| this._setUser(body); | |
| console.log('body', body); | |
| return body; | |
| // return Observable.fromPromise(this._setUser(body)); | |
| } | |
| ) | |
| } | |
| } | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment