Created
March 29, 2017 14:31
-
-
Save fildidi/df0b4cdbf1ecde35e9bfafa2c108b7b6 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} 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>; | |
| public decodedToken; | |
| public decodedTokenToDate; | |
| 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(null); | |
| this.currentUser = this._currentUser.asObservable(); | |
| const token = localStorage.getItem(this.STORAGE_IDENTIFIER + '_TOKEN'); | |
| if (token) { | |
| this.TOKEN = token; | |
| //decode the token | |
| let base64Url = this.TOKEN.split('.')[1]; | |
| let base64 = base64Url.replace('-', '+').replace('_', '/'); | |
| this.decodedToken = JSON.parse(window.atob(base64)); | |
| console.log('base64', this.decodedToken) | |
| } | |
| } | |
| public get(url: string, token?: string, options?: RequestOptionsArgs): Observable<Response> { | |
| return this.http.get(url, this.addAuthHeader(options, token)); | |
| } | |
| public post(url: string, body: any, token?: string, options?: RequestOptionsArgs): Observable<Response> { | |
| return this.http.post(url, body, this.addAuthHeader(options, token)); | |
| } | |
| public put(url: string, body: any, token?: string, options?: RequestOptionsArgs): Observable<Response> { | |
| return this.http.put(url, body, this.addAuthHeader(options, token)); | |
| } | |
| public delete(url: string, token?: string, options?: RequestOptionsArgs): Observable<Response> { | |
| return this.http.delete(url, this.addAuthHeader(options, token)); | |
| } | |
| public patch(url: string, body: any, token?: string, options?: RequestOptionsArgs): Observable<Response> { | |
| return this.http.patch(url, body, this.addAuthHeader(options, token)); | |
| } | |
| public upload(url: string, body: any, token?: string, 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)); | |
| }; | |
| let reqOptions = this.addAuthHeader(options, token); | |
| reqOptions.headers.forEach((values, name) => { | |
| _xhr.setRequestHeader(name, values.join(',')); | |
| }); | |
| // let formData = new FormData(); | |
| // for(let key in body) { | |
| // if(body.hasOwnProperty(key)) { | |
| // if(key === 'ASSET_FILE_NAME' || key === 'THUMBNAIL_FILE_NAME') { | |
| // return; | |
| // } | |
| // if(key === 'asset') { | |
| // formData.append(key, body[key], body['ASSET_FILE_NAME']) | |
| // } | |
| // if(key ==) '' | |
| // formData.append(key, body[key]); | |
| // } | |
| // } | |
| _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 addAuthHeader(options?: RequestOptionsArgs, token?: string): RequestOptionsArgs { | |
| let opts = new RequestOptions(options || {}); | |
| let headers = new Headers(); | |
| if (options && options.headers) { | |
| options.headers.forEach((values, name) => { | |
| headers.append(name, values.join(',')); | |
| }); | |
| } | |
| headers.append('N-Meta', 'web;development'); | |
| // should be this.decodedTokenToDate > new Date() | |
| //the following condition is just for test | |
| if (this.decodedTokenToDate < new Date()) { | |
| console.log('its valid') | |
| } else { | |
| console.log('its NOT valid') | |
| this.refreshToken(); | |
| } | |
| if (token) { | |
| headers.append('Authorization', 'Bearer ' + token); | |
| } | |
| opts.headers = headers; | |
| return opts; | |
| } | |
| // 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.TOKEN = user.token; | |
| this._currentUser.next(user); | |
| localStorage.setItem(this.STORAGE_IDENTIFIER + '_TOKEN', this.TOKEN); | |
| } | |
| /** | |
| * | |
| * @returns {Observable<R>} | |
| */ | |
| me(): Observable<any> { | |
| if (!this.TOKEN) { | |
| return Observable.throw(new Error('MISSING_TOKEN')); | |
| } | |
| let url = [ | |
| this.endpoints.root.production, | |
| this.endpoints.usersProperties.me | |
| ].join('/'); | |
| return this.get(url, this.TOKEN) | |
| .map(response => { | |
| let body = response.json(); | |
| this._setUser(body); | |
| return body; | |
| }) | |
| // .catch(this._handleError.bind(this)); | |
| } | |
| /** | |
| * Refresh auth token | |
| * @returns {any} | |
| */ | |
| public refreshToken() { | |
| // if (!this.TOKEN) { | |
| // return Observable.throw(new Error('MISSING_TOKEN')); | |
| // } | |
| let additionalHeaders = new Headers(); | |
| additionalHeaders.append('N-Meta', 'web;development'); | |
| additionalHeaders.append('Authorization', this.TOKEN); | |
| let requestOptions = new RequestOptions(); | |
| requestOptions.headers = additionalHeaders; | |
| console.log('inside refresh token'); | |
| let url = [ | |
| this.endpoints.root.production, | |
| this.endpoints.usersProperties.refreshToken | |
| ].join('/'); | |
| this.http | |
| .patch(url, this.TOKEN, requestOptions) | |
| .map(response => { | |
| let body = response.json(); | |
| console.log('body refresh token', body); | |
| //set the new received token in localstorage | |
| localStorage.setItem(this.STORAGE_IDENTIFIER + '_TOKEN', body.token); | |
| console.log('the new token should be in local storage'); | |
| return body; | |
| }) | |
| .catch(this.handleError) | |
| } | |
| /** | |
| * 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)); | |
| } | |
| ) | |
| } | |
| private handleError(error: any) { | |
| let errMsg = (error.message) ? error.message : | |
| error.status ? `${error.status} - ${error.statusText}` : 'Server error'; | |
| console.error(errMsg); | |
| return Observable.throw(errMsg); | |
| } | |
| } | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment