obs-portal/frontend/src/api.js

141 lines
3.6 KiB
JavaScript
Raw Normal View History

2021-02-14 18:21:34 +00:00
import {stringifyParams} from 'query'
2021-02-20 18:31:18 +00:00
import globalStore from 'store'
import {setLogin} from 'reducers/login'
import configPromise from 'config'
import download from 'downloadjs'
function getFileNameFromContentDispostionHeader(contentDisposition: string): string | undefined {
const standardPattern = /filename=(["']?)(.+)\1/i
const wrongPattern = /filename=([^"'][^;"'\n]+)/i
if (standardPattern.test(contentDisposition)) {
return contentDisposition.match(standardPattern)[2]
}
if (wrongPattern.test(contentDisposition)) {
return contentDisposition.match(wrongPattern)[1]
}
}
2021-02-14 18:21:34 +00:00
2021-02-23 20:52:57 +00:00
class RequestError extends Error {
constructor(message, errors) {
super(message)
this.errors = errors
}
}
class API {
2021-02-20 18:31:18 +00:00
constructor(store) {
this.store = store
}
2021-11-04 17:13:24 +00:00
async loadUser() {
try {
const result = await this.get('/user')
this.store.dispatch(setLogin(result))
} catch {
this.store.dispatch(setLogin(null))
2021-02-20 18:31:18 +00:00
}
}
2021-05-14 17:24:17 +00:00
async logout() {
2021-11-04 17:13:24 +00:00
const config = await configPromise
const url = new URL(config.apiUrl + '/logout')
url.searchParams.append('next', window.location.href) // bring us back to the current page
2021-05-14 17:24:17 +00:00
window.location.href = url.toString()
}
async makeLoginUrl() {
const config = await configPromise
2021-11-14 22:42:02 +00:00
const url = new URL(config.loginUrl || (config.apiUrl + '/login'))
2021-11-04 17:13:24 +00:00
url.searchParams.append('next', window.location.href) // bring us back to the current page
return url.toString()
}
async fetch(url, options = {}) {
const config = await configPromise
2021-02-20 18:31:18 +00:00
const {returnResponse = false, ...fetchOptions} = options
2021-11-04 17:13:24 +00:00
const response = await window.fetch(config.apiUrl + url, {
...fetchOptions,
2021-11-04 17:13:24 +00:00
credentials: 'include',
})
2021-02-20 18:31:18 +00:00
if (response.status === 401) {
throw new Error('401 Unauthorized')
}
if (returnResponse) {
if (response.status === 200) {
return response
} else if (response.status === 204) {
return null
} else {
throw new RequestError('Error code ' + response.status)
2021-02-23 20:52:57 +00:00
}
}
let json
try {
json = await response.json()
} catch (err) {
json = null
}
2021-02-23 20:52:57 +00:00
2021-02-14 18:21:34 +00:00
if (response.status === 200) {
2021-02-23 20:52:57 +00:00
return json
} else if (response.status === 204) {
return null
2021-02-14 18:21:34 +00:00
} else {
2021-02-23 20:52:57 +00:00
throw new RequestError('Error code ' + response.status, json?.errors)
2021-02-14 18:21:34 +00:00
}
}
async post(url, {body: body_, ...options}) {
2021-02-17 20:50:18 +00:00
let body = body_
let headers = {...(options.headers || {})}
if (!(typeof body === 'string' || body instanceof FormData)) {
2021-02-20 18:31:18 +00:00
body = JSON.stringify(body)
headers['Content-Type'] = 'application/json'
2021-02-17 20:50:18 +00:00
}
2021-02-14 18:27:16 +00:00
return await this.fetch(url, {
2021-02-23 20:52:57 +00:00
method: 'post',
2021-02-14 18:27:16 +00:00
...options,
body,
2021-02-20 18:31:18 +00:00
headers,
2021-02-14 18:21:34 +00:00
})
}
async get(url, {query, ...options} = {}) {
const queryString = query ? stringifyParams(query) : null
return await this.fetch(url + (queryString ? '?' + queryString : ''), {method: 'get', ...options})
}
async delete(url, options = {}) {
2021-02-14 18:27:16 +00:00
return await this.get(url, {...options, method: 'delete'})
}
2021-02-20 18:31:18 +00:00
2021-02-23 20:52:57 +00:00
async put(url, options = {}) {
return await this.post(url, {...options, method: 'put'})
}
async downloadFile(url, options = {}) {
const res = await this.fetch(url, {returnResponse: true, ...options})
const blob = await res.blob()
const filename = getFileNameFromContentDispostionHeader(res.headers.get('content-disposition'))
const contentType = res.headers.get('content-type')
// Apparently this workaround is needed for some browsers
const newBlob = new Blob([blob], {type: contentType})
download(newBlob, filename, contentType)
}
}
2021-02-20 18:31:18 +00:00
const api = new API(globalStore)
export default api