diff --git a/src/lib/ae_core_functions.ts b/src/lib/ae_core_functions.ts index 3052a47a..a143dffd 100644 --- a/src/lib/ae_core_functions.ts +++ b/src/lib/ae_core_functions.ts @@ -299,6 +299,7 @@ async function handle_download_export__obj_type( return_file=true, filename='no_filename.csv', auto_download=false, + limit=5000, params={}, // key value object is expected log_lvl=0 } : { @@ -310,6 +311,7 @@ async function handle_download_export__obj_type( return_file?: boolean, filename?: string, auto_download?: boolean, + limit?: number, params?: key_val, log_lvl?: number } @@ -332,6 +334,10 @@ async function handle_download_export__obj_type( let clean_filename = filename.replace(/[^a-zA-Z0-9\[\]-_.]/gi, '_'); // let clean_filename = filename.replace(/[^a-zA-Z0-9\[\]-\._ ]/gi, '_'); + if (limit >= 0) { + params['limit'] = limit; + } + ae_promises.download__sponsorship_export_file = await api.get_object({api_cfg: api_cfg, endpoint: endpoint, params: params, return_blob: return_file, filename: clean_filename, auto_download: auto_download, log_lvl: log_lvl}); console.log('ae_promises.download__sponsorship_export_file:', ae_promises.download__sponsorship_export_file); diff --git a/src/lib/api.ts b/src/lib/api.ts new file mode 100644 index 00000000..554a31c8 --- /dev/null +++ b/src/lib/api.ts @@ -0,0 +1,984 @@ +// Aether API Library (TS) +// This is intended to be used with the Aether API. +// This needs to be cleaned up and ideally removed the need for Axios. + +import { delete_object } from './api_delete_object'; +import { get_object } from './api_get_object'; +import { patch_object } from './api_patch_object'; +import { post_object } from './api_post_object'; + + +// Updated 2023-12-01 +export let get_ae_obj_id_crud = async function get_ae_obj_id_crud({ + api_cfg, + no_account_id=false, + obj_type, + obj_id, + use_alt_table=false, + use_alt_base=false, + inc={}, + enabled='enabled', + hidden='not_hidden', + limit=999999, + offset=0, + data={}, + // key, + jwt=null, + headers={}, + params={}, + timeout=25000, + return_meta=false, + log_lvl=0}) { + if (log_lvl) { + console.log('*** get_ae_obj_id_crud() ***'); + } + + // data = {}; + // data['super_key'] = key; + // data['jwt'] = jwt; + // NOTE: The key and or JWT should be in the header of the DELETE, GET, PATCH, POST + + let endpoint = ''; + if (obj_type == 'account') { + endpoint = `/crud/account/${obj_id}`; + } else if (obj_type == 'address') { + endpoint = `/crud/address/${obj_id}`; + } else if (obj_type == 'archive') { + endpoint = `/crud/archive/${obj_id}`; + } else if (obj_type == 'archive_content') { + endpoint = `/crud/archive/content/${obj_id}`; + } else if (obj_type == 'contact') { + endpoint = `/crud/contact/${obj_id}`; + } else if (obj_type == 'data_store') { + endpoint = `/crud/data_store/${obj_id}`; + } else if (obj_type == 'event') { + endpoint = `/crud/event/${obj_id}`; + } else if (obj_type == 'event_abstract') { + endpoint = `/crud/event/abstract/${obj_id}`; + } else if (obj_type == 'event_badge') { + endpoint = `/crud/event/badge/${obj_id}`; + } else if (obj_type == 'event_device') { + endpoint = `/crud/event/device/${obj_id}`; + } else if (obj_type == 'event_exhibit') { + endpoint = `/crud/event/exhibit/${obj_id}`; + } else if (obj_type == 'event_exhibit_tracking') { + endpoint = `/crud/event/exhibit/tracking/${obj_id}`; + } else if (obj_type == 'event_file') { + endpoint = `/crud/event/file/${obj_id}`; + } else if (obj_type == 'event_location') { + endpoint = `/crud/event/location/${obj_id}`; + } else if (obj_type == 'event_person') { + endpoint = `/crud/event/person/${obj_id}`; + } else if (obj_type == 'event_presentation') { + endpoint = `/crud/event/presentation/${obj_id}`; + } else if (obj_type == 'event_presenter') { + endpoint = `/crud/event/presenter/${obj_id}`; + } else if (obj_type == 'event_session') { + endpoint = `/crud/event/session/${obj_id}`; + } else if (obj_type == 'event_track') { + endpoint = `/crud/event/track/${obj_id}`; + } else if (obj_type == 'grant') { + endpoint = `/crud/grant/${obj_id}`; + } else if (obj_type == 'hosted_file') { + endpoint = `/crud/hosted_file/${obj_id}`; + } else if (obj_type == 'journal') { + endpoint = `/crud/journal/${obj_id}`; + } else if (obj_type == 'journal_entry') { + endpoint = `/crud/journal/entry/${obj_id}`; + } else if (obj_type == 'order') { + endpoint = `/crud/order/${obj_id}`; + } else if (obj_type == 'order_line') { + endpoint = `/crud/order/line/${obj_id}`; + } else if (obj_type == 'page') { + endpoint = `/crud/page/${obj_id}`; + } else if (obj_type == 'person') { + endpoint = `/crud/person/${obj_id}`; + } else if (obj_type == 'post') { + endpoint = `/crud/post/${obj_id}`; + } else if (obj_type == 'post_comment') { + endpoint = `/crud/post/comment/${obj_id}`; + } else if (obj_type == 'site') { + endpoint = `/crud/site/${obj_id}`; + } else if (obj_type == 'site_domain') { + endpoint = `/crud/site/domain/${obj_id}`; + } else if (obj_type == 'sponsorship_cfg') { + endpoint = `/crud/sponsorship/cfg/${obj_id}`; + } else if (obj_type == 'sponsorship') { + endpoint = `/crud/sponsorship/${obj_id}`; + // } else if (obj_type == 'user') { + // endpoint = `/crud/user/${obj_id}`; + } else { + console.log(`Unknown object type: ${obj_type}`); + return false; + } + if (log_lvl) { + console.log('Endpoint:', endpoint); + } + + params['use_alt_table'] = use_alt_table; + params['use_alt_base'] = use_alt_base; + + if (log_lvl) { + console.log('Params:', params); + } + + if (no_account_id) { + headers['x-no-account-id'] = 'Nothing to See Here'; + delete headers['x-account-id']; + delete api_cfg['headers']['x-account-id']; + // headers['x-account-id'] = null; + // headers['x-account-id'] = '_XY7DXtc9Mxx'; + // params['x_no_account_id_token'] = 'Nothing to See Here'; + + // Remove the x-account-id header + // if (headers['x-account-id']) { + // delete headers['x-account-id']; + // } + + // headers['x-account-id'] = null; + // headers['x-no-account-id-token'] = 'Nothing to See Here'; // get_object() will fix the underscores to dashes + } + + let object_obj_get_promise = await get_object({ + api_cfg: api_cfg, + endpoint: endpoint, + headers: headers, + params: params, + timeout: timeout, + log_lvl: log_lvl + }); + + if (log_lvl > 1) { + console.log(object_obj_get_promise); + } + + return object_obj_get_promise; +} + + +// Updated 2023-11-15 +export let get_ae_obj_li_for_obj_id_crud = async function get_ae_obj_li_for_obj_id_crud({ + api_cfg, + obj_type, + for_obj_type, + for_obj_id=null, // NOTE: Changed 2023-12-06 to no longer required + use_alt_table=false, + use_alt_base=false, + inc={}, + enabled='enabled', + hidden='not_hidden', + order_by_li=null, + limit=999999, + offset=0, + key, + jwt=null, + headers={}, + params_json=null, // NOTE: This is a JSON object that needs to be safely converted to a string for the params. This is used for the API endpoint. Example: { "fulltext_search": { "default_qry_str": "Search string for default", "address_default_qry_str": "Search string for address", "contact_1_default_qry_str": "Search string for contact_1" } } + // json_obj=null, // NOTE: This is a JSON object that needs to be safely converted to a string for the params. This is used for the search endpoint. + params={}, + return_meta=false, + log_lvl=0 + }) { + if (log_lvl) { + console.log('*** get_ae_obj_li_for_obj_id_crud() ***'); + } + + // data = {}; + // data['super_key'] = key; + // data['jwt'] = jwt; + // NOTE: The key and or JWT should be in the header of the DELETE, GET, PATCH, POST + + // const endpoint = `/crud/${obj_type}/list`; + + let endpoint = ''; + if (obj_type == 'account') { + endpoint = `/crud/account/list`; + } else if (obj_type == 'address') { + endpoint = `/crud/address/list`; + } else if (obj_type == 'archive') { + endpoint = `/crud/archive/list`; + } else if (obj_type == 'archive_content') { + endpoint = `/crud/archive/content/list`; + } else if (obj_type == 'contact') { + endpoint = `/crud/contact/list`; + } else if (obj_type == 'data_store') { + endpoint = `/crud/data_store/list`; + } else if (obj_type == 'event') { + endpoint = `/crud/event/list`; + } else if (obj_type == 'event_abstract') { + endpoint = `/crud/event/abstract/list`; + } else if (obj_type == 'event_badge') { + endpoint = `/crud/event/badge/list`; + } else if (obj_type == 'event_device') { + endpoint = `/crud/event/device/list`; + } else if (obj_type == 'event_exhibit') { + endpoint = `/crud/event/exhibit/list`; + } else if (obj_type == 'event_exhibit_tracking') { + endpoint = `/crud/event/exhibit/tracking/list`; + } else if (obj_type == 'event_file') { + endpoint = `/crud/event/file/list`; + } else if (obj_type == 'event_location') { + endpoint = `/crud/event/location/list`; + } else if (obj_type == 'event_person') { + endpoint = `/crud/event/person/list`; + } else if (obj_type == 'event_presentation') { + endpoint = `/crud/event/presentation/list`; + } else if (obj_type == 'event_presenter') { + endpoint = `/crud/event/presenter/list`; + } else if (obj_type == 'event_session') { + endpoint = `/crud/event/session/list`; + } else if (obj_type == 'event_track') { + endpoint = `/crud/event/track/list`; + } else if (obj_type == 'grant') { + endpoint = `/crud/grant/list`; + } else if (obj_type == 'hosted_file') { + endpoint = `/crud/hosted_file/list`; + } else if (obj_type == 'journal') { + endpoint = `/crud/journal/list`; + } else if (obj_type == 'journal_entry') { + endpoint = `/crud/journal/entry/list`; + } else if (obj_type == 'order') { + endpoint = `/crud/order/list`; + } else if (obj_type == 'order_line') { + endpoint = `/crud/order/line/list`; + } else if (obj_type == 'page') { + endpoint = `/crud/page/list`; + } else if (obj_type == 'person') { + endpoint = `/crud/person/list`; + } else if (obj_type == 'post') { + endpoint = `/crud/post/list`; + } else if (obj_type == 'post_comment') { + endpoint = `/crud/post/comment/list`; + } else if (obj_type == 'site') { + endpoint = `/crud/site/list`; + } else if (obj_type == 'sponsorship_cfg') { + endpoint = `/crud/sponsorship/cfg/list`; + } else if (obj_type == 'sponsorship') { + endpoint = `/crud/sponsorship/list`; + // } else if (obj_type == 'user') { + // endpoint = `/crud/user/list`; + } else if (obj_type == 'lu' && for_obj_type == 'country_subdivision') { + endpoint = `/crud/lu/country_subdivision/list`; + for_obj_type = null; + } else if (obj_type == 'lu' && for_obj_type == 'country') { + endpoint = `/crud/lu/country/list`; + for_obj_type = null; + } else if (obj_type == 'lu' && for_obj_type == 'time_zone') { + endpoint = `/crud/lu/time_zone/list`; + for_obj_type = null; + } else { + console.log(`Unknown object type: ${obj_type}`); + return false; + } + if (log_lvl) { + console.log('Endpoint:', endpoint); + } + + if (for_obj_type) { + params['for_obj_type'] = for_obj_type; + } + if (for_obj_id) { + params['for_obj_id'] = for_obj_id; + } + + params['use_alt_table'] = use_alt_table; + params['use_alt_base'] = use_alt_base; + + /* Need to deal with inc params here */ + + let allowed_enabled_list = ['all', 'enabled', 'not_enabled'] + if (allowed_enabled_list.includes(enabled) ) { + params['enabled'] = enabled; + } + + let allowed_hidden_list = ['all', 'hidden', 'not_hidden']; + if (allowed_hidden_list.includes(hidden) ) { + params['hidden'] = hidden; + } + + // NOTE: The order_by_li variable is in the "headers" because if is a the URL GET params do not handle multiple values very well. Maybe base64 encore in the future or something? Reminder that GET requests should not have a body (no JSON). + // NOTE: The order_by_li should be a key value pair of the property/DB field to sort and how to sort (ASC or DESC) + if (order_by_li) { + headers['order_by_li'] = order_by_li; + } + + if (limit >= 0) { + params['limit'] = limit; + } + + if (offset >= 0) { + params['offset'] = offset; + } + + if (params_json) { + // NOTE: This is a JSON object that needs to be safely converted to a string for the params. This is used for the search endpoint. + // Max characters for a GET request is 2083. This is a limitation of the browser (Microsoft IE and Edge). + console.log('JSON Object:', params_json); + console.log(JSON.stringify(params_json)); + // NOTE: "jp" stands for "JSON Params" + params['jp'] = encodeURIComponent(JSON.stringify(params_json)); + if (params['jp'].length > 2083) { + console.log(`The JSON object is too large to be used as a GET parameter. The overall max URL length is 2083 characters. Please use the POST endpoint instead. Length = ${params['jp'].length} [THIS DOES NOT EXIST YET]`); + return false; + } + } + + // if (json_obj) { + // // NOTE: This is a JSON object that needs to be safely converted to a string for the params. This is used for the search endpoint. + // // Max characters for a GET request is 2083. This is a limitation of the browser (Microsoft IE and Edge). + // console.log('JSON Object:', json_obj); + // params['json_str'] = encodeURIComponent(JSON.stringify(json_obj)); + // if (params['json_str'].length > 2083) { + // console.log(`The JSON object is too large to be used as a GET parameter. The overall max URL length is 2083 characters. Please use the POST endpoint instead. Length = ${params['json_str'].length} [THIS DOES NOT EXIST YET]`); + // return false; + // } + // } + + if (log_lvl) { + console.log('Params:', params); + } + + let object_li_get_promise = await api.get_object({ + api_cfg: api_cfg, + endpoint: endpoint, + headers: headers, + params: params, + return_meta: return_meta, + log_lvl: log_lvl + }); + + if (log_lvl > 1) { + console.log(object_li_get_promise); + } + + return object_li_get_promise; +} + + +// Updated 2023-07-24 +export let create_ae_obj_crud = async function create_ae_obj_crud({api_cfg, obj_type, field_name=null, field_value=null, fields={}, key, jwt=null, headers={}, params={}, data={}, return_obj=false, obj_v_name='', return_meta=false, log_lvl=0}) { + if (log_lvl) { + console.log('*** create_ae_obj_crud() ***'); + } + + data['super_key'] = key; + data['jwt'] = jwt; + // NOTE: The key and or JWT should be in the header of the DELETE, GET, PATCH, POST + + // This obj_v_name is the view name to use when returning data. Do not prefix it with v_. This is checked and done automatically by the API. + // This is not currently being exposed to other areas of the code. It is only used here. For now? + if (obj_v_name) { + obj_v_name = ''; + } + + let endpoint = ''; + if (obj_type == 'account') { + endpoint = `/crud/account`; + } else if (obj_type == 'address') { + endpoint = `/crud/address`; + } else if (obj_type == 'archive') { + endpoint = `/crud/archive`; + } else if (obj_type == 'archive_content') { + endpoint = `/crud/archive/content`; + } else if (obj_type == 'contact') { + endpoint = `/crud/contact`; + } else if (obj_type == 'data_store') { + endpoint = `/crud/data_store`; + } else if (obj_type == 'event') { + endpoint = `/crud/event`; + } else if (obj_type == 'event_abstract') { + endpoint = `/crud/event/abstract`; + } else if (obj_type == 'event_badge') { + endpoint = `/crud/event/badge`; + } else if (obj_type == 'event_device') { + endpoint = `/crud/event/device`; + } else if (obj_type == 'event_exhibit') { + endpoint = `/crud/event/exhibit`; + } else if (obj_type == 'event_exhibit_tracking') { + endpoint = `/crud/event/exhibit/tracking`; + } else if (obj_type == 'event_file') { + endpoint = `/crud/event/file`; + } else if (obj_type == 'event_location') { + endpoint = `/crud/event/location`; + } else if (obj_type == 'event_person') { + endpoint = `/crud/event/person`; + } else if (obj_type == 'event_presentation') { + endpoint = `/crud/event/presentation`; + } else if (obj_type == 'event_presenter') { + endpoint = `/crud/event/presenter`; + // obj_v_name = 'event_presenter_soft_links'; + } else if (obj_type == 'event_session') { + endpoint = `/crud/event/session`; + } else if (obj_type == 'event_track') { + endpoint = `/crud/event/track`; + } else if (obj_type == 'grant') { + endpoint = `/crud/grant`; + } else if (obj_type == 'hosted_file') { + endpoint = `/crud/hosted_file`; + } else if (obj_type == 'journal') { + endpoint = `/crud/journal`; + } else if (obj_type == 'journal_entry') { + endpoint = `/crud/journal/entry`; + } else if (obj_type == 'order') { + endpoint = `/crud/order`; + } else if (obj_type == 'order_line') { + endpoint = `/crud/order/line`; + } else if (obj_type == 'page') { + endpoint = `/crud/page`; + } else if (obj_type == 'person') { + endpoint = `/crud/person`; + } else if (obj_type == 'post') { + endpoint = `/crud/post`; + } else if (obj_type == 'post_comment') { + endpoint = `/crud/post/comment`; + } else if (obj_type == 'sponsorship_cfg') { + endpoint = `/crud/sponsorship/cfg`; + } else if (obj_type == 'sponsorship') { + endpoint = `/crud/sponsorship`; + } else if (obj_type == 'site') { + endpoint = `/crud/site`; + // } else if (obj_type == 'user') { + // endpoint = `/crud/user`; + } else { + console.log(`Unknown object type: ${obj_type}`); + return false; + } + if (log_lvl) { + console.log('Endpoint:', endpoint); + } + + if (return_obj) { + params['return_obj'] = true; + + // Pass along the view name to use for returning data. + if (obj_v_name) { + params['obj_v_name'] = obj_v_name; + } + } else { + params['return_obj'] = false; // NOTE: This is needed because the current default on the API is to return the object. + } + + if (field_name) { + data['data_list'] = {}; // Really an object/dict + data['data_list'][field_name] = field_value; + // data['data_list']['testing'] = 'asdf 1234'; + } else if (fields) { + data['data_list'] = fields; // Really an object/dict + } + + // NOTE: The data object may contain objects that need to be converted to JSON strings. This is done by adding "_json" to the end of the property name. This is done because the API does not support nested objects. This is a limitation of the API. + if (data['data_list']) { + if (log_lvl > 1) { + console.log('Data List:', data['data_list']); + } + for (const [key, value] of Object.entries(data['data_list'])) { + // console.log(key, value); + if (key.endsWith('_json')) { + if (log_lvl) { + console.log(`${key}: ${value}`); + } + data['data_list'][key] = JSON.stringify(value); + } + } + } + + if (log_lvl) { + console.log('Data:', data); + } + // params['xxxxx run_safety_check xxxxx'] = false; + params['by_alias'] = false; + + if (log_lvl) { + console.log('Params:', params); + } + + let object_obj_post_promise = await post_object({api_cfg: api_cfg, endpoint: endpoint, params: params, data: data, log_lvl: log_lvl}); + + if (log_lvl > 1) { + console.log(object_obj_post_promise); + } + + return object_obj_post_promise; +} + + +// Updated 2023-06-28 +export let update_ae_obj_id_crud = async function update_ae_obj_id_crud({api_cfg, obj_type, obj_id, field_name, field_value, fields={}, key, jwt=null, headers={}, params={}, data={}, return_obj=false, obj_v_name='', return_meta=false, log_lvl=0}) { + if (log_lvl) { + console.log('*** update_ae_obj_id_crud() ***'); + } + + data['super_key'] = key; + data['jwt'] = jwt; + // NOTE: The key and or JWT should be in the header of the DELETE, GET, PATCH, POST + + // This obj_v_name is the view name to use when returning data. Do not prefix it with v_. This is checked and done automatically by the API. + // This is not currently being exposed to other areas of the code. It is only used here. For now? + if (obj_v_name) { + obj_v_name = ''; + } + + let endpoint = ''; + if (obj_type == 'account') { + endpoint = `/crud/account/${obj_id}`; + } else if (obj_type == 'address') { + endpoint = `/crud/address/${obj_id}`; + } else if (obj_type == 'archive') { + endpoint = `/crud/archive/${obj_id}`; + } else if (obj_type == 'archive_content') { + endpoint = `/crud/archive/content/${obj_id}`; + } else if (obj_type == 'contact') { + endpoint = `/crud/contact/${obj_id}`; + } else if (obj_type == 'data_store') { + endpoint = `/crud/data_store/${obj_id}`; + } else if (obj_type == 'event') { + endpoint = `/crud/event/${obj_id}`; + } else if (obj_type == 'event_abstract') { + endpoint = `/crud/event/abstract/${obj_id}`; + } else if (obj_type == 'event_badge') { + endpoint = `/crud/event/badge/${obj_id}`; + } else if (obj_type == 'event_device') { + endpoint = `/crud/event/device/${obj_id}`; + } else if (obj_type == 'event_exhibit') { + endpoint = `/crud/event/exhibit/${obj_id}`; + } else if (obj_type == 'event_exhibit_tracking') { + endpoint = `/crud/event/exhibit/tracking/${obj_id}`; + } else if (obj_type == 'event_file') { + endpoint = `/crud/event/file/${obj_id}`; + } else if (obj_type == 'event_location') { + endpoint = `/crud/event/location/${obj_id}`; + } else if (obj_type == 'event_person') { + endpoint = `/crud/event/person/${obj_id}`; + } else if (obj_type == 'event_presentation') { + endpoint = `/crud/event/presentation/${obj_id}`; + } else if (obj_type == 'event_presenter') { + endpoint = `/crud/event/presenter/${obj_id}`; + // obj_v_name = 'event_presenter_soft_links'; + } else if (obj_type == 'event_session') { + endpoint = `/crud/event/session/${obj_id}`; + } else if (obj_type == 'event_track') { + endpoint = `/crud/event/track/${obj_id}`; + } else if (obj_type == 'grant') { + endpoint = `/crud/grant/${obj_id}`; + } else if (obj_type == 'hosted_file') { + endpoint = `/crud/hosted_file/${obj_id}`; + } else if (obj_type == 'journal') { + endpoint = `/crud/journal/${obj_id}`; + } else if (obj_type == 'journal_entry') { + endpoint = `/crud/journal/entry/${obj_id}`; + } else if (obj_type == 'order') { + endpoint = `/crud/order/${obj_id}`; + } else if (obj_type == 'order_line') { + endpoint = `/crud/order/line/${obj_id}`; + } else if (obj_type == 'page') { + endpoint = `/crud/page/${obj_id}`; + } else if (obj_type == 'person') { + endpoint = `/crud/person/${obj_id}`; + } else if (obj_type == 'post') { + endpoint = `/crud/post/${obj_id}`; + } else if (obj_type == 'post_comment') { + endpoint = `/crud/post/comment/${obj_id}`; + } else if (obj_type == 'site') { + endpoint = `/crud/site/${obj_id}`; + } else if (obj_type == 'sponsorship_cfg') { + endpoint = `/crud/sponsorship/cfg/${obj_id}`; + } else if (obj_type == 'sponsorship') { + endpoint = `/crud/sponsorship/${obj_id}`; + // } else if (obj_type == 'user') { + // endpoint = `/crud/user/${obj_id}`; + } else { + console.log(`Unknown object type: ${obj_type}`); + return false; + } + if (log_lvl) { + console.log('Endpoint:', endpoint); + } + + if (return_obj) { + params['return_obj'] = true; + + // Pass along the view name to use for returning data. + if (obj_v_name) { + params['obj_v_name'] = obj_v_name; + } + } else { + params['return_obj'] = false; // NOTE: This is needed because the current default on the API is to return the object. + } + + if (field_name) { + data['data_list'] = {}; // Really an object/dict + data['data_list'][field_name] = field_value; + // data['data_list']['testing'] = 'asdf 1234'; + } else if (fields) { + data['data_list'] = fields; // Really an object/dict + } + + // NOTE: The data object may contain objects that need to be converted to JSON strings. This is done by adding "_json" to the end of the property name. This is done because the API does not support nested objects. This is a limitation of the API. + if (data['data_list']) { + if (log_lvl > 1) { + console.log('Data List:', data['data_list']); + } + for (const [key, value] of Object.entries(data['data_list'])) { + // console.log(key, value); + if (key.endsWith('_json')) { + if (log_lvl) { + console.log(`${key}: ${value}`); + } + data['data_list'][key] = JSON.stringify(value); + } + } + } + + // If the data is an object then we need to loop through the object and convert any objects to JSON strings, but only if the property name ends with "_json". + // if (Array.isArray(data)) { + // // console.log('Data is an array'); + // for (let i = 0; i < data.length; i++) { + // // console.log(data[i]); + // if (typeof data[i] == 'object') { + // // console.log('Data is an object'); + // for (const [key, value] of Object.entries(data[i])) { + // // console.log(key, value); + // if (key.endsWith('_json')) { + // console.log(`${key}: ${value}`); + // data[i][key] = JSON.stringify(value); + // } + // } + + // } + // } + // } else if (typeof data == 'object') { + // // console.log('Data is an object'); + // for (const [key, value] of Object.entries(data)) { + // // console.log(key, value); + // if (key.endsWith('_json')) { + // console.log(`${key}: ${value}`); + // data[key] = JSON.stringify(value); + // } + // } + // } + + if (log_lvl) { + console.log('Data:', data); + } + // params['xxxxx run_safety_check xxxxx'] = false; + params['by_alias'] = false; + + if (log_lvl) { + console.log('Params:', params); + } + + let object_obj_patch_promise = await patch_object({api_cfg: api_cfg, endpoint: endpoint, params: params, data: data, log_lvl: log_lvl}); + + if (log_lvl > 1) { + console.log(object_obj_patch_promise); + } + + return object_obj_patch_promise; +} + + +// Updated 2023-11-14 +export let delete_ae_obj_id_crud = async function delete_ae_obj_id_crud({api_cfg, obj_type, obj_id, key, jwt=null, headers={}, params={}, data={}, method='delete', return_meta=false, log_lvl=0}) { + if (log_lvl) { + console.log(`*** delete_ae_obj_id_crud() *** obj_type: ${obj_type} obj_id: ${obj_id}`); + } + + data['super_key'] = key; + data['jwt'] = jwt; + // NOTE: The key and or JWT should be in the header of the DELETE, GET, PATCH, POST + + let endpoint = ''; + if (obj_type == 'account') { + endpoint = `/crud/account/${obj_id}`; + } else if (obj_type == 'address') { + endpoint = `/crud/address/${obj_id}`; + } else if (obj_type == 'archive') { + endpoint = `/crud/archive/${obj_id}`; + } else if (obj_type == 'archive_content') { + endpoint = `/crud/archive/content/${obj_id}`; + } else if (obj_type == 'contact') { + endpoint = `/crud/contact/${obj_id}`; + } else if (obj_type == 'data_store') { + endpoint = `/crud/data_store/${obj_id}`; + } else if (obj_type == 'event') { + endpoint = `/crud/event/${obj_id}`; + } else if (obj_type == 'event_abstract') { + endpoint = `/crud/event/abstract/${obj_id}`; + } else if (obj_type == 'event_badge') { + endpoint = `/crud/event/badge/${obj_id}`; + } else if (obj_type == 'event_device') { + endpoint = `/crud/event/device/${obj_id}`; + } else if (obj_type == 'event_exhibit') { + endpoint = `/crud/event/exhibit/${obj_id}`; + } else if (obj_type == 'event_exhibit_tracking') { + endpoint = `/crud/event/exhibit/tracking/${obj_id}`; + } else if (obj_type == 'event_file') { + endpoint = `/crud/event/file/${obj_id}`; + } else if (obj_type == 'event_location') { + endpoint = `/crud/event/location/${obj_id}`; + } else if (obj_type == 'event_person') { + endpoint = `/crud/event/person/${obj_id}`; + } else if (obj_type == 'event_presentation') { + endpoint = `/crud/event/presentation/${obj_id}`; + } else if (obj_type == 'event_presenter') { + endpoint = `/crud/event/presenter/${obj_id}`; + } else if (obj_type == 'event_session') { + endpoint = `/crud/event/session/${obj_id}`; + } else if (obj_type == 'event_track') { + endpoint = `/crud/event/track/${obj_id}`; + } else if (obj_type == 'grant') { + endpoint = `/crud/grant/${obj_id}`; + } else if (obj_type == 'hosted_file') { + endpoint = `/crud/hosted_file/${obj_id}`; + } else if (obj_type == 'journal') { + endpoint = `/crud/journal/${obj_id}`; + } else if (obj_type == 'journal_entry') { + endpoint = `/crud/journal/entry/${obj_id}`; + } else if (obj_type == 'order') { + endpoint = `/crud/order/${obj_id}`; + } else if (obj_type == 'order_line') { + endpoint = `/crud/order/line/${obj_id}`; + } else if (obj_type == 'page') { + endpoint = `/crud/page/${obj_id}`; + } else if (obj_type == 'person') { + endpoint = `/crud/person/${obj_id}`; + } else if (obj_type == 'post') { + endpoint = `/crud/post/${obj_id}`; + } else if (obj_type == 'post_comment') { + endpoint = `/crud/post/comment/${obj_id}`; + } else if (obj_type == 'site') { + endpoint = `/crud/site/${obj_id}`; + } else if (obj_type == 'sponsorship_cfg') { + endpoint = `/crud/sponsorship/cfg/${obj_id}`; + } else if (obj_type == 'sponsorship') { + endpoint = `/crud/sponsorship/${obj_id}`; + // } else if (obj_type == 'user') { + // endpoint = `/crud/user/${obj_id}`; + } else { + console.log(`Unknown object type: ${obj_type}`); + return false; + } + if (log_lvl) { + console.log('Endpoint:', endpoint); + } + + if (method) { // NOTE: method options: 'delete', 'disable', 'hide' + params['method'] = method; + } + + if (log_lvl) { + console.log('Params:', params); + } + + let object_obj_delete_promise = await delete_object({api_cfg: api_cfg, endpoint: endpoint, params: params, data: data, log_lvl: log_lvl}); + + if (log_lvl > 1) { + console.log(object_obj_delete_promise); + } + + return object_obj_delete_promise; +} + + +/* BEGIN: Hosted File Related */ + +// Updated 2023-08-17 +export let download_hosted_file = async function download_hosted_file({ + api_cfg, + hosted_file_id, + return_file=true, + filename=null, + auto_download=false, + params={}, + log_lvl=0 + }) { + console.log('*** stores_hosted_api.js: download_hosted_file() ***'); + + const endpoint = `/hosted_file/${hosted_file_id}/download`; + if (filename) { + params['filename'] = filename; + } + params['return_file'] = true; + + let hosted_file_download_get_promise = await api.get_object({api_cfg: api_cfg, endpoint: endpoint, params: params, return_blob: true, filename: filename, auto_download: auto_download, log_lvl: log_lvl}); + // console.log(hosted_file_download_get_promise); + return hosted_file_download_get_promise; +} + +// Updated 2023-12-15 +export let delete_hosted_file = async function delete_hosted_file({api_cfg, hosted_file_id, link_to_type=null, link_to_id=null, rm_orphan=false, params={}, data={}, log_lvl=1}) { + console.log('*** stores_hosted_api.js: delete_hosted_file() ***'); + + const endpoint = `/hosted_file/${hosted_file_id}`; + if (link_to_type) { + params['link_to_type'] = link_to_type; + } + if (link_to_id) { + params['link_to_id'] = link_to_id; + } + if (rm_orphan) { + params['rm_orphan'] = rm_orphan; + } + + let hosted_file_obj_delete_promise = await api.delete_object({api_cfg: api_cfg, endpoint: endpoint, params: params, data: data, log_lvl: log_lvl}); + // console.log(hosted_file_obj_delete_promise); + return hosted_file_obj_delete_promise; +} +/* END: Hosted File Related */ + + +/* BEGIN: Data Store Related */ + +// Updated 2023-06-29 +export let get_data_store_obj_w_code = async function get_data_store_obj_w_code({ + api_cfg, + data_store_code, + data_type='text', + headers={}, + params={}, + timeout=25000, + log_lvl=0 + }) { + if (log_lvl) { + console.log('*** get_data_store_obj_w_code() ***'); + } + + // let get_item_result = window.localStorage.getItem(code); + + const endpoint = `/data_store/code/${data_store_code}`; + let data_store_obj_get_promise = await api.get_object({api_cfg: api_cfg, endpoint: endpoint, headers: headers, params: params, timeout: timeout, log_lvl: log_lvl}); + + if (data_store_obj_get_promise === false) { + console.log('Data Store - RUN AGAIN WITH BACKUP'); + let original_api_base_url = api_cfg['base_url']; + + let temp_api = api_cfg; + temp_api['base_url'] = temp_api['base_url_bak'] + + data_store_obj_get_promise = await api.get_object({api_cfg: temp_api, endpoint: endpoint, headers: headers, params: params, timeout: timeout, log_lvl: log_lvl}); + temp_api['base_url'] = original_api_base_url; + } + + let data_store_obj = data_store_obj_get_promise; + + if (data_type == 'text') { + // console.log(data_store_obj.text); + // window.localStorage.setItem(data_store_code, data_store_obj.text); + // localStorage.setItem(data_store_code, data_store_obj.text); + } else if (data_type == 'json') { + // console.log(data_store_obj.json); + // window.localStorage.setItem(data_store_code, JSON.stringify(data_store_obj.json)); + // localStorage.setItem(data_store_code, JSON.stringify(data_store_obj.json)); + } + + if (log_lvl > 1) { + console.log('Response Data:', data_store_obj); + } + return data_store_obj; +} +/* END: Data Store Related */ + + +/* BEGIN: Utility: Email Related */ + +// Updated 2023-06-29 +export let send_email = async function send_email({api_cfg, from_email, from_name='', to_email, to_name='', cc_email=null, cc_name=null, bcc_email=null, bcc_name=null, subject, body_html, body_text=null, headers={}, params={}, data={}, return_obj=false, return_meta=false, log_lvl=0}) { + console.log('*** send_email() ***'); + + let endpoint = `/util/email/send`; + + data['from_email'] = from_email; // Required + data['from_name'] = from_name; + + data['to_email'] = to_email; // Required + data['to_name'] = to_name; + + data['cc_email'] = cc_email; + data['cc_name'] = cc_name; + + data['bcc_email'] = bcc_email; + data['bcc_name'] = bcc_name; + + data['subject'] = subject; + if (log_lvl) { + console.log('Data:', data); + } + + data['body_html'] = body_html; + + data['body_text'] = body_text; + + if (return_obj) { + params['return_obj'] = true; + } + + let send_email_post_promise = await api.post_object({api_cfg: api_cfg, endpoint: endpoint, headers: headers, params: params, data: data, return_meta: return_meta, log_lvl: log_lvl}); + + if (log_lvl > 1) { + console.log('Response Data:', send_email_post_promise); + } + if (return_obj) { + return send_email_post_promise; + } else { + return send_email_post_promise.event_abstract_id_random; + } +} + +/* END: Utility: Email Related */ + +function resolved(result) { + console.log('Resolved'); +} + +function rejected(result) { + console.error(result); +} + +const parse_params = (params) => { + const keys = Object.keys(params); + let options = ''; + + keys.forEach((key) => { + const isParamTypeObject = typeof params[key] === 'object'; + const isParamTypeArray = isParamTypeObject && (params[key].length >= 0); + + if (!isParamTypeObject) { + let encoded_value = encodeURIComponent(params[key]); + options += `${key}=${encoded_value}&`; + // options += `${key}=${params[key]}&`; + } + + if (isParamTypeObject && isParamTypeArray) { + params[key].forEach((element) => { + let encoded_value = encodeURIComponent(element); + options += `${key}=${encoded_value}&`; + // options += `${key}=${element}&`; + }); + } + }); + + return options ? options.slice(0, -1) : options; +}; + + +// export let test = async function test() { +// console.log('Exported test function from API.'); +// } + +let obj = {}; +obj.delete_object = delete_object; +obj.get_object = get_object; +obj.patch_object = patch_object; +obj.post_object = post_object; +obj.get_ae_obj_id_crud = get_ae_obj_id_crud; +obj.get_ae_obj_li_for_obj_id_crud = get_ae_obj_li_for_obj_id_crud; +obj.create_ae_obj_crud = create_ae_obj_crud; +obj.update_ae_obj_id_crud = update_ae_obj_id_crud; +obj.delete_ae_obj_id_crud = delete_ae_obj_id_crud; +obj.download_hosted_file = download_hosted_file; +obj.delete_hosted_file = delete_hosted_file; +obj.get_data_store_obj_w_code = get_data_store_obj_w_code; +obj.send_email = send_email; +// obj.test = test; +export let api = obj; +// module.exports = api; \ No newline at end of file diff --git a/src/lib/api.js b/src/lib/api_2024-05-23.js similarity index 94% rename from src/lib/api.js rename to src/lib/api_2024-05-23.js index 68f13be2..64c3ee17 100644 --- a/src/lib/api.js +++ b/src/lib/api_2024-05-23.js @@ -61,7 +61,7 @@ export let get_object_percent_completed = temp_get_object_percent_completed; // Updated 2022-10-28 export let get_object = async function get_object( { - api_cfg, + api_cfg=null, endpoint='', headers={}, params={}, @@ -72,6 +72,8 @@ export let get_object = async function get_object( filename=null, auto_download=false, as_list=false, + // The task_id value should be a random string that is unique to the task. This is used to identify the task in the message event. + task_id='get_object_x', log_lvl=0 // } : { // api_cfg: any, @@ -89,7 +91,7 @@ export let get_object = async function get_object( } ) { if (log_lvl) { - console.log(`*** get_object() *** Endpoint: ${endpoint}`); + console.log(`*** get_object() *** Endpoint: ${endpoint} Task ID: ${task_id}`); console.log('Params:', params); if (log_lvl > 1) { console.log('Data:', data); @@ -101,7 +103,6 @@ export let get_object = async function get_object( console.log(`Return Blob: ${return_blob}`); console.log(`Filename: ${filename}`); console.log(`Auto Download: ${auto_download}`); - console.log(`As List: ${as_list}`); } } @@ -306,14 +307,19 @@ export let get_object = async function get_object( let percent_completed = Math.round( (progressEvent.loaded * 100) / progressEvent.total ); - console.log('GET Blob Timestamp:', progressEvent.timeStamp, 'Total:', progressEvent.total, 'Loaded:', progressEvent.loaded, 'Percent Completed', percent_completed); + console.log('GET Blob Progress:', progressEvent.progress, 'Total:', progressEvent.total, 'Loaded:', progressEvent.loaded, 'Percent Completed', percent_completed); temp_get_blob_percent_completed = percent_completed; // WARNING: This needs to be tied to an object type and ID. This is a temporary solution. try { window.postMessage({ - type: 'api_download_blob', endpoint: endpoint, filename: filename, size_total: progressEvent.total, size_loaded: progressEvent.loaded, percent_completed: percent_completed + type: 'api_download_blob', + endpoint: endpoint, + filename: filename, + size_total: progressEvent.total, + size_loaded: progressEvent.loaded, + percent_completed: percent_completed }, '*' ); @@ -426,17 +432,37 @@ export let patch_object = async function patch_object({api_cfg=null, endpoint='' } +export let temp_post_blob_percent_completed = 0; +export let post_blob_percent_completed = temp_post_blob_percent_completed; +export let temp_post_object_percent_completed = 0; +export let post_object_percent_completed = temp_post_object_percent_completed; + // Updated 2023-11-10 -export let post_object = async function post_object({api_cfg=null, endpoint='', params={}, data={}, form_data=null, return_meta=false, return_blob=false, filename=null, auto_download=false, log_lvl=0}) { - console.log('*** post_object() ***'); +export let post_object = async function post_object( + { + api_cfg=null, + endpoint='', + params={}, + data={}, + form_data=null, + return_meta=false, + return_blob=false, + filename='', + auto_download=false, + // The task_id value should be a random string that is unique to the task. This is used to identify the task in the message event. + task_id='post_object_x', + log_lvl=0 + } + ) { if (log_lvl) { - // console.log(api_cfg); - console.log('Endpoint:', endpoint); + console.log(`*** post_object() *** Endpoint: ${endpoint} Task ID: ${task_id}`); console.log('Params:', params); if (log_lvl > 1) { console.log('Data:', data); console.log(typeof data); + console.log(`Base URL: ${api_cfg['base_url']}`); + console.log('API Config:', api_cfg); } if (log_lvl > 2) { console.log(`Return Meta: ${return_meta}`); @@ -445,7 +471,6 @@ export let post_object = async function post_object({api_cfg=null, endpoint='', console.log(`Auto Download: ${auto_download}`); } // console.log(return_meta); - // console.log(as_list); } let axios_api = axios.create({ @@ -466,7 +491,37 @@ export let post_object = async function post_object({api_cfg=null, endpoint='', if (!return_blob) { - let response_data = await axios_api.post(endpoint, data, { params: params }) + let response_data = await axios_api.post( + endpoint, + data, + { + params: params, + onUploadProgress: (progressEvent) => { + let percent_completed = Math.round( + (progressEvent.loaded * 100) / progressEvent.total + ); + console.log('POST Progress:', progressEvent.progress, 'Total:', progressEvent.total, 'Loaded:', progressEvent.loaded, 'Percent Completed', percent_completed); + + temp_post_object_percent_completed = percent_completed; + + try { + window.postMessage({ + type: 'api_post_json_form', + endpoint: endpoint, + size_total: progressEvent.total, + size_loaded: progressEvent.loaded, + percent_completed: percent_completed, + progress: progressEvent.progress, + rate: progressEvent.rate, + }, + '*' + ); + } catch (error) { + console.log('Error posting message to window:', error); + } + } + } + ) .then(function (response) { console.log('POST Response Data:', response.data); if (response.data['data'].result === null) { diff --git a/src/lib/api_delete_object.ts b/src/lib/api_delete_object.ts new file mode 100644 index 00000000..7cbcff3a --- /dev/null +++ b/src/lib/api_delete_object.ts @@ -0,0 +1,63 @@ +import axios from 'axios'; + +// Updated 2024-05-23 +export let delete_object = async function delete_object( + { + api_cfg=null, + endpoint='', + params={}, + data={}, + return_meta=false, + log_lvl=0 + }: { + api_cfg: any, + endpoint: string, + params?: any, + data?: any, + return_meta?: boolean, + log_lvl?: number + } + ) { +console.log('*** delete_object() ***'); + +if (log_lvl) { + // console.log(api_cfg); + console.log(endpoint); + console.log(params); + if (log_lvl > 1) { + console.log('Data:', data); + console.log(typeof data); + } + // console.log(return_meta); + // console.log(as_list); +} + +// https://stackoverflow.com/questions/51069552/axios-delete-request-with-body-and-headers + +let axios_api = axios.create({ + baseURL: api_cfg['base_url'], + // timeout: 2000, + /* other custom settings */ +}); +axios_api.defaults.headers = api_cfg['headers']; + +//OLD: axios_api.delete(endpoint, { 'data': data }) +let response_data = await axios_api.delete(endpoint, { params: params, 'data': data }) +.then(function (response) { + console.log(response.data); + return response.data; +}) +.catch(function (error) { + if (error.response && error.response.status === 404) { + return null; // Returning null since there were no results + } + console.log(error); + return false; // Returning false since something may have gone wrong. Also more in line with what the API returns. + // return error; +}); + +if (log_lvl > 1) { + console.log(response_data); +} +return response_data; +} diff --git a/src/lib/api_get_object.ts b/src/lib/api_get_object.ts new file mode 100644 index 00000000..4754fcb9 --- /dev/null +++ b/src/lib/api_get_object.ts @@ -0,0 +1,342 @@ +import axios from 'axios'; + +export let temp_get_blob_percent_completed = 0; +// export let get_blob_percent_completed = readable(temp_get_blob_percent_completed); +export let get_blob_percent_completed = temp_get_blob_percent_completed; + +export let temp_get_object_percent_completed = 0; +// export let get_object_percent_completed = readable(temp_get_object_percent_completed); +export let get_object_percent_completed = temp_get_object_percent_completed; + +// Updated 2024-05-23 +export let get_object = async function get_object( + { + api_cfg=null, + endpoint='', + headers={}, + params={}, + data={}, + timeout=60000, + return_meta=false, + return_blob=false, + filename='', + auto_download=false, + as_list=false, + // The task_id value should be a random string that is unique to the task. This is used to identify the task in the message event. + task_id='get_object_x', + log_lvl=0 + } : { + api_cfg: any, + endpoint: string, + headers?: any, + params?: any, + data?: any, + timeout?: number, + return_meta?: boolean, + return_blob?: boolean, + filename?: string, + auto_download?: boolean, + as_list?: boolean, + task_id?: string, + log_lvl?: number + } + ) { + if (log_lvl) { + console.log(`*** get_object() *** Endpoint: ${endpoint} Task ID: ${task_id}`); + console.log('Params:', params); + if (log_lvl > 1) { + console.log('Data:', data); + console.log(`Base URL: ${api_cfg['base_url']}`); + console.log('API Config:', api_cfg); + } + if (log_lvl > 2) { + console.log(`Return Meta: ${return_meta}`); + console.log(`Return Blob: ${return_blob}`); + console.log(`Filename: ${filename}`); + console.log(`Auto Download: ${auto_download}`); + } + } + + if (!api_cfg) { + console.log('No API Config was provided. Returning false.'); + return false; + } + + let axios_api = axios.create({ + baseURL: api_cfg['base_url'], + timeout: timeout, // in milliseconds; 60000 = 60 seconds + /* other custom settings */ + }); + axios_api.defaults.headers = api_cfg['headers']; + if (log_lvl) { + console.log('axios_api.defaults.headers:', axios_api.defaults.headers); + console.log('Additional headers:', headers); + } + + // console.log('Clean the headers. No _underscores_!') + let headers_cleaned = {}; + for (const prop in headers) { + // No underscores allowed in the header parameters! + let prop_cleaned = prop.replaceAll('_', '-'); + + // The value must be a string for the header! + if (typeof headers[prop] != 'string') { + headers[prop] = JSON.stringify(headers[prop]); + } + + headers_cleaned[prop_cleaned] = headers[prop]; + + if (log_lvl) { + console.log(`${prop_cleaned}: ${headers_cleaned[prop_cleaned]}`); + } + } + headers = headers_cleaned; + if (log_lvl) { + console.log('All headers cleaned:', headers); + } + + if (log_lvl) { + console.log('URL params:'); + } + for (const prop in params) { + if (log_lvl) { + console.log(`URL param: ${prop}: ${params[prop]}`); + } + if (params[prop] === null ) { + params[prop] = 'null'; + } + } + + if (!return_blob) { + // let response_data_promise = await axios_api.get( + // endpoint, + // { + // params: params, + // 'paramsSerializer': params => parse_params(params), + // onDownloadProgress: (progressEvent) => { + // let percent_completed = Math.round( + // (progressEvent.loaded * 100) / progressEvent.total + // ); + // console.log('GET Data Timestamp:', progressEvent.timeStamp, 'Total:', progressEvent.total, 'Loaded:', progressEvent.loaded, 'Percent Completed', percent_completed); + + // temp_get_object_percent_completed = percent_completed; + // } + // } + // ) + let response_data_promise = await axios_api.get( + endpoint, + { + headers: headers, + params: params, + onDownloadProgress: (progressEvent) => { + let percent_completed = Math.round( + (progressEvent.loaded * 100) / progressEvent.total + ); + // console.log('GET Data Timestamp:', progressEvent.timeStamp, 'Total:', progressEvent.total, 'Loaded:', progressEvent.loaded, 'Percent Completed', percent_completed); + + temp_get_object_percent_completed = percent_completed; + } + } + ) + .then(function (response) { + if (log_lvl) { + console.log(`GET Response: status=${response.status} statusText=${response.statusText} baseURL=${response.config.baseURL} url=${response.config.url} method=${response.config.method} headers=${response.config.headers} params=${JSON.stringify(response.config.params)}`); + } + if (log_lvl > 1) { + console.log('GET Response:', response); + } + if (!Array.isArray(response.data['data']) && as_list) { + if (log_lvl) { + console.log('Data result is a dictionary/object, not an array/list. Forcing return as an array/list'); + } + let return_data = []; + return_data.push(response.data['data']); + return return_data; + } else if (response.data['data']) { + let return_data = response.data['data']; + if (log_lvl) { + if (Array.isArray(return_data)) { + console.log(`Data result is an array/list. Array length: ${return_data.length}`); + } else { + console.log(`Data result is a dictionary/object, not an array/list.`); + } + } + return return_data; + } else { + let return_data = response.data; + if (log_lvl) { + if (Array.isArray(return_data)) { + console.log(`Not a standard response from Aether's API. Data result is an array/list. Array length: ${return_data.length}`); + } else { + console.log(`Not a standard response from Aether's API. Data result is a dictionary/object, not an array/list.`); + } + } + return return_data; + } + }) + .catch(function (error) { + if (log_lvl) { + console.log(`Base URL: ${api_cfg['base_url']} | Endpoint: ${endpoint}`); + console.log('Error Message:', error.message); // Is this needed here or below in the in the else portion??? + + if (error.response) { + // The request was made and the server responded with a status code that falls out of the range of 2xx + console.log('Error Response Data', error.response.data); + console.log('Error Response Status', error.response.status); + console.log('Error Response Headers', error.response.headers); + } else if (error.request) { + // The request was made but no response was received `error.request` is an instance of XMLHttpRequest in the browser and an instance of http.ClientRequest in node.js + if (log_lvl > 1) { + console.log('Error Request', error.request); + } + } else { + // Something happened in setting up the request that triggered an Error + console.log('Error Message', error.message); + } + } + if (log_lvl > 2) { + console.log('Error:', error); + console.log(error.config); + } + + if (error.response && error.response.status === 404) { + if (log_lvl) { + console.log('The response was a 404 not found "error". Returning null.'); + } + if (log_lvl > 1) { + console.log(error.response); + } + if (log_lvl > 2) { + console.log(error); + } + return null; // Returning null since there were no results + } + if (error.code === 'ECONNABORTED') { + // Timeout Error (You can implement retry here where suitable) + console.log('Timeout Error: ', error.message); + } + if (log_lvl) { + console.log('The response was an error. Returning false.'); + } + + return false; // Returning false since something may have gone wrong. This includes timeouts. Also more in line with what the API returns. + // return error; + }); + + if (log_lvl > 1) { + // console.log(`Response Data: ${response_data_promise}`); + console.log(`Response Data:`, response_data_promise); + // console.log(response_data_promise); + } + if (response_data_promise) { + // The most common and expected response. + // console.log('Returning result. This is generally expected.'); + return response_data_promise; + } else if (response_data_promise === null) { + // Less common, but expected response if no results were returned. + console.log('Returning null. This is expected if no results were found.'); + return response_data_promise; + } else if (response_data_promise === false) { + // Not common, but expected response if the request to the API had an issue. + console.log('Returning false. There may have been an issue with this request.'); + return response_data_promise; + } else { + // This generally should not happen. It likely means the query was bad or an API issue. + console.log('Returning unknown. This should not happen in most cases.'); + Promise.reject(new Error('fail')).then(resolved, rejected); + } + } else { + // console.log('Expecting a Blob to be returned...'); + + let response_data_promise = await axios_api.get( + endpoint, + { + params: params, + // 'paramsSerializer': params => parse_params(params), + responseType: 'blob', + onDownloadProgress: (progressEvent) => { + let percent_completed = Math.round( + (progressEvent.loaded * 100) / progressEvent.total + ); + console.log('GET Blob Progress:', progressEvent.progress, 'Total:', progressEvent.total, 'Loaded:', progressEvent.loaded, 'Percent Completed', percent_completed); + + temp_get_blob_percent_completed = percent_completed; + + // WARNING: This needs to be tied to an object type and ID. This is a temporary solution. + try { + window.postMessage({ + type: 'api_download_blob', + endpoint: endpoint, + filename: filename, + size_total: progressEvent.total, + size_loaded: progressEvent.loaded, + percent_completed: percent_completed + }, + '*' + ); + } catch (error) { + console.log('Error posting message to window:', error); + } + } + } + ) + .then(function (response) { + if (log_lvl) { + console.log(`GET (blob) Response: status=${response.status} statusText=${response.statusText} baseURL=${response.config.baseURL} url=${response.config.url} method=${response.config.method} headers=${response.config.headers} params=${response.config.params}`); + } + if (log_lvl > 1) { + console.log('GET (blob) Response:', response); + } + + const { data, headers } = response; + + // Careful if this download filename needs to be changed to a different file extension. The browser/client may not know how to handle it. + if (filename) { + } else if (headers['content-disposition']) { + filename = headers['content-disposition'].replace(/\w+;filename=(.*)/, '$1'); + } else { + filename = 'unknown_file.ext'; + } + + // WARNING: This needs to be tied to an object type and ID. This is a temporary solution. + try { + window.postMessage({ + type: 'api_download_blob', endpoint: endpoint, filename: filename, size_total: 0, size_loaded: 0, percent_completed: 100 + }, + '*' + ); + } catch (error) { + console.log('Error posting message to window:', error); + } + + if (auto_download) { + if (log_lvl) { + console.log(`Auto Download: ${filename}`); + } + const url = window.URL.createObjectURL(new Blob([response.data])); + const link = document.createElement('a'); + link.href = url; + link.setAttribute('download', filename); + document.body.appendChild(link); + link.click(); + return true; + } else { + return response; + } + }); + + if (response_data_promise) { + // The most common and expected response. + // console.log('Returning result. This is generally expected.'); + // let test_blob = new Blob([response_data_promise.data]); + // console.log(test_blob); + // return test_blob; + // console.log(response_data_promise.blob()); + return response_data_promise; + } else { + // This generally should not happen. It likely means the query was bad or an API issue. + console.log('Returning (blob) unknown. This should not happen in most cases.'); + Promise.reject(new Error('fail')).then(resolved, rejected); + } + } +} diff --git a/src/lib/api_patch_object.ts b/src/lib/api_patch_object.ts new file mode 100644 index 00000000..dabd27a4 --- /dev/null +++ b/src/lib/api_patch_object.ts @@ -0,0 +1,60 @@ +import axios from 'axios'; + +// Updated 2024-05-23 +export let patch_object = async function patch_object( + { + api_cfg=null, + endpoint='', + params={}, + data={}, + return_meta=false, + log_lvl=0 + } : { + api_cfg: any, + endpoint: string, + params?: any, + data?: any, + return_meta?: boolean, + log_lvl?: number + } +) { +console.log('*** patch_object() ***'); + +if (log_lvl) { + // console.log(api_cfg); + console.log(endpoint); + console.log(params); + if (log_lvl > 1) { + console.log(data); + } + // console.log(return_meta); + // console.log(as_list); +} + +let axios_api = axios.create({ + baseURL: api_cfg['base_url'], + /* other custom settings */ +}); +axios_api.defaults.headers = api_cfg['headers']; + +let response_data = await axios_api.patch(endpoint, data, { params: params }) +.then(function (response) { + console.log(response.data); + return response.data['data']; + //return response.data; +}) +.catch(function (error) { + if (error.response && error.response.status === 404) { + return null; // Returning null since there were no results + } + console.log(error); + return false; // Returning false since something may have gone wrong. Also more in line with what the API returns. + // return error; +}); + +if (log_lvl > 1) { + console.log(response_data); +} +return response_data; +} + diff --git a/src/lib/api_post_object.ts b/src/lib/api_post_object.ts new file mode 100644 index 00000000..fb201f19 --- /dev/null +++ b/src/lib/api_post_object.ts @@ -0,0 +1,195 @@ +import axios from 'axios'; + +export let temp_post_blob_percent_completed = 0; +export let post_blob_percent_completed = temp_post_blob_percent_completed; +export let temp_post_object_percent_completed = 0; +export let post_object_percent_completed = temp_post_object_percent_completed; + +// Updated 2024-05-23 +export let post_object = async function post_object( + { + api_cfg=null, + endpoint='', + params={}, + data={}, + form_data=null, + return_meta=false, + return_blob=false, + filename='', + auto_download=false, + // The task_id value should be a random string that is unique to the task. This is used to identify the task in the message event. + task_id='post_object_x', + log_lvl=0 + } : { + api_cfg: any, + endpoint: string, + params?: any, + data?: any, + form_data?: any, + return_meta?: boolean, + return_blob?: boolean, + filename?: string, + auto_download?: boolean, + task_id?: string, + log_lvl?: number + } + ) { + + if (log_lvl) { + console.log(`*** post_object() *** Endpoint: ${endpoint} Task ID: ${task_id}`); + console.log('Params:', params); + if (log_lvl > 1) { + console.log('Data:', data); + console.log(typeof data); + console.log(`Base URL: ${api_cfg['base_url']}`); + console.log('API Config:', api_cfg); + } + if (log_lvl > 2) { + console.log(`Return Meta: ${return_meta}`); + console.log(`Return Blob: ${return_blob}`); + console.log(`Filename: ${filename}`); + console.log(`Auto Download: ${auto_download}`); + } + // console.log(return_meta); + } + + let axios_api = axios.create({ + baseURL: api_cfg['base_url'], + /* other custom settings */ + }); + axios_api.defaults.headers = api_cfg['headers']; + console.log('Axios API', axios_api); + // console.log('Axios API POST', axios_api.post); + + // if (typeof data == 'FormData') { + if (form_data) { + axios_api.defaults.headers['content-type'] = 'multipart/form-data'; + data = form_data; + } else { + axios_api.defaults.headers['content-type'] = 'application/json'; + } + + + if (!return_blob) { + let response_data = await axios_api.post( + endpoint, + data, + { + params: params, + onUploadProgress: (progressEvent) => { + let percent_completed = Math.round( + (progressEvent.loaded * 100) / progressEvent.total + ); + console.log('POST Progress:', progressEvent.progress, 'Total:', progressEvent.total, 'Loaded:', progressEvent.loaded, 'Percent Completed', percent_completed); + + temp_post_object_percent_completed = percent_completed; + + try { + window.postMessage({ + type: 'api_post_json_form', + endpoint: endpoint, + size_total: progressEvent.total, + size_loaded: progressEvent.loaded, + percent_completed: percent_completed, + progress: progressEvent.progress, + rate: progressEvent.rate, + }, + '*' + ); + } catch (error) { + console.log('Error posting message to window:', error); + } + } + } + ) + .then(function (response) { + console.log('POST Response Data:', response.data); + if (response.data['data'].result === null) { + // This should mean that the request was successful, but a result of None/null was returned from Aether API. + // console.log('Returning null after POST'); + return null; + } else { + // This should mean that the request was successful, and a result with data was returned from Aether API. + // console.log('Returning data after POST'); + return response.data['data']; + } + //return response.data; + }) + .catch(function (error) { + if (error.response && error.response.status === 404) { + return null; // Returning null since there were no results + } + console.log(error); + return false; // Returning false since something may have gone wrong. Also more in line with what the API returns. + // return error; + }); + + if (log_lvl > 1) { + console.log('Response Data:', response_data); + } + axios_api.defaults.headers['content-type'] = 'application/json'; + return response_data; + + } else { + // console.log('Expecting a Blob to be returned...'); + + let response_data_promise = await axios_api.post( + endpoint, + data, + { + params: params, + responseType: 'blob', + onDownloadProgress: (progressEvent) => { + let percent_completed = Math.round( + (progressEvent.loaded * 100) / progressEvent.total + ); + console.log('POST Blob Progress:', progressEvent.progress, 'Total:', progressEvent.total, 'Loaded:', progressEvent.loaded, 'Percent Completed', percent_completed); + + temp_get_blob_percent_completed = percent_completed; + } + } + ) + .then(function (response) { + if (log_lvl) { + console.log(response); + } + + const { data, headers } = response + console.log(headers); + + if (filename) { + } else if (headers['content-disposition']) { + filename = headers['content-disposition'].replace(/\w+;filename=(.*)/, '$1'); + } else { + filename = 'unknown_file.ext'; + } + + if (auto_download) { + const url = window.URL.createObjectURL(new Blob([response.data])); + const link = document.createElement('a'); + link.href = url; + // link.setAttribute('download', 'event_exhibit_tracking_export.xlsx'); //or any other extension + link.setAttribute('download', filename); //or any other extension + document.body.appendChild(link); + link.click(); + return true; + } else { + return response; + } + }); + + if (response_data_promise) { + // The most common and expected response. + // console.log('Returning result. This is generally expected.'); + // let test_blob = new Blob([response_data_promise.data]); + // console.log(test_blob); + // return test_blob; + // console.log(response_data_promise.blob()); + return response_data_promise; + } else { + // This generally should not happen. It likely means the query was bad or an API issue. + console.log('Returning unknown. This should not happen in most cases.'); + Promise.reject(new Error('fail')).then(resolved, rejected); + } + } +} diff --git a/src/lib/element_qr_scanner backup.svelte b/src/lib/element_qr_scanner backup.svelte index 25f8e88d..27c57b90 100644 --- a/src/lib/element_qr_scanner backup.svelte +++ b/src/lib/element_qr_scanner backup.svelte @@ -180,7 +180,7 @@ async function handle_start_qr_scanning() { return; } - + } @@ -213,7 +213,7 @@ async function handle_stop_qr_scanning() { console.log('html5_qr_code object found. Nothing to stop?'); return false; } - + let state = html5_qr_code.getState(); console.log('html5_qr_code state:', state); diff --git a/src/lib/element_qr_scanner backup_2.svelte b/src/lib/element_qr_scanner backup_2.svelte index fc89614c..482c5f74 100644 --- a/src/lib/element_qr_scanner backup_2.svelte +++ b/src/lib/element_qr_scanner backup_2.svelte @@ -76,24 +76,24 @@ onMount(() => { // navigator.mediaDevices.getUserMedia(constraints) // .then(get_user_media_success, get_user_media_error) // .catch(function(err) { - // //log to console first + // //log to console first // console.log(err); /* handle the error */ // if (err.name == "NotFoundError" || err.name == "DevicesNotFoundError") { - // //required track is missing + // //required track is missing // } else if (err.name == "NotReadableError" || err.name == "TrackStartError") { - // //webcam or mic are already in use + // //webcam or mic are already in use // } else if (err.name == "OverconstrainedError" || err.name == "ConstraintNotSatisfiedError") { - // //constraints can not be satisfied by avb. devices + // //constraints can not be satisfied by avb. devices // } else if (err.name == "NotAllowedError" || err.name == "PermissionDeniedError") { - // //permission denied in browser + // //permission denied in browser // } else if (err.name == "TypeError" || err.name == "TypeError") { - // //empty constraints object + // //empty constraints object // } else { - // //other errors + // //other errors // } // }); - + // navigator.mediaDevices.getUserMedia({video: true}) @@ -107,7 +107,7 @@ onMount(() => { // navigator.mediaDevices.getUserMedia({video: true}) // .then(get_user_media_success, get_user_media_error); - + // }, 750); // console.log('** Element Mounted: ** QR Scanner - setTimeout end 750ms'); @@ -116,7 +116,7 @@ onMount(() => { // handle_start_qr_scanning(); // } - + }); @@ -144,13 +144,13 @@ var get_user_media_success = function(error: any) { // // document.getElementById('qr_scanner_viewfinder').classList.remove('d_none'); // } else { // console.log('html5_qr_code not found. Creating new Html5Qrcode...'); - // debug_info = 'html5_qr_code not found. Creating new Html5Qrcode...'; + // debug_info = 'html5_qr_code not found. Creating new Html5Qrcode...'; // } html5_qr_code = new Html5Qrcode( 'qr_scanner_viewfinder', { formatsToSupport: [ Html5QrcodeSupportedFormats.QR_CODE ] } ); - + debug_comment = 'Html5Qrcode created'; debug_info = 'new Html5Qrcode for element id=qr_scanner_viewfinder QR_CODE'; @@ -164,7 +164,7 @@ var get_user_media_success = function(error: any) { }, 2500); // console.log('** Element Mounted: ** QR Scanner - setTimeout end'); - + } // let subject = 'Camera Access Allowed'; @@ -257,14 +257,14 @@ async function handle_start_qr_scanning() { // ); // } else { // console.log('html5_qr_code not found. Creating new Html5Qrcode...'); - // debug_info = 'html5_qr_code not found. Creating new Html5Qrcode...'; + // debug_info = 'html5_qr_code not found. Creating new Html5Qrcode...'; // html5_qr_code = new Html5Qrcode( // 'qr_scanner_viewfinder', { formatsToSupport: [ Html5QrcodeSupportedFormats.QR_CODE ] } // ); // } - debug_info = 'Check the state and start if not started...'; + debug_info = 'Check the state and start if not started...'; let current_state = await html5_qr_code.getState() @@ -312,7 +312,7 @@ async function handle_start_qr_scanning() { return; } - + } @@ -345,7 +345,7 @@ async function handle_stop_qr_scanning() { console.log('html5_qr_code object found. Nothing to stop?'); return false; } - + let state = html5_qr_code.getState(); console.log('html5_qr_code state:', state); diff --git a/src/lib/element_qr_scanner.svelte b/src/lib/element_qr_scanner.svelte index 99882d66..350ae1aa 100644 --- a/src/lib/element_qr_scanner.svelte +++ b/src/lib/element_qr_scanner.svelte @@ -79,7 +79,7 @@ onMount(() => { // handle_start_qr_scanning(); // } - + }); @@ -107,13 +107,13 @@ var successCallback = function(error: any) { // document.getElementById('qr_scanner_viewfinder').classList.remove('d_none'); } else { console.log('html5_qr_code not found. Creating new Html5Qrcode...'); - debug_info = 'html5_qr_code not found. Creating new Html5Qrcode...'; + debug_info = 'html5_qr_code not found. Creating new Html5Qrcode...'; } html5_qr_code = new Html5Qrcode( 'qr_scanner_viewfinder', { formatsToSupport: [ Html5QrcodeSupportedFormats.QR_CODE ] } ); - + debug_info = 'new Html5Qrcode for element id=qr_scanner_viewfinder'; @@ -213,14 +213,14 @@ async function handle_start_qr_scanning() { // ); // } else { // console.log('html5_qr_code not found. Creating new Html5Qrcode...'); - // debug_info = 'html5_qr_code not found. Creating new Html5Qrcode...'; + // debug_info = 'html5_qr_code not found. Creating new Html5Qrcode...'; // html5_qr_code = new Html5Qrcode( // 'qr_scanner_viewfinder', { formatsToSupport: [ Html5QrcodeSupportedFormats.QR_CODE ] } // ); // } - debug_info = 'Check the state and start if not started...'; + debug_info = 'Check the state and start if not started...'; let current_state = await html5_qr_code.getState() @@ -262,7 +262,7 @@ async function handle_start_qr_scanning() { return; } - + } @@ -295,7 +295,7 @@ async function handle_stop_qr_scanning() { console.log('html5_qr_code object found. Nothing to stop?'); return false; } - + let state = html5_qr_code.getState(); console.log('html5_qr_code state:', state); @@ -542,7 +542,7 @@ function send_init_confirm_email(subject, message) { {:else} - - + - - + {#if (scanning_status == 'scanning')} - {/if} - + - + diff --git a/src/routes/events_badges/stats/+page.svelte b/src/routes/events_badges/stats/+page.svelte index 49c232a5..ef1a1653 100644 --- a/src/routes/events_badges/stats/+page.svelte +++ b/src/routes/events_badges/stats/+page.svelte @@ -160,7 +160,7 @@ $: if ($events_trigger == 'load__event_badge_obj_li' && $events_slct.event_id) { } else { let type_code = $events_sess.badges.search_badge_type_code; - + let search_str = $events_sess.badges.fulltext_search_qry_str.trim(); let search_method = 'lk'; // 'ft', 'lk', 'eq' let ft_search_str_new = ''; @@ -205,9 +205,9 @@ $: if ($events_trigger == 'load__event_badge_obj_li' && $events_slct.event_id) { $events_sess.status_qry__search = 'loading'; search_submit_results = events_func.handle_search__event_badge({ - api_cfg: $ae_api, - event_id: $events_slct.event_id, - type_code: type_code, + api_cfg: $ae_api, + event_id: $events_slct.event_id, + type_code: type_code, fulltext_search_qry_str: ft_search_str_new, like_search_qry_str: lk_search_str_new, external_event_id: $events_loc.badges.default__external_registration_id, @@ -226,10 +226,10 @@ $: if ($events_trigger == 'load__event_badge_obj_li' && $events_slct.event_id) { $events_sess.status_qry__search = 'loading'; search_submit_results = events_func.handle_search__event_badge({ - api_cfg: $ae_api, - event_id: $events_slct.event_id, - type_code: type_code, - fulltext_search_qry_str: ft_search_str_new, + api_cfg: $ae_api, + event_id: $events_slct.event_id, + type_code: type_code, + fulltext_search_qry_str: ft_search_str_new, like_search_qry_str: lk_search_str_new, external_event_id: $events_loc.badges.default__external_registration_id, params: params, @@ -491,7 +491,7 @@ function handle_qr_camera(event) { on:click={() => { localStorage.setItem('ae_badge_printed_redirect_path', '/events_badges/review'); // goto('/events_badges/print', {replaceState: true}); - + $events_sess.badges.show_form__search = false; $events_sess.badges.show_form__search_results = false; $events_sess.badges.show_form__scan = true; @@ -559,7 +559,7 @@ function handle_qr_camera(event) { {#each $events_slct.badge_obj_li as badge_obj} -= 1 || badge_obj.hide) && !$ae_loc.trusted_access} class:fade_50={(badge_obj.print_count >= 1 || badge_obj.hide) && $ae_loc.trusted_access} > @@ -584,7 +584,7 @@ function handle_qr_camera(event) { {:else} - {/if} + {/if} {#if badge_obj.print_count >= 1} @@ -643,7 +643,7 @@ function handle_qr_camera(event) {
{badge_obj.badge_type} - +
- + {#if $ae_loc.administrator_access} @@ -687,7 +687,7 @@ function handle_qr_camera(event) { {/if} - +
- +
diff --git a/src/routes/events_leads/+page.svelte b/src/routes/events_leads/+page.svelte index b485fbcc..95502d79 100644 --- a/src/routes/events_leads/+page.svelte +++ b/src/routes/events_leads/+page.svelte @@ -198,7 +198,7 @@ function handle_update_event_exhibit_staff_passcode(exhibit_id, reset_passcode)