mirror of
https://gitlab.com/bramw/baserow.git
synced 2025-04-12 08:18:07 +00:00
229 lines
6 KiB
JavaScript
229 lines
6 KiB
JavaScript
import axios from 'axios'
|
|
|
|
import { lowerCaseFirst } from '@baserow/modules/core/utils/string'
|
|
|
|
export class ResponseErrorMessage {
|
|
constructor(title, message) {
|
|
this.title = title
|
|
this.message = message
|
|
}
|
|
}
|
|
|
|
class ErrorHandler {
|
|
constructor(store, response, code = null, detail = null) {
|
|
this.isHandled = false
|
|
this.store = store
|
|
this.response = response
|
|
this.setError(code, detail)
|
|
|
|
// A temporary global errorMap containing error messages for certain errors codes.
|
|
// This must later be replaced by a more dynamic way.
|
|
this.errorMap = {
|
|
ERROR_USER_NOT_IN_GROUP: new ResponseErrorMessage(
|
|
'Action not allowed.',
|
|
"The action couldn't be completed because you aren't a " +
|
|
'member of the related group.'
|
|
),
|
|
// @TODO move these errors to the module.
|
|
ERROR_TABLE_DOES_NOT_EXIST: new ResponseErrorMessage(
|
|
"Table doesn't exist.",
|
|
"The action couldn't be completed because the related table doesn't exist" +
|
|
' anymore.'
|
|
),
|
|
ERROR_ROW_DOES_NOT_EXIST: new ResponseErrorMessage(
|
|
"Row doesn't exist.",
|
|
"The action couldn't be completed because the related row doesn't exist" +
|
|
' anymore.'
|
|
),
|
|
}
|
|
|
|
// A temporary notFoundMap containing the error messages for when the
|
|
// response contains a 404 error based on the provided context name. Note
|
|
// that an entry is not found a default message will be generated.
|
|
this.notFoundMap = {}
|
|
}
|
|
|
|
/**
|
|
* Changes the error code and details.
|
|
*/
|
|
setError(code, detail) {
|
|
this.code = code
|
|
this.detail = detail
|
|
}
|
|
|
|
/**
|
|
* Returns true if there is a readable error.
|
|
* @return {boolean}
|
|
*/
|
|
hasError() {
|
|
return this.response !== undefined && this.response.code !== null
|
|
}
|
|
|
|
/**
|
|
* Returns true is the response status code is equal to not found (404).
|
|
* @return {boolean}
|
|
*/
|
|
isNotFound() {
|
|
return this.response !== undefined && this.response.status === 404
|
|
}
|
|
|
|
/**
|
|
* Return true if there is a network error.
|
|
* @return {boolean}
|
|
*/
|
|
hasNetworkError() {
|
|
return this.response === undefined
|
|
}
|
|
|
|
/**
|
|
* Finds a message in the global errors or in the provided specific error map.
|
|
*/
|
|
getErrorMessage(specificErrorMap = null) {
|
|
if (
|
|
specificErrorMap !== null &&
|
|
Object.prototype.hasOwnProperty.call(specificErrorMap, this.code)
|
|
) {
|
|
return specificErrorMap[this.code]
|
|
}
|
|
|
|
if (Object.prototype.hasOwnProperty.call(this.errorMap, this.code)) {
|
|
return this.errorMap[this.code]
|
|
}
|
|
|
|
return new ResponseErrorMessage(
|
|
'Action not completed.',
|
|
"The action couldn't be completed because an unknown error has" +
|
|
' occured.'
|
|
)
|
|
}
|
|
|
|
/**
|
|
* Finds a not found message for a given context.
|
|
*/
|
|
getNotFoundMessage(name) {
|
|
if (!Object.prototype.hasOwnProperty.call(this.notFoundMap, name)) {
|
|
return new ResponseErrorMessage(
|
|
`${lowerCaseFirst(name)} not found.`,
|
|
`The selected ${name.toLowerCase()} wasn't found, maybe it has already been deleted.`
|
|
)
|
|
}
|
|
return this.notFoundMap[name]
|
|
}
|
|
|
|
/**
|
|
* Returns a standard network error message. For example if the API server
|
|
* could not be reached.
|
|
*/
|
|
getNetworkErrorMessage() {
|
|
return new ResponseErrorMessage(
|
|
'Network error',
|
|
'Could not connect to the API server.'
|
|
)
|
|
}
|
|
|
|
/**
|
|
* If there is an error or the requested detail is not found an error
|
|
* message related to the problem is returned.
|
|
*/
|
|
getMessage(name = null, specificErrorMap = null) {
|
|
if (this.hasNetworkError()) {
|
|
return this.getNetworkErrorMessage()
|
|
}
|
|
if (this.hasError()) {
|
|
return this.getErrorMessage(specificErrorMap)
|
|
}
|
|
if (this.isNotFound()) {
|
|
return this.getNotFoundMessage(name)
|
|
}
|
|
return null
|
|
}
|
|
|
|
/**
|
|
* If there is an error or the requested detail is not found we will try to
|
|
* get find an existing message of one is not provided and notify the user
|
|
* about what went wrong. After that the error is marked as handled.
|
|
*/
|
|
notifyIf(name = null, message = null) {
|
|
if (
|
|
!(this.hasError() || this.hasNetworkError() || this.isNotFound()) ||
|
|
this.isHandled
|
|
) {
|
|
return
|
|
}
|
|
|
|
if (message === null) {
|
|
message = this.getMessage(name)
|
|
}
|
|
|
|
this.store.dispatch(
|
|
'notification/error',
|
|
{
|
|
title: message.title,
|
|
message: message.message,
|
|
},
|
|
{ root: true }
|
|
)
|
|
|
|
this.handled()
|
|
}
|
|
|
|
/**
|
|
* Will mark the error as handled so that the same error message isn't shown
|
|
* twice.
|
|
*/
|
|
handled() {
|
|
this.isHandled = true
|
|
}
|
|
}
|
|
|
|
export default function ({ store, app }, inject) {
|
|
const url =
|
|
(process.client
|
|
? app.$env.PUBLIC_BACKEND_URL
|
|
: app.$env.PRIVATE_BACKEND_URL) + '/api/v0'
|
|
const client = axios.create({
|
|
baseURL: url,
|
|
withCredentials: false,
|
|
headers: {
|
|
Accept: 'application/json',
|
|
'Content-Type': 'application/json',
|
|
},
|
|
})
|
|
|
|
// Create a request interceptor to add the authorization token to every
|
|
// request if the user is authenticated.
|
|
client.interceptors.request.use((config) => {
|
|
if (store.getters['auth/isAuthenticated']) {
|
|
const token = store.getters['auth/token']
|
|
config.headers.Authorization = `JWT ${token}`
|
|
}
|
|
return config
|
|
})
|
|
|
|
// Create a response interceptor to add more detail tot the error message
|
|
// and to create a notification when there is a network error.
|
|
client.interceptors.response.use(
|
|
(response) => {
|
|
return response
|
|
},
|
|
(error) => {
|
|
error.handler = new ErrorHandler(store, error.response)
|
|
|
|
// Add the error message in the response to the error object.
|
|
if (
|
|
error.response &&
|
|
'error' in error.response.data &&
|
|
'detail' in error.response.data
|
|
) {
|
|
error.handler.setError(
|
|
error.response.data.error,
|
|
error.response.data.detail
|
|
)
|
|
}
|
|
|
|
return Promise.reject(error)
|
|
}
|
|
)
|
|
|
|
inject('client', client)
|
|
}
|