Skip to content

Instantly share code, notes, and snippets.

@fildidi
Created March 30, 2017 08:53
Show Gist options
  • Select an option

  • Save fildidi/dc1e71126a959376805ff3d34cf29a00 to your computer and use it in GitHub Desktop.

Select an option

Save fildidi/dc1e71126a959376805ff3d34cf29a00 to your computer and use it in GitHub Desktop.
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