UNPKG

@applica-software-guru/crud-client

Version:

Libreria per l'accesso ai servizi REST di Applica.

329 lines (303 loc) 9.84 kB
import { AttachmentParserResult, CreateHeaderOptions, ErrorMapperResult } from './types'; import _ from 'lodash'; import { stringify } from 'query-string'; import { GetListParams, GetManyParams } from 'ra-core'; function createHeadersFromOptions(options: CreateHeaderOptions): Headers | any { const requestHeaders = options.headers || new Headers({ Accept: 'application/json' }); if ( !requestHeaders.has('Content-Type') && !(options && (!options.method || options.method === 'GET')) && !(options && options.body && options.body instanceof FormData) ) { requestHeaders.set('Content-Type', 'application/json'); } if (options.user && options.user && options.user.token) { requestHeaders.set('Authorization', options.user.token); } return requestHeaders; } function createFormData(body: any): string { return Object.keys(body) .map((key) => encodeURIComponent(key) + '=' + encodeURIComponent(body[key])) .join('&'); } function fetchJson(url: string, options: any = {}, HttpErrorClass: any = Error, timeout?: number): Promise<any> { const controller = new AbortController(); const timeoutId = timeout ? setTimeout(() => controller.abort(), timeout) : null; const fetchOptions = { ...options, signal: controller.signal }; return fetch(url, fetchOptions) .then((response) => response.text().then((text) => ({ status: response.status, statusText: response.statusText, headers: response.headers, body: text })) ) .then(({ status, headers, body }) => { if (timeoutId) clearTimeout(timeoutId); if (status === 401) { return Promise.reject(new HttpErrorClass('iam.error.unauthorized', status, {})); } else if (status === 403) { return Promise.reject(new HttpErrorClass('iam.error.forbidden', status, {})); } else if (status === 404) { return Promise.reject(new HttpErrorClass('error.not_found', 404, {})); } let json; try { json = JSON.parse(body); } catch (e) { return Promise.reject(new HttpErrorClass('error.invalid_json_response', status, {})); } if (json?.responseCode === 'error.validation' || json?.responseCode === 'error.generic') { const body = { errors: createErrorMapper(json?.result) }; return Promise.reject(new HttpErrorClass(json?.responseCode, status, body)); } else if (json?.responseCode !== undefined && json?.responseCode !== 'ok') { return Promise.reject(new HttpErrorClass(json?.responseCode, status, body)); } return Promise.resolve({ status, headers, body, json }); }) .catch((error) => { if (timeoutId) clearTimeout(timeoutId); if (error.name === 'AbortError') { return Promise.reject(new HttpErrorClass('error.request_timeout', 408, {})); } throw error; }); } function isValidObject(value: any): boolean { if (!value) { return false; } const isArray = Array.isArray(value); // eslint-disable-next-line no-undef const isBuffer = typeof Buffer !== 'undefined' && Buffer.isBuffer(value); const isObject = Object.prototype.toString.call(value) === '[object Object]'; const hasKeys = !!Object.keys(value).length; return !isArray && !isBuffer && isObject && hasKeys; } function flattenObject(value: any, path: string[] = []): any { if (isValidObject(value)) { return Object.assign({}, ...Object.keys(value).map((key: string) => flattenObject(value[key], path.concat([key])))); } else { return path.length ? { [path.join('.')]: value } : value; } } const queryParameters = stringify; function createGetQuery(params: GetListParams | GetManyParams | any) { const filter = params?.filter || {}; const page = params?.pagination?.page || 1; const perPage = params?.pagination?.perPage || 10; const field = params?.sort?.field || 'id'; const order = params?.sort?.order || 'DESC'; return { filters: Object.keys(filter).reduce((acc: any[], key) => { let property = key; if (property === 'keyword') { return acc; } let value = filter[key]; let type = 'eq'; if (property.includes('__')) { const args = property.split('__'); property = args[0]; type = args[1]; } else if (typeof value === 'object') { type = Object.keys(value)[0]; value = value[type]; } return acc.concat([ { property, value, type } ]); }, []), page: page, rowsPerPage: perPage, keyword: filter?.keyword, sorts: [ { property: field, descending: 'DESC' === order.toUpperCase() } ] }; } type ConvertFileToBase64Result = null | { name: string; data: string | ArrayBuffer | null }; function convertFileToBase64(file: any): Promise<ConvertFileToBase64Result> { if (!file.rawFile) { return Promise.resolve(file); } return new Promise((resolve, reject) => { const reader = new FileReader(); reader.readAsDataURL(file.rawFile); reader.onload = () => { resolve({ name: file.rawFile.name, data: reader.result }); }; reader.onerror = reject; }); } async function convertFile(file: any) { return file.rawFile ? convertFileToBase64(file).then((convertedFile) => ({ data: convertedFile, name: file.rawFile.name, size: file.rawFile.size, type: file.rawFile.type })) : Promise.resolve(file); } function uuid(): string { let d = new Date().getTime(); if (window.performance && typeof window.performance.now === 'function') { d += performance.now(); //use high-precision timer if available } const uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) { const r = (d + Math.random() * 16) % 16 | 0; d = Math.floor(d / 16); return (c == 'x' ? r : (r & 0x3) | 0x8).toString(16); }); return uuid; } function convertFileToPart(item: any, parts: any[]): string { let data = item; const file = item?.rawFile || item; if (file instanceof File) { const id = uuid(); const { name, size, type } = file; parts.push({ id, file }); data = { id, name, size, contentType: type, action: 'Add' }; } return data; } function springErrorMapper(errors: any[]): any[] { const validationErrors = errors.reduce( (errorMap, error) => ({ ...errorMap, [error.property]: error.message }), {} ); return validationErrors; } function createErrorMapper(result: ErrorMapperResult): any | any[] | boolean { const errors = result?.errors || []; if (errors) { const mappedErrors = springErrorMapper(errors); return mappedErrors; } else { return false; } } function flattenKeys(obj: any, prefix: string = '.'): any { const keys = []; if (typeof obj === 'object' && obj !== null) { for (const key in obj) { let newPrefix = prefix + key + '.'; if (newPrefix.startsWith('.')) { newPrefix = newPrefix.substring(1); } keys.push(...flattenKeys(obj[key], newPrefix)); } } else { if (prefix.endsWith('.') && prefix.length > 1) { prefix = prefix.substring(0, prefix.length - 1); } keys.push(prefix); } return keys; } /** * Configure a parser capable of working with attachments managed within forms. * * @param {Array<String>} fields * @returns {Function} Returns a parser function that can be used to parse attachments. * @example * import { createAttachmentsParser } from '@applica-software-guru/crud-client'; * const parser = createAttachmentsParser(); */ function createAttachmentsParser() { return async (data: any): Promise<AttachmentParserResult> => { const parts: any[] = []; const regex = new RegExp(/__attachment_*|__file_*|__image_*/); const fields = flattenKeys(data).filter((f: string) => regex.test(f)); for (let i = 0; i < fields.length; i++) { const attachment = fields[i]; const type = regex.exec(attachment); if (type && type[0]) { const theKey = attachment.replace(type[0], ''); const value = _.get(data, theKey); const isAttachment = type[0] === '__attachment__'; if (!value) { if (!isAttachment) { data = _.set(data, `_${theKey}`, null); } } else { const _value = _.get(data, theKey); if (Array.isArray(_value)) { if (!isAttachment) { throw new Error('Array of file/image is not supported, please use Attachment instead.'); } for (let j = 0; j < _value.length; j++) { const item = _value[j]; const file = convertFileToPart(item, parts); _value[j] = file; } _.set(data, theKey, _value); } else { const file = ( isAttachment ? await convertFileToPart(_value, parts) : await convertFileToBase64(_value) ) as any; const alreadyStoredBase64Value = _.get(data, `_${theKey}`); _.set( data, isAttachment ? theKey : `_${theKey}`, isAttachment ? file : file.data || alreadyStoredBase64Value ); if (!isAttachment && file?.name) { _.set(data, theKey, file.name); } } } } data = _.omit(data, attachment); } return { data, parts }; }; } export { convertFile, convertFileToBase64, convertFileToPart, createAttachmentsParser, createErrorMapper, createFormData, createGetQuery, createHeadersFromOptions, fetchJson, flattenKeys, flattenObject, queryParameters, springErrorMapper, uuid };