import { Meteor } from 'meteor/meteor'; import { Accounts } from 'meteor/accounts-base'; import { baseURI } from './baseuri'; import { process2faReturn } from '../../../2fa/client/callWithTwoFactorRequired'; export const mountArrayQueryParameters = (label, array) => array.reduce((acc, item) => { acc += `${ label }[]=${ item }&`; return acc; }, ''); export const APIClient = { delete(endpoint, params) { return APIClient._jqueryCall('DELETE', endpoint, params); }, get(endpoint, params) { return APIClient._jqueryCall('GET', endpoint, params); }, post(endpoint, params, body) { if (!body) { body = params; params = {}; } return APIClient._jqueryCall('POST', endpoint, params, body); }, upload(endpoint, params, formData, xhrOptions) { if (!formData) { formData = params; params = {}; } return APIClient._jqueryFormDataCall(endpoint, params, formData, xhrOptions); }, getCredentials() { return { 'X-User-Id': Meteor._localStorage.getItem(Accounts.USER_ID_KEY), 'X-Auth-Token': Meteor._localStorage.getItem(Accounts.LOGIN_TOKEN_KEY), }; }, _generateQueryFromParams(params) { let query = ''; if (params && typeof params === 'object') { Object.keys(params).forEach((key) => { query += query === '' ? '?' : '&'; if (Array.isArray(params[key])) { const joinedArray = params[key].join(`&${ key }[]=`); query += `${ key }[]=${ joinedArray }`; } else { query += `${ key }=${ params[key] }`; } }); } return query; }, _jqueryCall(method, endpoint, params, body, headers = {}) { const query = APIClient._generateQueryFromParams(params); return new Promise(function _rlRestApiGet(resolve, reject) { jQuery.ajax({ method, url: `${ baseURI }api/${ endpoint }${ query }`, headers: Object.assign({ 'Content-Type': 'application/json', ...APIClient.getCredentials(), }, headers), data: JSON.stringify(body), success: function _rlGetSuccess(result) { resolve(result); }, error: function _rlGetFailure(xhr, status, errorThrown) { APIClient.processTwoFactorError({ xhr, params: [method, endpoint, params, body, headers], resolve, reject, originalCallback() { const error = new Error(errorThrown); error.xhr = xhr; reject(error); }, }); }, }); }); }, _jqueryFormDataCall(endpoint, params, formData, { progress = () => {}, error = () => {} } = {}) { const ret = { }; const query = APIClient._generateQueryFromParams(params); if (!(formData instanceof FormData)) { throw new Error('The formData parameter MUST be an instance of the FormData class.'); } ret.promise = new Promise(function _jqueryFormDataPromise(resolve, reject) { ret.xhr = jQuery.ajax({ xhr() { const xhr = new window.XMLHttpRequest(); xhr.upload.addEventListener('progress', function(evt) { if (evt.lengthComputable) { const percentComplete = evt.loaded / evt.total; progress(percentComplete * 100); } }, false); xhr.upload.addEventListener('error', error, false); return xhr; }, url: `${ baseURI }api/${ endpoint }${ query }`, headers: APIClient.getCredentials(), data: formData, processData: false, contentType: false, type: 'POST', success: function _jqueryFormDataSuccess(result) { resolve(result); }, error: function _jqueryFormDataError(xhr, status, errorThrown) { const error = new Error(errorThrown); error.xhr = xhr; reject(error); }, }); }); return ret; }, processTwoFactorError({ xhr, params, originalCallback, resolve, reject }) { if (!xhr.responseJSON || !xhr.responseJSON.errorType) { return originalCallback(); } process2faReturn({ error: xhr.responseJSON, originalCallback, onCode(code, method) { const headers = params[params.length - 1]; headers['x-2fa-code'] = code; headers['x-2fa-method'] = method; APIClient._jqueryCall(...params).then(resolve).catch(reject); }, }); }, v1: { delete(endpoint, params) { return APIClient.delete(`v1/${ endpoint }`, params); }, get(endpoint, params) { return APIClient.get(`v1/${ endpoint }`, params); }, post(endpoint, params, body) { return APIClient.post(`v1/${ endpoint }`, params, body); }, upload(endpoint, params, formData) { return APIClient.upload(`v1/${ endpoint }`, params, formData); }, }, };