2018-10-29 23:23:46 +00:00
/* global XMLHttpRequest FormData */
2018-11-07 20:06:36 +00:00
'use strict'
2018-10-29 23:23:46 +00:00
2018-11-07 20:06:36 +00:00
let ajaxcfg = { }
2018-10-29 23:23:46 +00:00
class AjaxError extends Error {
constructor ( reason , data , xhr ) {
2018-11-07 20:06:36 +00:00
super ( reason )
this . data = data
this . xhr = xhr
2018-10-29 23:23:46 +00:00
}
}
export default class Ajax {
static async get ( opts ) {
2018-11-12 22:07:55 +00:00
return Ajax . ajax ( {
... ( opts || { } ) ,
method : 'get'
} )
2018-10-29 23:23:46 +00:00
}
static async post ( opts ) {
2018-11-12 22:07:55 +00:00
return Ajax . ajax ( {
... ( opts || { } ) ,
method : 'post'
} )
2018-10-29 23:23:46 +00:00
}
static async put ( opts ) {
2018-11-12 22:07:55 +00:00
return Ajax . ajax ( {
... ( opts || { } ) ,
method : 'put'
} )
2018-10-29 23:23:46 +00:00
}
static async patch ( opts ) {
2018-11-12 22:07:55 +00:00
return Ajax . ajax ( {
... ( opts || { } ) ,
method : 'patch'
} )
2018-10-29 23:23:46 +00:00
}
static async delete ( opts ) {
2018-11-12 22:07:55 +00:00
return Ajax . ajax ( {
... ( opts || { } ) ,
method : 'delete'
} )
2018-10-29 23:23:46 +00:00
}
static async head ( opts ) {
2018-11-12 22:07:55 +00:00
return Ajax . ajax ( {
... ( opts || { } ) ,
method : 'head'
} )
2018-10-29 23:23:46 +00:00
}
static async options ( opts ) {
2018-11-12 22:07:55 +00:00
return Ajax . ajax ( {
... ( opts || { } ) ,
method : 'options'
} )
2018-10-29 23:23:46 +00:00
}
static ajax ( opts ) {
return new Promise ( ( resolve , reject ) => {
2018-11-07 20:06:36 +00:00
if ( ! opts ) { reject ( new Error ( 'Missing required options parameter.' ) ) }
2018-10-29 23:23:46 +00:00
if ( opts . method ) {
2018-11-07 20:06:36 +00:00
if ( ! [ 'get' , 'post' , 'put' , 'patch' , 'delete' , 'head' , 'options' ] . includes ( opts . method . toLowerCase ( ) ) ) { reject ( new Error ( 'opts.method must be one of: GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS.' ) ) }
opts . method = opts . method . toUpperCase ( )
2018-10-29 23:23:46 +00:00
}
2018-11-07 20:06:36 +00:00
var xhr = opts . xhr || new XMLHttpRequest ( )
2018-10-29 23:23:46 +00:00
2018-11-07 20:06:36 +00:00
var fd = null
var qs = ''
2018-10-29 23:23:46 +00:00
if ( opts . data && opts . method . toLowerCase ( ) !== 'get' ) {
2018-11-07 20:06:36 +00:00
fd = new FormData ( )
2018-10-29 23:23:46 +00:00
for ( let key in opts . data ) {
2018-11-07 20:06:36 +00:00
fd . append ( key , opts . data [ key ] )
2018-10-29 23:23:46 +00:00
}
} else if ( opts . data ) {
2018-11-07 20:06:36 +00:00
qs += '?'
let params = [ ]
2018-10-29 23:23:46 +00:00
for ( let key in opts . data ) {
2018-11-07 20:06:36 +00:00
params . push ( [ key , opts . data [ key ] ] . join ( '=' ) )
2018-10-29 23:23:46 +00:00
}
2018-11-07 20:06:36 +00:00
qs += params . join ( '&' )
2018-10-29 23:23:46 +00:00
}
xhr . onload = ( ) => {
2018-11-07 20:06:36 +00:00
if ( xhr . status !== 200 ) { return xhr . onerror ( ) }
var data = xhr . response
2018-10-29 23:23:46 +00:00
resolve ( {
data ,
xhr
2018-11-07 20:06:36 +00:00
} )
}
2018-10-29 23:23:46 +00:00
xhr . onerror = ( ) => {
2018-11-07 20:06:36 +00:00
var data = xhr . response
2018-10-29 23:23:46 +00:00
// method not allowed
if ( xhr . status === 405 ) {
2018-11-07 20:06:36 +00:00
reject ( new AjaxError ( '405 Method Not Allowed' , data , xhr ) )
return
2018-10-29 23:35:27 +00:00
} else if ( xhr . status === 404 ) {
2018-11-07 20:06:36 +00:00
reject ( new AjaxError ( '404 Not Found' , data , xhr ) )
return
2018-10-29 23:23:46 +00:00
}
try {
// if the access token is invalid, try to use the refresh token
2018-11-07 20:06:36 +00:00
var json = JSON . parse ( data )
2018-10-29 23:23:46 +00:00
if ( json . error === 'access_denied' && json . hint . includes ( 'token' ) && json . hint . includes ( 'invalid' ) && ajaxcfg . refresh _token ) {
2018-11-07 20:06:36 +00:00
return Ajax . refresh ( opts )
2018-10-29 23:23:46 +00:00
} else if ( json . error === 'access_denied' && json . hint . includes ( 'token' ) && json . hint . includes ( 'revoked' ) ) {
2018-11-07 20:06:36 +00:00
reject ( new AjaxError ( 'token revoked' , data , xhr ) )
2018-10-29 23:23:46 +00:00
}
} catch ( e ) {
2018-11-07 20:06:36 +00:00
reject ( new AjaxError ( e . toString ( ) , data , xhr ) )
2018-10-29 23:23:46 +00:00
} finally {
2018-11-07 20:06:36 +00:00
reject ( new AjaxError ( data , xhr . status , xhr ) )
2018-10-29 23:23:46 +00:00
}
2018-11-07 20:06:36 +00:00
}
2018-10-29 23:23:46 +00:00
2018-11-07 20:06:36 +00:00
xhr . open ( opts . method || 'GET' , opts . url + qs || window . location . href )
2018-10-29 23:23:46 +00:00
if ( opts . headers ) {
2018-11-07 20:06:36 +00:00
for ( let key in opts . headers ) { xhr . setRequestHeader ( key , opts . headers [ key ] ) }
2018-10-29 23:23:46 +00:00
}
2018-11-07 20:06:36 +00:00
if ( ajaxcfg . access _token && ! ( opts . headers || { } ) . Authorization ) { xhr . setRequestHeader ( 'Authorization' , 'Bearer ' + ajaxcfg . access _token ) }
xhr . send ( fd )
} )
2018-10-29 23:23:46 +00:00
}
static refresh ( opts ) {
return new Promise ( ( resolve , reject ) => {
2018-11-07 20:06:36 +00:00
var xhr = new XMLHttpRequest ( )
2018-10-29 23:23:46 +00:00
2018-11-07 20:06:36 +00:00
var fd = new FormData ( )
2018-10-29 23:23:46 +00:00
const OAUTH _TOKEN _REQUEST = {
grant _type : 'refresh_token' ,
refresh _token : ajaxcfg . refresh _token ,
client _id : 'foxfile' ,
client _secret : 1
2018-11-07 20:06:36 +00:00
}
2018-10-29 23:23:46 +00:00
for ( var key in OAUTH _TOKEN _REQUEST ) {
2018-11-07 20:06:36 +00:00
fd . append ( key , OAUTH _TOKEN _REQUEST [ key ] )
2018-10-29 23:23:46 +00:00
}
// try original request
xhr . onload = ( ) => {
2018-11-07 20:06:36 +00:00
if ( xhr . status !== 200 ) { return xhr . onerror ( ) }
if ( ajaxcfg . refresh ) { ajaxcfg . refresh ( xhr . response ) }
var json = JSON . parse ( xhr . response )
ajaxcfg . access _token = json . access _token
ajaxcfg . refresh _token = json . refresh _token
return Ajax . ajax ( opts )
}
2018-10-29 23:23:46 +00:00
// if this fails, dont try again
xhr . onerror = ( ) => {
2018-11-07 20:06:36 +00:00
var data = xhr . response
reject ( new AjaxError ( xhr . status , data , xhr ) )
}
xhr . open ( 'POST' , ajaxcfg . refresh _url )
xhr . send ( fd )
} )
2018-10-29 23:23:46 +00:00
}
static setTokenData ( tokens ) {
2018-11-07 20:06:36 +00:00
if ( ! tokens ) { throw new Error ( 'Missing tokens.' ) }
if ( ! tokens . access _token && ! tokens . refresh _token && ! tokens . refresh _url ) { throw new Error ( 'Missing at least one of: access_token, refresh_token, refresh_url.' ) }
if ( tokens . access _token ) { ajaxcfg . access _token = tokens . access _token }
if ( tokens . refresh _token ) { ajaxcfg . refresh _token = tokens . refresh _token }
if ( tokens . refresh _url ) { ajaxcfg . refresh _url = tokens . refresh _url }
return true
2018-10-29 23:23:46 +00:00
}
static onRefresh ( func ) {
2018-11-07 20:06:36 +00:00
ajaxcfg . refresh = func
2018-10-29 23:23:46 +00:00
}
}