Skip to content

Instantly share code, notes, and snippets.

@fildidi
Created March 29, 2017 14:32
Show Gist options
  • Select an option

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

Select an option

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