From 8e157a4ed3704f7092c3c6109d87837b0e93a65c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20Ruz=CC=8Cevic=CC=81?= Date: Wed, 31 Aug 2022 10:28:32 +0200 Subject: [PATCH 01/12] adding greenhouse fix --- src/Blocks/components/form/assets/form.js | 4 +++ src/Blocks/components/form/assets/index.js | 1 + .../custom/forms/components/forms-options.js | 14 ++++---- src/Enqueue/Blocks/EnqueueBlocks.php | 1 + .../Greenhouse/GreenhouseClient.php | 32 ++++++++++++------- src/Integrations/Hubspot/Hubspot.php | 2 +- src/Labels/Labels.php | 2 +- src/Rest/Routes/AbstractBaseRoute.php | 10 +++++- src/Rest/Routes/AbstractFormSubmit.php | 6 ++++ src/Rest/Routes/CacheDeleteRoute.php | 8 ++--- src/Rest/Routes/FormSettingsSubmitRoute.php | 6 ++-- src/Rest/Routes/FormSubmitCustomRoute.php | 15 +++++++-- 12 files changed, 70 insertions(+), 31 deletions(-) diff --git a/src/Blocks/components/form/assets/form.js b/src/Blocks/components/form/assets/form.js index ff7f9be06..2d4be4bbc 100644 --- a/src/Blocks/components/form/assets/form.js +++ b/src/Blocks/components/form/assets/form.js @@ -79,6 +79,7 @@ export class Form { this.hideGlobalMessageTimeout = options.hideGlobalMessageTimeout ?? 6000; this.hideLoadingStateTimeout = options.hideLoadingStateTimeout ?? 600; this.fileCustomRemoveLabel = options.fileCustomRemoveLabel ?? ''; + this.formServerErrorMsg = options.formServerErrorMsg ?? ''; this.captcha = options.captcha ?? ''; this.storageConfig = options.storageConfig ?? ''; @@ -232,6 +233,9 @@ export class Form { this.hideGlobalMsg(element); }, parseInt(this.hideGlobalMessageTimeout, 10)); } + }) + .catch(function() { + this.setGlobalMsg(element, this.formServerErrorMsg, 'error'); }); }; diff --git a/src/Blocks/components/form/assets/index.js b/src/Blocks/components/form/assets/index.js index 1d287c71a..02c7f4d06 100644 --- a/src/Blocks/components/form/assets/index.js +++ b/src/Blocks/components/form/assets/index.js @@ -47,6 +47,7 @@ function initAll() { redirectionTimeout: form.redirectionTimeout, hideGlobalMessageTimeout: form.hideGlobalMessageTimeout, captchaSiteKey: esFormsLocalization.captcha, + formServerErrorMsg: esFormsLocalization.formServerErrorMsg, files: form.files, customSelects: form.customSelects, customFiles: form.customFiles, diff --git a/src/Blocks/custom/forms/components/forms-options.js b/src/Blocks/custom/forms/components/forms-options.js index 64646a229..28e501554 100644 --- a/src/Blocks/custom/forms/components/forms-options.js +++ b/src/Blocks/custom/forms/components/forms-options.js @@ -112,7 +112,7 @@ export const FormsOptions = ({ attributes, setAttributes, preview }) => { isLarge icon={icons.trash} onClick={removeItem} - label={__('Remove', 'eightshift-form')} + label={__('Remove', 'eightshift-forms')} style={{ marginTop: '0.2rem' }} /> @@ -210,7 +210,7 @@ export const FormsOptions = ({ attributes, setAttributes, preview }) => { setIsModalOpen(true); }} > - {__('Geolocation rules', 'eightshift-form')} + {__('Geolocation rules', 'eightshift-forms')} {geoRepeater?.length > 0 && @@ -229,7 +229,7 @@ export const FormsOptions = ({ attributes, setAttributes, preview }) => { {

{__('Geolocation rules allow you to display alternate forms based on the user\'s location.', 'eightshift-forms')}

{__('If no rules are added and the "Show form only if in countries" field is populated, the form will only be shown in these countries. Otherwise, the form is shown everywhere.', 'eightshift-forms')}

{geolocationApi && -

{__('You can find complete list of countries and regions on this', 'eightshift-forms')} {__('link', 'eightshift-form')}.

+

{__('You can find complete list of countries and regions on this', 'eightshift-forms')} {__('link', 'eightshift-forms')}.

}
@@ -248,7 +248,7 @@ export const FormsOptions = ({ attributes, setAttributes, preview }) => { icon={icons.add} onClick={addItem} > - {__('Add rule', 'eightshift-form')} + {__('Add rule', 'eightshift-forms')} {geoRepeater?.length > 0 && @@ -284,7 +284,7 @@ export const FormsOptions = ({ attributes, setAttributes, preview }) => { setAttributes({ formsFormGeolocationAlternatives: prevGeoRepeater }); setIsModalOpen(false); }}> - {__('Cancel', 'eightshift-form')} + {__('Cancel', 'eightshift-forms')} } diff --git a/src/Enqueue/Blocks/EnqueueBlocks.php b/src/Enqueue/Blocks/EnqueueBlocks.php index 4fbc046f7..65c3da82b 100644 --- a/src/Enqueue/Blocks/EnqueueBlocks.php +++ b/src/Enqueue/Blocks/EnqueueBlocks.php @@ -227,6 +227,7 @@ protected function getLocalizations(): array SettingsGeneral::SETTINGS_GENERAL_DISABLE_DEFAULT_ENQUEUE_KEY ), 'formResetOnSuccess' => !Variables::isDevelopMode(), + 'formServerErrorMsg' => esc_html__('An server error occurred while submitting your form. Please try again.', 'eightshift-forms'), 'captcha' => '', 'storageConfig' => '', ]; diff --git a/src/Integrations/Greenhouse/GreenhouseClient.php b/src/Integrations/Greenhouse/GreenhouseClient.php index 4f8bc1e24..d842fcb71 100644 --- a/src/Integrations/Greenhouse/GreenhouseClient.php +++ b/src/Integrations/Greenhouse/GreenhouseClient.php @@ -135,14 +135,21 @@ public function postApplication(string $itemId, array $params, array $files, str $this->prepareFiles($files) ); + error_log( print_r( ( $body ), true ) ); + error_log( print_r( ( $this->getHeaders(true) ), true ) ); + + + $response = \wp_remote_post( self::BASE_URL . "boards/{$this->getBoardToken()}/jobs/{$itemId}", [ 'headers' => $this->getHeaders(true), - 'body' => \wp_json_encode($body), + 'body' => $body, ] ); + error_log( print_r( ( $response ), true ) ); + if (\is_wp_error($response)) { Helper::logger([ 'integration' => 'greenhouse', @@ -289,18 +296,19 @@ private function getGreenhouseJob(string $jobId) /** * Set headers used for fetching data. * - * @param boolean $useAuth If using post method we need to send Authorization header in the request. + * @param boolean $postHeaders If using post method we need to send Authorization header and type in the request. * * @return array */ - private function getHeaders(bool $useAuth = false): array + private function getHeaders(bool $postHeaders = false): array { $headers = [ - 'Content-Type' => 'application/json; charset=utf-8', + 'Content-Type' => 'application/json', ]; - if ($useAuth) { + if ($postHeaders) { $headers['Authorization'] = "Basic {$this->getApiKey()}"; + $headers['Content-Type'] = 'multipart/form-data'; } return $headers; @@ -317,6 +325,10 @@ private function prepareParams(array $params): array { $output = []; + if (isset($params['es-form-storage'])) { + unset($params['es-form-storage']); + } + foreach ($params as $key => $value) { // Get gh_src from url and map it. if ($key === 'es-form-storage' && isset($value['value']['gh_src'])) { @@ -326,10 +338,6 @@ private function prepareParams(array $params): array } } - if (isset($params['es-form-storage'])) { - unset($params['es-form-storage']); - } - return $output; } @@ -353,13 +361,13 @@ private function prepareFiles(array $files): array $fileName = $file['fileName'] ?? ''; $path = $file['path'] ?? ''; $id = $file['id'] ?? ''; + $type = $file['type'] ?? ''; - if (!$path || !$fileName || !$id) { + if (!$path || !$fileName || !$id || !$type) { continue; } - $output["{$id}_content"] = \base64_encode((string) \file_get_contents($path)); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode, WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents - $output["{$id}_content_filename"] = $fileName; + $output[$id] = new \CURLFile(\realpath($path), $type, $fileName); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode, WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents } } diff --git a/src/Integrations/Hubspot/Hubspot.php b/src/Integrations/Hubspot/Hubspot.php index 9ff182528..bae2c1e04 100644 --- a/src/Integrations/Hubspot/Hubspot.php +++ b/src/Integrations/Hubspot/Hubspot.php @@ -162,7 +162,7 @@ private function getFields(array $data, string $formId, bool $ssr): array 'component' => 'rich-text', 'richTextId' => "rich-text-{$key}", 'richTextName' => "rich-text-{$key}", - 'richTextFieldLabel' => \__('Rich text', 'eightshift-form') . '-' . $key, + 'richTextFieldLabel' => \__('Rich text', 'eightshift-forms') . '-' . $key, 'richTextContent' => $richText, 'blockSsr' => $ssr, ]; diff --git a/src/Labels/Labels.php b/src/Labels/Labels.php index dce89cb78..ce998d45c 100644 --- a/src/Labels/Labels.php +++ b/src/Labels/Labels.php @@ -38,7 +38,7 @@ class Labels implements LabelsInterface 'hubspotSuccess', 'mailerliteSuccess', 'goodbitsSuccess', - 'clearbitSuccess', + 'customSuccess', ]; /** diff --git a/src/Rest/Routes/AbstractBaseRoute.php b/src/Rest/Routes/AbstractBaseRoute.php index 7b120ec8d..df3920ad6 100644 --- a/src/Rest/Routes/AbstractBaseRoute.php +++ b/src/Rest/Routes/AbstractBaseRoute.php @@ -217,7 +217,9 @@ protected function getFormType(array $params): string $formType = $params['es-form-type'] ?? ''; if (!$formType) { - return ''; + throw new UnverifiedRequestException( + \__('Something went wrong while submitting your form. Please try again.', 'eightshift-forms') + ); } return $formType['value'] ?? ''; @@ -267,6 +269,12 @@ protected function getFormId(array $params): string $formId = $formId['value'] ?? ''; + if (!$formId) { + throw new UnverifiedRequestException( + \__('Something went wrong while submitting your form. Please try again.', 'eightshift-forms') + ); + } + return $formId; } diff --git a/src/Rest/Routes/AbstractFormSubmit.php b/src/Rest/Routes/AbstractFormSubmit.php index 48a5b9264..8323273ca 100644 --- a/src/Rest/Routes/AbstractFormSubmit.php +++ b/src/Rest/Routes/AbstractFormSubmit.php @@ -66,6 +66,12 @@ public function routeCallback(WP_REST_Request $request) // Get form ID. $formId = $this->getFormId($params); + if (!$formId) { + throw new UnverifiedRequestException( + \esc_html__('Invalid nonce.', 'eightshift-forms') + ); + } + // Determine form type. $formType = $this->getFormType($params); diff --git a/src/Rest/Routes/CacheDeleteRoute.php b/src/Rest/Routes/CacheDeleteRoute.php index 9139b5cc0..9d14306ce 100644 --- a/src/Rest/Routes/CacheDeleteRoute.php +++ b/src/Rest/Routes/CacheDeleteRoute.php @@ -82,7 +82,7 @@ public function routeCallback(WP_REST_Request $request) \rest_ensure_response([ 'code' => 400, 'status' => 'error', - 'message' => \esc_html__('Error, you don\'t have enough permissions to perform this action!', 'eightshift-form'), + 'message' => \esc_html__('Error, you don\'t have enough permissions to perform this action!', 'eightshift-forms'), ]); } @@ -92,7 +92,7 @@ public function routeCallback(WP_REST_Request $request) return \rest_ensure_response([ 'code' => 400, 'status' => 'error', - 'message' => \esc_html__('Error, no cache type key was provided.', 'eightshift-form'), + 'message' => \esc_html__('Error, no cache type key was provided.', 'eightshift-forms'), ]); } @@ -102,7 +102,7 @@ public function routeCallback(WP_REST_Request $request) return \rest_ensure_response([ 'code' => 400, 'status' => 'error', - 'message' => \esc_html__('Error, provided cache type doesn\'t exist.', 'eightshift-form'), + 'message' => \esc_html__('Error, provided cache type doesn\'t exist.', 'eightshift-forms'), ]); } @@ -114,7 +114,7 @@ public function routeCallback(WP_REST_Request $request) 'code' => 200, 'status' => 'success', // translators: %s will be replaced with the cache type. - 'message' => \sprintf(\esc_html__('%s cache successfully deleted!', 'eightshift-form'), \ucfirst($type)), + 'message' => \sprintf(\esc_html__('%s cache successfully deleted!', 'eightshift-forms'), \ucfirst($type)), ]); } } diff --git a/src/Rest/Routes/FormSettingsSubmitRoute.php b/src/Rest/Routes/FormSettingsSubmitRoute.php index 46ef25c89..a2a345bd8 100644 --- a/src/Rest/Routes/FormSettingsSubmitRoute.php +++ b/src/Rest/Routes/FormSettingsSubmitRoute.php @@ -147,7 +147,7 @@ public function routeCallback(WP_REST_Request $request) return \rest_ensure_response([ 'code' => 200, 'status' => 'success', - 'message' => \esc_html__('Changes saved!', 'eightshift-form'), + 'message' => \esc_html__('Changes saved!', 'eightshift-forms'), ]); } catch (UnverifiedRequestException $e) { // Die if any of the validation fails. @@ -175,7 +175,7 @@ private function cache(array $params) \rest_ensure_response([ 'code' => 400, 'status' => 'error', - 'message' => \esc_html__('You don\'t have enough permissions to perform this action!', 'eightshift-form'), + 'message' => \esc_html__('You don\'t have enough permissions to perform this action!', 'eightshift-forms'), ]); } @@ -192,7 +192,7 @@ private function cache(array $params) return \rest_ensure_response([ 'code' => 200, 'status' => 'success', - 'message' => \esc_html__('Selected cache successfully deleted!', 'eightshift-form'), + 'message' => \esc_html__('Selected cache successfully deleted!', 'eightshift-forms'), ]); } } diff --git a/src/Rest/Routes/FormSubmitCustomRoute.php b/src/Rest/Routes/FormSubmitCustomRoute.php index b65b414b9..6adc644fb 100644 --- a/src/Rest/Routes/FormSubmitCustomRoute.php +++ b/src/Rest/Routes/FormSubmitCustomRoute.php @@ -81,9 +81,20 @@ public function submitAction(string $formId, array $params = [], $files = []) ]); } + if (isset($params['es-form-storage'])) { + unset($params['es-form-storage']); + } + // Format body parameters to a key/value array. foreach ($params as $param) { - $body[$param['name']] = $param['value']; + $name = $param['name'] ?? ''; + $value = $param['value'] ?? ''; + + if ($name || !$value) { + continue; + } + + $body[$name] = $value; } // Create a custom form action request. @@ -112,7 +123,7 @@ public function submitAction(string $formId, array $params = [], $files = []) // If form action is valid we'll return the generic success message. return \rest_ensure_response([ 'status' => 'success', - 'code' => $customResponseCode, + 'code' => 200, 'message' => $this->labels->getLabel('customSuccess', $formId), ]); } From 7b3f7f54e73ce996db933e8b42f5b24d68153182 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20Ruz=CC=8Cevic=CC=81?= Date: Thu, 1 Sep 2022 14:39:29 +0200 Subject: [PATCH 02/12] adding fixes for forms integrations and fields --- .../components/form/assets-admin/index.js | 5 + src/Blocks/components/form/assets/form.js | 102 ++++++++---------- src/Blocks/components/form/assets/index.js | 3 + .../components/active-campaign-options.js | 4 +- .../components/form-selector-editor.js | 6 +- .../mailchimp/components/mailchimp-options.js | 4 +- src/Enqueue/Admin/EnqueueAdmin.php | 2 + src/Enqueue/Blocks/EnqueueBlocks.php | 59 +++++----- src/Helpers/Helper.php | 2 +- src/Hooks/FiltersTracking.md | 32 ++++-- .../ActiveCampaign/ActiveCampaign.php | 15 +-- .../ActiveCampaign/ActiveCampaignClient.php | 31 +++--- .../ActiveCampaign/SettingsActiveCampaign.php | 10 +- src/Integrations/Goodbits/GoodbitsClient.php | 15 ++- src/Integrations/Greenhouse/Greenhouse.php | 10 -- .../Greenhouse/GreenhouseClient.php | 32 +++--- src/Integrations/Hubspot/Hubspot.php | 21 ++++ src/Integrations/Hubspot/HubspotClient.php | 38 ++++--- src/Integrations/Mailchimp/Mailchimp.php | 18 ++-- .../Mailchimp/MailchimpClient.php | 55 +++++----- .../Mailchimp/SettingsMailchimp.php | 2 +- .../Mailerlite/MailerliteClient.php | 22 ++-- src/Mailer/Mailer.php | 19 ++-- src/Rest/Routes/AbstractBaseRoute.php | 98 +++++++++++------ src/Rest/Routes/AbstractFormSubmit.php | 5 +- src/Rest/Routes/FormSettingsSubmitRoute.php | 14 ++- src/Rest/Routes/FormSubmitCustomRoute.php | 21 ++-- src/Validation/Validator.php | 9 +- 28 files changed, 366 insertions(+), 288 deletions(-) diff --git a/src/Blocks/components/form/assets-admin/index.js b/src/Blocks/components/form/assets-admin/index.js index 2cb7ba3b4..e0dc2bb48 100644 --- a/src/Blocks/components/form/assets-admin/index.js +++ b/src/Blocks/components/form/assets-admin/index.js @@ -4,6 +4,10 @@ import domReady from '@wordpress/dom-ready'; import manifest from './../manifest.json'; domReady(() => { + if (typeof esFormsLocalization === 'undefined') { + throw 'Your project is missing global variable esFormsLocalization called from the enqueue script.'; + } + const { componentJsClass, componentCacheJsClass, @@ -17,6 +21,7 @@ domReady(() => { formSelector: selector, formSubmitRestApiUrl: esFormsLocalization.formSettingsSubmitRestApiUrl, formIsAdmin: true, + customFormParams: esFormsLocalization.customFormParams, }); form.init(); diff --git a/src/Blocks/components/form/assets/form.js b/src/Blocks/components/form/assets/form.js index 2d4be4bbc..dcac5c18d 100644 --- a/src/Blocks/components/form/assets/form.js +++ b/src/Blocks/components/form/assets/form.js @@ -62,15 +62,12 @@ export class Form { this.selectSelector = `${this.fieldSelector} select`; this.fileSelector = `${this.fieldSelector} input[type='file']`; - // State selectors. - this.CLASS_ACTIVE = FORM_SELECTORS.CLASS_ACTIVE; - this.CLASS_FILLED = FORM_SELECTORS.CLASS_FILLED; - this.CLASS_LOADING = FORM_SELECTORS.CLASS_LOADING; - this.CLASS_HAS_ERROR = FORM_SELECTORS.CLASS_HAS_ERROR; - // LocalStorage this.STORAGE_NAME = 'es-storage'; + // Custom fields params. + this.FORM_CUSTOM_FORM_PARAMS = options.customFormParams; + // Settings options. this.formDisableScrollToFieldOnError = options.formDisableScrollToFieldOnError ?? true; this.formDisableScrollToGlobalMessageOnSuccess = options.formDisableScrollToGlobalMessageOnSuccess ?? true; @@ -88,14 +85,6 @@ export class Form { this.customTextareas = []; this.customSelects = []; this.customFiles = []; - - // Data attributes. - this.DATA_ATTR_FORM_TYPE = FORM_DATA_ATTRIBUTES.DATA_ATTR_FORM_TYPE; - this.DATA_ATTR_FIELD_ID = FORM_DATA_ATTRIBUTES.DATA_ATTR_FIELD_ID; - this.DATA_ATTR_FORM_POST_ID = FORM_DATA_ATTRIBUTES.DATA_ATTR_FORM_POST_ID; - this.DATA_ATTR_TRACKING_EVENT_NAME = FORM_DATA_ATTRIBUTES.DATA_ATTR_TRACKING_EVENT_NAME; - this.DATA_ATTR_TRACKING = FORM_DATA_ATTRIBUTES.DATA_ATTR_TRACKING; - this.DATA_ATTR_TRACKING_SELECT_LABEL = FORM_DATA_ATTRIBUTES.DATA_ATTR_TRACKING_SELECT_LABEL; } // Init all actions. @@ -123,7 +112,7 @@ export class Form { } // Get form ID. - const formId = element.getAttribute(this.DATA_ATTR_FORM_POST_ID); + const formId = element.getAttribute(FORM_DATA_ATTRIBUTES.DATA_ATTR_FORM_POST_ID); // All fields selectors. const inputs = element.querySelectorAll(this.inputSelector); @@ -198,7 +187,7 @@ export class Form { }, body: JSON.stringify({ token, - formId: element.getAttribute(this.DATA_ATTR_FORM_POST_ID), + formId: element.getAttribute(FORM_DATA_ATTRIBUTES.DATA_ATTR_FORM_POST_ID), }), credentials: 'same-origin', redirect: 'follow', @@ -251,7 +240,7 @@ export class Form { const formData = this.getFormData(element, singleSubmit); - const formType = element.getAttribute(this.DATA_ATTR_FORM_TYPE); + const formType = element.getAttribute(FORM_DATA_ATTRIBUTES.DATA_ATTR_FORM_TYPE); // Populate body data. const body = { @@ -375,7 +364,7 @@ export class Form { // Check if we are saving group items in one key. if (groups.length && !singleSubmit) { for (const [key, group] of Object.entries(groups)) { // eslint-disable-line no-unused-vars - const groupId = group.getAttribute(this.DATA_ATTR_FIELD_ID); + const groupId = group.getAttribute(FORM_DATA_ATTRIBUTES.DATA_ATTR_FIELD_ID); const groupInner = group.querySelectorAll(` ${this.groupInnerSelector} input, ${this.groupInnerSelector} select, @@ -413,8 +402,7 @@ export class Form { textarea:not(${this.groupInnerSelector} textarea) `); - const formType = element.getAttribute(this.DATA_ATTR_FORM_TYPE); - const formAction = element.getAttribute('action'); + const formType = element.getAttribute(FORM_DATA_ATTRIBUTES.DATA_ATTR_FORM_TYPE); // If single submit override items and pass only one item to submit. if (singleSubmit) { @@ -487,43 +475,43 @@ export class Form { } // Add form ID field. - formData.append('es-form-post-id', JSON.stringify({ - value: element.getAttribute(this.DATA_ATTR_FORM_POST_ID), + formData.append(this.FORM_CUSTOM_FORM_PARAMS.postId, JSON.stringify({ + value: element.getAttribute(FORM_DATA_ATTRIBUTES.DATA_ATTR_FORM_POST_ID), type: 'hidden', })); // Add form type field. - formData.append('es-form-type', JSON.stringify({ + formData.append(this.FORM_CUSTOM_FORM_PARAMS.type, JSON.stringify({ value: formType, type: 'hidden', })); // Add form action field. - formData.append('action', JSON.stringify({ - value: formAction, + formData.append(this.FORM_CUSTOM_FORM_PARAMS.action, JSON.stringify({ + value: element.getAttribute('action'), type: 'hidden', })); // Add additional options for HubSpot only. if (formType === 'hubspot' && !this.formIsAdmin) { - formData.append('es-form-hubspot-cookie', JSON.stringify({ + formData.append(this.FORM_CUSTOM_FORM_PARAMS.hubspotCookie, JSON.stringify({ value: cookies.getCookie('hubspotutk'), type: 'hidden', })); - formData.append('es-form-hubspot-page-name', JSON.stringify({ + formData.append(this.FORM_CUSTOM_FORM_PARAMS.hubspotPageName, JSON.stringify({ value: document.title, type: 'hidden', })); - formData.append('es-form-hubspot-page-url', JSON.stringify({ + formData.append(this.FORM_CUSTOM_FORM_PARAMS.hubspotPageUrl, JSON.stringify({ value: window.location.href, type: 'hidden', })); } if (singleSubmit && this.formIsAdmin) { - formData.append('es-form-single-submit', JSON.stringify({ + formData.append(this.FORM_CUSTOM_FORM_PARAMS.singleSubmit, JSON.stringify({ value: 'true', type: 'hidden', })); @@ -532,7 +520,7 @@ export class Form { // Set localStorage to hidden field. const storage = this.getLocalStorage(); if (storage) { - formData.append('es-form-storage', JSON.stringify({ + formData.append(this.FORM_CUSTOM_FORM_PARAMS.storage, JSON.stringify({ value: storage, type: 'hidden', })); @@ -547,7 +535,7 @@ export class Form { for (const [key] of Object.entries(fields)) { const item = element.querySelector(`${this.errorSelector}[data-id="${key}"]`); - item?.closest(this.fieldSelector).classList.add(this.CLASS_HAS_ERROR); + item?.closest(this.fieldSelector).classList.add(FORM_SELECTORS.CLASS_HAS_ERROR); if (item !== null) { item.innerHTML = fields[key]; @@ -567,7 +555,7 @@ export class Form { if (this.formResetOnSuccess) { element.reset(); - const formId = element.getAttribute(this.DATA_ATTR_FORM_POST_ID); + const formId = element.getAttribute(FORM_DATA_ATTRIBUTES.DATA_ATTR_FORM_POST_ID); // Unset the choices in the submitted form. if (this.customSelects[formId]) { @@ -586,9 +574,9 @@ export class Form { const fields = element.querySelectorAll(this.fieldSelector); [...fields].forEach((item) => { - item.classList.remove(this.CLASS_FILLED); - item.classList.remove(this.CLASS_ACTIVE); - item.classList.remove(this.CLASS_HAS_ERROR); + item.classList.remove(FORM_SELECTORS.CLASS_FILLED); + item.classList.remove(FORM_SELECTORS.CLASS_ACTIVE); + item.classList.remove(FORM_SELECTORS.CLASS_HAS_ERROR); }); // Remove focus from last input. @@ -607,7 +595,7 @@ export class Form { }); // Reset all error classes on fields. - element.querySelectorAll(`.${this.CLASS_HAS_ERROR}`).forEach((element) => element.classList.remove(this.CLASS_HAS_ERROR)); + element.querySelectorAll(`.${FORM_SELECTORS.CLASS_HAS_ERROR}`).forEach((element) => element.classList.remove(FORM_SELECTORS.CLASS_HAS_ERROR)); this.unsetGlobalMsg(element); }; @@ -616,13 +604,13 @@ export class Form { showLoader = (element) => { const loader = element.querySelector(this.loaderSelector); - element?.classList?.add(this.CLASS_LOADING); + element?.classList?.add(FORM_SELECTORS.CLASS_LOADING); if (!loader) { return; } - loader.classList.add(this.CLASS_ACTIVE); + loader.classList.add(FORM_SELECTORS.CLASS_ACTIVE); }; // Hide loader. @@ -630,13 +618,13 @@ export class Form { const loader = element.querySelector(this.loaderSelector); setTimeout(() => { - element?.classList?.remove(this.CLASS_LOADING); + element?.classList?.remove(FORM_SELECTORS.CLASS_LOADING); if (!loader) { return; } - loader.classList.remove(this.CLASS_ACTIVE); + loader.classList.remove(FORM_SELECTORS.CLASS_ACTIVE); }, parseInt(this.hideLoadingStateTimeout, 10)); }; @@ -652,7 +640,7 @@ export class Form { return; } - messageContainer.classList.add(this.CLASS_ACTIVE); + messageContainer.classList.add(FORM_SELECTORS.CLASS_ACTIVE); messageContainer.dataset.status = status; messageContainer.innerHTML = `${msg}`; @@ -670,7 +658,7 @@ export class Form { return; } - messageContainer.classList.remove(this.CLASS_ACTIVE); + messageContainer.classList.remove(FORM_SELECTORS.CLASS_ACTIVE); messageContainer.dataset.status = ''; messageContainer.innerHTML = ''; } @@ -683,12 +671,12 @@ export class Form { return; } - messageContainer.classList.remove(this.CLASS_ACTIVE); + messageContainer.classList.remove(FORM_SELECTORS.CLASS_ACTIVE); } // Submit GTM event. gtmSubmit(element) { - const eventName = element.getAttribute(this.DATA_ATTR_TRACKING_EVENT_NAME); + const eventName = element.getAttribute(FORM_DATA_ATTRIBUTES.DATA_ATTR_TRACKING_EVENT_NAME); if (eventName) { const gtmData = this.getGtmData(element, eventName); @@ -702,7 +690,7 @@ export class Form { // Build GTM data for the data layer. getGtmData(element, eventName) { - const items = element.querySelectorAll(`[${this.DATA_ATTR_TRACKING}]`); + const items = element.querySelectorAll(`[${FORM_DATA_ATTRIBUTES.DATA_ATTR_TRACKING}]`); const dataTemp = {}; if (!items.length) { @@ -710,7 +698,7 @@ export class Form { } [...items].forEach((item) => { - const tracking = item.getAttribute(this.DATA_ATTR_TRACKING); + const tracking = item.getAttribute(FORM_DATA_ATTRIBUTES.DATA_ATTR_TRACKING); if (tracking) { const {type, checked} = item; @@ -728,7 +716,7 @@ export class Form { } // Check if you have this data attr and if so use select label. - if (item.hasAttribute(this.DATA_ATTR_TRACKING_SELECT_LABEL)) { + if (item.hasAttribute(FORM_DATA_ATTRIBUTES.DATA_ATTR_TRACKING_SELECT_LABEL)) { dataTemp[tracking] = item.selectedOptions[0].label; return; } @@ -870,11 +858,11 @@ export class Form { // On add one file. myDropzone.on("addedfile", (file) => { setTimeout(() => { - file.previewTemplate.classList.add(this.CLASS_ACTIVE); + file.previewTemplate.classList.add(FORM_SELECTORS.CLASS_ACTIVE); }, 200); setTimeout(() => { - file.previewTemplate.classList.add(this.CLASS_FILLED); + file.previewTemplate.classList.add(FORM_SELECTORS.CLASS_FILLED); }, 1200); }); @@ -914,20 +902,20 @@ export class Form { case 'checkbox': case 'radio': if (input.checked) { - input.closest(this.fieldSelector).classList.add(this.CLASS_FILLED); + input.closest(this.fieldSelector).classList.add(FORM_SELECTORS.CLASS_FILLED); } break; case 'select-custom': { const customSelect = input.config.choices; if (customSelect.some((item) => item.selected === true && item.value !== '')) { - input.passedElement.element.closest(this.fieldSelector).classList.add(this.CLASS_FILLED); + input.passedElement.element.closest(this.fieldSelector).classList.add(FORM_SELECTORS.CLASS_FILLED); } break; } default: if (input.value && input.value.length) { - input.closest(this.fieldSelector).classList.add(this.CLASS_FILLED); + input.closest(this.fieldSelector).classList.add(FORM_SELECTORS.CLASS_FILLED); } break; } @@ -935,7 +923,7 @@ export class Form { // On Focus event for regular fields. onFocusEvent = (event) => { - event.target.closest(this.fieldSelector).classList.add(this.CLASS_ACTIVE); + event.target.closest(this.fieldSelector).classList.add(FORM_SELECTORS.CLASS_ACTIVE); }; // On Blur generic method. Check for length of value. @@ -974,10 +962,10 @@ export class Form { } if (condition) { - field.classList.remove(this.CLASS_ACTIVE); - field.classList.add(this.CLASS_FILLED); + field.classList.remove(FORM_SELECTORS.CLASS_ACTIVE); + field.classList.add(FORM_SELECTORS.CLASS_FILLED); } else { - field.classList.remove(this.CLASS_ACTIVE, this.CLASS_FILLED); + field.classList.remove(FORM_SELECTORS.CLASS_ACTIVE, FORM_SELECTORS.CLASS_FILLED); } }; @@ -993,7 +981,7 @@ export class Form { // Regular submit. element.removeEventListener('submit', this.onFormSubmit); - const formId = element.getAttribute(this.DATA_ATTR_FORM_POST_ID); + const formId = element.getAttribute(FORM_DATA_ATTRIBUTES.DATA_ATTR_FORM_POST_ID); const inputs = element.querySelectorAll(this.inputSelector); const textareas = element.querySelectorAll(this.textareaSelector); diff --git a/src/Blocks/components/form/assets/index.js b/src/Blocks/components/form/assets/index.js index 02c7f4d06..609f7da12 100644 --- a/src/Blocks/components/form/assets/index.js +++ b/src/Blocks/components/form/assets/index.js @@ -36,6 +36,7 @@ function initAll() { fileCustomRemoveLabel: esFormsLocalization.fileCustomRemoveLabel, captcha: esFormsLocalization.captcha, storageConfig: esFormsLocalization.storageConfig, + customFormParams: esFormsLocalization.customFormParams, }); // Run forms. @@ -53,6 +54,8 @@ function initAll() { customFiles: form.customFiles, customTextareas: form.customTextareas, storageConfig: form.storageConfig, + customFormParams: form.FORM_CUSTOM_FORM_PARAMS, + storageName: form.STORAGE_NAME, init: () => { form.init(); }, diff --git a/src/Blocks/custom/active-campaign/components/active-campaign-options.js b/src/Blocks/custom/active-campaign/components/active-campaign-options.js index 4e5f189f8..7d360165e 100644 --- a/src/Blocks/custom/active-campaign/components/active-campaign-options.js +++ b/src/Blocks/custom/active-campaign/components/active-campaign-options.js @@ -1,4 +1,4 @@ -/* global esFormsBlocksLocalization */ +/* global esFormsLocalization */ import React from 'react'; import { __ } from '@wordpress/i18n'; @@ -11,7 +11,7 @@ export const ActiveCampaignOptions = ({ postId }) => { settingsPageUrl, } = select(STORE_NAME).getSettings(); - const wpAdminUrl = esFormsBlocksLocalization.wpAdminUrl; + const wpAdminUrl = esFormsLocalization.wpAdminUrl; return ( diff --git a/src/Blocks/custom/form-selector/components/form-selector-editor.js b/src/Blocks/custom/form-selector/components/form-selector-editor.js index ccda859e5..8262039c0 100644 --- a/src/Blocks/custom/form-selector/components/form-selector-editor.js +++ b/src/Blocks/custom/form-selector/components/form-selector-editor.js @@ -27,11 +27,7 @@ export const FormSelectorEditor = ({ attributes, clientId }) => { const hasInnerBlocksCheck = useSelect((select) => { const { innerBlocks } = select('core/block-editor').getBlock(clientId); - if (!innerBlocks.length) { - return false; - } - - return true; + return innerBlocks.length; }); // If parent block has inner blocks set internal state. diff --git a/src/Blocks/custom/mailchimp/components/mailchimp-options.js b/src/Blocks/custom/mailchimp/components/mailchimp-options.js index d3b77b685..19a97a207 100644 --- a/src/Blocks/custom/mailchimp/components/mailchimp-options.js +++ b/src/Blocks/custom/mailchimp/components/mailchimp-options.js @@ -1,4 +1,4 @@ -/* global esFormsLocalizations */ +/* global esFormsLocalization */ import React from 'react'; import { __ } from '@wordpress/i18n'; @@ -11,7 +11,7 @@ export const MailchimpOptions = ({ postId }) => { settingsPageUrl, } = select(STORE_NAME).getSettings(); - const wpAdminUrl = esFormsLocalizations.wpAdminUrl; + const wpAdminUrl = esFormsLocalization.wpAdminUrl; return ( diff --git a/src/Enqueue/Admin/EnqueueAdmin.php b/src/Enqueue/Admin/EnqueueAdmin.php index 0a6b5cca8..862983054 100644 --- a/src/Enqueue/Admin/EnqueueAdmin.php +++ b/src/Enqueue/Admin/EnqueueAdmin.php @@ -11,6 +11,7 @@ namespace EightshiftForms\Enqueue\Admin; use EightshiftForms\Config\Config; +use EightshiftForms\Rest\Routes\AbstractBaseRoute; use EightshiftForms\Rest\Routes\CacheDeleteRoute; use EightshiftForms\Rest\Routes\FormSettingsSubmitRoute; use EightshiftFormsVendor\EightshiftLibs\Manifest\ManifestInterface; @@ -76,6 +77,7 @@ protected function getLocalizations(): array return [ 'esFormsLocalization' => [ + 'customFormParams' => AbstractBaseRoute::CUSTOM_FORM_PARAMS, 'formSettingsSubmitRestApiUrl' => $restRoutesPath . FormSettingsSubmitRoute::ROUTE_SLUG, 'clearCacheRestUrl' => $restRoutesPath . CacheDeleteRoute::ROUTE_SLUG, ] diff --git a/src/Enqueue/Blocks/EnqueueBlocks.php b/src/Enqueue/Blocks/EnqueueBlocks.php index 7d54f12c0..6250deb9a 100644 --- a/src/Enqueue/Blocks/EnqueueBlocks.php +++ b/src/Enqueue/Blocks/EnqueueBlocks.php @@ -14,6 +14,7 @@ use EightshiftForms\Geolocation\SettingsGeolocation; use EightshiftForms\Hooks\Filters; use EightshiftForms\Hooks\Variables; +use EightshiftForms\Rest\Routes\AbstractBaseRoute; use EightshiftForms\Rest\Routes\GeolocationCountriesRoute; use EightshiftForms\Settings\Settings\SettingsGeneral; use EightshiftForms\Settings\SettingsHelper; @@ -158,7 +159,9 @@ public function getAssetsVersion(): string */ protected function getLocalizations(): array { - $output = []; + $output = [ + 'customFormParams' => AbstractBaseRoute::CUSTOM_FORM_PARAMS, + ]; // Admin part. if (\is_admin()) { @@ -203,34 +206,32 @@ protected function getLocalizations(): array // Frontend part. $restRoutesPath = \rest_url() . Config::getProjectRoutesNamespace() . '/' . Config::getProjectRoutesVersion(); - $hideGlobalMsgTimeoutFilterName = Filters::getBlockFilterName('form', 'hideGlobalMsgTimeout'); - $redirectionTimeoutFilterName = Filters::getBlockFilterName('form', 'redirectionTimeout'); - $previewRemoveLabelFilterName = Filters::getBlockFilterName('file', 'previewRemoveLabel'); - $hideLoadingStateTimeoutFilterName = Filters::getBlockFilterName('form', 'hideLoadingStateTimeout'); - - $output = [ - 'formSubmitRestApiUrl' => $restRoutesPath . '/form-submit', - 'hideGlobalMessageTimeout' => \apply_filters($hideGlobalMsgTimeoutFilterName, 6000), - 'redirectionTimeout' => \apply_filters($redirectionTimeoutFilterName, 300), - 'hideLoadingStateTimeout' => \apply_filters($hideLoadingStateTimeoutFilterName, 600), - 'fileCustomRemoveLabel' => \apply_filters($previewRemoveLabelFilterName, \esc_html__('Remove', 'eightshift-forms')), - 'formDisableScrollToFieldOnError' => $this->isCheckboxOptionChecked( - SettingsGeneral::SETTINGS_GENERAL_DISABLE_SCROLL_TO_FIELD_ON_ERROR, - SettingsGeneral::SETTINGS_GENERAL_DISABLE_SCROLL_KEY - ), - 'formDisableScrollToGlobalMessageOnSuccess' => $this->isCheckboxOptionChecked( - SettingsGeneral::SETTINGS_GENERAL_DISABLE_SCROLL_TO_GLOBAL_MESSAGE_ON_SUCCESS, - SettingsGeneral::SETTINGS_GENERAL_DISABLE_SCROLL_KEY - ), - 'formDisableAutoInit' => $this->isCheckboxOptionChecked( - SettingsGeneral::SETTINGS_GENERAL_DISABLE_AUTOINIT_ENQUEUE_SCRIPT_KEY, - SettingsGeneral::SETTINGS_GENERAL_DISABLE_DEFAULT_ENQUEUE_KEY - ), - 'formResetOnSuccess' => !Variables::isDevelopMode(), - 'formServerErrorMsg' => esc_html__('An server error occurred while submitting your form. Please try again.', 'eightshift-forms'), - 'captcha' => '', - 'storageConfig' => '', - ]; + $hideGlobalMessageTimeout = Filters::getBlockFilterName('form', 'hideGlobalMsgTimeout'); + $redirectionTimeout = Filters::getBlockFilterName('form', 'redirectionTimeout'); + $hideLoadingStateTimeout = Filters::getBlockFilterName('form', 'hideLoadingStateTimeout'); + $fileCustomRemoveLabel = Filters::getBlockFilterName('file', 'previewRemoveLabel'); + + $output['formSubmitRestApiUrl'] = $restRoutesPath . '/form-submit'; + $output['hideGlobalMessageTimeout'] = \apply_filters($hideGlobalMessageTimeout, 6000); + $output['redirectionTimeout'] = \apply_filters($redirectionTimeout, 300); + $output['hideLoadingStateTimeout'] = \apply_filters($hideLoadingStateTimeout, 600); + $output['fileCustomRemoveLabel'] = \apply_filters($fileCustomRemoveLabel, \esc_html__('Remove', 'eightshift-forms')); + $output['formDisableScrollToFieldOnError'] = $this->isCheckboxOptionChecked( + SettingsGeneral::SETTINGS_GENERAL_DISABLE_SCROLL_TO_FIELD_ON_ERROR, + SettingsGeneral::SETTINGS_GENERAL_DISABLE_SCROLL_KEY + ); + $output['formDisableScrollToGlobalMessageOnSuccess'] = $this->isCheckboxOptionChecked( + SettingsGeneral::SETTINGS_GENERAL_DISABLE_SCROLL_TO_GLOBAL_MESSAGE_ON_SUCCESS, + SettingsGeneral::SETTINGS_GENERAL_DISABLE_SCROLL_KEY + ); + $output['formDisableAutoInit'] = $this->isCheckboxOptionChecked( + SettingsGeneral::SETTINGS_GENERAL_DISABLE_AUTOINIT_ENQUEUE_SCRIPT_KEY, + SettingsGeneral::SETTINGS_GENERAL_DISABLE_DEFAULT_ENQUEUE_KEY + ); + $output['formResetOnSuccess'] = !Variables::isDevelopMode(); + $output['formServerErrorMsg'] = \esc_html__('An server error occurred while submitting your form. Please try again.', 'eightshift-forms'); + $output['captcha'] = ''; + $output['storageConfig'] = ''; // Check if Captcha data is set and valid. $isCaptchaSettingsGlobalValid = \apply_filters(SettingsCaptcha::FILTER_SETTINGS_GLOBAL_IS_VALID_NAME, false); diff --git a/src/Helpers/Helper.php b/src/Helpers/Helper.php index cc52e4864..913a4fa4b 100644 --- a/src/Helpers/Helper.php +++ b/src/Helpers/Helper.php @@ -3,7 +3,7 @@ /** * Trait that holds all generic helpers. * - * @package EightshiftLibs\Helpers + * @package EightshiftForms\Helpers */ declare(strict_types=1); diff --git a/src/Hooks/FiltersTracking.md b/src/Hooks/FiltersTracking.md index aa7c6f464..583d33bc5 100644 --- a/src/Hooks/FiltersTracking.md +++ b/src/Hooks/FiltersTracking.md @@ -40,33 +40,43 @@ This filter provides you with the ability to map you local storage tags got from **Filter example:** ```php // Map Hubspot fields with custom tags from local storage. -\add_filter('es_forms_integration_hubspot_local_storage_map', [$this, 'getIntegrationHubspotLocalStorageMap'], 10, 2); +\add_filter('es_forms_integration_hubspot_local_storage_map', [$this, 'getIntegrationHubspotLocalStorageMap'], 10, 3); /** * Map Hubspot fields with custom tags from local storage. * - * @param array $params Params from Hubspot integration. + * @param array $params Params from Hubspot integration prepared for output. * @param array $storage Data form storage. + * @param array $originalParams Original params with all custom fields. * * @return array */ -public function getIntegrationHubspotLocalStorageMap(array $params, array $storage): array +public function getIntegrationHubspotLocalStorageMap(array $params, array $storage, array $originalParams): array { if (!$storage) { return $params; } - foreach ($params as $key => $param) { - $name = $param['name'] ?? ''; + // Additional tags to allow. + $allowedTags = \array_flip([ + 'utm_source', + 'utm_content', + 'utm_campaign', + ]); - if (!$name) { - continue; - } + foreach ($storage as $key => $param) { + if (isset($allowedTags[$key]) && isset($originalParams[$key])) { + $name = $originalParams[$key]['name'] ?? ''; - if ($name === 'utm_source' || $name === 'utm_content' || $name === 'utm_campaign') { - if (isset($storage[$name])) { - $params[$key]['value'] = $storage[$name]; + if (!$name) { + continue; } + + $params[] = [ + 'name' => $name, + 'value' => $param, + 'objectTypeId' => $originalParams[$key]['objectTypeId'] ?? '', + ]; } } diff --git a/src/Integrations/ActiveCampaign/ActiveCampaign.php b/src/Integrations/ActiveCampaign/ActiveCampaign.php index 440cc86ae..32a278821 100644 --- a/src/Integrations/ActiveCampaign/ActiveCampaign.php +++ b/src/Integrations/ActiveCampaign/ActiveCampaign.php @@ -15,7 +15,6 @@ use EightshiftForms\Integrations\ActiveCampaign\ActiveCampaignClientInterface; use EightshiftForms\Integrations\MapperInterface; use EightshiftForms\Settings\SettingsHelper; -use EightshiftForms\Validation\ValidatorInterface; use EightshiftFormsVendor\EightshiftLibs\Services\ServiceInterface; /** @@ -62,25 +61,13 @@ class ActiveCampaign extends AbstractFormBuilder implements MapperInterface, Ser */ private $activeCampaignClient; - /** - * Instance variable of ValidatorInterface data. - * - * @var ValidatorInterface - */ - private $validator; - /** * Create a new instance. * * @param ActiveCampaignClientInterface $activeCampaignClient Inject ActiveCampaign which holds ActiveCampaign connection data. - * @param ValidatorInterface $validator Inject ValidatorInterface which holds validation methods. */ - public function __construct( - ActiveCampaignClientInterface $activeCampaignClient, - ValidatorInterface $validator - ) { + public function __construct(ActiveCampaignClientInterface $activeCampaignClient) { $this->activeCampaignClient = $activeCampaignClient; - $this->validator = $validator; } /** diff --git a/src/Integrations/ActiveCampaign/ActiveCampaignClient.php b/src/Integrations/ActiveCampaign/ActiveCampaignClient.php index ce339bb8a..c72511aa7 100644 --- a/src/Integrations/ActiveCampaign/ActiveCampaignClient.php +++ b/src/Integrations/ActiveCampaign/ActiveCampaignClient.php @@ -13,7 +13,9 @@ use EightshiftForms\Hooks\Variables; use EightshiftForms\Integrations\ActiveCampaign\ActiveCampaignClientInterface; use EightshiftForms\Rest\ApiHelper; +use EightshiftForms\Rest\Routes\AbstractBaseRoute; use EightshiftForms\Settings\SettingsHelper; +use EightshiftFormsVendor\EightshiftLibs\Helpers\Components; /** * ActiveCampaignClient integration class. @@ -154,7 +156,7 @@ public function postApplication(string $itemId, array $params, array $files, str return $this->getApiSuccessOutput( SettingsActiveCampaign::SETTINGS_TYPE_KEY, [ - 'contactId' => $body['fieldValues'][0]['contact'], + 'contactId' => $body['contact']['id'], ] ); case 403: @@ -590,28 +592,23 @@ private function prepareParams(array $params): array { $output = []; + $customFields = \array_flip(Components::flattenArray(AbstractBaseRoute::CUSTOM_FORM_PARAMS)); $standardFields = \array_flip(ActiveCampaign::STANDARD_FIELDS); - // Remove unecesery storage field. - if (isset($params['es-form-storage'])) { - unset($params['es-form-storage']); - } - - // Remove unecesery action tags field. - if (isset($params['actionTags'])) { - unset($params['actionTags']); - } - - // Remove unecesery action lists field. - if (isset($params['actionLists'])) { - unset($params['actionLists']); - } - // Map params. foreach ($params as $key => $param) { $value = $param['value'] ?? ''; - if (!$value) { + if ($key === 'actionTags') { + continue; + } + + if ($key === 'actionLists') { + continue; + } + + // Remove unecesery fields. + if (isset($customFields[$key])) { continue; } diff --git a/src/Integrations/ActiveCampaign/SettingsActiveCampaign.php b/src/Integrations/ActiveCampaign/SettingsActiveCampaign.php index be60d85e9..32fa36922 100644 --- a/src/Integrations/ActiveCampaign/SettingsActiveCampaign.php +++ b/src/Integrations/ActiveCampaign/SettingsActiveCampaign.php @@ -206,7 +206,7 @@ public function getSettingsData(string $formId): array [ 'component' => 'highlighted-content', 'highlightedContentTitle' => \__('Something went wrong', 'eightshift-forms'), - 'highlightedContentSubtitle' => \__('Data from ActiveCampaign couldn\'t be fetched. Check the API key.', 'eightshift-forms'), + 'highlightedContentSubtitle' => \__('Data from ActiveCampaign couldn\'t be fetched. Check the API key, url or if you have any form created.', 'eightshift-forms'), 'highlightedContentIcon' => 'error', ], ]; @@ -317,11 +317,9 @@ public function getSettingsGlobalData(): array // phpcs:ignore WordPress.WP.I18n.NoHtmlWrappedStrings 'introSubtitle' => \__('
  1. Log in to your ActiveCampaign Account.
  2. -
  3. Navigate to your user profile image (bottom left corner).
  4. -
  5. Click on Account.
  6. -
  7. Click on Extras and API Keys in the tabs section.
  8. -
  9. Click on the Create a Key button.
  10. -
  11. Copy the API key into the field below or use the global constant.
  12. +
  13. Navigate to your settings page (gear) (bottom left corner).
  14. +
  15. Click on Developer.
  16. +
  17. Copy the API key and url into the fields below or use the global constant.
', 'eightshift-forms'), ], [ diff --git a/src/Integrations/Goodbits/GoodbitsClient.php b/src/Integrations/Goodbits/GoodbitsClient.php index efaf690b7..c96392ff7 100644 --- a/src/Integrations/Goodbits/GoodbitsClient.php +++ b/src/Integrations/Goodbits/GoodbitsClient.php @@ -13,7 +13,9 @@ use EightshiftForms\Helpers\Helper; use EightshiftForms\Hooks\Variables; use EightshiftForms\Integrations\ClientInterface; +use EightshiftForms\Rest\Routes\AbstractBaseRoute; use EightshiftForms\Settings\SettingsHelper; +use EightshiftFormsVendor\EightshiftLibs\Helpers\Components; use EightshiftFormsVendor\EightshiftLibs\Helpers\ObjectHelperTrait; /** @@ -220,12 +222,15 @@ private function prepareParams(array $params): array { $output = []; - foreach ($params as $key => $value) { - $output[$key] = $value['value'] ?? ''; - } + $customFields = \array_flip(Components::flattenArray(AbstractBaseRoute::CUSTOM_FORM_PARAMS)); + + foreach ($params as $key => $param) { + // Remove unecesery fields. + if (isset($customFields[$key])) { + continue; + } - if (isset($params['es-form-storage'])) { - unset($params['es-form-storage']); + $output[$key] = $param['value'] ?? ''; } return $output; diff --git a/src/Integrations/Greenhouse/Greenhouse.php b/src/Integrations/Greenhouse/Greenhouse.php index e2eb8ee8b..192ca9f6e 100644 --- a/src/Integrations/Greenhouse/Greenhouse.php +++ b/src/Integrations/Greenhouse/Greenhouse.php @@ -256,16 +256,6 @@ static function ($selectOption) { 'inputId' => 'latitude', 'inputName' => 'latitude', ]; - - global $wp; - - $output[] = [ - 'component' => 'input', - 'inputType' => 'hidden', - 'inputId' => 'es-form-url', - 'inputName' => 'es-form-url', - 'inputValue' => \esc_url(\site_url(\add_query_arg([$_GET], $wp->request))), // phpcs:ignore WordPress.Security.NonceVerification.Recommended - ]; } $output[] = [ diff --git a/src/Integrations/Greenhouse/GreenhouseClient.php b/src/Integrations/Greenhouse/GreenhouseClient.php index 3bb653397..fb5e03ed5 100644 --- a/src/Integrations/Greenhouse/GreenhouseClient.php +++ b/src/Integrations/Greenhouse/GreenhouseClient.php @@ -10,10 +10,13 @@ namespace EightshiftForms\Integrations\Greenhouse; +use CURLFile; use EightshiftForms\Helpers\Helper; use EightshiftForms\Settings\SettingsHelper; use EightshiftForms\Hooks\Variables; use EightshiftForms\Integrations\ClientInterface; +use EightshiftForms\Rest\Routes\AbstractBaseRoute; +use EightshiftFormsVendor\EightshiftLibs\Helpers\Components; /** * GreenhouseClient integration class. @@ -135,11 +138,6 @@ public function postApplication(string $itemId, array $params, array $files, str $this->prepareFiles($files) ); - error_log( print_r( ( $body ), true ) ); - error_log( print_r( ( $this->getHeaders(true) ), true ) ); - - - $response = \wp_remote_post( self::BASE_URL . "boards/{$this->getBoardToken()}/jobs/{$itemId}", [ @@ -148,8 +146,6 @@ public function postApplication(string $itemId, array $params, array $files, str ] ); - error_log( print_r( ( $response ), true ) ); - if (\is_wp_error($response)) { Helper::logger([ 'integration' => 'greenhouse', @@ -325,17 +321,21 @@ private function prepareParams(array $params): array { $output = []; - if (isset($params['es-form-storage'])) { - unset($params['es-form-storage']); - } + $customFields = \array_flip(Components::flattenArray(AbstractBaseRoute::CUSTOM_FORM_PARAMS)); - foreach ($params as $key => $value) { + foreach ($params as $key => $param) { // Get gh_src from url and map it. - if ($key === 'es-form-storage' && isset($value['value']['gh_src'])) { - $output['mapped_url_token'] = $value['value']['gh_src']; - } else { - $output[$key] = $value['value'] ?? ''; + if ($key === AbstractBaseRoute::CUSTOM_FORM_PARAM_STORAGE && isset($param['value']['gh_src'])) { + $output['mapped_url_token'] = $param['value']['gh_src']; + continue; } + + // Remove unecesery fields. + if (isset($customFields[$key])) { + continue; + } + + $output[$key] = $param['value'] ?? ''; } return $output; @@ -367,7 +367,7 @@ private function prepareFiles(array $files): array continue; } - $output[$id] = new \CURLFile(\realpath($path), $type, $fileName); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode, WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents + $output[$id] = new CURLFile(\realpath($path), $type, $fileName); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode, WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents } } diff --git a/src/Integrations/Hubspot/Hubspot.php b/src/Integrations/Hubspot/Hubspot.php index bae2c1e04..aab0ba46e 100644 --- a/src/Integrations/Hubspot/Hubspot.php +++ b/src/Integrations/Hubspot/Hubspot.php @@ -40,6 +40,27 @@ class Hubspot extends AbstractFormBuilder implements MapperInterface, ServiceInt */ public const FILTER_FORM_FIELDS_NAME = 'es_hubspot_form_fields_filter'; + /** + * Custom form param for cookie. + * + * @var string + */ + public const CUSTOM_FORM_PARAM_HUBSPOT_COOKIE = 'es-form-hubspot-cookie'; + + /** + * Custom form param for page name. + * + * @var string + */ + public const CUSTOM_FORM_PARAM_HUBSPOT_PAGE_NAME = 'es-form-hubspot-page-name'; + + /** + * Custom form param for page url. + * + * @var string + */ + public const CUSTOM_FORM_PARAM_HUBSPOT_PAGE_URL = 'es-form-hubspot-page-url'; + /** * Instance variable for Hubspot data. * diff --git a/src/Integrations/Hubspot/HubspotClient.php b/src/Integrations/Hubspot/HubspotClient.php index d24336fdc..d39995ec6 100644 --- a/src/Integrations/Hubspot/HubspotClient.php +++ b/src/Integrations/Hubspot/HubspotClient.php @@ -16,6 +16,8 @@ use EightshiftForms\Settings\SettingsHelper; use EightshiftForms\Hooks\Variables; use EightshiftForms\Integrations\ClientInterface; +use EightshiftForms\Rest\Routes\AbstractBaseRoute; +use EightshiftFormsVendor\EightshiftLibs\Helpers\Components; /** * HubspotClient integration class. @@ -193,9 +195,9 @@ static function ($item) { $body = [ 'context' => [ 'ipAddress' => isset($_SERVER['REMOTE_ADDR']) ? \sanitize_text_field(\wp_unslash($_SERVER['REMOTE_ADDR'])) : '', // phpcs:ignore WordPress.Security.NonceVerification.Recommended - 'hutk' => $params['es-form-hubspot-cookie']['value'], - 'pageUri' => $params['es-form-hubspot-page-url']['value'], - 'pageName' => $params['es-form-hubspot-page-name']['value'], + 'hutk' => $params[Hubspot::CUSTOM_FORM_PARAM_HUBSPOT_COOKIE]['value'], + 'pageUri' => $params[Hubspot::CUSTOM_FORM_PARAM_HUBSPOT_PAGE_URL]['value'], + 'pageName' => $params[Hubspot::CUSTOM_FORM_PARAM_HUBSPOT_PAGE_NAME]['value'], ], ]; @@ -333,8 +335,14 @@ public function postContactProperty(string $email, array $params): array $properties = []; + $customFields = \array_flip(Components::flattenArray(AbstractBaseRoute::CUSTOM_FORM_PARAMS)); foreach ($params as $key => $value) { + // Remove unecesery fields. + if (isset($customFields[$key])) { + continue; + } + $properties[] = [ 'property' => $key, 'value' => $value, @@ -689,19 +697,13 @@ private function prepareParams(array $params): array { $output = []; - unset($params['es-form-hubspot-cookie']); - unset($params['es-form-hubspot-page-name']); - unset($params['es-form-hubspot-page-url']); + $customFields = \array_flip(Components::flattenArray(AbstractBaseRoute::CUSTOM_FORM_PARAMS)); foreach ($params as $key => $param) { - if ($key === 'es-form-storage') { - continue; - } - $type = $param['type'] ?? ''; $value = $param['value'] ?? ''; - if (!$param) { + if (!$value) { continue; } @@ -717,6 +719,11 @@ private function prepareParams(array $params): array $value = \str_replace(', ', ';', $value); } + // Remove unecesery fields. + if (isset($customFields[$key])) { + continue; + } + $output[] = [ 'name' => $param['name'] ?? '', 'value' => $value, @@ -725,8 +732,13 @@ private function prepareParams(array $params): array } $filterName = Filters::getIntegrationFilterName(SettingsHubspot::SETTINGS_TYPE_KEY, 'localStorageMap'); - if (isset($params['es-form-storage']['value']) && \has_filter($filterName)) { - return \apply_filters($filterName, $output, $params['es-form-storage']['value']) ?? []; + if (isset($params[AbstractBaseRoute::CUSTOM_FORM_PARAM_STORAGE]['value']) && \has_filter($filterName)) { + return \apply_filters( + $filterName, + $output, + $params[AbstractBaseRoute::CUSTOM_FORM_PARAM_STORAGE]['value'], + $params + ) ?? []; } return $output; diff --git a/src/Integrations/Mailchimp/Mailchimp.php b/src/Integrations/Mailchimp/Mailchimp.php index ebc4e9a89..da7c9f9b4 100644 --- a/src/Integrations/Mailchimp/Mailchimp.php +++ b/src/Integrations/Mailchimp/Mailchimp.php @@ -42,11 +42,11 @@ class Mailchimp extends AbstractFormBuilder implements MapperInterface, ServiceI public const FILTER_FORM_FIELDS_NAME = 'es_mailchimp_form_fields_filter'; /** - * Field Mailchimp Tags. + * Custom form param for tags. * * @var string */ - public const FIELD_MAILCHIMP_TAGS_KEY = 'es-form-mailchimp-tags'; + public const CUSTOM_FORM_PARAM_MAILCHIMP_TAGS = 'es-form-mailchimp-tags'; /** * Instance variable for Mailchimp data. @@ -324,9 +324,9 @@ static function ($item) use ($selectedIds) { $output[] = [ 'component' => 'select', 'selectFieldLabel' => \__('Tags', 'eightshift-forms'), - 'selectId' => self::FIELD_MAILCHIMP_TAGS_KEY, - 'selectName' => self::FIELD_MAILCHIMP_TAGS_KEY, - 'selectTracking' => self::FIELD_MAILCHIMP_TAGS_KEY, + 'selectId' => self::CUSTOM_FORM_PARAM_MAILCHIMP_TAGS, + 'selectName' => self::CUSTOM_FORM_PARAM_MAILCHIMP_TAGS, + 'selectTracking' => self::CUSTOM_FORM_PARAM_MAILCHIMP_TAGS, 'selectOptions' => \array_merge( [ [ @@ -359,7 +359,7 @@ static function ($option) use ($tagsLabels) { ]; break; case 'checkboxes': - $checkboxesFieldName = self::FIELD_MAILCHIMP_TAGS_KEY; + $checkboxesFieldName = self::CUSTOM_FORM_PARAM_MAILCHIMP_TAGS; $output[] = [ 'component' => 'checkboxes', @@ -403,9 +403,9 @@ static function ($item) { $output[] = [ 'component' => 'input', 'inputType' => 'hidden', - 'inputId' => self::FIELD_MAILCHIMP_TAGS_KEY, - 'inputName' => self::FIELD_MAILCHIMP_TAGS_KEY, - 'inputTracking' => self::FIELD_MAILCHIMP_TAGS_KEY, + 'inputId' => self::CUSTOM_FORM_PARAM_MAILCHIMP_TAGS, + 'inputName' => self::CUSTOM_FORM_PARAM_MAILCHIMP_TAGS, + 'inputTracking' => self::CUSTOM_FORM_PARAM_MAILCHIMP_TAGS, 'inputValue' => $tagsItems, 'blockSsr' => $ssr, ]; diff --git a/src/Integrations/Mailchimp/MailchimpClient.php b/src/Integrations/Mailchimp/MailchimpClient.php index 4dbb6140c..8f68ae9e9 100644 --- a/src/Integrations/Mailchimp/MailchimpClient.php +++ b/src/Integrations/Mailchimp/MailchimpClient.php @@ -13,7 +13,9 @@ use EightshiftForms\Helpers\Helper; use EightshiftForms\Hooks\Variables; use EightshiftForms\Integrations\ClientInterface; +use EightshiftForms\Rest\Routes\AbstractBaseRoute; use EightshiftForms\Settings\SettingsHelper; +use EightshiftFormsVendor\EightshiftLibs\Helpers\Components; /** * MailchimpClient integration class. @@ -362,40 +364,37 @@ private function prepareParams(array $params): array { $output = []; - if (isset($params['email_address'])) { - unset($params['email_address']); - } - - if (isset($params[Mailchimp::FIELD_MAILCHIMP_TAGS_KEY])) { - unset($params[Mailchimp::FIELD_MAILCHIMP_TAGS_KEY]); - } + $customFields = \array_flip(Components::flattenArray(AbstractBaseRoute::CUSTOM_FORM_PARAMS)); foreach ($params as $key => $param) { $value = $param['value'] ?? ''; - switch ($param['name']) { - case 'address': - if ($value) { - $output[$key] = [ - 'addr1' => $value, - 'addr2' => '', - 'city' => '&sbsp;', - 'state' => '', - 'zip' => '&sbsp;', - 'country' => '', - ]; - } - break; - default: - $output[$key] = $value; - break; + // Remove email. + if ($key === 'email_address') { + continue; } - } - if (isset($params['es-form-storage'])) { - unset($params['es-form-storage']); - } + // Check for custom address. + if ($key === 'ADDRESS' && $value) { + $output[$key] = [ + 'addr1' => $value, + 'addr2' => '', + 'city' => '&sbsp;', + 'state' => '', + 'zip' => '&sbsp;', + 'country' => '', + ]; + + continue; + } + // Remove unecesery fields. + if (isset($customFields[$key])) { + continue; + } + + $output[$key] = $value; + } return $output; } @@ -409,7 +408,7 @@ private function prepareParams(array $params): array */ private function prepareTags(array $params): array { - $key = Mailchimp::FIELD_MAILCHIMP_TAGS_KEY; + $key = Mailchimp::CUSTOM_FORM_PARAM_MAILCHIMP_TAGS; if (!isset($params[$key])) { return []; diff --git a/src/Integrations/Mailchimp/SettingsMailchimp.php b/src/Integrations/Mailchimp/SettingsMailchimp.php index 0172b11d1..a74ca5b00 100644 --- a/src/Integrations/Mailchimp/SettingsMailchimp.php +++ b/src/Integrations/Mailchimp/SettingsMailchimp.php @@ -410,7 +410,7 @@ function ($tag) use ($formId) { $this->mailchimp->getFormFields($formId), $formId, [ - Mailchimp::FIELD_MAILCHIMP_TAGS_KEY + Mailchimp::CUSTOM_FORM_PARAM_MAILCHIMP_TAGS ] ), ] diff --git a/src/Integrations/Mailerlite/MailerliteClient.php b/src/Integrations/Mailerlite/MailerliteClient.php index 5ace4befc..b6af010eb 100644 --- a/src/Integrations/Mailerlite/MailerliteClient.php +++ b/src/Integrations/Mailerlite/MailerliteClient.php @@ -13,7 +13,9 @@ use EightshiftForms\Helpers\Helper; use EightshiftForms\Hooks\Variables; use EightshiftForms\Integrations\ClientInterface; +use EightshiftForms\Rest\Routes\AbstractBaseRoute; use EightshiftForms\Settings\SettingsHelper; +use EightshiftFormsVendor\EightshiftLibs\Helpers\Components; /** * MailerliteClient integration class. @@ -269,16 +271,20 @@ private function prepareParams(array $params): array { $output = []; - if (isset($params['email'])) { - unset($params['email']); - } + $customFields = \array_flip(Components::flattenArray(AbstractBaseRoute::CUSTOM_FORM_PARAMS)); - foreach ($params as $key => $value) { - $output[$key] = $value['value'] ?? ''; - } + foreach ($params as $key => $param) { + // Remove email. + if ($key === 'email') { + continue; + } + + // Remove unecesery fields. + if (isset($customFields[$key])) { + continue; + } - if (isset($params['es-form-storage'])) { - unset($params['es-form-storage']); + $output[$key] = $param['value'] ?? ''; } return $output; diff --git a/src/Mailer/Mailer.php b/src/Mailer/Mailer.php index 2389c7af4..589d0a9d7 100644 --- a/src/Mailer/Mailer.php +++ b/src/Mailer/Mailer.php @@ -10,7 +10,9 @@ namespace EightshiftForms\Mailer; +use EightshiftForms\Rest\Routes\AbstractBaseRoute; use EightshiftForms\Settings\SettingsHelper; +use EightshiftFormsVendor\EightshiftLibs\Helpers\Components; /** * Class Mailer @@ -161,17 +163,20 @@ protected function prepareFields(array $fields): array { $output = []; - foreach ($fields as $field) { + $customFields = \array_flip(Components::flattenArray(AbstractBaseRoute::CUSTOM_FORM_PARAMS)); + + foreach ($fields as $key => $param) { + // Remove unecesery fields. + if (isset($customFields[$key])) { + continue; + } + $output[] = [ - 'name' => $field['name'] ?? '', - 'value' => $field['value'] ?? '', + 'name' => $param['name'] ?? '', + 'value' => $param['value'] ?? '', ]; } - if (isset($fields['es-form-storage'])) { - unset($fields['es-form-storage']); - } - return $output; } diff --git a/src/Rest/Routes/AbstractBaseRoute.php b/src/Rest/Routes/AbstractBaseRoute.php index df3920ad6..528d1fb60 100644 --- a/src/Rest/Routes/AbstractBaseRoute.php +++ b/src/Rest/Routes/AbstractBaseRoute.php @@ -12,6 +12,8 @@ use EightshiftForms\Config\Config; use EightshiftForms\Exception\UnverifiedRequestException; +use EightshiftForms\Integrations\Hubspot\Hubspot; +use EightshiftForms\Integrations\Mailchimp\Mailchimp; use EightshiftFormsVendor\EightshiftLibs\Rest\Routes\AbstractRoute; use EightshiftFormsVendor\EightshiftLibs\Rest\CallableRouteInterface; use EightshiftForms\Validation\Validator; // phpcs:ignore @@ -23,6 +25,56 @@ */ abstract class AbstractBaseRoute extends AbstractRoute implements CallableRouteInterface { + /** + * Custom form param for post ID. + * + * @var string + */ + public const CUSTOM_FORM_PARAM_POST_ID = 'es-form-post-id'; + + /** + * Custom form param for type. + * + * @var string + */ + public const CUSTOM_FORM_PARAM_TYPE = 'es-form-type'; + + /** + * Custom form param for single submit. + * + * @var string + */ + public const CUSTOM_FORM_PARAM_SINGLE_SUBMIT = 'es-form-single-submit'; + + /** + * Custom form param for storage. + * + * @var string + */ + public const CUSTOM_FORM_PARAM_STORAGE = 'es-form-storage'; + + /** + * Custom form param for action. + * + * @var string + */ + public const CUSTOM_FORM_PARAM_ACTION = 'es-form-action'; + + /** + * List of all custom form params used. + */ + public const CUSTOM_FORM_PARAMS = [ + 'postId' => self::CUSTOM_FORM_PARAM_POST_ID, + 'type' => self::CUSTOM_FORM_PARAM_TYPE, + 'singleSubmit' => self::CUSTOM_FORM_PARAM_SINGLE_SUBMIT, + 'storage' => self::CUSTOM_FORM_PARAM_STORAGE, + 'action' => self::CUSTOM_FORM_PARAM_ACTION, + 'hubspotCookie' => Hubspot::CUSTOM_FORM_PARAM_HUBSPOT_COOKIE, + 'hubspotPageName' => Hubspot::CUSTOM_FORM_PARAM_HUBSPOT_PAGE_NAME, + 'hubspotPageUrl' => Hubspot::CUSTOM_FORM_PARAM_HUBSPOT_PAGE_URL, + 'mailchimpTags' => Mailchimp::CUSTOM_FORM_PARAM_MAILCHIMP_TAGS, + ]; + /** * Method that returns project Route namespace. * @@ -210,11 +262,13 @@ static function ($item) { * * @param array $params Array of params got from form. * + * @throws UnverifiedRequestException Wrong request response. + * * @return string */ protected function getFormType(array $params): string { - $formType = $params['es-form-type'] ?? ''; + $formType = $params[self::CUSTOM_FORM_PARAM_TYPE] ?? ''; if (!$formType) { throw new UnverifiedRequestException( @@ -256,12 +310,15 @@ protected function getSenderDetails(array $params): array * Return form ID from form params and determins if ID needs decrypting. * * @param array $params Array of params got from form. + * @param bool $throwError Throw error if missing post Id. + * + * @throws UnverifiedRequestException Wrong request response. * * @return string */ - protected function getFormId(array $params): string + protected function getFormId(array $params, bool $throwError = true): string { - $formId = $params['es-form-post-id'] ?? ''; + $formId = $params[self::CUSTOM_FORM_PARAM_POST_ID] ?? ''; if (!$formId) { return ''; @@ -269,7 +326,7 @@ protected function getFormId(array $params): string $formId = $formId['value'] ?? ''; - if (!$formId) { + if (!$formId && $throwError) { throw new UnverifiedRequestException( \__('Something went wrong while submitting your form. Please try again.', 'eightshift-forms') ); @@ -278,33 +335,6 @@ protected function getFormId(array $params): string return $formId; } - /** - * Remove uncesesery params before submitting data to validation. - * - * @param array $params Array of params got from form. - * - * @return array - */ - protected function removeUneceseryParams(array $params): array - { - foreach ($params as $key => $value) { - if ($key === 'es-form-type') { - // Allow action parameter for forms with custom actions. - if ($value['value'] !== 'custom') { - unset($params['action']); - } - - unset($params['es-form-type']); - } - - if ($key === 'es-form-post-id') { - unset($params['es-form-post-id']); - } - } - - return $params; - } - /** * Extract storage parameters from params. * @@ -314,11 +344,11 @@ protected function removeUneceseryParams(array $params): array */ protected function extractStorageParams(array $params): array { - if (!isset($params['es-form-storage'])) { + if (!isset($params[self::CUSTOM_FORM_PARAM_STORAGE])) { return $params; } - $storage = $params['es-form-storage']['value'] ?? []; + $storage = $params[self::CUSTOM_FORM_PARAM_STORAGE]['value'] ?? []; if (!$storage) { return $params; @@ -326,7 +356,7 @@ protected function extractStorageParams(array $params): array $storage = \json_decode($storage, true); - $params['es-form-storage']['value'] = $storage; + $params[self::CUSTOM_FORM_PARAM_STORAGE]['value'] = $storage; return $params; } diff --git a/src/Rest/Routes/AbstractFormSubmit.php b/src/Rest/Routes/AbstractFormSubmit.php index 8323273ca..ef8873913 100644 --- a/src/Rest/Routes/AbstractFormSubmit.php +++ b/src/Rest/Routes/AbstractFormSubmit.php @@ -51,6 +51,8 @@ protected function getCallbackArguments(): array * * @param WP_REST_Request $request Data got from endpoint url. * + * @throws UnverifiedRequestException Wrong config error. + * * @return WP_REST_Response|mixed If response generated an error, WP_Error, if response * is already an instance, WP_HTTP_Response, otherwise * returns a new WP_REST_Response instance. @@ -88,9 +90,6 @@ public function routeCallback(WP_REST_Request $request) ); } - // Remove unecesery internal params before continue. - $params = $this->removeUneceseryParams($params); - // Extract hidden params from local storage set on the frontend. $params = $this->extractStorageParams($params); diff --git a/src/Rest/Routes/FormSettingsSubmitRoute.php b/src/Rest/Routes/FormSettingsSubmitRoute.php index a8ea7ef0f..8012f385b 100644 --- a/src/Rest/Routes/FormSettingsSubmitRoute.php +++ b/src/Rest/Routes/FormSettingsSubmitRoute.php @@ -16,6 +16,7 @@ use EightshiftForms\Hooks\Filters; use EightshiftForms\Hooks\Variables; use EightshiftForms\Validation\ValidatorInterface; +use EightshiftFormsVendor\EightshiftLibs\Helpers\Components; use WP_REST_Request; /** @@ -82,12 +83,12 @@ protected function getCallbackArguments(): array public function routeCallback(WP_REST_Request $request) { - // Try catch request. + // Try catch request. try { $params = $this->prepareParams($request->get_body_params()); // Get encripted form ID and decrypt it. - $formId = $this->getFormId($params); + $formId = $this->getFormId($params, false); // Determine form type. $formType = $this->getFormType($params); @@ -112,7 +113,14 @@ public function routeCallback(WP_REST_Request $request) } // Remove unecesery internal params before continue. - $params = $this->removeUneceseryParams($params); + $customFields = \array_flip(Components::flattenArray(AbstractBaseRoute::CUSTOM_FORM_PARAMS)); + + // Remove unecesery params. + foreach ($params as $key => $value) { + if (isset($customFields[$key])) { + unset($params[$key]); + } + } // Determine form type to use. switch ($formType) { diff --git a/src/Rest/Routes/FormSubmitCustomRoute.php b/src/Rest/Routes/FormSubmitCustomRoute.php index b7c19a764..21e5513d8 100644 --- a/src/Rest/Routes/FormSubmitCustomRoute.php +++ b/src/Rest/Routes/FormSubmitCustomRoute.php @@ -12,12 +12,19 @@ use EightshiftForms\Validation\ValidatorInterface; use EightshiftForms\Labels\LabelsInterface; +use EightshiftForms\Rest\ApiHelper; +use EightshiftFormsVendor\EightshiftLibs\Helpers\Components; /** * Class FormSubmitCustomRoute */ class FormSubmitCustomRoute extends AbstractFormSubmit { + /** + * Use api helper trait. + */ + use ApiHelper; + /** * Instance variable of ValidatorInterface data. * @@ -69,8 +76,7 @@ public function submitAction(string $formId, array $params = [], $files = []) { $body = []; - $formAction = $params['action']['value']; - unset($params['action']); + $formAction = $params[self::CUSTOM_FORM_PARAM_ACTION]['value']; // If form action is not set or empty. if (!$formAction) { @@ -81,12 +87,11 @@ public function submitAction(string $formId, array $params = [], $files = []) ]); } - if (isset($params['es-form-storage'])) { - unset($params['es-form-storage']); - } + // Remove unecesery internal params before continue. + $customFields = \array_flip(Components::flattenArray(AbstractBaseRoute::CUSTOM_FORM_PARAMS)); // Format body parameters to a key/value array. - foreach ($params as $param) { + foreach ($params as $key => $param) { $name = $param['name'] ?? ''; $value = $param['value'] ?? ''; @@ -94,6 +99,10 @@ public function submitAction(string $formId, array $params = [], $files = []) continue; } + if (isset($customFields[$key])) { + continue; + } + $body[$name] = $value; } diff --git a/src/Validation/Validator.php b/src/Validation/Validator.php index f4740f95c..fe33f3e08 100644 --- a/src/Validation/Validator.php +++ b/src/Validation/Validator.php @@ -12,6 +12,7 @@ use EightshiftFormsVendor\EightshiftLibs\Helpers\Components; use EightshiftForms\Labels\LabelsInterface; +use EightshiftForms\Rest\Routes\AbstractBaseRoute; use EightshiftForms\Settings\SettingsHelper; use EightshiftFormsVendor\EightshiftLibs\Helpers\ObjectHelperTrait; @@ -80,7 +81,7 @@ public function __construct(LabelsInterface $labels) public function validate(array $params = [], array $files = [], string $formId = '', array $formData = []): array { // If single submit skip all validations. - if (isset($params['es-form-single-submit'])) { + if (isset($params[AbstractBaseRoute::CUSTOM_FORM_PARAM_SINGLE_SUBMIT])) { return []; } @@ -201,6 +202,12 @@ private function validateParams(array $params, array $validationReference, strin // Check params. foreach ($params as $paramKey => $paramValue) { $inputValue = $paramValue['value'] ?? ''; + $inputType = $paramValue['type'] ?? ''; + + // No need to validate hidden fields. + if ($inputType === 'hidden') { + continue; + } // Find validation reference by ID. $reference = $validationReference[$paramKey] ?? []; From 058a3e6049ecfa7840de6b4beb85b360e420e378 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20Ruz=CC=8Cevic=CC=81?= Date: Thu, 1 Sep 2022 19:11:34 +0200 Subject: [PATCH 03/12] conveting greenhouse to curl --- src/Blocks/components/form/assets/form.js | 14 ++++-- src/Blocks/components/form/assets/index.js | 1 + src/General/General.php | 13 ++++- src/Hooks/Filters.php | 2 +- src/Hooks/FiltersGeneral.md | 20 ++++---- .../ActiveCampaign/ActiveCampaign.php | 3 +- .../Greenhouse/GreenhouseClient.php | 47 ++++++++++++------- 7 files changed, 63 insertions(+), 37 deletions(-) diff --git a/src/Blocks/components/form/assets/form.js b/src/Blocks/components/form/assets/form.js index dcac5c18d..37c92f328 100644 --- a/src/Blocks/components/form/assets/form.js +++ b/src/Blocks/components/form/assets/form.js @@ -222,9 +222,6 @@ export class Form { this.hideGlobalMsg(element); }, parseInt(this.hideGlobalMessageTimeout, 10)); } - }) - .catch(function() { - this.setGlobalMsg(element, this.formServerErrorMsg, 'error'); }); }; @@ -352,6 +349,17 @@ export class Form { // Dispatch event. this.dispatchFormEvent(element, FORM_EVENTS.AFTER_FORM_SUBMIT_END); + }) + .catch(() => { + this.setGlobalMsg(element, this.formServerErrorMsg, 'error'); + + // Remove loader. + this.hideLoader(element); + + // Hide global msg in any case after some time. + setTimeout(() => { + this.hideGlobalMsg(element); + }, parseInt(this.hideGlobalMessageTimeout, 10)); }); }; diff --git a/src/Blocks/components/form/assets/index.js b/src/Blocks/components/form/assets/index.js index 609f7da12..9bced4315 100644 --- a/src/Blocks/components/form/assets/index.js +++ b/src/Blocks/components/form/assets/index.js @@ -34,6 +34,7 @@ function initAll() { formDisableScrollToGlobalMessageOnSuccess: esFormsLocalization.formDisableScrollToGlobalMessageOnSuccess, formResetOnSuccess: esFormsLocalization.formResetOnSuccess, fileCustomRemoveLabel: esFormsLocalization.fileCustomRemoveLabel, + formServerErrorMsg: esFormsLocalization.formServerErrorMsg, captcha: esFormsLocalization.captcha, storageConfig: esFormsLocalization.storageConfig, customFormParams: esFormsLocalization.customFormParams, diff --git a/src/General/General.php b/src/General/General.php index 53d6dc896..90d63567b 100644 --- a/src/General/General.php +++ b/src/General/General.php @@ -18,6 +18,13 @@ */ class General implements ServiceInterface { + /** + * Default timeout for all http requests. + * + * @var int + */ + public const HTTP_REQUEST_TIMEOUT_DEFAULT = 30; + /** * Register all hooks. * @@ -37,8 +44,10 @@ public function register(): void */ public function getHttpRequestArgs(array $args): array { - $args['timeout'] = 30; + $filterName = Filters::getGeneralSettingsFilterName('httpRequestTimeout'); + + $args['timeout'] = \apply_filters($filterName, self::HTTP_REQUEST_TIMEOUT_DEFAULT); - return \apply_filters(Filters::getGeneralSettingsFilterName('httpRequestArgs'), $args); // phpcs:ignore WordPress.NamingConventions.ValidHookName.NotLowercase + return $args; } } diff --git a/src/Hooks/Filters.php b/src/Hooks/Filters.php index bfad018a4..41155cb39 100644 --- a/src/Hooks/Filters.php +++ b/src/Hooks/Filters.php @@ -268,7 +268,7 @@ class Filters 'failMimetypeValidationWhenFileNotOnFS' => 'force_mimetype_from_fs', ], 'general' => [ - 'httpRequestArgs' => 'http_request_args', + 'httpRequestTimeout' => 'http_request_timeout', ], ]; diff --git a/src/Hooks/FiltersGeneral.md b/src/Hooks/FiltersGeneral.md index fbd8835ce..b8eaecd24 100644 --- a/src/Hooks/FiltersGeneral.md +++ b/src/Hooks/FiltersGeneral.md @@ -1,28 +1,24 @@ # Filters General This document will provide you with the code examples for forms filters used in general. -## Change http request arguments +## Change http request timeout This filter can be used to change CURL timeout for the file upload if you have to upload large files. **Filter name:** -`es_forms_general_http_request_args` +`es_forms_general_http_request_timeout` **Filter example:** ```php -// Return http request args. -add_filter('es_forms_general_http_request_args', [$this, 'getHttpRequestArgs']); +// Return http request timeout. +add_filter('es_forms_general_http_request_timeout', [$this, 'getHttpRequestTimeout']); /** - * Return http request args. + * Return http request timeout. * - * @param array $args Arguments from core. - * - * @return array + * @return int */ -public function getHttpRequestArgs(array $args): array +public function getHttpRequestTimeout(): int { - $args['timeout'] = 50; - - return $args; + return 50; } ``` diff --git a/src/Integrations/ActiveCampaign/ActiveCampaign.php b/src/Integrations/ActiveCampaign/ActiveCampaign.php index 32a278821..9d160e3b8 100644 --- a/src/Integrations/ActiveCampaign/ActiveCampaign.php +++ b/src/Integrations/ActiveCampaign/ActiveCampaign.php @@ -66,7 +66,8 @@ class ActiveCampaign extends AbstractFormBuilder implements MapperInterface, Ser * * @param ActiveCampaignClientInterface $activeCampaignClient Inject ActiveCampaign which holds ActiveCampaign connection data. */ - public function __construct(ActiveCampaignClientInterface $activeCampaignClient) { + public function __construct(ActiveCampaignClientInterface $activeCampaignClient) + { $this->activeCampaignClient = $activeCampaignClient; } diff --git a/src/Integrations/Greenhouse/GreenhouseClient.php b/src/Integrations/Greenhouse/GreenhouseClient.php index fb5e03ed5..e1106cc30 100644 --- a/src/Integrations/Greenhouse/GreenhouseClient.php +++ b/src/Integrations/Greenhouse/GreenhouseClient.php @@ -11,7 +11,9 @@ namespace EightshiftForms\Integrations\Greenhouse; use CURLFile; +use EightshiftForms\General\General; use EightshiftForms\Helpers\Helper; +use EightshiftForms\Hooks\Filters; use EightshiftForms\Settings\SettingsHelper; use EightshiftForms\Hooks\Variables; use EightshiftForms\Integrations\ClientInterface; @@ -138,15 +140,28 @@ public function postApplication(string $itemId, array $params, array $files, str $this->prepareFiles($files) ); - $response = \wp_remote_post( - self::BASE_URL . "boards/{$this->getBoardToken()}/jobs/{$itemId}", + $filterName = Filters::getGeneralSettingsFilterName('httpRequestTimeout'); + + // Curl used because files are not sent via wp request. + $curl = \curl_init(); // phpcs:ignore WordPress.WP.AlternativeFunctions.curl_curl_init + \curl_setopt_array( // phpcs:ignore WordPress.WP.AlternativeFunctions.curl_curl_setopt_array + $curl, [ - 'headers' => $this->getHeaders(true), - 'body' => $body, + \CURLOPT_URL => self::BASE_URL . "boards/{$this->getBoardToken()}/jobs/{$itemId}", + \CURLOPT_HTTPAUTH => \CURLAUTH_BASIC, + \CURLOPT_RETURNTRANSFER => true, + \CURLOPT_TIMEOUT => \apply_filters($filterName, General::HTTP_REQUEST_TIMEOUT_DEFAULT), + \CURLOPT_POST => true, + \CURLOPT_POSTFIELDS => $body, + \CURLOPT_HTTPHEADER => $this->getHeaders(true), ] ); + $response = \curl_exec($curl); // phpcs:ignore WordPress.WP.AlternativeFunctions.curl_curl_exec + $code = \curl_getinfo($curl, \CURLINFO_RESPONSE_CODE); // phpcs:ignore WordPress.WP.AlternativeFunctions.curl_curl_getinfo + + \curl_close($curl); // phpcs:ignore WordPress.WP.AlternativeFunctions.curl_curl_close - if (\is_wp_error($response)) { + if ($code === 401) { Helper::logger([ 'integration' => 'greenhouse', 'type' => 'wp', @@ -161,8 +176,6 @@ public function postApplication(string $itemId, array $params, array $files, str ]; } - $code = $response['response']['code'] ? $response['response']['code'] : 200; - if ($code === 200) { return [ 'status' => 'success', @@ -171,7 +184,7 @@ public function postApplication(string $itemId, array $params, array $files, str ]; } - $responseBody = \json_decode(\wp_remote_retrieve_body($response), true); + $responseBody = \json_decode($response, true); $responseMessage = $responseBody['error'] ?? ''; $output = [ @@ -184,7 +197,6 @@ public function postApplication(string $itemId, array $params, array $files, str 'integration' => 'greenhouse', 'type' => 'service', 'body' => $paramsPrepared, - 'response' => $response['response'], 'responseBody' => $responseBody, 'output' => $output, ]); @@ -294,20 +306,19 @@ private function getGreenhouseJob(string $jobId) * * @param boolean $postHeaders If using post method we need to send Authorization header and type in the request. * - * @return array + * @return array */ private function getHeaders(bool $postHeaders = false): array { - $headers = [ - 'Content-Type' => 'application/json', - ]; - if ($postHeaders) { - $headers['Authorization'] = "Basic {$this->getApiKey()}"; - $headers['Content-Type'] = 'multipart/form-data'; + return [ + 'Authorization: Basic ' . $this->getApiKey(), + ]; } - return $headers; + return [ + 'Content-Type' => 'application/json', + ]; } /** @@ -363,7 +374,7 @@ private function prepareFiles(array $files): array $id = $file['id'] ?? ''; $type = $file['type'] ?? ''; - if (!$path || !$fileName || !$id || !$type) { + if (!$path) { continue; } From 83cc0671dade628754de39dd766d08f71b651b7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20Ru=C5=BEevi=C4=87?= Date: Fri, 2 Sep 2022 10:51:30 +0200 Subject: [PATCH 04/12] Apply suggestions from code review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Goran Alković <77000136+goranalkovic-infinum@users.noreply.github.com> Co-authored-by: Igor Obradović --- src/Blocks/components/form/assets-admin/index.js | 2 +- src/Enqueue/Blocks/EnqueueBlocks.php | 2 +- src/Hooks/FiltersGeneral.md | 6 +++--- .../ActiveCampaign/SettingsActiveCampaign.php | 6 +++--- src/Integrations/Hubspot/HubspotClient.php | 2 +- src/Integrations/Mailchimp/MailchimpClient.php | 2 +- src/Integrations/Mailerlite/MailerliteClient.php | 2 +- src/Mailer/Mailer.php | 2 +- src/Rest/Routes/CacheDeleteRoute.php | 8 ++++---- src/Rest/Routes/FormSettingsSubmitRoute.php | 6 +++--- src/Rest/Routes/FormSubmitCustomRoute.php | 2 +- 11 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/Blocks/components/form/assets-admin/index.js b/src/Blocks/components/form/assets-admin/index.js index e0dc2bb48..e160ba5dc 100644 --- a/src/Blocks/components/form/assets-admin/index.js +++ b/src/Blocks/components/form/assets-admin/index.js @@ -5,7 +5,7 @@ import manifest from './../manifest.json'; domReady(() => { if (typeof esFormsLocalization === 'undefined') { - throw 'Your project is missing global variable esFormsLocalization called from the enqueue script.'; + throw 'Your project is missing the global "esFormsLocalization" variable called from the enqueue script.'; } const { diff --git a/src/Enqueue/Blocks/EnqueueBlocks.php b/src/Enqueue/Blocks/EnqueueBlocks.php index 6250deb9a..b1c1cb4c2 100644 --- a/src/Enqueue/Blocks/EnqueueBlocks.php +++ b/src/Enqueue/Blocks/EnqueueBlocks.php @@ -229,7 +229,7 @@ protected function getLocalizations(): array SettingsGeneral::SETTINGS_GENERAL_DISABLE_DEFAULT_ENQUEUE_KEY ); $output['formResetOnSuccess'] = !Variables::isDevelopMode(); - $output['formServerErrorMsg'] = \esc_html__('An server error occurred while submitting your form. Please try again.', 'eightshift-forms'); + $output['formServerErrorMsg'] = \esc_html__('A server error occurred while submitting your form. Please try again.', 'eightshift-forms'); $output['captcha'] = ''; $output['storageConfig'] = ''; diff --git a/src/Hooks/FiltersGeneral.md b/src/Hooks/FiltersGeneral.md index b8eaecd24..b3bbe8b85 100644 --- a/src/Hooks/FiltersGeneral.md +++ b/src/Hooks/FiltersGeneral.md @@ -2,18 +2,18 @@ This document will provide you with the code examples for forms filters used in general. ## Change http request timeout -This filter can be used to change CURL timeout for the file upload if you have to upload large files. +This filter can be used to change the cURL timeout for the file upload, useful if you have to upload large files. **Filter name:** `es_forms_general_http_request_timeout` **Filter example:** ```php -// Return http request timeout. +// Return the HTTP request timeout. add_filter('es_forms_general_http_request_timeout', [$this, 'getHttpRequestTimeout']); /** - * Return http request timeout. + * Return the HTTP request timeout. * * @return int */ diff --git a/src/Integrations/ActiveCampaign/SettingsActiveCampaign.php b/src/Integrations/ActiveCampaign/SettingsActiveCampaign.php index 32fa36922..23060c95e 100644 --- a/src/Integrations/ActiveCampaign/SettingsActiveCampaign.php +++ b/src/Integrations/ActiveCampaign/SettingsActiveCampaign.php @@ -206,7 +206,7 @@ public function getSettingsData(string $formId): array [ 'component' => 'highlighted-content', 'highlightedContentTitle' => \__('Something went wrong', 'eightshift-forms'), - 'highlightedContentSubtitle' => \__('Data from ActiveCampaign couldn\'t be fetched. Check the API key, url or if you have any form created.', 'eightshift-forms'), + 'highlightedContentSubtitle' => \__('Data from ActiveCampaign couldn\'t be fetched. Check the API key, URL or if you have any form created.', 'eightshift-forms'), 'highlightedContentIcon' => 'error', ], ]; @@ -317,9 +317,9 @@ public function getSettingsGlobalData(): array // phpcs:ignore WordPress.WP.I18n.NoHtmlWrappedStrings 'introSubtitle' => \__('
  1. Log in to your ActiveCampaign Account.
  2. -
  3. Navigate to your settings page (gear) (bottom left corner).
  4. +
  5. Navigate to your Settings page (gear icon in the bottom-left corner).
  6. Click on Developer.
  7. -
  8. Copy the API key and url into the fields below or use the global constant.
  9. +
  10. Copy the API key and URL into the fields below or use the global constant.
', 'eightshift-forms'), ], [ diff --git a/src/Integrations/Hubspot/HubspotClient.php b/src/Integrations/Hubspot/HubspotClient.php index d39995ec6..182a7e8b3 100644 --- a/src/Integrations/Hubspot/HubspotClient.php +++ b/src/Integrations/Hubspot/HubspotClient.php @@ -719,7 +719,7 @@ private function prepareParams(array $params): array $value = \str_replace(', ', ';', $value); } - // Remove unecesery fields. + // Remove unnecessary fields. if (isset($customFields[$key])) { continue; } diff --git a/src/Integrations/Mailchimp/MailchimpClient.php b/src/Integrations/Mailchimp/MailchimpClient.php index 8f68ae9e9..88410d079 100644 --- a/src/Integrations/Mailchimp/MailchimpClient.php +++ b/src/Integrations/Mailchimp/MailchimpClient.php @@ -388,7 +388,7 @@ private function prepareParams(array $params): array continue; } - // Remove unecesery fields. + // Remove unnecessary fields. if (isset($customFields[$key])) { continue; } diff --git a/src/Integrations/Mailerlite/MailerliteClient.php b/src/Integrations/Mailerlite/MailerliteClient.php index b6af010eb..28aecb9fa 100644 --- a/src/Integrations/Mailerlite/MailerliteClient.php +++ b/src/Integrations/Mailerlite/MailerliteClient.php @@ -279,7 +279,7 @@ private function prepareParams(array $params): array continue; } - // Remove unecesery fields. + // Remove unnecessary fields. if (isset($customFields[$key])) { continue; } diff --git a/src/Mailer/Mailer.php b/src/Mailer/Mailer.php index 589d0a9d7..f25b2bb6f 100644 --- a/src/Mailer/Mailer.php +++ b/src/Mailer/Mailer.php @@ -166,7 +166,7 @@ protected function prepareFields(array $fields): array $customFields = \array_flip(Components::flattenArray(AbstractBaseRoute::CUSTOM_FORM_PARAMS)); foreach ($fields as $key => $param) { - // Remove unecesery fields. + // Remove unnecessary fields. if (isset($customFields[$key])) { continue; } diff --git a/src/Rest/Routes/CacheDeleteRoute.php b/src/Rest/Routes/CacheDeleteRoute.php index bd669fb4e..17043d9a7 100644 --- a/src/Rest/Routes/CacheDeleteRoute.php +++ b/src/Rest/Routes/CacheDeleteRoute.php @@ -82,7 +82,7 @@ public function routeCallback(WP_REST_Request $request) \rest_ensure_response([ 'code' => 400, 'status' => 'error', - 'message' => \esc_html__('Error, you don\'t have enough permissions to perform this action!', 'eightshift-forms'), + 'message' => \esc_html__('Error: you don\'t have enough permissions to perform this action!', 'eightshift-forms'), ]); } @@ -92,7 +92,7 @@ public function routeCallback(WP_REST_Request $request) return \rest_ensure_response([ 'code' => 400, 'status' => 'error', - 'message' => \esc_html__('Error, no cache type key was provided.', 'eightshift-forms'), + 'message' => \esc_html__('Error: cache type key was not provided.', 'eightshift-forms'), ]); } @@ -102,7 +102,7 @@ public function routeCallback(WP_REST_Request $request) return \rest_ensure_response([ 'code' => 400, 'status' => 'error', - 'message' => \esc_html__('Error, provided cache type doesn\'t exist.', 'eightshift-forms'), + 'message' => \esc_html__('Error: provided cache type doesn\'t exist.', 'eightshift-forms'), ]); } @@ -114,7 +114,7 @@ public function routeCallback(WP_REST_Request $request) 'code' => 200, 'status' => 'success', // translators: %s will be replaced with the cache type. - 'message' => \sprintf(\esc_html__('%s cache successfully deleted!', 'eightshift-forms'), \ucfirst($type)), + 'message' => \sprintf(\esc_html__('%s cache deleted successfully!', 'eightshift-forms'), \ucfirst($type)), ]); } } diff --git a/src/Rest/Routes/FormSettingsSubmitRoute.php b/src/Rest/Routes/FormSettingsSubmitRoute.php index 8012f385b..15b823924 100644 --- a/src/Rest/Routes/FormSettingsSubmitRoute.php +++ b/src/Rest/Routes/FormSettingsSubmitRoute.php @@ -87,7 +87,7 @@ public function routeCallback(WP_REST_Request $request) try { $params = $this->prepareParams($request->get_body_params()); - // Get encripted form ID and decrypt it. + // Get encrypted form ID and decrypt it. $formId = $this->getFormId($params, false); // Determine form type. @@ -112,10 +112,10 @@ public function routeCallback(WP_REST_Request $request) ); } - // Remove unecesery internal params before continue. + // Remove unnecessary internal params before continue. $customFields = \array_flip(Components::flattenArray(AbstractBaseRoute::CUSTOM_FORM_PARAMS)); - // Remove unecesery params. + // Remove unnecessary params. foreach ($params as $key => $value) { if (isset($customFields[$key])) { unset($params[$key]); diff --git a/src/Rest/Routes/FormSubmitCustomRoute.php b/src/Rest/Routes/FormSubmitCustomRoute.php index 21e5513d8..5419ac7cc 100644 --- a/src/Rest/Routes/FormSubmitCustomRoute.php +++ b/src/Rest/Routes/FormSubmitCustomRoute.php @@ -87,7 +87,7 @@ public function submitAction(string $formId, array $params = [], $files = []) ]); } - // Remove unecesery internal params before continue. + // Remove unnecessary internal params before continue. $customFields = \array_flip(Components::flattenArray(AbstractBaseRoute::CUSTOM_FORM_PARAMS)); // Format body parameters to a key/value array. From fe3f760bea5f9deeb74a4b618c2514754297268c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20Ruz=CC=8Cevic=CC=81?= Date: Fri, 2 Sep 2022 15:22:37 +0200 Subject: [PATCH 05/12] adding fallback email for integrations --- src/Helpers/Helper.php | 5 + src/Hooks/Filters.php | 9 +- .../ActiveCampaign/ActiveCampaignClient.php | 10 -- src/Integrations/Goodbits/GoodbitsClient.php | 35 ++-- .../Greenhouse/GreenhouseClient.php | 38 ++-- src/Integrations/Hubspot/HubspotClient.php | 36 ++-- .../Mailchimp/MailchimpClient.php | 36 ++-- .../Mailerlite/MailerliteClient.php | 35 ++-- src/Mailer/Mailer.php | 103 +++++++++++ src/Mailer/MailerInterface.php | 9 + src/Rest/Routes/FormSubmitGoodbitsRoute.php | 18 +- src/Rest/Routes/FormSubmitGreenhouseRoute.php | 18 +- src/Rest/Routes/FormSubmitHubspotRoute.php | 18 +- src/Rest/Routes/FormSubmitMailchimpRoute.php | 18 +- src/Rest/Routes/FormSubmitMailerliteRoute.php | 19 +- .../SettingsTroubleshooting.php | 164 ++++++++++++++++++ 16 files changed, 439 insertions(+), 132 deletions(-) create mode 100644 src/Troubleshooting/SettingsTroubleshooting.php diff --git a/src/Helpers/Helper.php b/src/Helpers/Helper.php index 913a4fa4b..927808647 100644 --- a/src/Helpers/Helper.php +++ b/src/Helpers/Helper.php @@ -202,6 +202,11 @@ public static function logger(array $message): void if (!empty($wpContentDir)) { $message['time'] = \gmdate("Y-m-d H:i:s"); + + if (isset($message['files'])) { + unset($message['files']); + } + \error_log((string) \wp_json_encode($message) . "\n -------------------------------------", 3, \WP_CONTENT_DIR . '/eightshift-forms-debug.log'); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log } } diff --git a/src/Hooks/Filters.php b/src/Hooks/Filters.php index 41155cb39..21fed0067 100644 --- a/src/Hooks/Filters.php +++ b/src/Hooks/Filters.php @@ -31,6 +31,7 @@ use EightshiftForms\Settings\Settings\SettingsGeneral; use EightshiftForms\Settings\Settings\SettingsLocation; use EightshiftForms\Settings\Settings\SettingsTest; +use EightshiftForms\Troubleshooting\SettingsTroubleshooting; use EightshiftForms\Validation\SettingsCaptcha; use EightshiftForms\Validation\SettingsValidation; @@ -123,7 +124,7 @@ class Filters 'global' => SettingsClearbit::FILTER_SETTINGS_GLOBAL_NAME, 'settingsSidebar' => SettingsClearbit::FILTER_SETTINGS_SIDEBAR_NAME, 'fields' => Goodbits::FILTER_FORM_FIELDS_NAME, - 'icon' => '', + 'icon' => '', 'integration' => [ SettingsHubspot::SETTINGS_TYPE_KEY => [ 'use' => SettingsHubspot::SETTINGS_HUBSPOT_USE_CLEARBIT_KEY, @@ -150,6 +151,12 @@ class Filters 'settingsSidebar' => SettingsGeolocation::FILTER_SETTINGS_SIDEBAR_NAME, 'icon' => '', ], + SettingsTroubleshooting::SETTINGS_TYPE_KEY => [ + 'global' => SettingsTroubleshooting::FILTER_SETTINGS_GLOBAL_NAME, + 'settingsSidebar' => SettingsTroubleshooting::FILTER_SETTINGS_SIDEBAR_NAME, + 'valid' => SettingsTroubleshooting::FILTER_SETTINGS_IS_VALID_NAME, + 'icon' => '', + ], SettingsTest::SETTINGS_TYPE_KEY => [ 'global' => SettingsTest::FILTER_SETTINGS_GLOBAL_NAME, 'settingsSidebar' => SettingsTest::FILTER_SETTINGS_SIDEBAR_NAME, diff --git a/src/Integrations/ActiveCampaign/ActiveCampaignClient.php b/src/Integrations/ActiveCampaign/ActiveCampaignClient.php index c72511aa7..f0e71281a 100644 --- a/src/Integrations/ActiveCampaign/ActiveCampaignClient.php +++ b/src/Integrations/ActiveCampaign/ActiveCampaignClient.php @@ -140,16 +140,6 @@ public function postApplication(string $itemId, array $params, array $files, str $code = $details['code']; $body = $details['body']; - // Bailout if wp error. - if (\is_wp_error($response)) { - return $this->getApiWpErrorOutput( - SettingsActiveCampaign::SETTINGS_TYPE_KEY, - $details, - $requestBody, - $response->get_error_message() - ); - } - switch ($code) { case 200: case 201: diff --git a/src/Integrations/Goodbits/GoodbitsClient.php b/src/Integrations/Goodbits/GoodbitsClient.php index c96392ff7..40567cc65 100644 --- a/src/Integrations/Goodbits/GoodbitsClient.php +++ b/src/Integrations/Goodbits/GoodbitsClient.php @@ -113,23 +113,9 @@ public function postApplication(string $itemId, array $params, array $files, str ] ); - if (\is_wp_error($response)) { - Helper::logger([ - 'integration' => 'goodbits', - 'type' => 'wp', - 'body' => $body, - 'response' => $response, - ]); - return [ - 'status' => 'error', - 'code' => 400, - 'message' => $this->getErrorMsg('submitWpError'), - ]; - } - $code = $response['response']['code'] ? $response['response']['code'] : 200; - if ($code === 200 || $code === 201) { + if ($code >= 200 && $code <= 299) { return [ 'status' => 'success', 'code' => 200, @@ -141,20 +127,23 @@ public function postApplication(string $itemId, array $params, array $files, str $responseMessage = !\is_array($responseBody['errors']) ? $responseBody['errors'] : ''; $responseErrors = \is_array($responseBody['errors']) ? $responseBody['errors']['message'] : []; + $outputData = [ + 'integration' => SettingsGoodbits::SETTINGS_TYPE_KEY, + 'params' => $this->prepareParams($params), + 'files' => $files, + 'response' => $response['body'], + 'listId' => $itemId, + 'formId' => $formId, + ]; + $output = [ 'status' => 'error', 'code' => $code, 'message' => $this->getErrorMsg($responseMessage, $responseErrors), + 'data' => $outputData, ]; - Helper::logger([ - 'integration' => 'goodbits', - 'type' => 'service', - 'body' => $body, - 'response' => $response['response'], - 'responseBody' => $responseBody, - 'output' => $output, - ]); + Helper::logger($outputData); return $output; } diff --git a/src/Integrations/Greenhouse/GreenhouseClient.php b/src/Integrations/Greenhouse/GreenhouseClient.php index e1106cc30..fc8486d37 100644 --- a/src/Integrations/Greenhouse/GreenhouseClient.php +++ b/src/Integrations/Greenhouse/GreenhouseClient.php @@ -134,10 +134,11 @@ public function getItem(string $itemId): array public function postApplication(string $itemId, array $params, array $files, string $formId): array { $paramsPrepared = $this->prepareParams($params); + $paramsFiles = $this->prepareFiles($files); $body = \array_merge( $paramsPrepared, - $this->prepareFiles($files) + $paramsFiles ); $filterName = Filters::getGeneralSettingsFilterName('httpRequestTimeout'); @@ -161,22 +162,7 @@ public function postApplication(string $itemId, array $params, array $files, str \curl_close($curl); // phpcs:ignore WordPress.WP.AlternativeFunctions.curl_curl_close - if ($code === 401) { - Helper::logger([ - 'integration' => 'greenhouse', - 'type' => 'wp', - 'body' => $paramsPrepared, - 'response' => $response, - ]); - - return [ - 'status' => 'error', - 'code' => 400, - 'message' => $this->getErrorMsg('submitWpError'), - ]; - } - - if ($code === 200) { + if ($code >= 200 && $code <= 299) { return [ 'status' => 'success', 'code' => $code, @@ -187,19 +173,23 @@ public function postApplication(string $itemId, array $params, array $files, str $responseBody = \json_decode($response, true); $responseMessage = $responseBody['error'] ?? ''; + $outputData = [ + 'integration' => SettingsGreenhouse::SETTINGS_TYPE_KEY, + 'params' => $paramsPrepared, + 'files' => $paramsFiles, + 'response' => $response, + 'listId' => $itemId, + 'formId' => $formId, + ]; + $output = [ 'status' => 'error', 'code' => $code, 'message' => $this->getErrorMsg($responseMessage), + 'data' => $outputData, ]; - Helper::logger([ - 'integration' => 'greenhouse', - 'type' => 'service', - 'body' => $paramsPrepared, - 'responseBody' => $responseBody, - 'output' => $output, - ]); + Helper::logger($outputData); return $output; } diff --git a/src/Integrations/Hubspot/HubspotClient.php b/src/Integrations/Hubspot/HubspotClient.php index d39995ec6..9c90e9f69 100644 --- a/src/Integrations/Hubspot/HubspotClient.php +++ b/src/Integrations/Hubspot/HubspotClient.php @@ -243,20 +243,6 @@ static function ($item) { ] ); - if (\is_wp_error($response)) { - Helper::logger([ - 'integration' => 'hubspot', - 'type' => 'wp', - 'body' => $body, - 'response' => $response, - ]); - return [ - 'status' => 'error', - 'code' => 400, - 'message' => $this->getErrorMsg('submitWpError'), - ]; - } - $code = $response['response']['code'] ? $response['response']['code'] : 200; if ($code === 200) { @@ -271,20 +257,26 @@ static function ($item) { $responseMessage = $responseBody['message'] ?? ''; $responseErrors = $responseBody['errors'] ?? []; + $outputData = [ + 'integration' => SettingsHubspot::SETTINGS_TYPE_KEY, + 'params' => $body, + 'files' => $files, + 'response' => $response['body'], + 'listId' => $itemId, + 'formId' => $formId, + ]; + $output = [ 'status' => 'error', 'code' => $code, 'message' => $this->getErrorMsg($responseMessage, $responseErrors), + 'data' => $outputData, ]; - Helper::logger([ - 'integration' => 'hubspot', - 'type' => 'service', - 'body' => $body, - 'response' => $response['response'], - 'responseBody' => $responseBody, - 'output' => $output, - ]); + Helper::logger($outputData); + + error_log( print_r( ( $output ), true ) ); + return $output; } diff --git a/src/Integrations/Mailchimp/MailchimpClient.php b/src/Integrations/Mailchimp/MailchimpClient.php index 8f68ae9e9..8a073c68e 100644 --- a/src/Integrations/Mailchimp/MailchimpClient.php +++ b/src/Integrations/Mailchimp/MailchimpClient.php @@ -177,24 +177,9 @@ public function postApplication(string $itemId, array $params, array $files, str ] ); - if (\is_wp_error($response)) { - Helper::logger([ - 'integration' => 'mailchimp', - 'type' => 'wp', - 'body' => $body, - 'response' => $response, - ]); - - return [ - 'status' => 'error', - 'code' => 400, - 'message' => $this->getErrorMsg('submitWpError'), - ]; - } - $code = $response['response']['code'] ? $response['response']['code'] : 200; - if ($code === 200) { + if ($code >= 200 && $code <= 299) { return [ 'status' => 'success', 'code' => $code, @@ -206,20 +191,23 @@ public function postApplication(string $itemId, array $params, array $files, str $responseMessage = $responseBody['detail'] ?? ''; $responseErrors = $responseBody['errors'] ?? []; + $outputData = [ + 'integration' => SettingsMailchimp::SETTINGS_TYPE_KEY, + 'params' => $body, + 'files' => $files, + 'response' => $response['body'], + 'listId' => $itemId, + 'formId' => $formId, + ]; + $output = [ 'status' => 'error', 'code' => $code, 'message' => $this->getErrorMsg($responseMessage, $responseErrors), + 'data' => $outputData, ]; - Helper::logger([ - 'integration' => 'mailchimp', - 'type' => 'service', - 'body' => $body, - 'response' => $response['response'], - 'responseBody' => $responseBody, - 'output' => $output, - ]); + Helper::logger($outputData); return $output; } diff --git a/src/Integrations/Mailerlite/MailerliteClient.php b/src/Integrations/Mailerlite/MailerliteClient.php index b6af010eb..0397dbcd4 100644 --- a/src/Integrations/Mailerlite/MailerliteClient.php +++ b/src/Integrations/Mailerlite/MailerliteClient.php @@ -141,23 +141,9 @@ public function postApplication(string $itemId, array $params, array $files, str ] ); - if (\is_wp_error($response)) { - Helper::logger([ - 'integration' => 'mailerlite', - 'type' => 'wp', - 'body' => $body, - 'response' => $response, - ]); - return [ - 'status' => 'error', - 'code' => 400, - 'message' => $this->getErrorMsg('submitWpError'), - ]; - } - $code = $response['response']['code'] ? $response['response']['code'] : 200; - if ($code === 200) { + if ($code >= 200 && $code <= 299) { return [ 'status' => 'success', 'code' => $code, @@ -168,20 +154,23 @@ public function postApplication(string $itemId, array $params, array $files, str $responseBody = \json_decode(\wp_remote_retrieve_body($response), true); $responseMessage = $responseBody['error']['message'] ?? ''; + $outputData = [ + 'integration' => SettingsMailerlite::SETTINGS_TYPE_KEY, + 'params' => $body, + 'files' => $files, + 'response' => $response['body'], + 'listId' => $itemId, + 'formId' => $formId, + ]; + $output = [ 'status' => 'error', 'code' => $code, 'message' => $this->getErrorMsg($responseMessage), + 'data' => $outputData, ]; - Helper::logger([ - 'integration' => 'mailerlite', - 'type' => 'service', - 'body' => $body, - 'response' => $response['response'], - 'responseBody' => $responseBody, - 'output' => $output, - ]); + Helper::logger($outputData); return $output; } diff --git a/src/Mailer/Mailer.php b/src/Mailer/Mailer.php index 589d0a9d7..b0bca7f91 100644 --- a/src/Mailer/Mailer.php +++ b/src/Mailer/Mailer.php @@ -10,8 +10,10 @@ namespace EightshiftForms\Mailer; +use CURLFile; use EightshiftForms\Rest\Routes\AbstractBaseRoute; use EightshiftForms\Settings\SettingsHelper; +use EightshiftForms\Troubleshooting\SettingsTroubleshooting; use EightshiftFormsVendor\EightshiftLibs\Helpers\Components; /** @@ -64,6 +66,81 @@ public function sendFormEmail( return \wp_mail($to, $subject, $templateHtml, $headers, $files); } + /** + * Send fallback email + * + * @param array $data Data to extract data from. + * + * @return boolean + */ + public function fallbackEmail(array $data): bool + { + $isSettingsValid = apply_filters(SettingsTroubleshooting::FILTER_SETTINGS_IS_VALID_NAME, []); + + if (!$isSettingsValid) { + return false; + } + + $integration = $data['integration'] ?? ''; + $files = $data['files'] ?? []; + $response = $data['response'] ?? ''; + $formId = $data['formId'] ?? ''; + $listId = $data['listId'] ?? ''; + $params = $data['params'] ?? []; + + if (is_array($listId)) { + $listId = implode(', ', $listId); + } + + $paramsOutput = " +

Form Details:

+
    +
  • formId: {$formId}
  • +
  • listId: {$listId}
  • +
  • integration: {$integration}
  • +
+ "; + + if ($params) { + $paramsOutput .= "

Data sent to integration:

"; + $paramsOutput .= $this->fallbackEmailPrepareParams($params); + } + + $paramsOutput .= " +

Data got from integration response:

+ {$response} + "; + + $filesOutput = []; + if ($files) { + foreach ($files as $file) { + if ($file instanceof CURLFile) { + $filesOutput[] = $file->name; + } + + if (is_array($file)) { + foreach ($file as $fileItem) { + if (isset($fileItem['path'])) { + $filesOutput[] = $fileItem['path']; + } + } + } + } + } + + $to = $this->getOptionValue(SettingsTroubleshooting::SETTINGS_TROUBLESHOOTING_FALLBACK_EMAIL_KEY); + $subject = sprintf(__("Your %s form failed: %s", 'eightshift-forms'), $integration, $formId); + $headers = $this->getType(); + $templateHtml = sprintf(__(" +

It looks like something went wrong with the users form submition, here is all the data to debug.

+ %s", 'eightshift-forms'), + $paramsOutput + ); + + // Send email. + return \wp_mail($to, $subject, $templateHtml, $headers, $filesOutput); + } + /** * Get Email type. * We use HTML for all. @@ -213,4 +290,30 @@ protected function prepareFiles(array $files): array return $output; } + + /** + * Prepare recursive params for fallback email. + * + * @param array $params Params to check. + * + * @return string + */ + private function fallbackEmailPrepareParams(array $params): string + { + $output = ''; + + foreach($params as $paramKey => $paramValue) { + if (is_array($paramValue)) { + $paramValueOutput = '
    '; + $paramValueOutput .= $this->fallbackEmailPrepareParams($paramValue); + $paramValueOutput .= '
'; + + $paramValue = $paramValueOutput; + } + + $output .= "
  • {$paramKey}: {$paramValue}
  • "; + } + + return $output; + } } diff --git a/src/Mailer/MailerInterface.php b/src/Mailer/MailerInterface.php index d301e7b0c..18e019c84 100644 --- a/src/Mailer/MailerInterface.php +++ b/src/Mailer/MailerInterface.php @@ -35,4 +35,13 @@ public function sendFormEmail( array $files = [], array $fields = [] ): bool; + + /** + * Send fallback email. + * + * @param array $data Data to extract data from. + * + * @return boolean + */ + public function fallbackEmail (array $data): bool; } diff --git a/src/Rest/Routes/FormSubmitGoodbitsRoute.php b/src/Rest/Routes/FormSubmitGoodbitsRoute.php index f83e44279..4c06c0e67 100644 --- a/src/Rest/Routes/FormSubmitGoodbitsRoute.php +++ b/src/Rest/Routes/FormSubmitGoodbitsRoute.php @@ -15,6 +15,7 @@ use EightshiftForms\Integrations\ClientInterface; use EightshiftForms\Integrations\Goodbits\SettingsGoodbits; use EightshiftForms\Labels\LabelsInterface; +use EightshiftForms\Mailer\MailerInterface; use EightshiftForms\Validation\ValidatorInterface; /** @@ -53,21 +54,31 @@ class FormSubmitGoodbitsRoute extends AbstractFormSubmit */ protected $goodbitsClient; + /** + * Instance variable of MailerInterface data. + * + * @var MailerInterface + */ + public $mailer; + /** * Create a new instance that injects classes * * @param ValidatorInterface $validator Inject ValidatorInterface which holds validation methods. * @param LabelsInterface $labels Inject LabelsInterface which holds labels data. * @param ClientInterface $goodbitsClient Inject Goodbits which holds Goodbits connect data. + * @param MailerInterface $mailer Inject MailerInterface which holds mailer methods. */ public function __construct( ValidatorInterface $validator, LabelsInterface $labels, - ClientInterface $goodbitsClient + ClientInterface $goodbitsClient, + MailerInterface $mailer ) { $this->validator = $validator; $this->labels = $labels; $this->goodbitsClient = $goodbitsClient; + $this->mailer = $mailer; } /** @@ -112,6 +123,11 @@ public function submitAction(string $formId, array $params = [], $files = []) $formId ); + if ($response['status'] === 'error') { + // Send fallback email. + $this->mailer->fallbackEmail($response['data'] ?? []); + } + // Finish. return \rest_ensure_response([ 'code' => $response['code'], diff --git a/src/Rest/Routes/FormSubmitGreenhouseRoute.php b/src/Rest/Routes/FormSubmitGreenhouseRoute.php index 4e625fd62..7aa7fa9bd 100644 --- a/src/Rest/Routes/FormSubmitGreenhouseRoute.php +++ b/src/Rest/Routes/FormSubmitGreenhouseRoute.php @@ -15,6 +15,7 @@ use EightshiftForms\Integrations\Greenhouse\SettingsGreenhouse; use EightshiftForms\Integrations\ClientInterface; use EightshiftForms\Labels\LabelsInterface; +use EightshiftForms\Mailer\MailerInterface; use EightshiftForms\Validation\ValidatorInterface; /** @@ -53,21 +54,31 @@ class FormSubmitGreenhouseRoute extends AbstractFormSubmit */ protected $greenhouseClient; + /** + * Instance variable of MailerInterface data. + * + * @var MailerInterface + */ + public $mailer; + /** * Create a new instance that injects classes * * @param ValidatorInterface $validator Inject ValidatorInterface which holds validation methods. * @param LabelsInterface $labels Inject LabelsInterface which holds labels data. * @param ClientInterface $greenhouseClient Inject ClientInterface which holds Greenhouse connect data. + * @param MailerInterface $mailer Inject MailerInterface which holds mailer methods. */ public function __construct( ValidatorInterface $validator, LabelsInterface $labels, - ClientInterface $greenhouseClient + ClientInterface $greenhouseClient, + MailerInterface $mailer ) { $this->validator = $validator; $this->labels = $labels; $this->greenhouseClient = $greenhouseClient; + $this->mailer = $mailer; } /** @@ -112,6 +123,11 @@ public function submitAction(string $formId, array $params = [], $files = []) $formId ); + if ($response['status'] === 'error') { + // Send fallback email. + $this->mailer->fallbackEmail($response['data'] ?? []); + } + // Always delete the files from the disk. if ($files) { $this->deleteFiles($files); diff --git a/src/Rest/Routes/FormSubmitHubspotRoute.php b/src/Rest/Routes/FormSubmitHubspotRoute.php index 730208aed..bfd74cd32 100644 --- a/src/Rest/Routes/FormSubmitHubspotRoute.php +++ b/src/Rest/Routes/FormSubmitHubspotRoute.php @@ -18,6 +18,7 @@ use EightshiftForms\Integrations\Hubspot\HubspotClientInterface; use EightshiftForms\Integrations\Hubspot\SettingsHubspot; use EightshiftForms\Labels\LabelsInterface; +use EightshiftForms\Mailer\MailerInterface; use EightshiftForms\Validation\ValidatorInterface; /** @@ -63,6 +64,13 @@ class FormSubmitHubspotRoute extends AbstractFormSubmit */ protected $clearbitClient; + /** + * Instance variable of MailerInterface data. + * + * @var MailerInterface + */ + public $mailer; + /** * Create a new instance that injects classes * @@ -70,17 +78,20 @@ class FormSubmitHubspotRoute extends AbstractFormSubmit * @param LabelsInterface $labels Inject LabelsInterface which holds labels data. * @param HubspotClientInterface $hubspotClient Inject HubSpot which holds HubSpot connect data. * @param ClearbitClientInterface $clearbitClient Inject Clearbit which holds clearbit connect data. + * @param MailerInterface $mailer Inject MailerInterface which holds mailer methods. */ public function __construct( ValidatorInterface $validator, LabelsInterface $labels, HubspotClientInterface $hubspotClient, - ClearbitClientInterface $clearbitClient + ClearbitClientInterface $clearbitClient, + MailerInterface $mailer ) { $this->validator = $validator; $this->labels = $labels; $this->hubspotClient = $hubspotClient; $this->clearbitClient = $clearbitClient; + $this->mailer = $mailer; } /** @@ -143,6 +154,11 @@ public function submitAction(string $formId, array $params = [], $files = []) } } + if ($response['status'] === 'error') { + // Send fallback email. + $this->mailer->fallbackEmail($response['data'] ?? []); + } + // Always delete the files from the disk. if ($files) { $this->deleteFiles($files); diff --git a/src/Rest/Routes/FormSubmitMailchimpRoute.php b/src/Rest/Routes/FormSubmitMailchimpRoute.php index 7048c34cf..42ad7e52e 100644 --- a/src/Rest/Routes/FormSubmitMailchimpRoute.php +++ b/src/Rest/Routes/FormSubmitMailchimpRoute.php @@ -13,6 +13,7 @@ use EightshiftForms\Integrations\Mailchimp\MailchimpClientInterface; use EightshiftForms\Integrations\Mailchimp\SettingsMailchimp; use EightshiftForms\Labels\LabelsInterface; +use EightshiftForms\Mailer\MailerInterface; use EightshiftForms\Validation\ValidatorInterface; /** @@ -41,21 +42,31 @@ class FormSubmitMailchimpRoute extends AbstractFormSubmit */ protected $mailchimpClient; + /** + * Instance variable of MailerInterface data. + * + * @var MailerInterface + */ + public $mailer; + /** * Create a new instance that injects classes * * @param ValidatorInterface $validator Inject ValidatorInterface which holds validation methods. * @param LabelsInterface $labels Inject LabelsInterface which holds labels data. * @param MailchimpClientInterface $mailchimpClient Inject Mailchimp which holds Mailchimp connect data. + * @param MailerInterface $mailer Inject MailerInterface which holds mailer methods. */ public function __construct( ValidatorInterface $validator, LabelsInterface $labels, - MailchimpClientInterface $mailchimpClient + MailchimpClientInterface $mailchimpClient, + MailerInterface $mailer ) { $this->validator = $validator; $this->labels = $labels; $this->mailchimpClient = $mailchimpClient; + $this->mailer = $mailer; } /** @@ -99,6 +110,11 @@ public function submitAction(string $formId, array $params = [], $files = []) $formId ); + if ($response['status'] === 'error') { + // Send fallback email. + $this->mailer->fallbackEmail($response['data'] ?? []); + } + // Finish. return \rest_ensure_response([ 'code' => $response['code'], diff --git a/src/Rest/Routes/FormSubmitMailerliteRoute.php b/src/Rest/Routes/FormSubmitMailerliteRoute.php index b1e770cb5..9b09cb876 100644 --- a/src/Rest/Routes/FormSubmitMailerliteRoute.php +++ b/src/Rest/Routes/FormSubmitMailerliteRoute.php @@ -15,6 +15,7 @@ use EightshiftForms\Integrations\ClientInterface; use EightshiftForms\Integrations\Mailerlite\SettingsMailerlite; use EightshiftForms\Labels\LabelsInterface; +use EightshiftForms\Mailer\MailerInterface; use EightshiftForms\Validation\ValidatorInterface; /** @@ -53,21 +54,32 @@ class FormSubmitMailerliteRoute extends AbstractFormSubmit */ protected $mailerliteClient; + /** + * Instance variable of MailerInterface data. + * + * @var MailerInterface + */ + public $mailer; + /** * Create a new instance that injects classes * * @param ValidatorInterface $validator Inject ValidatorInterface which holds validation methods. * @param LabelsInterface $labels Inject LabelsInterface which holds labels data. * @param ClientInterface $mailerliteClient Inject Mailerlite which holds Mailerlite connect data. + * @param MailerInterface $mailer Inject MailerInterface which holds mailer methods. */ public function __construct( ValidatorInterface $validator, LabelsInterface $labels, - ClientInterface $mailerliteClient + ClientInterface $mailerliteClient, + MailerInterface $mailer + ) { $this->validator = $validator; $this->labels = $labels; $this->mailerliteClient = $mailerliteClient; + $this->mailer = $mailer; } /** @@ -112,6 +124,11 @@ public function submitAction(string $formId, array $params = [], $files = []) $formId ); + if ($response['status'] === 'error') { + // Send fallback email. + $this->mailer->fallbackEmail($response['data'] ?? []); + } + // Finish. return \rest_ensure_response([ 'code' => $response['code'], diff --git a/src/Troubleshooting/SettingsTroubleshooting.php b/src/Troubleshooting/SettingsTroubleshooting.php new file mode 100644 index 000000000..c649fa911 --- /dev/null +++ b/src/Troubleshooting/SettingsTroubleshooting.php @@ -0,0 +1,164 @@ +isCheckboxOptionChecked(self::SETTINGS_TROUBLESHOOTING_USE_KEY, self::SETTINGS_TROUBLESHOOTING_USE_KEY); + $email = $this->getOptionValue(self::SETTINGS_TROUBLESHOOTING_FALLBACK_EMAIL_KEY); + + if (!$isUsed || empty($email)) { + return false; + } + + return true; + } + + /** + * Get Settings sidebar data. + * + * @return array + */ + public function getSettingsSidebar(): array + { + return [ + 'label' => \__('Troubleshooting', 'eightshift-forms'), + 'value' => self::SETTINGS_TYPE_KEY, + 'icon' => Filters::ALL[self::SETTINGS_TYPE_KEY]['icon'], + ]; + } + + /** + * Get Form settings data array + * + * @param string $formId Form Id. + * + * @return array> + */ + public function getSettingsData(string $formId): array + { + return []; + } + + /** + * Get global settings array for building settings page. + * + * @return array> + */ + public function getSettingsGlobalData(): array + { + $output = [ + [ + 'component' => 'intro', + 'introTitle' => \__('Fallback emails', 'eightshift-forms'), + 'introSubtitle' => \__('Your forms will send email fallbacks with all the data if there is any kind of error. This can email can be used to debug or provide manual input of the data to any integration.', 'eightshift-forms'), + ], + [ + 'component' => 'checkboxes', + 'checkboxesFieldLabel' => '', + 'checkboxesName' => $this->getSettingsName(self::SETTINGS_TROUBLESHOOTING_USE_KEY), + 'checkboxesId' => $this->getSettingsName(self::SETTINGS_TROUBLESHOOTING_USE_KEY), + 'checkboxesContent' => [ + [ + 'component' => 'checkbox', + 'checkboxLabel' => \__('Use Fallback emails', 'eightshift-forms'), + 'checkboxIsChecked' => $this->isCheckboxOptionChecked(self::SETTINGS_TROUBLESHOOTING_USE_KEY, self::SETTINGS_TROUBLESHOOTING_USE_KEY), + 'checkboxValue' => self::SETTINGS_TROUBLESHOOTING_USE_KEY, + 'checkboxSingleSubmit' => true, + ] + ] + ], + ]; + + $isUsedFallbackEmails = $this->isCheckboxOptionChecked(self::SETTINGS_TROUBLESHOOTING_USE_KEY, self::SETTINGS_TROUBLESHOOTING_USE_KEY); + + if ($isUsedFallbackEmails) { + $output[] = [ + 'component' => 'input', + 'inputName' => $this->getSettingsName(self::SETTINGS_TROUBLESHOOTING_FALLBACK_EMAIL_KEY), + 'inputId' => $this->getSettingsName(self::SETTINGS_TROUBLESHOOTING_FALLBACK_EMAIL_KEY), + 'inputFieldLabel' => \__('Fallback e-mail', 'eightshift-forms'), + 'inputFieldHelp' => \__('Set email where all fallback emails will be sent.', 'eightshift-forms'), + 'inputType' => 'text', + 'inputIsEmail' => true, + 'inputIsRequired' => true, + 'inputValue' => $this->getOptionValue(self::SETTINGS_TROUBLESHOOTING_FALLBACK_EMAIL_KEY), + ]; + } + + return $output; + } +} From 96ffa4d54587c555c17b74f155be06ca4aaef959 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20Ruz=CC=8Cevic=CC=81?= Date: Mon, 5 Sep 2022 13:04:18 +0200 Subject: [PATCH 06/12] conveting ali api responses to usage of helper --- src/Helpers/Helper.php | 2 +- .../ActiveCampaign/ActiveCampaignClient.php | 333 +++++++++--------- src/Integrations/Clearbit/ClearbitClient.php | 173 +++++---- .../Clearbit/ClearbitClientInterface.php | 8 +- src/Integrations/Goodbits/GoodbitsClient.php | 71 ++-- .../Greenhouse/GreenhouseClient.php | 110 +++--- src/Integrations/Hubspot/HubspotClient.php | 229 ++++++------ .../Mailchimp/MailchimpClient.php | 134 ++++--- .../Mailerlite/MailerliteClient.php | 112 +++--- src/Mailer/Mailer.php | 46 ++- src/Mailer/MailerInterface.php | 2 +- src/Rest/ApiHelper.php | 107 +++--- .../Routes/FormSubmitActiveCampaignRoute.php | 20 +- src/Rest/Routes/FormSubmitCustomRoute.php | 3 +- src/Rest/Routes/FormSubmitHubspotRoute.php | 38 +- src/Rest/Routes/FormSubmitMailerliteRoute.php | 1 - .../SettingsTroubleshooting.php | 5 +- 17 files changed, 740 insertions(+), 654 deletions(-) diff --git a/src/Helpers/Helper.php b/src/Helpers/Helper.php index 927808647..1342fb028 100644 --- a/src/Helpers/Helper.php +++ b/src/Helpers/Helper.php @@ -202,7 +202,7 @@ public static function logger(array $message): void if (!empty($wpContentDir)) { $message['time'] = \gmdate("Y-m-d H:i:s"); - + if (isset($message['files'])) { unset($message['files']); } diff --git a/src/Integrations/ActiveCampaign/ActiveCampaignClient.php b/src/Integrations/ActiveCampaign/ActiveCampaignClient.php index f0e71281a..cb5ec338d 100644 --- a/src/Integrations/ActiveCampaign/ActiveCampaignClient.php +++ b/src/Integrations/ActiveCampaign/ActiveCampaignClient.php @@ -120,65 +120,70 @@ public function getItem(string $itemId): array */ public function postApplication(string $itemId, array $params, array $files, string $formId): array { + $params = $this->prepareParams($params); + // Map body. $requestBody = [ - 'contact' => $this->prepareParams($params), + 'contact' => $params, ]; + $url = "{$this->getBaseUrl()}contacts"; + // Make an API request. - $response = \wp_remote_request( - "{$this->getBaseUrl()}contacts", + $response = \wp_remote_post( + $url, [ 'headers' => $this->getHeaders(), - 'method' => 'POST', 'body' => \wp_json_encode($requestBody), ] ); - // Output response details. - $details = $this->getApiReponseDetails($response); + // Structure response details. + $details = $this->getApiReponseDetails( + SettingsActiveCampaign::SETTINGS_TYPE_KEY, + $response, + $url, + $params, + $files, + $itemId, + $formId + ); + $code = $details['code']; $body = $details['body']; - switch ($code) { - case 200: - case 201: - return $this->getApiSuccessOutput( - SettingsActiveCampaign::SETTINGS_TYPE_KEY, - [ - 'contactId' => $body['contact']['id'], - ] - ); + // On success return output. + if ($code >= 200 && $code <= 299) { + return $this->getApiSuccessOutput( + $details, + [ + 'contactId' => $body['contact']['id'], + ] + ); + } + + // Filter different error outputs. + switch ($details['code']) { case 403: - return $this->getApiErrorOutput( - SettingsActiveCampaign::SETTINGS_TYPE_KEY, - $details, - $requestBody, - $this->getErrorMsg([ - [ - 'code' => 'activeCampaignForbidden', - ] - ]), - ); + $error = 'activeCampaignForbidden'; + break; case 500: - return $this->getApiErrorOutput( - SettingsActiveCampaign::SETTINGS_TYPE_KEY, - $details, - $requestBody, - $this->getErrorMsg([ - [ - 'code' => 'activeCampaign500', - ] - ]), - ); + $error = 'activeCampaign500'; + break; default: - return $this->getApiErrorOutput( - SettingsActiveCampaign::SETTINGS_TYPE_KEY, - $details, - $requestBody, - $this->getErrorMsg($body['errors'] ?? []), - ); + $error = $body['errors'] ?? []; + break; } + + // Output error. + return $this->getApiErrorOutput( + $details, + $this->getErrorMsg([ + [ + 'code' => $error, + ] + ]), + ); } /** @@ -208,44 +213,37 @@ public function postTag(string $tag, string $contactId): array ]; // Make request to map contact with tags. - $response = \wp_remote_request( - "{$this->getBaseUrl()}contactTags", + $url = "{$this->getBaseUrl()}contactTags"; + + $response = \wp_remote_post( + $url, [ 'headers' => $this->getHeaders(), - 'method' => 'POST', 'body' => \wp_json_encode($requestBody), ] ); - // Output response details. - $details = $this->getApiReponseDetails($response); + // Structure response details. + $details = $this->getApiReponseDetails( + SettingsActiveCampaign::SETTINGS_TYPE_KEY, + $response, + $url, + $requestBody + ); + $code = $details['code']; $body = $details['body']; - // Bailout on wp error. - if (\is_wp_error($response)) { - return $this->getApiWpErrorOutput( - SettingsActiveCampaign::SETTINGS_TYPE_KEY, - $details, - $requestBody, - $response->get_error_message() - ); + // On success return output. + if ($code >= 200 && $code <= 299) { + return $this->getApiSuccessOutput($details); } - switch ($code) { - case 200: - case 201: - return $this->getApiSuccessOutput( - SettingsActiveCampaign::SETTINGS_TYPE_KEY, - ); - default: - return $this->getApiErrorOutput( - SettingsActiveCampaign::SETTINGS_TYPE_KEY, - $details, - $requestBody, - $this->getErrorMsg($body['errors'] ?? []), - ); - } + // Output error. + return $this->getApiErrorOutput( + $details, + $this->getErrorMsg($body), + ); } /** @@ -268,44 +266,36 @@ public function postList(string $list, string $contactId): array ]; // Make request to map contact with lists. - $response = \wp_remote_request( - "{$this->getBaseUrl()}contactLists", + $url = "{$this->getBaseUrl()}contactLists"; + + $response = \wp_remote_post( + $url, [ 'headers' => $this->getHeaders(), - 'method' => 'POST', 'body' => \wp_json_encode($requestBody), ] ); - // Output response details. - $details = $this->getApiReponseDetails($response); + // Structure response details. + $details = $this->getApiReponseDetails( + SettingsActiveCampaign::SETTINGS_TYPE_KEY, + $response, + $url + ); + $code = $details['code']; $body = $details['body']; - // Bailout on wp error. - if (\is_wp_error($response)) { - return $this->getApiWpErrorOutput( - SettingsActiveCampaign::SETTINGS_TYPE_KEY, - $details, - $requestBody, - $response->get_error_message() - ); + // On success return output. + if ($code >= 200 && $code <= 299) { + return $this->getApiSuccessOutput($details); } - switch ($code) { - case 200: - case 201: - return $this->getApiSuccessOutput( - SettingsActiveCampaign::SETTINGS_TYPE_KEY, - ); - default: - return $this->getApiErrorOutput( - SettingsActiveCampaign::SETTINGS_TYPE_KEY, - $details, - $requestBody, - $this->getErrorMsg($body['errors'] ?? []), - ); - } + // Output error. + return $this->getApiErrorOutput( + $details, + $this->getErrorMsg($body), + ); } /** @@ -319,56 +309,48 @@ private function getExistingTagId(string $tag): string { $requestBody = []; + $url = "{$this->getBaseUrl()}tags"; + // Make api request to check if tag exists. - $response = \wp_remote_request( - "{$this->getBaseUrl()}tags", + $response = \wp_remote_get( + $url, [ 'headers' => $this->getHeaders(), - 'method' => 'GET', ] ); - // Output response details. - $details = $this->getApiReponseDetails($response); + // Structure response details. + $details = $this->getApiReponseDetails( + SettingsActiveCampaign::SETTINGS_TYPE_KEY, + $response, + $url + ); + $code = $details['code']; $body = $details['body']; - // Bailout on wp error. - if (\is_wp_error($response)) { - $this->getApiWpErrorOutput( - SettingsActiveCampaign::SETTINGS_TYPE_KEY, - $details, - $requestBody, - $response->get_error_message() + // On success return output. + if ($code >= 200 && $code <= 299) { + // Find tag id from array. + $tagId = \array_filter( + $body['tags'], + static function ($item) use ($tag) { + return $item['tag'] === $tag && $item['tagType'] === 'contact'; + } ); - return ''; - } + $tagId = \array_values($tagId); - switch ($code) { - case 200: - case 201: - // Find tag id from array. - $tagId = \array_filter( - $body['tags'], - static function ($item) use ($tag) { - return $item['tag'] === $tag && $item['tagType'] === 'contact'; - } - ); + return $tagId[0]['id'] ?? ''; + } - $tagId = \array_values($tagId); + // Output error. + $this->getApiErrorOutput( + $details, + $this->getErrorMsg($body), + ); - return $tagId[0]['id'] ?? ''; - default: - $this->getApiErrorOutput( - SettingsActiveCampaign::SETTINGS_TYPE_KEY, - $details, - $requestBody, - $this->getErrorMsg($body['errors'] ?? []), - ); - - return ''; - } + return ''; } /** @@ -388,64 +370,57 @@ private function createNewTag(string $tag): string ], ]; + $url = "{$this->getBaseUrl()}tags"; + // Make api request to create a new tag. - $response = \wp_remote_request( - "{$this->getBaseUrl()}tags", + $response = \wp_remote_post( + $url, [ 'headers' => $this->getHeaders(), - 'method' => 'POST', 'body' => \wp_json_encode($requestBody), ] ); - // Output response details. - $details = $this->getApiReponseDetails($response); + // Structure response details. + $details = $this->getApiReponseDetails( + SettingsActiveCampaign::SETTINGS_TYPE_KEY, + $response, + $url, + $requestBody + ); + $code = $details['code']; $body = $details['body']; - // Bailout on wp error. - if (\is_wp_error($response)) { - $this->getApiWpErrorOutput( - SettingsActiveCampaign::SETTINGS_TYPE_KEY, - $details, - $requestBody, - $response->get_error_message() - ); - - return ''; + // On success return output. + if ($code >= 200 && $code <= 299) { + return $body['id'] ?? ''; } - switch ($code) { - case 200: - case 201: - return $body['id'] ?? ''; - default: - $this->getApiErrorOutput( - SettingsActiveCampaign::SETTINGS_TYPE_KEY, - $details, - $requestBody, - $this->getErrorMsg($body['errors'] ?? []), - ); - - return ''; - } + // Output error. + $this->getApiErrorOutput( + $details, + $this->getErrorMsg($body), + ); + + return ''; } /** * Map service messages with our own. * - * @param array> $errors Additional errors got from the API. + * @param array $body API response body. * * @return string */ - private function getErrorMsg(array $errors): string + private function getErrorMsg(array $body): string { $msg = ''; $code = ''; - if ($errors && isset($errors[0])) { - $code = $errors[0]['code'] ?? ''; - $msg = $errors[0]['error'] ?? ''; + if (isset($body[0]['code'])) { + $code = $body[0]['code'] ?? ''; + $msg = $body[0]['error'] ?? ''; } if (!$msg) { @@ -490,17 +465,23 @@ private function getHeaders(): array */ private function getActiveCampaignListFields(string $listId) { + $url = "{$this->getBaseUrl()}forms/{$listId}"; + // Make api request to get form details. $response = \wp_remote_get( - "{$this->getBaseUrl()}forms/{$listId}", + $url, [ 'headers' => $this->getHeaders(), - 'timeout' => 60, ] ); - // Output response details. - $details = $this->getApiReponseDetails($response); + // Structure response details. + $details = $this->getApiReponseDetails( + SettingsActiveCampaign::SETTINGS_TYPE_KEY, + $response, + $url + ); + $body = $details['body']; // Bailout if fields are missing. @@ -552,16 +533,22 @@ private function getActiveCampaignListFields(string $listId) */ private function getActiveCampaignLists() { + $url = "{$this->getBaseUrl()}forms"; + $response = \wp_remote_get( - "{$this->getBaseUrl()}forms", + $url, [ 'headers' => $this->getHeaders(), - 'timeout' => 60, ] ); - // Output response details. - $details = $this->getApiReponseDetails($response); + // Structure response details. + $details = $this->getApiReponseDetails( + SettingsActiveCampaign::SETTINGS_TYPE_KEY, + $response, + $url + ); + $body = $details['body']; if (!isset($body['forms'])) { diff --git a/src/Integrations/Clearbit/ClearbitClient.php b/src/Integrations/Clearbit/ClearbitClient.php index 7d79bf9f8..0b7aea0f0 100644 --- a/src/Integrations/Clearbit/ClearbitClient.php +++ b/src/Integrations/Clearbit/ClearbitClient.php @@ -10,10 +10,12 @@ namespace EightshiftForms\Integrations\Clearbit; -use EightshiftForms\Helpers\Helper; use EightshiftForms\Hooks\Filters; use EightshiftForms\Hooks\Variables; +use EightshiftForms\Rest\ApiHelper; +use EightshiftForms\Rest\Routes\AbstractBaseRoute; use EightshiftForms\Settings\SettingsHelper; +use EightshiftFormsVendor\EightshiftLibs\Helpers\Components; use EightshiftFormsVendor\EightshiftLibs\Helpers\ObjectHelperTrait; /** @@ -31,6 +33,11 @@ class ClearbitClient implements ClearbitClientInterface */ use ObjectHelperTrait; + /** + * Use API helper trait. + */ + use ApiHelper; + /** * Return Clearbit base url. * @@ -41,115 +48,70 @@ class ClearbitClient implements ClearbitClientInterface /** * API request to post application. * - * @param string $emailKey Email key to map in params. + * @param string $email Email key to map in params. * @param array $params Params array. * @param array $mapData Map data from settings. + * @param string $itemId Item id to search. + * @param string $formId FormId value. * * @return array */ - public function getApplication(string $emailKey, array $params, array $mapData): array + public function getApplication(string $email, array $params, array $mapData, string $itemId, string $formId): array { - $email = isset($params[$emailKey]['value']) ? $params[$emailKey]['value'] : ''; - - if (!$email) { - $output = [ - 'status' => 'error', - 'code' => 400, - 'message' => 'clearbitMissingEmail', - ]; - - Helper::logger([ - 'integration' => 'clearbit', - 'email' => $email, - 'mapKeys' => $mapData, - 'output' => $output, - ]); - - return $output; - } + $url = self::BASE_URL . "combined/find?email={$email}"; - if (!$mapData) { - $output = [ - 'status' => 'error', - 'code' => 400, - 'message' => 'clearbitMissingMapKeys', - ]; - - Helper::logger([ - 'integration' => 'clearbit', - 'email' => $email, - 'mapKeys' => $mapData, - 'output' => $output, - ]); - - return $output; - } + $params = $this->prepareParamsOutput($params); $response = \wp_remote_get( - self::BASE_URL . "combined/find?email={$email}", + $url, [ 'headers' => $this->getHeaders(), ] ); - if (\is_wp_error($response)) { - Helper::logger([ - 'integration' => 'clearbit', - 'type' => 'wp', - 'email' => $email, - 'mapKeys' => $mapData, - 'response' => $response, - ]); - return [ - 'status' => 'error', - 'code' => 400, - 'message' => $this->getErrorMsg('submitWpError'), - ]; - } - - $code = $response['response']['code'] ? $response['response']['code'] : 200; + // Structure response details. + $details = $this->getApiReponseDetails( + SettingsClearbit::SETTINGS_TYPE_KEY, + $response, + $url, + $params, + [], + $itemId, + $formId + ); - $responseBody = \json_decode(\wp_remote_retrieve_body($response), true); + $code = $details['code']; + $body = $details['body']; - if ($code === 200) { + // On success return output. + if ($code >= 200 && $code <= 299) { $dataOutput = []; - foreach ($this->prepareParams($responseBody) as $key => $value) { + foreach ($this->prepareParams($body) as $key => $value) { if (\array_key_exists($key, $mapData) && !empty($value) && !empty($mapData[$key])) { $dataOutput[$mapData[$key]] = $value; } } - return [ - 'status' => 'success', - 'type' => 'service', - 'code' => $code, - 'message' => 'clearbitSuccess', - 'email' => $email, - 'data' => $dataOutput, - ]; + return $this->getApiSuccessOutput( + $details, + [ + 'email' => $email, + 'data' => $dataOutput, + ] + ); } - $responseMessage = $responseBody['error']['type'] ?? ''; - - $output = [ - 'status' => 'error', - 'code' => $code, - 'email' => $email, - 'mapKeys' => $mapData, - 'message' => $this->getErrorMsg($responseMessage), - ]; - - Helper::logger([ - 'integration' => 'clearbit', - 'email' => $email, - 'mapKeys' => $mapData, - 'response' => $response['response'], - 'responseBody' => $responseBody, - 'output' => $output, - ]); - - return $output; + // Output error. + return $this->getApiErrorOutput( + \array_merge( + $details, + [ + 'email' => $email, + ] + ), + $this->getErrorMsg($body), + ); } /** @@ -168,6 +130,39 @@ public function getParams(): array return $output; } + /** + * Prepare params for api. + * + * @param array $params Params. + * + * @return array + */ + private function prepareParamsOutput(array $params = []): array + { + $output = []; + + $customFields = \array_flip(Components::flattenArray(AbstractBaseRoute::CUSTOM_FORM_PARAMS)); + + foreach ($params as $key => $param) { + // Remove unecesery fields. + if (isset($customFields[$key])) { + continue; + } + + if (!isset($param['value'])) { + continue; + } + + if (!isset($param['type']) || $param['type'] === 'hidden') { + continue; + } + + $output[$key] = $param; + } + + return $output; + } + /** * Prepare params * @@ -305,15 +300,19 @@ private function prepareParams(array $params = []): array /** * Map service messages with our own. * - * @param string $msg Message got from the API. + * @param array $body API response body. * * @return string */ - private function getErrorMsg(string $msg): string + private function getErrorMsg(array $body): string { + $msg = $body['error']['type'] ?? ''; + switch ($msg) { case 'auth_required': return 'clearbitAuthRequired'; + case 'email_invalid': + return 'clearbitInvalidEmail'; default: return 'submitWpError'; } diff --git a/src/Integrations/Clearbit/ClearbitClientInterface.php b/src/Integrations/Clearbit/ClearbitClientInterface.php index c478f935e..eb9c3425a 100644 --- a/src/Integrations/Clearbit/ClearbitClientInterface.php +++ b/src/Integrations/Clearbit/ClearbitClientInterface.php @@ -21,13 +21,15 @@ interface ClearbitClientInterface public function getParams(): array; /** - * API request to get application. + * API request to post application. * - * @param string $emailKey Email key to map in params. + * @param string $email Email key to map in params. * @param array $params Params array. * @param array $mapData Map data from settings. + * @param string $itemId Item id to search. + * @param string $formId FormId value. * * @return array */ - public function getApplication(string $emailKey, array $params, array $mapData): array; + public function getApplication(string $email, array $params, array $mapData, string $itemId, string $formId): array; } diff --git a/src/Integrations/Goodbits/GoodbitsClient.php b/src/Integrations/Goodbits/GoodbitsClient.php index 40567cc65..6ba49f498 100644 --- a/src/Integrations/Goodbits/GoodbitsClient.php +++ b/src/Integrations/Goodbits/GoodbitsClient.php @@ -10,9 +10,9 @@ namespace EightshiftForms\Integrations\Goodbits; -use EightshiftForms\Helpers\Helper; use EightshiftForms\Hooks\Variables; use EightshiftForms\Integrations\ClientInterface; +use EightshiftForms\Rest\ApiHelper; use EightshiftForms\Rest\Routes\AbstractBaseRoute; use EightshiftForms\Settings\SettingsHelper; use EightshiftFormsVendor\EightshiftLibs\Helpers\Components; @@ -33,6 +33,11 @@ class GoodbitsClient implements ClientInterface */ use ObjectHelperTrait; + /** + * Use API helper trait. + */ + use ApiHelper; + /** * Return Goodbits base url. * @@ -104,60 +109,54 @@ public function postApplication(string $itemId, array $params, array $files, str 'subscriber' => $this->prepareParams($params), ]; - $response = \wp_remote_request( - self::BASE_URL . "subscribers", + $url = self::BASE_URL . "subscribers"; + + $response = \wp_remote_post( + $url, [ 'headers' => $this->getHeaders($itemId), - 'method' => 'POST', 'body' => \wp_json_encode($body), ] ); - $code = $response['response']['code'] ? $response['response']['code'] : 200; + // Structure response details. + $details = $this->getApiReponseDetails( + SettingsGoodbits::SETTINGS_TYPE_KEY, + $response, + $url, + $body, + $files, + $itemId, + $formId + ); + + $code = $details['code']; + $body = $details['body']; + // On success return output. if ($code >= 200 && $code <= 299) { - return [ - 'status' => 'success', - 'code' => 200, - 'message' => 'goodbitsSuccess', - ]; + return $this->getApiSuccessOutput($details); } - $responseBody = \json_decode(\wp_remote_retrieve_body($response), true); - $responseMessage = !\is_array($responseBody['errors']) ? $responseBody['errors'] : ''; - $responseErrors = \is_array($responseBody['errors']) ? $responseBody['errors']['message'] : []; - - $outputData = [ - 'integration' => SettingsGoodbits::SETTINGS_TYPE_KEY, - 'params' => $this->prepareParams($params), - 'files' => $files, - 'response' => $response['body'], - 'listId' => $itemId, - 'formId' => $formId, - ]; - - $output = [ - 'status' => 'error', - 'code' => $code, - 'message' => $this->getErrorMsg($responseMessage, $responseErrors), - 'data' => $outputData, - ]; - - Helper::logger($outputData); - - return $output; + // Output error. + return $this->getApiErrorOutput( + $details, + $this->getErrorMsg($body), + ); } /** * Map service messages with our own. * - * @param string $msg Message got from the API. - * @param array $errors Additional errors got from the API. + * @param array $body API response body. * * @return string */ - private function getErrorMsg(string $msg, array $errors = []): string + private function getErrorMsg(array $body): string { + $msg = !\is_array($body['errors']) ? $body['errors'] : ''; + $errors = \is_array($body['errors']) ? $body['errors']['message'] : []; + if ($errors) { $invalidEmail = \array_filter( $errors, diff --git a/src/Integrations/Greenhouse/GreenhouseClient.php b/src/Integrations/Greenhouse/GreenhouseClient.php index fc8486d37..5db0be368 100644 --- a/src/Integrations/Greenhouse/GreenhouseClient.php +++ b/src/Integrations/Greenhouse/GreenhouseClient.php @@ -12,11 +12,11 @@ use CURLFile; use EightshiftForms\General\General; -use EightshiftForms\Helpers\Helper; use EightshiftForms\Hooks\Filters; use EightshiftForms\Settings\SettingsHelper; use EightshiftForms\Hooks\Variables; use EightshiftForms\Integrations\ClientInterface; +use EightshiftForms\Rest\ApiHelper; use EightshiftForms\Rest\Routes\AbstractBaseRoute; use EightshiftFormsVendor\EightshiftLibs\Helpers\Components; @@ -30,6 +30,11 @@ class GreenhouseClient implements ClientInterface */ use SettingsHelper; + /** + * Use API helper trait. + */ + use ApiHelper; + /** * Return Greenhouse base url. * @@ -143,12 +148,14 @@ public function postApplication(string $itemId, array $params, array $files, str $filterName = Filters::getGeneralSettingsFilterName('httpRequestTimeout'); + $url = self::BASE_URL . "boards/{$this->getBoardToken()}/jobs/{$itemId}"; + // Curl used because files are not sent via wp request. $curl = \curl_init(); // phpcs:ignore WordPress.WP.AlternativeFunctions.curl_curl_init \curl_setopt_array( // phpcs:ignore WordPress.WP.AlternativeFunctions.curl_curl_setopt_array $curl, [ - \CURLOPT_URL => self::BASE_URL . "boards/{$this->getBoardToken()}/jobs/{$itemId}", + \CURLOPT_URL => $url, \CURLOPT_HTTPAUTH => \CURLAUTH_BASIC, \CURLOPT_RETURNTRANSFER => true, \CURLOPT_TIMEOUT => \apply_filters($filterName, General::HTTP_REQUEST_TIMEOUT_DEFAULT), @@ -162,47 +169,44 @@ public function postApplication(string $itemId, array $params, array $files, str \curl_close($curl); // phpcs:ignore WordPress.WP.AlternativeFunctions.curl_curl_close - if ($code >= 200 && $code <= 299) { - return [ - 'status' => 'success', - 'code' => $code, - 'message' => 'greenhouseSuccess', - ]; - } - - $responseBody = \json_decode($response, true); - $responseMessage = $responseBody['error'] ?? ''; - - $outputData = [ - 'integration' => SettingsGreenhouse::SETTINGS_TYPE_KEY, - 'params' => $paramsPrepared, - 'files' => $paramsFiles, - 'response' => $response, - 'listId' => $itemId, - 'formId' => $formId, - ]; + // Structure response details. + $details = $this->getApiReponseDetails( + SettingsGreenhouse::SETTINGS_TYPE_KEY, + \json_decode($response, true), + $url, + $paramsPrepared, + $paramsFiles, + $itemId, + $formId, + true + ); - $output = [ - 'status' => 'error', - 'code' => $code, - 'message' => $this->getErrorMsg($responseMessage), - 'data' => $outputData, - ]; + $code = $details['code']; + $body = $details['body']; - Helper::logger($outputData); + // On success return output. + if ($code >= 200 && $code <= 299) { + return $this->getApiSuccessOutput($details); + } - return $output; + // Output error. + return $this->getApiErrorOutput( + $details, + $this->getErrorMsg($body) + ); } /** * Map service messages with our own. * - * @param string $msg Message got from the API. + * @param array $body API response body. * * @return string */ - private function getErrorMsg(string $msg): string + private function getErrorMsg(array $body): string { + $msg = $body['error'] ?? ''; + switch ($msg) { case 'Bad Request': return 'greenhouseBadRequestError'; @@ -248,21 +252,31 @@ private function getErrorMsg(string $msg): string */ private function getGreenhouseJobs() { + $url = self::BASE_URL . "boards/{$this->getBoardToken()}/jobs"; + $response = \wp_remote_get( - self::BASE_URL . "boards/{$this->getBoardToken()}/jobs", + $url, [ 'headers' => $this->getHeaders(), - 'timeout' => 60, ] ); - $body = \json_decode(\wp_remote_retrieve_body($response), true); + // Structure response details. + $details = $this->getApiReponseDetails( + SettingsGreenhouse::SETTINGS_TYPE_KEY, + $response, + $url, + ); - if (!isset($body['jobs'])) { - return []; + $code = $details['code']; + $body = $details['body']; + + // On success return output. + if ($code >= 200 && $code <= 299) { + return $body['jobs'] ?? []; } - return $body['jobs']; + return []; } /** @@ -274,21 +288,31 @@ private function getGreenhouseJobs() */ private function getGreenhouseJob(string $jobId) { + $url = self::BASE_URL . "boards/{$this->getBoardToken()}/jobs/{$jobId}?questions=true"; + $response = \wp_remote_get( - self::BASE_URL . "boards/{$this->getBoardToken()}/jobs/{$jobId}?questions=true", + $url, [ 'headers' => $this->getHeaders(), - 'timeout' => 60, ] ); - $body = \json_decode(\wp_remote_retrieve_body($response), true); + // Structure response details. + $details = $this->getApiReponseDetails( + SettingsGreenhouse::SETTINGS_TYPE_KEY, + $response, + $url, + ); + + $code = $details['code']; + $body = $details['body']; - if (isset($body['error'])) { - return []; + // On success return output. + if ($code >= 200 && $code <= 299) { + return $body ?? []; } - return $body; + return []; } /** diff --git a/src/Integrations/Hubspot/HubspotClient.php b/src/Integrations/Hubspot/HubspotClient.php index 9c90e9f69..6ebb0ce92 100644 --- a/src/Integrations/Hubspot/HubspotClient.php +++ b/src/Integrations/Hubspot/HubspotClient.php @@ -11,11 +11,11 @@ namespace EightshiftForms\Integrations\Hubspot; use CURLFile; -use EightshiftForms\Helpers\Helper; use EightshiftForms\Hooks\Filters; use EightshiftForms\Settings\SettingsHelper; use EightshiftForms\Hooks\Variables; use EightshiftForms\Integrations\ClientInterface; +use EightshiftForms\Rest\ApiHelper; use EightshiftForms\Rest\Routes\AbstractBaseRoute; use EightshiftFormsVendor\EightshiftLibs\Helpers\Components; @@ -29,6 +29,11 @@ class HubspotClient implements HubspotClientInterface */ use SettingsHelper; + /** + * Use API helper trait. + */ + use ApiHelper; + /** * Transient cache name for items. */ @@ -230,55 +235,48 @@ static function ($item) { } } + $paramsPrepared = $this->prepareParams($params); + $paramsFiles = $this->prepareFiles($files, $formId); + $body['fields'] = \array_merge( $this->prepareParams($params), $this->prepareFiles($files, $formId) ); + $url = $this->getBaseUrl("submissions/v3/integration/secure/submit/{$itemId[1]}/{$itemId[0]}"); + $response = \wp_remote_post( - $this->getBaseUrl("submissions/v3/integration/secure/submit/{$itemId[1]}/{$itemId[0]}"), + $url, [ 'headers' => $this->getHeaders(), 'body' => \wp_json_encode($body), ] ); - $code = $response['response']['code'] ? $response['response']['code'] : 200; - - if ($code === 200) { - return [ - 'status' => 'success', - 'code' => $code, - 'message' => 'hubspotSuccess', - ]; - } - - $responseBody = \json_decode(\wp_remote_retrieve_body($response), true); - $responseMessage = $responseBody['message'] ?? ''; - $responseErrors = $responseBody['errors'] ?? []; - - $outputData = [ - 'integration' => SettingsHubspot::SETTINGS_TYPE_KEY, - 'params' => $body, - 'files' => $files, - 'response' => $response['body'], - 'listId' => $itemId, - 'formId' => $formId, - ]; - - $output = [ - 'status' => 'error', - 'code' => $code, - 'message' => $this->getErrorMsg($responseMessage, $responseErrors), - 'data' => $outputData, - ]; + // Structure response details. + $details = $this->getApiReponseDetails( + SettingsHubspot::SETTINGS_TYPE_KEY, + $response, + $url, + $paramsPrepared, + $paramsFiles, + \implode(', ', $itemId), + $formId + ); - Helper::logger($outputData); + $code = $details['code']; + $body = $details['body']; - error_log( print_r( ( $output ), true ) ); - + // On success return output. + if ($code >= 200 && $code <= 299) { + return $this->getApiSuccessOutput($details); + } - return $output; + // Output error. + return $this->getApiErrorOutput( + $details, + $this->getErrorMsg($body) + ); } /** @@ -291,105 +289,60 @@ static function ($item) { */ public function postContactProperty(string $email, array $params): array { - if (!$email) { - $output = [ - 'status' => 'error', - 'code' => 400, - 'message' => 'hubspotContactPropertyMissingEmail', - ]; - - Helper::logger([ - 'integration' => 'hubspot', - 'email' => $email, - 'mapKeys' => $params, - 'output' => $output, - ]); - - return $output; - } - - if (!$params) { - $output = [ - 'status' => 'error', - 'code' => 400, - 'message' => 'hubspotContactPropertyMissingMapKeys', - ]; - - Helper::logger([ - 'integration' => 'hubspot', - 'email' => $email, - 'mapKeys' => $params, - 'output' => $output, - ]); - - return $output; - } - $properties = []; $customFields = \array_flip(Components::flattenArray(AbstractBaseRoute::CUSTOM_FORM_PARAMS)); - foreach ($params as $key => $value) { - // Remove unecesery fields. - if (isset($customFields[$key])) { - continue; - } + if ($params) { + foreach ($params as $key => $value) { + // Remove unecesery fields. + if (isset($customFields[$key])) { + continue; + } - $properties[] = [ - 'property' => $key, - 'value' => $value, - ]; + $properties[] = [ + 'property' => $key, + 'value' => $value, + ]; + } } $body = [ 'properties' => $properties, ]; + $url = $this->getBaseUrl("contacts/v1/contact/createOrUpdate/email/{$email}", true); + $response = \wp_remote_post( - $this->getBaseUrl("contacts/v1/contact/createOrUpdate/email/{$email}", true), + $url, [ 'headers' => $this->getHeaders(), 'body' => \wp_json_encode($body), ] ); - if (\is_wp_error($response)) { - return [ - 'status' => 'error', - 'code' => 400, - 'message' => $this->getErrorMsg('submitWpError'), - ]; - } - - $code = $response['response']['code'] ? $response['response']['code'] : 200; - - if ($code === 200) { - return [ - 'status' => 'success', - 'code' => $code, - 'message' => 'hubspotContactPropertySuccess', - ]; - } + // Structure response details. + $details = $this->getApiReponseDetails( + SettingsHubspot::SETTINGS_TYPE_KEY, + $response, + $url, + $body + ); - $responseBody = \json_decode(\wp_remote_retrieve_body($response), true); - $responseMessage = $responseBody['message'] ?? ''; - $responseErrors = $responseBody['errors'] ?? []; - $output = [ - 'status' => 'error', - 'code' => $code, - 'message' => $this->getErrorMsg($responseMessage, $responseErrors), - ]; + $code = $details['code']; + $body = $details['body']; - Helper::logger([ - 'integration' => 'hubspot', - 'body' => $body, - 'response' => $response['response'], - 'responseBody' => $responseBody, - 'output' => $output, - ]); + // On success return output. + if ($code >= 200 && $code <= 299) { + return $this->getApiSuccessOutput($details); + } - return $output; + // Output error. + return $this->getApiErrorOutput( + $details, + $this->getErrorMsg($body) + ); } /** @@ -468,13 +421,15 @@ private function postFileMedia(array $file, string $formId): string /** * Map service messages with our own. * - * @param string $msg Message got from the API. - * @param array $errors Additional errors got from the API. + * @param array $body API response body. * * @return string */ - private function getErrorMsg(string $msg, array $errors = []): string + private function getErrorMsg(array $body): string { + $msg = $body['message'] ?? ''; + $errors = $body['errors'] ?? []; + if ($errors && isset($errors[0])) { $msg = $errors[0]['errorType']; } @@ -543,15 +498,31 @@ private function getErrorMsg(string $msg, array $errors = []): string */ private function getHubspotContactProperties() { + $url = $this->getBaseUrl('properties/v1/contacts/properties', true); + $response = \wp_remote_get( - $this->getBaseUrl('properties/v1/contacts/properties', true), + $url, [ 'headers' => $this->getHeaders(), - 'timeout' => 60, ] ); - return \json_decode(\wp_remote_retrieve_body($response), true); + // Structure response details. + $details = $this->getApiReponseDetails( + SettingsHubspot::SETTINGS_TYPE_KEY, + $response, + $url, + ); + + $code = $details['code']; + $body = $details['body']; + + // On success return output. + if ($code >= 200 && $code <= 299) { + return $body ?? []; + } + + return []; } /** @@ -561,15 +532,31 @@ private function getHubspotContactProperties() */ private function getHubspotItems() { + $url = $this->getBaseUrl('forms/v2/forms', true); + $response = \wp_remote_get( - $this->getBaseUrl('forms/v2/forms', true), + $url, [ 'headers' => $this->getHeaders(), - 'timeout' => 60, ] ); - return \json_decode(\wp_remote_retrieve_body($response), true); + // Structure response details. + $details = $this->getApiReponseDetails( + SettingsHubspot::SETTINGS_TYPE_KEY, + $response, + $url, + ); + + $code = $details['code']; + $body = $details['body']; + + // On success return output. + if ($code >= 200 && $code <= 299) { + return $body ?? []; + } + + return []; } /** diff --git a/src/Integrations/Mailchimp/MailchimpClient.php b/src/Integrations/Mailchimp/MailchimpClient.php index 8a073c68e..3cadeeccb 100644 --- a/src/Integrations/Mailchimp/MailchimpClient.php +++ b/src/Integrations/Mailchimp/MailchimpClient.php @@ -10,9 +10,9 @@ namespace EightshiftForms\Integrations\Mailchimp; -use EightshiftForms\Helpers\Helper; use EightshiftForms\Hooks\Variables; use EightshiftForms\Integrations\ClientInterface; +use EightshiftForms\Rest\ApiHelper; use EightshiftForms\Rest\Routes\AbstractBaseRoute; use EightshiftForms\Settings\SettingsHelper; use EightshiftFormsVendor\EightshiftLibs\Helpers\Components; @@ -27,6 +27,11 @@ class MailchimpClient implements MailchimpClientInterface */ use SettingsHelper; + /** + * Use API helper trait. + */ + use ApiHelper; + /** * Transient cache name for items. */ @@ -168,8 +173,10 @@ public function postApplication(string $itemId, array $params, array $files, str $body['merge_fields'] = $prepareParams; } + $url = "{$this->getBaseUrl()}lists/{$itemId}/members/{$emailHash}"; + $response = \wp_remote_request( - "{$this->getBaseUrl()}lists/{$itemId}/members/{$emailHash}", + $url, [ 'headers' => $this->getHeaders(), 'method' => 'PUT', @@ -177,51 +184,44 @@ public function postApplication(string $itemId, array $params, array $files, str ] ); - $code = $response['response']['code'] ? $response['response']['code'] : 200; + // Structure response details. + $details = $this->getApiReponseDetails( + SettingsMailchimp::SETTINGS_TYPE_KEY, + $response, + $url, + $body, + $files, + $itemId, + $formId + ); + + $code = $details['code']; + $body = $details['body']; + // On success return output. if ($code >= 200 && $code <= 299) { - return [ - 'status' => 'success', - 'code' => $code, - 'message' => 'mailchimpSuccess', - ]; + return $this->getApiSuccessOutput($details); } - $responseBody = \json_decode(\wp_remote_retrieve_body($response), true); - $responseMessage = $responseBody['detail'] ?? ''; - $responseErrors = $responseBody['errors'] ?? []; - - $outputData = [ - 'integration' => SettingsMailchimp::SETTINGS_TYPE_KEY, - 'params' => $body, - 'files' => $files, - 'response' => $response['body'], - 'listId' => $itemId, - 'formId' => $formId, - ]; - - $output = [ - 'status' => 'error', - 'code' => $code, - 'message' => $this->getErrorMsg($responseMessage, $responseErrors), - 'data' => $outputData, - ]; - - Helper::logger($outputData); - - return $output; + // Output error. + return $this->getApiErrorOutput( + $details, + $this->getErrorMsg($body), + ); } /** * Map service messages with our own. * - * @param string $msg Message got from the API. - * @param array $errors Additional errors got from the API. + * @param array $body API response body. * * @return string */ - private function getErrorMsg(string $msg, array $errors = []): string + private function getErrorMsg(array $body): string { + $msg = $body['detail'] ?? ''; + $errors = $body['errors'] ?? []; + if ($errors) { $invalidEmail = \array_filter( $errors, @@ -259,21 +259,31 @@ static function ($error) { */ private function getMailchimpTags(string $itemId): array { + $url = "{$this->getBaseUrl()}lists/{$itemId}/tag-search"; + $response = \wp_remote_get( - "{$this->getBaseUrl()}lists/{$itemId}/tag-search", + $url, [ 'headers' => $this->getHeaders(), - 'timeout' => 60, ] ); - $body = \json_decode(\wp_remote_retrieve_body($response), true); + // Structure response details. + $details = $this->getApiReponseDetails( + SettingsMailchimp::SETTINGS_TYPE_KEY, + $response, + $url, + ); - if (!isset($body['tags'])) { - return []; + $code = $details['code']; + $body = $details['body']; + + // On success return output. + if ($code >= 200 && $code <= 299) { + return $body['tags'] ?? []; } - return $body['tags']; + return []; } /** @@ -300,21 +310,31 @@ private function getHeaders(): array */ private function getMailchimpListFields(string $listId) { + $url = "{$this->getBaseUrl()}lists/{$listId}/merge-fields?count=1000"; + $response = \wp_remote_get( - "{$this->getBaseUrl()}lists/{$listId}/merge-fields?count=1000", + $url, [ 'headers' => $this->getHeaders(), - 'timeout' => 60, ] ); - $body = \json_decode(\wp_remote_retrieve_body($response), true); + // Structure response details. + $details = $this->getApiReponseDetails( + SettingsMailchimp::SETTINGS_TYPE_KEY, + $response, + $url, + ); - if (!isset($body['merge_fields'])) { - return []; + $code = $details['code']; + $body = $details['body']; + + // On success return output. + if ($code >= 200 && $code <= 299) { + return $body['merge_fields'] ?? []; } - return $body['merge_fields']; + return []; } /** @@ -324,21 +344,31 @@ private function getMailchimpListFields(string $listId) */ private function getMailchimpLists() { + $url = "{$this->getBaseUrl()}lists?count=100"; + $response = \wp_remote_get( - "{$this->getBaseUrl()}lists?count=100", + $url, [ 'headers' => $this->getHeaders(), - 'timeout' => 60, ] ); - $body = \json_decode(\wp_remote_retrieve_body($response), true); + // Structure response details. + $details = $this->getApiReponseDetails( + SettingsMailchimp::SETTINGS_TYPE_KEY, + $response, + $url, + ); - if (!isset($body['lists'])) { - return []; + $code = $details['code']; + $body = $details['body']; + + // On success return output. + if ($code >= 200 && $code <= 299) { + return $body['lists'] ?? []; } - return $body['lists']; + return []; } /** diff --git a/src/Integrations/Mailerlite/MailerliteClient.php b/src/Integrations/Mailerlite/MailerliteClient.php index 0397dbcd4..ebb38d0a9 100644 --- a/src/Integrations/Mailerlite/MailerliteClient.php +++ b/src/Integrations/Mailerlite/MailerliteClient.php @@ -10,9 +10,9 @@ namespace EightshiftForms\Integrations\Mailerlite; -use EightshiftForms\Helpers\Helper; use EightshiftForms\Hooks\Variables; use EightshiftForms\Integrations\ClientInterface; +use EightshiftForms\Rest\ApiHelper; use EightshiftForms\Rest\Routes\AbstractBaseRoute; use EightshiftForms\Settings\SettingsHelper; use EightshiftFormsVendor\EightshiftLibs\Helpers\Components; @@ -27,6 +27,11 @@ class MailerliteClient implements ClientInterface */ use SettingsHelper; + /** + * Use API helper trait. + */ + use ApiHelper; + /** * Return Mailerlite base url. * @@ -132,58 +137,53 @@ public function postApplication(string $itemId, array $params, array $files, str 'fields' => $this->prepareParams($params), ]; - $response = \wp_remote_request( - self::BASE_URL . "groups/{$itemId}/subscribers", + $url = self::BASE_URL . "groups/{$itemId}/subscribers"; + + $response = \wp_remote_post( + $url, [ 'headers' => $this->getHeaders(), - 'method' => 'POST', 'body' => \wp_json_encode($body), ] ); - $code = $response['response']['code'] ? $response['response']['code'] : 200; + // Structure response details. + $details = $this->getApiReponseDetails( + SettingsMailerlite::SETTINGS_TYPE_KEY, + $response, + $url, + $body, + $files, + $itemId, + $formId + ); + + $code = $details['code']; + $body = $details['body']; + // On success return output. if ($code >= 200 && $code <= 299) { - return [ - 'status' => 'success', - 'code' => $code, - 'message' => 'mailerliteSuccess', - ]; + return $this->getApiSuccessOutput($details); } - $responseBody = \json_decode(\wp_remote_retrieve_body($response), true); - $responseMessage = $responseBody['error']['message'] ?? ''; - - $outputData = [ - 'integration' => SettingsMailerlite::SETTINGS_TYPE_KEY, - 'params' => $body, - 'files' => $files, - 'response' => $response['body'], - 'listId' => $itemId, - 'formId' => $formId, - ]; - - $output = [ - 'status' => 'error', - 'code' => $code, - 'message' => $this->getErrorMsg($responseMessage), - 'data' => $outputData, - ]; - - Helper::logger($outputData); - - return $output; + // Output error. + return $this->getApiErrorOutput( + $details, + $this->getErrorMsg($body) + ); } /** * Map service messages with our own. * - * @param string $msg Message got from the API. + * @param array $body API response body. * * @return string */ - private function getErrorMsg(string $msg): string + private function getErrorMsg(array $body): string { + $msg = $body['error']['message'] ?? ''; + switch ($msg) { case 'Bad Request': return 'mailerliteBadRequestError'; @@ -218,17 +218,31 @@ private function getHeaders(): array */ private function getMailerliteListFields() { + $url = self::BASE_URL . "fields"; + $response = \wp_remote_get( - self::BASE_URL . "fields", + $url, [ 'headers' => $this->getHeaders(), - 'timeout' => 60, ] ); - $body = \json_decode(\wp_remote_retrieve_body($response), true); + // Structure response details. + $details = $this->getApiReponseDetails( + SettingsMailerlite::SETTINGS_TYPE_KEY, + $response, + $url, + ); + + $code = $details['code']; + $body = $details['body']; + + // On success return output. + if ($code >= 200 && $code <= 299) { + return $body ?? []; + } - return $body ?? []; + return []; } /** @@ -238,15 +252,31 @@ private function getMailerliteListFields() */ private function getMailerliteLists() { + $url = self::BASE_URL . "groups"; + $response = \wp_remote_get( - self::BASE_URL . "groups", + $url, [ 'headers' => $this->getHeaders(), - 'timeout' => 60, ] ); - return \json_decode(\wp_remote_retrieve_body($response), true) ?? []; + // Structure response details. + $details = $this->getApiReponseDetails( + SettingsMailerlite::SETTINGS_TYPE_KEY, + $response, + $url, + ); + + $code = $details['code']; + $body = $details['body']; + + // On success return output. + if ($code >= 200 && $code <= 299) { + return $body ?? []; + } + + return []; } /** diff --git a/src/Mailer/Mailer.php b/src/Mailer/Mailer.php index b0bca7f91..24be8c7de 100644 --- a/src/Mailer/Mailer.php +++ b/src/Mailer/Mailer.php @@ -75,21 +75,24 @@ public function sendFormEmail( */ public function fallbackEmail(array $data): bool { - $isSettingsValid = apply_filters(SettingsTroubleshooting::FILTER_SETTINGS_IS_VALID_NAME, []); + $isSettingsValid = \apply_filters(SettingsTroubleshooting::FILTER_SETTINGS_IS_VALID_NAME, []); if (!$isSettingsValid) { return false; } $integration = $data['integration'] ?? ''; + $url = $data['url'] ?? ''; $files = $data['files'] ?? []; - $response = $data['response'] ?? ''; + $response = $data['response'] ? \wp_json_encode($data['response']) : ''; $formId = $data['formId'] ?? ''; $listId = $data['listId'] ?? ''; $params = $data['params'] ?? []; + $code = $data['code'] ?? 400; + $body = $data['body'] ? \wp_json_encode($data['body']) : ''; - if (is_array($listId)) { - $listId = implode(', ', $listId); + if (\is_array($listId)) { + $listId = \implode(', ', $listId); } $paramsOutput = " @@ -98,6 +101,8 @@ public function fallbackEmail(array $data): bool
  • formId: {$formId}
  • listId: {$listId}
  • integration: {$integration}
  • +
  • response code: {$code}
  • +
  • url: {$url}
  • "; @@ -106,10 +111,19 @@ public function fallbackEmail(array $data): bool $paramsOutput .= $this->fallbackEmailPrepareParams($params); } - $paramsOutput .= " -

    Data got from integration response:

    - {$response} - "; + if ($response) { + $paramsOutput .= " +

    Data got from integration response:

    + {$response} + "; + } + + if ($body) { + $paramsOutput .= " +

    Data got from integration response body:

    + {$body} + "; + } $filesOutput = []; if ($files) { @@ -118,7 +132,7 @@ public function fallbackEmail(array $data): bool $filesOutput[] = $file->name; } - if (is_array($file)) { + if (\is_array($file)) { foreach ($file as $fileItem) { if (isset($fileItem['path'])) { $filesOutput[] = $fileItem['path']; @@ -129,13 +143,11 @@ public function fallbackEmail(array $data): bool } $to = $this->getOptionValue(SettingsTroubleshooting::SETTINGS_TROUBLESHOOTING_FALLBACK_EMAIL_KEY); - $subject = sprintf(__("Your %s form failed: %s", 'eightshift-forms'), $integration, $formId); + // translators: %1$s replaces the integration name and %2$s formId. + $subject = \sprintf(\__('Your %1$s form failed: %2$s', 'eightshift-forms'), $integration, $formId); $headers = $this->getType(); - $templateHtml = sprintf(__(" -

    It looks like something went wrong with the users form submition, here is all the data to debug.

    - %s", 'eightshift-forms'), - $paramsOutput - ); + // translators: %s replaces the parameters list html. + $templateHtml = \sprintf(\__("

    It looks like something went wrong with the users form submition, here is all the data to debug.

    %s", 'eightshift-forms'), $paramsOutput); // Send email. return \wp_mail($to, $subject, $templateHtml, $headers, $filesOutput); @@ -302,8 +314,8 @@ private function fallbackEmailPrepareParams(array $params): string { $output = ''; - foreach($params as $paramKey => $paramValue) { - if (is_array($paramValue)) { + foreach ($params as $paramKey => $paramValue) { + if (\is_array($paramValue)) { $paramValueOutput = '
      '; $paramValueOutput .= $this->fallbackEmailPrepareParams($paramValue); $paramValueOutput .= '
    '; diff --git a/src/Mailer/MailerInterface.php b/src/Mailer/MailerInterface.php index 18e019c84..706795c74 100644 --- a/src/Mailer/MailerInterface.php +++ b/src/Mailer/MailerInterface.php @@ -43,5 +43,5 @@ public function sendFormEmail( * * @return boolean */ - public function fallbackEmail (array $data): bool; + public function fallbackEmail(array $data): bool; } diff --git a/src/Rest/ApiHelper.php b/src/Rest/ApiHelper.php index 438c4ed65..fe75a469a 100644 --- a/src/Rest/ApiHelper.php +++ b/src/Rest/ApiHelper.php @@ -19,101 +19,94 @@ trait ApiHelper { /** - * Return API response array with logger. + * Return API response array details. * - * @param string $integration Integration name. - * @param array $details Details from response. - * @param array $requestBody Request body sent to the API. - * @param string $msg Msg for the user. + * @param array $response Response got from the API. * - * @return array + * @return array */ - public function getApiWpErrorOutput( - string $integration, - array $details, - array $requestBody, - string $msg - ): array { - Helper::logger([ - 'integration' => Components::kebabToCamelCase($integration, '-'), - 'type' => 'wp', - 'response' => $details, - 'requestBody' => $requestBody, - 'msg' => $msg, - ]); - - return [ - 'status' => 'error', - 'code' => 400, - 'message' => 'submitWpError', - ]; - } - /** * Return API response array details. * - * @param array $response Response got from the API. + * @param string $integration Integration name from settings. + * @param array $response API full reponse. + * @param string $url Url of the request. + * @param array $params All params prepared for API. + * @param array $files All files prepared for API. + * @param string $listId List Id used for API (questions, form id, list id, item id). + * @param string $formId Internal form ID. + * @param boolean $isCurl Used for some changed if native cURL is used. * * @return array */ - public function getApiReponseDetails($response): array - { + public function getApiReponseDetails( + string $integration, + array $response, + string $url, + array $params = [], + array $files = [], + string $listId = '', + string $formId = '', + bool $isCurl = false + ): array { + if ($isCurl) { + $code = $response['status'] ?? 200; + $body = $response; + } else { + $code = $response['response']['code'] ?? 200; + $body = \json_decode($response['body'] ?? '', true) ?? []; + } + return [ - 'code' => $response['response']['code'] ? $response['response']['code'] : 200, - 'body' => \json_decode(\wp_remote_retrieve_body($response), true) ?? [], + 'integration' => Components::kebabToCamelCase($integration, '-'), + 'params' => $params, + 'files' => $files, 'response' => $response['response'] ?? [], - 'url' => $response['url'] ?? '', + 'code' => $code, + 'body' => $body, + 'url' => $url, + 'listId' => $listId, + 'formId' => $formId, ]; } /** * Return API error response array with logger. * - * @param string $integration Integration name. - * @param array $details Details from response. - * @param array $requestBody Request body sent to the API. + * @param array $details Details provided by getApiReponseDetails method. * @param string $msg Msg for the user. * - * @return array + * @return array */ - public function getApiErrorOutput( - string $integration, - array $details, - array $requestBody, - string $msg - ): array { - // Log output. - Helper::logger([ - 'integration' => Components::kebabToCamelCase($integration, '-'), - 'type' => 'service', - 'response' => $details, - 'requestBody' => $requestBody, - 'msg' => $msg, - ]); + public function getApiErrorOutput(array $details, string $msg): array + { + Helper::logger($details); return [ 'status' => 'error', - 'code' => $details['code'], + 'code' => $details['code'] ?? 400, 'message' => $msg, + 'data' => $details, ]; } /** * Return API success response array. * - * @param string $integration Integration name. + * @param array $details Details provided by getApiReponseDetails method. * @param array $additional Additional array details to attach to the success output. * - * @return array + * @return array */ - public function getApiSuccessOutput(string $integration, array $additional = []): array + public function getApiSuccessOutput(array $details, array $additional = []): array { - $integration = Components::kebabToCamelCase($integration, '-'); + + $integration = $details['integration'] ?? ''; return \array_merge( [ 'status' => 'success', - 'code' => 200, + 'code' => $details['code'] ?? 200, 'message' => "{$integration}Success", ], $additional diff --git a/src/Rest/Routes/FormSubmitActiveCampaignRoute.php b/src/Rest/Routes/FormSubmitActiveCampaignRoute.php index fc42ac4d2..e538fffb0 100644 --- a/src/Rest/Routes/FormSubmitActiveCampaignRoute.php +++ b/src/Rest/Routes/FormSubmitActiveCampaignRoute.php @@ -13,6 +13,7 @@ use EightshiftForms\Integrations\ActiveCampaign\ActiveCampaignClientInterface; use EightshiftForms\Integrations\ActiveCampaign\SettingsActiveCampaign; use EightshiftForms\Labels\LabelsInterface; +use EightshiftForms\Mailer\MailerInterface; use EightshiftForms\Validation\ValidatorInterface; /** @@ -41,21 +42,31 @@ class FormSubmitActiveCampaignRoute extends AbstractFormSubmit */ private $activeCampaignClient; + /** + * Instance variable of MailerInterface data. + * + * @var MailerInterface + */ + public $mailer; + /** * Create a new instance that injects classes * * @param ValidatorInterface $validator Inject ValidatorInterface which holds validation methods. * @param LabelsInterface $labels Inject LabelsInterface which holds labels data. * @param ActiveCampaignClientInterface $activeCampaignClient Inject ActiveCampaign which holds ActiveCampaign connect data. + * @param MailerInterface $mailer Inject MailerInterface which holds mailer methods. */ public function __construct( ValidatorInterface $validator, LabelsInterface $labels, - ActiveCampaignClientInterface $activeCampaignClient + ActiveCampaignClientInterface $activeCampaignClient, + MailerInterface $mailer ) { $this->validator = $validator; $this->labels = $labels; $this->activeCampaignClient = $activeCampaignClient; + $this->mailer = $mailer; } /** @@ -100,7 +111,7 @@ public function submitAction(string $formId, array $params = [], $files = []) ); // Make an additional requests to the API. - if ($response['code'] === 200 && !empty($response['contactId'])) { + if ($response['status'] === 'success' && !empty($response['contactId'])) { // If form has action to save tags. $actionTags = $params['actionTags']['value'] ?? ''; @@ -132,6 +143,11 @@ public function submitAction(string $formId, array $params = [], $files = []) } } + if ($response['status'] === 'error') { + // Send fallback email. + $this->mailer->fallbackEmail($response['data'] ?? []); + } + // Finish. return \rest_ensure_response([ 'code' => $response['code'], diff --git a/src/Rest/Routes/FormSubmitCustomRoute.php b/src/Rest/Routes/FormSubmitCustomRoute.php index 21e5513d8..2a699005e 100644 --- a/src/Rest/Routes/FormSubmitCustomRoute.php +++ b/src/Rest/Routes/FormSubmitCustomRoute.php @@ -107,13 +107,12 @@ public function submitAction(string $formId, array $params = [], $files = []) } // Create a custom form action request. - $customResponse = \wp_remote_request( + $customResponse = \wp_remote_post( $formAction, [ 'headers' => [ 'Content-Type' => 'application/x-www-form-urlencoded', ], - 'method' => 'POST', 'body' => \http_build_query($body), ] ); diff --git a/src/Rest/Routes/FormSubmitHubspotRoute.php b/src/Rest/Routes/FormSubmitHubspotRoute.php index bfd74cd32..546edc883 100644 --- a/src/Rest/Routes/FormSubmitHubspotRoute.php +++ b/src/Rest/Routes/FormSubmitHubspotRoute.php @@ -126,9 +126,11 @@ public function submitAction(string $formId, array $params = [], $files = []) ]); } + $itemId = $this->getSettingsValue(SettingsHubspot::SETTINGS_HUBSPOT_ITEM_ID_KEY, $formId); + // Send application to Hubspot. $response = $this->hubspotClient->postApplication( - $this->getSettingsValue(SettingsHubspot::SETTINGS_HUBSPOT_ITEM_ID_KEY, $formId), + $itemId, $params, $files, $formId @@ -138,19 +140,29 @@ public function submitAction(string $formId, array $params = [], $files = []) $useClearbit = \apply_filters(SettingsClearbit::FILTER_SETTINGS_IS_VALID_NAME, $formId, SettingsHubspot::SETTINGS_TYPE_KEY); if ($useClearbit) { - // Get Clearbit data. - $clearbitResponse = $this->clearbitClient->getApplication( - $this->getSettingsValue(Filters::ALL[SettingsClearbit::SETTINGS_TYPE_KEY]['integration'][SettingsHubspot::SETTINGS_TYPE_KEY]['email'], $formId), - $params, - $this->getOptionValueGroup(Filters::ALL[SettingsClearbit::SETTINGS_TYPE_KEY]['integration'][SettingsHubspot::SETTINGS_TYPE_KEY]['map']) - ); - - // If Clearbit data is ok send data to Hubspot. - if ($clearbitResponse['code'] === 200) { - $this->hubspotClient->postContactProperty( - $clearbitResponse['email'] ?? '', - $clearbitResponse['data'] ?? [] + $emailKey = $this->getSettingsValue(Filters::ALL[SettingsClearbit::SETTINGS_TYPE_KEY]['integration'][SettingsHubspot::SETTINGS_TYPE_KEY]['email'], $formId); + $email = isset($params[$emailKey]['value']) ? $params[$emailKey]['value'] : ''; + + if ($email) { + // Get Clearbit data. + $clearbitResponse = $this->clearbitClient->getApplication( + $email, + $params, + $this->getOptionValueGroup(Filters::ALL[SettingsClearbit::SETTINGS_TYPE_KEY]['integration'][SettingsHubspot::SETTINGS_TYPE_KEY]['map']), + $itemId, + $formId ); + + // If Clearbit data is ok send data to Hubspot. + if ($clearbitResponse['code'] >= 200 && $clearbitResponse['code'] <= 299) { + $this->hubspotClient->postContactProperty( + $clearbitResponse['email'] ?? '', + $clearbitResponse['data'] ?? [] + ); + } else { + // Send fallback email. + $this->mailer->fallbackEmail($clearbitResponse['data'] ?? []); + } } } diff --git a/src/Rest/Routes/FormSubmitMailerliteRoute.php b/src/Rest/Routes/FormSubmitMailerliteRoute.php index 9b09cb876..31ab85ca6 100644 --- a/src/Rest/Routes/FormSubmitMailerliteRoute.php +++ b/src/Rest/Routes/FormSubmitMailerliteRoute.php @@ -74,7 +74,6 @@ public function __construct( LabelsInterface $labels, ClientInterface $mailerliteClient, MailerInterface $mailer - ) { $this->validator = $validator; $this->labels = $labels; diff --git a/src/Troubleshooting/SettingsTroubleshooting.php b/src/Troubleshooting/SettingsTroubleshooting.php index c649fa911..e4219b1c4 100644 --- a/src/Troubleshooting/SettingsTroubleshooting.php +++ b/src/Troubleshooting/SettingsTroubleshooting.php @@ -11,10 +11,7 @@ namespace EightshiftForms\Troubleshooting; use EightshiftForms\Hooks\Filters; -use EightshiftForms\Labels\Labels; use EightshiftForms\Settings\SettingsHelper; -use EightshiftForms\Labels\LabelsInterface; -use EightshiftForms\Helpers\Helper; use EightshiftForms\Settings\Settings\SettingsDataInterface; use EightshiftFormsVendor\EightshiftLibs\Services\ServiceInterface; @@ -28,7 +25,7 @@ class SettingsTroubleshooting implements SettingsDataInterface, ServiceInterface */ use SettingsHelper; - /** + /** * Filter settings sidebar key. */ public const FILTER_SETTINGS_SIDEBAR_NAME = 'es_forms_settings_sidebar_troubleshooting'; From 7fd744b18a6a724b8b44b1eda8a7a936f16a35e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20Ruz=CC=8Cevic=CC=81?= Date: Mon, 5 Sep 2022 16:06:35 +0200 Subject: [PATCH 07/12] adding separators to sidebar menu --- .../FormGlobalSettingsAdminSubMenu.php | 7 +- src/AdminMenus/FormSettingsAdminSubMenu.php | 7 +- .../admin-settings-section-admin.scss | 16 ++- .../admin-settings/admin-settings.php | 38 +++---- .../partials/sidebar-section.php | 75 ++++++++++++++ src/Cache/SettingsCache.php | 2 + src/Enqueue/Blocks/EnqueueBlocks.php | 3 +- src/Geolocation/Geolocation.php | 71 +++++++++----- src/Geolocation/SettingsGeolocation.php | 2 + src/Helpers/Helper.php | 17 ++-- src/Hooks/Variables.md | 18 +--- src/Hooks/Variables.php | 22 +---- .../ActiveCampaign/SettingsActiveCampaign.php | 20 +++- .../Clearbit/SettingsClearbit.php | 2 + .../Goodbits/SettingsGoodbits.php | 20 +++- .../Greenhouse/SettingsGreenhouse.php | 20 +++- src/Integrations/Hubspot/SettingsHubspot.php | 24 ++++- .../Mailchimp/SettingsMailchimp.php | 20 +++- .../Mailerlite/SettingsMailerlite.php | 20 +++- src/Mailer/Mailer.php | 9 +- src/Mailer/SettingsMailer.php | 2 + src/Rest/ApiHelper.php | 11 ++- src/Rest/Routes/AbstractFormSubmit.php | 4 +- src/Rest/Routes/FormSettingsSubmitRoute.php | 10 +- src/Settings/Settings/SettingsAll.php | 40 ++++++++ src/Settings/Settings/SettingsGeneral.php | 1 + src/Settings/Settings/SettingsLocation.php | 1 + src/Settings/Settings/SettingsTest.php | 1 + .../SettingsTroubleshooting.php | 98 +++++++++++++++++-- .../SettingsTroubleshootingDataInterface.php | 28 ++++++ src/Validation/SettingsCaptcha.php | 2 + src/Validation/SettingsValidation.php | 2 + 32 files changed, 483 insertions(+), 130 deletions(-) create mode 100644 src/Blocks/components/admin-settings/partials/sidebar-section.php create mode 100644 src/Troubleshooting/SettingsTroubleshootingDataInterface.php diff --git a/src/AdminMenus/FormGlobalSettingsAdminSubMenu.php b/src/AdminMenus/FormGlobalSettingsAdminSubMenu.php index 2e1d16931..4d9d1c560 100644 --- a/src/AdminMenus/FormGlobalSettingsAdminSubMenu.php +++ b/src/AdminMenus/FormGlobalSettingsAdminSubMenu.php @@ -173,13 +173,18 @@ protected function processAttributes($attr): array { $type = isset($_GET['type']) ? \sanitize_text_field(\wp_unslash($_GET['type'])) : SettingsGeneral::SETTINGS_TYPE_KEY; // phpcs:ignore WordPress.Security.NonceVerification.Recommended + $settingsSidebarOutput = []; + foreach ($this->settingsGlobal->getSettingsSidebar($type) as $item) { + $settingsSidebarOutput[$item['type'] ?? 'general'][] = $item; + } + return [ // translators: %s replaces form title name. 'adminSettingsPageTitle' => \esc_html__('Settings', 'eightshift-forms'), 'adminSettingsSubTitle' => \esc_html__('These settings apply to all forms.', 'eightshift-forms'), 'adminSettingsBackLink' => Helper::getListingPageUrl(), 'adminSettingsLink' => Helper::getSettingsGlobalPageUrl(''), - 'adminSettingsSidebar' => $this->settingsGlobal->getSettingsSidebar($type), + 'adminSettingsSidebar' => $settingsSidebarOutput, 'adminSettingsForm' => $this->settingsGlobal->getSettingsForm($type), 'adminSettingsType' => $type, 'adminSettingsIsGlobal' => true, diff --git a/src/AdminMenus/FormSettingsAdminSubMenu.php b/src/AdminMenus/FormSettingsAdminSubMenu.php index 90c34daa2..7ebaed0b5 100644 --- a/src/AdminMenus/FormSettingsAdminSubMenu.php +++ b/src/AdminMenus/FormSettingsAdminSubMenu.php @@ -186,13 +186,18 @@ protected function processAttributes($attr): array $formTitle = \esc_html__('No form title', 'eightshift-forms'); } + $settingsSidebarOutput = []; + foreach ($this->settingsAll->getSettingsSidebar($formId, $type) as $item) { + $settingsSidebarOutput[$item['type'] ?? 'general'][] = $item; + } + return [ // translators: %s replaces the form name. 'adminSettingsPageTitle' => \sprintf(\esc_html__('Form settings: %s', 'eightshift-forms'), $formTitle), 'adminSettingsBackLink' => Helper::getListingPageUrl(), 'adminSettingsFormEditLink' => Helper::getFormEditPageUrl($formId), 'adminSettingsLink' => Helper::getSettingsPageUrl($formId, ''), - 'adminSettingsSidebar' => $this->settingsAll->getSettingsSidebar($formId, $type), + 'adminSettingsSidebar' => $settingsSidebarOutput, 'adminSettingsForm' => $this->settingsAll->getSettingsForm($formId, $type), 'adminSettingsType' => $type, ]; diff --git a/src/Blocks/components/admin-settings-section/admin-settings-section-admin.scss b/src/Blocks/components/admin-settings-section/admin-settings-section-admin.scss index 134cbba9f..f606c8323 100644 --- a/src/Blocks/components/admin-settings-section/admin-settings-section-admin.scss +++ b/src/Blocks/components/admin-settings-section/admin-settings-section-admin.scss @@ -13,12 +13,26 @@ &__sidebar { background-color: var(--global-colors-es-white); + height: 100vh; + overflow-x: hidden; > * { margin-bottom: var(--global-es-spacing-horizontal); + border-top: 1px solid var(--global-colors-es-ebb); + + &:first-child { + border-top: 0; + } } } + &__sidebar-label { + padding: 1rem 1.1rem 0.5rem; + font-size: 1.1rem; + font-weight: bold; + line-height: 1.2; + } + &__main { border-left: 1px solid var(--global-colors-es-ebb); @@ -87,7 +101,7 @@ } &:hover, - &:focus, { + &:focus { color: var(--global-colors-es-matisse); background-color: var(--global-colors-es-matisse-05); } diff --git a/src/Blocks/components/admin-settings/admin-settings.php b/src/Blocks/components/admin-settings/admin-settings.php index 3ca0ced63..28f044a73 100644 --- a/src/Blocks/components/admin-settings/admin-settings.php +++ b/src/Blocks/components/admin-settings/admin-settings.php @@ -13,6 +13,7 @@ echo Components::outputCssVariablesGlobal(); // phpcs:ignore Eightshift.Security.ComponentsEscape.OutputNotEscaped +$componentName = $manifest['componentName'] ?? ''; $componentClass = $manifest['componentClass'] ?? ''; $sectionClass = $manifestSection['componentClass'] ?? ''; @@ -47,30 +48,19 @@ -
    "> -
    "> - -
    -
    + $adminSettingsSidebar, + 'sectionClass' => $sectionClass, + 'adminSettingsLink' => $adminSettingsLink, + 'adminSettingsType' => $adminSettingsType, + ] + ); + ?>
    ">
    "> diff --git a/src/Blocks/components/admin-settings/partials/sidebar-section.php b/src/Blocks/components/admin-settings/partials/sidebar-section.php new file mode 100644 index 000000000..f0d5eabae --- /dev/null +++ b/src/Blocks/components/admin-settings/partials/sidebar-section.php @@ -0,0 +1,75 @@ + array_search($key2, $sortOrder, true)) ? 1 : -1); +}); + +foreach ($items as $key => $innerItems) { + switch ($key) { + case SettingsAll::SETTINGS_SIEDBAR_TYPE_INTEGRATION: + $sidebarTitle = __('Integrations', 'eightshift-forms'); + break; + case SettingsAll::SETTINGS_SIEDBAR_TYPE_TROUBLESHOOTING: + $sidebarTitle = __('Troubleshooting', 'eightshift-forms'); + break; + case SettingsAll::SETTINGS_SIEDBAR_TYPE_DEVELOP: + $sidebarTitle = __('Develop Mode', 'eightshift-forms'); + break; + default: + $sidebarTitle = __('General', 'eightshift-forms'); + break; + } + ?> + +
    "> +
    "> +
    "> + +
    + +
    +
    + + \__('Clear cache', 'eightshift-forms'), 'value' => self::SETTINGS_TYPE_KEY, 'icon' => Filters::ALL[self::SETTINGS_TYPE_KEY]['icon'], + 'type' => SettingsAll::SETTINGS_SIEDBAR_TYPE_TROUBLESHOOTING, ]; } diff --git a/src/Enqueue/Blocks/EnqueueBlocks.php b/src/Enqueue/Blocks/EnqueueBlocks.php index 6250deb9a..54aa6eb5f 100644 --- a/src/Enqueue/Blocks/EnqueueBlocks.php +++ b/src/Enqueue/Blocks/EnqueueBlocks.php @@ -19,6 +19,7 @@ use EightshiftForms\Settings\Settings\SettingsGeneral; use EightshiftForms\Settings\SettingsHelper; use EightshiftForms\Tracking\TrackingInterface; +use EightshiftForms\Troubleshooting\SettingsTroubleshooting; use EightshiftForms\Validation\SettingsCaptcha; use EightshiftForms\Validation\ValidatorInterface; use EightshiftFormsVendor\EightshiftLibs\Enqueue\Blocks\AbstractEnqueueBlocks; @@ -228,7 +229,7 @@ protected function getLocalizations(): array SettingsGeneral::SETTINGS_GENERAL_DISABLE_AUTOINIT_ENQUEUE_SCRIPT_KEY, SettingsGeneral::SETTINGS_GENERAL_DISABLE_DEFAULT_ENQUEUE_KEY ); - $output['formResetOnSuccess'] = !Variables::isDevelopMode(); + $output['formResetOnSuccess'] = !$this->isCheckboxOptionChecked(SettingsTroubleshooting::SETTINGS_TROUBLESHOOTING_SKIP_RESET_KEY, SettingsTroubleshooting::SETTINGS_TROUBLESHOOTING_DEBUGGING_KEY); $output['formServerErrorMsg'] = \esc_html__('An server error occurred while submitting your form. Please try again.', 'eightshift-forms'); $output['captcha'] = ''; $output['storageConfig'] = ''; diff --git a/src/Geolocation/Geolocation.php b/src/Geolocation/Geolocation.php index b024fbdb5..85317c8ae 100644 --- a/src/Geolocation/Geolocation.php +++ b/src/Geolocation/Geolocation.php @@ -15,6 +15,7 @@ use EightshiftForms\Hooks\Filters; use EightshiftForms\Hooks\Variables; use EightshiftForms\Settings\SettingsHelper; +use EightshiftForms\Troubleshooting\SettingsTroubleshooting; use EightshiftFormsVendor\EightshiftLibs\Services\ServiceInterface; use Throwable; @@ -23,6 +24,9 @@ */ class Geolocation implements ServiceInterface, GeolocationInterface { + /** + * Use general helper trait. + */ use SettingsHelper; /** @@ -111,15 +115,20 @@ public function isUserGeolocated(string $formId, array $defaultLocations, array return $formId; } + $useLogger = $this->isCheckboxOptionChecked(SettingsTroubleshooting::SETTINGS_TROUBLESHOOTING_LOG_MODE_KEY, SettingsTroubleshooting::SETTINGS_TROUBLESHOOTING_DEBUGGING_KEY); + // Add ability to disable geolocation from external source. (Generaly used for GDPR). $filterName = Filters::getGeolocationFilterName('disable'); if (\has_filter($filterName) && \apply_filters($filterName, null)) { - Helper::logger([ - 'geolocation' => 'Filter disabled active, skip geolocation.', - 'formIdOriginal' => $formId, - 'formIdUsed' => $formId, - 'userLocation' => '', - ]); + if ($useLogger) { + Helper::logger([ + 'geolocation' => 'Filter disabled active, skip geolocation.', + 'formIdOriginal' => $formId, + 'formIdUsed' => $formId, + 'userLocation' => '', + ]); + } + return $formId; } @@ -155,12 +164,14 @@ function ($geo) use ($userLocation) { // If additional locations match output that new form. if ($matchAdditionalLocations) { - Helper::logger([ - 'geolocation' => 'Locations exists, locations match. Outputing new form.', - 'formIdOriginal' => $formId, - 'formIdUsed' => $matchAdditionalLocations['formId'] ?? '', - 'userLocation' => $userLocation, - ]); + if ($useLogger) { + Helper::logger([ + 'geolocation' => 'Locations exists, locations match. Outputing new form.', + 'formIdOriginal' => $formId, + 'formIdUsed' => $matchAdditionalLocations['formId'] ?? '', + 'userLocation' => $userLocation, + ]); + } return $matchAdditionalLocations['formId'] ?? ''; } } @@ -181,32 +192,38 @@ function ($location) use ($userLocation) { // If default locations match output that new form. if ($matchDefaultLocations) { + if ($useLogger) { + Helper::logger([ + 'geolocation' => 'Locations doesn\'t match or exist, default location match. Outputing new form.', + 'formIdOriginal' => $formId, + 'formIdUsed' => $formId, + 'userLocation' => $userLocation, + ]); + } + return $formId; + } + + // If we have set default locations but no match return empty form. + if ($useLogger) { Helper::logger([ - 'geolocation' => 'Locations doesn\'t match or exist, default location match. Outputing new form.', + 'geolocation' => 'Locations doesn\'t exists, default location doesn\'t match. Outputing nothing.', 'formIdOriginal' => $formId, - 'formIdUsed' => $formId, + 'formIdUsed' => '', 'userLocation' => $userLocation, ]); - return $formId; } + return ''; + } - // If we have set default locations but no match return empty form. + // Final fallback if the user has no locations, no default locations or they didn't match. Just return the current form. + if ($useLogger) { Helper::logger([ - 'geolocation' => 'Locations doesn\'t exists, default location doesn\'t match. Outputing nothing.', + 'geolocation' => 'Final fallback that returns the current form. Outputing the original form.', 'formIdOriginal' => $formId, - 'formIdUsed' => '', + 'formIdUsed' => $formId, 'userLocation' => $userLocation, ]); - return ''; } - - // Final fallback if the user has no locations, no default locations or they didn't match. Just return the current form. - Helper::logger([ - 'geolocation' => 'Final fallback that returns the current form. Outputing the original form.', - 'formIdOriginal' => $formId, - 'formIdUsed' => $formId, - 'userLocation' => $userLocation, - ]); return $formId; } diff --git a/src/Geolocation/SettingsGeolocation.php b/src/Geolocation/SettingsGeolocation.php index 6c99a0358..6007f6b2a 100644 --- a/src/Geolocation/SettingsGeolocation.php +++ b/src/Geolocation/SettingsGeolocation.php @@ -11,6 +11,7 @@ namespace EightshiftForms\Geolocation; use EightshiftForms\Hooks\Filters; +use EightshiftForms\Settings\Settings\SettingsAll; use EightshiftForms\Settings\Settings\SettingsDataInterface; use EightshiftForms\Settings\SettingsHelper; use EightshiftFormsVendor\EightshiftLibs\Services\ServiceInterface; @@ -83,6 +84,7 @@ public function getSettingsSidebar(): array 'label' => \__('Geolocation', 'eightshift-forms'), 'value' => self::SETTINGS_TYPE_KEY, 'icon' => Filters::ALL[self::SETTINGS_TYPE_KEY]['icon'], + 'type' => SettingsAll::SETTINGS_SIEDBAR_TYPE_GENERAL, ]; } diff --git a/src/Helpers/Helper.php b/src/Helpers/Helper.php index 1342fb028..14d36a108 100644 --- a/src/Helpers/Helper.php +++ b/src/Helpers/Helper.php @@ -14,7 +14,6 @@ use EightshiftForms\AdminMenus\FormSettingsAdminSubMenu; use EightshiftForms\AdminMenus\FormListingAdminSubMenu; use EightshiftForms\CustomPostType\Forms; -use EightshiftForms\Hooks\Variables; use EightshiftForms\Settings\Settings\SettingsGeneral; /** @@ -197,18 +196,16 @@ public static function getFormNames(string $formId): string */ public static function logger(array $message): void { - if (Variables::isLogMode()) { - $wpContentDir = \defined('WP_CONTENT_DIR') ? \WP_CONTENT_DIR : ''; + $wpContentDir = \defined('WP_CONTENT_DIR') ? \WP_CONTENT_DIR : ''; - if (!empty($wpContentDir)) { - $message['time'] = \gmdate("Y-m-d H:i:s"); + if (!empty($wpContentDir)) { + $message['time'] = \gmdate("Y-m-d H:i:s"); - if (isset($message['files'])) { - unset($message['files']); - } - - \error_log((string) \wp_json_encode($message) . "\n -------------------------------------", 3, \WP_CONTENT_DIR . '/eightshift-forms-debug.log'); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log + if (isset($message['files'])) { + unset($message['files']); } + + \error_log((string) \wp_json_encode($message) . "\n -------------------------------------", 3, \WP_CONTENT_DIR . '/eightshift-forms-debug.log'); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log } } diff --git a/src/Hooks/Variables.md b/src/Hooks/Variables.md index 9a7954508..898f706ef 100644 --- a/src/Hooks/Variables.md +++ b/src/Hooks/Variables.md @@ -5,28 +5,12 @@ This document will provide you with the code examples for forms global variables ## Set forms to develop mode This variable will set forms to develop mode that will do the following actions: -* disable value removal after the form is successfully submitted. +* output new global settings for testing inputs ```php define('ES_DEVELOP_MODE', true); ``` -## Set forms to skip validation. - -This variable will set forms to skip validation when submitting. This is useful when adding a new integration or testing API responses. - -```php -define('ES_DEVELOP_MODE_SKIP_VALIDATION', true); -``` - -## Set forms to output log. - -This variable will set forms to output log file for all requests and responses. This is useful when adding a new integration or testing API responses. - -```php -define('ES_LOG_MODE', true); -``` - ## Set Hubspot api key This variable will set forms Hubspot api key and you will not be able to change it from the admin. diff --git a/src/Hooks/Variables.php b/src/Hooks/Variables.php index 707b8d521..204d47ef5 100644 --- a/src/Hooks/Variables.php +++ b/src/Hooks/Variables.php @@ -16,7 +16,7 @@ class Variables { /** - * Get forms mode. + * Get forms develop mode, this will output new global settings for testing inputs. * * @return bool */ @@ -25,26 +25,6 @@ public static function isDevelopMode(): bool return \defined('ES_DEVELOP_MODE') ? true : false; } - /** - * Get forms to skip validation used for development of integration. - * - * @return bool - */ - public static function skipFormValidation(): bool - { - return \defined('ES_DEVELOP_MODE_SKIP_VALIDATION') ? true : false; - } - - /** - * Get forms to log out requests/responses. - * - * @return bool - */ - public static function isLogMode(): bool - { - return \defined('ES_LOG_MODE') ? true : false; - } - /** * Get API Key for HubSpot. * diff --git a/src/Integrations/ActiveCampaign/SettingsActiveCampaign.php b/src/Integrations/ActiveCampaign/SettingsActiveCampaign.php index 32fa36922..90e645f01 100644 --- a/src/Integrations/ActiveCampaign/SettingsActiveCampaign.php +++ b/src/Integrations/ActiveCampaign/SettingsActiveCampaign.php @@ -18,7 +18,9 @@ use EightshiftForms\Integrations\ActiveCampaign\ActiveCampaignClientInterface; use EightshiftForms\Integrations\MapperInterface; use EightshiftForms\Settings\GlobalSettings\SettingsGlobalDataInterface; +use EightshiftForms\Settings\Settings\SettingsAll; use EightshiftForms\Settings\Settings\SettingsDataInterface; +use EightshiftForms\Troubleshooting\SettingsTroubleshootingDataInterface; use EightshiftFormsVendor\EightshiftLibs\Services\ServiceInterface; /** @@ -95,18 +97,28 @@ class SettingsActiveCampaign implements SettingsDataInterface, SettingsGlobalDat */ private $activeCampaign; + /** + * Instance variable for Troubleshooting settings. + * + * @var SettingsTroubleshootingDataInterface + */ + protected $settingsTroubleshooting; + /** * Create a new instance. * * @param ActiveCampaignClientInterface $activeCampaignClient Inject ActiveCampaign which holds ActiveCampaign connect data. * @param MapperInterface $activeCampaign Inject ActiveCampaign which holds ActiveCampaign form data. + * @param SettingsTroubleshootingDataInterface $settingsTroubleshooting Inject Troubleshooting which holds Troubleshooting settings data. */ public function __construct( ActiveCampaignClientInterface $activeCampaignClient, - MapperInterface $activeCampaign + MapperInterface $activeCampaign, + SettingsTroubleshootingDataInterface $settingsTroubleshooting ) { $this->activeCampaignClient = $activeCampaignClient; $this->activeCampaign = $activeCampaign; + $this->settingsTroubleshooting = $settingsTroubleshooting; } /** @@ -173,6 +185,7 @@ public function getSettingsSidebar(): array 'label' => \__('ActiveCampaign', 'eightshift-forms'), 'value' => self::SETTINGS_TYPE_KEY, 'icon' => Filters::ALL[self::SETTINGS_TYPE_KEY]['icon'], + 'type' => SettingsAll::SETTINGS_SIEDBAR_TYPE_INTEGRATION, ]; } @@ -376,6 +389,9 @@ public function getSettingsGlobalData(): array ); } - return $output; + return [ + ...$output, + ...$this->settingsTroubleshooting->getOutputGlobalTroubleshooting(SettingsActiveCampaign::SETTINGS_TYPE_KEY), + ]; } } diff --git a/src/Integrations/Clearbit/SettingsClearbit.php b/src/Integrations/Clearbit/SettingsClearbit.php index c07ff35d1..b28cbc14b 100644 --- a/src/Integrations/Clearbit/SettingsClearbit.php +++ b/src/Integrations/Clearbit/SettingsClearbit.php @@ -13,6 +13,7 @@ use EightshiftForms\Hooks\Filters; use EightshiftForms\Settings\SettingsHelper; use EightshiftForms\Hooks\Variables; +use EightshiftForms\Settings\Settings\SettingsAll; use EightshiftFormsVendor\EightshiftLibs\Services\ServiceInterface; /** @@ -164,6 +165,7 @@ public function getSettingsSidebar(): array 'label' => \__('Clearbit', 'eightshift-forms'), 'value' => self::SETTINGS_TYPE_KEY, 'icon' => Filters::ALL[self::SETTINGS_TYPE_KEY]['icon'], + 'type' => SettingsAll::SETTINGS_SIEDBAR_TYPE_INTEGRATION, ]; } diff --git a/src/Integrations/Goodbits/SettingsGoodbits.php b/src/Integrations/Goodbits/SettingsGoodbits.php index b9014dfee..da3e31dee 100644 --- a/src/Integrations/Goodbits/SettingsGoodbits.php +++ b/src/Integrations/Goodbits/SettingsGoodbits.php @@ -16,7 +16,9 @@ use EightshiftForms\Hooks\Variables; use EightshiftForms\Integrations\ClientInterface; use EightshiftForms\Integrations\MapperInterface; +use EightshiftForms\Settings\Settings\SettingsAll; use EightshiftForms\Settings\Settings\SettingsDataInterface; +use EightshiftForms\Troubleshooting\SettingsTroubleshootingDataInterface; use EightshiftFormsVendor\EightshiftLibs\Services\ServiceInterface; /** @@ -88,18 +90,28 @@ class SettingsGoodbits implements SettingsDataInterface, ServiceInterface */ protected $goodbits; + /** + * Instance variable for Troubleshooting settings. + * + * @var SettingsTroubleshootingDataInterface + */ + protected $settingsTroubleshooting; + /** * Create a new instance. * * @param ClientInterface $goodbitsClient Inject Goodbits which holds Goodbits connect data. * @param MapperInterface $goodbits Inject Goodbits which holds Goodbits form data. + * @param SettingsTroubleshootingDataInterface $settingsTroubleshooting Inject Troubleshooting which holds Troubleshooting settings data. */ public function __construct( ClientInterface $goodbitsClient, - MapperInterface $goodbits + MapperInterface $goodbits, + SettingsTroubleshootingDataInterface $settingsTroubleshooting ) { $this->goodbitsClient = $goodbitsClient; $this->goodbits = $goodbits; + $this->settingsTroubleshooting = $settingsTroubleshooting; } /** * Register all the hooks @@ -164,6 +176,7 @@ public function getSettingsSidebar(): array 'label' => \__('Goodbits', 'eightshift-forms'), 'value' => self::SETTINGS_TYPE_KEY, 'icon' => Filters::ALL[self::SETTINGS_TYPE_KEY]['icon'], + 'type' => SettingsAll::SETTINGS_SIEDBAR_TYPE_INTEGRATION, ]; } @@ -348,6 +361,9 @@ public function getSettingsGlobalData(): array ); } - return $output; + return [ + ...$output, + ...$this->settingsTroubleshooting->getOutputGlobalTroubleshooting(SettingsGoodbits::SETTINGS_TYPE_KEY), + ]; } } diff --git a/src/Integrations/Greenhouse/SettingsGreenhouse.php b/src/Integrations/Greenhouse/SettingsGreenhouse.php index daa415f43..bccefc494 100644 --- a/src/Integrations/Greenhouse/SettingsGreenhouse.php +++ b/src/Integrations/Greenhouse/SettingsGreenhouse.php @@ -17,7 +17,9 @@ use EightshiftForms\Hooks\Variables; use EightshiftForms\Integrations\ClientInterface; use EightshiftForms\Integrations\MapperInterface; +use EightshiftForms\Settings\Settings\SettingsAll; use EightshiftForms\Settings\Settings\SettingsDataInterface; +use EightshiftForms\Troubleshooting\SettingsTroubleshootingDataInterface; use EightshiftFormsVendor\EightshiftLibs\Services\ServiceInterface; /** @@ -94,18 +96,28 @@ class SettingsGreenhouse implements SettingsDataInterface, ServiceInterface */ protected $greenhouse; + /** + * Instance variable for Troubleshooting settings. + * + * @var SettingsTroubleshootingDataInterface + */ + protected $settingsTroubleshooting; + /** * Create a new instance. * * @param ClientInterface $greenhouseClient Inject Greenhouse which holds Greenhouse connect data. * @param MapperInterface $greenhouse Inject Greenhouse which holds Greenhouse form data. + * @param SettingsTroubleshootingDataInterface $settingsTroubleshooting Inject Troubleshooting which holds Troubleshooting settings data. */ public function __construct( ClientInterface $greenhouseClient, - MapperInterface $greenhouse + MapperInterface $greenhouse, + SettingsTroubleshootingDataInterface $settingsTroubleshooting ) { $this->greenhouseClient = $greenhouseClient; $this->greenhouse = $greenhouse; + $this->settingsTroubleshooting = $settingsTroubleshooting; } /** @@ -172,6 +184,7 @@ public function getSettingsSidebar(): array 'label' => \__('Greenhouse', 'eightshift-forms'), 'value' => self::SETTINGS_TYPE_KEY, 'icon' => Filters::ALL[self::SETTINGS_TYPE_KEY]['icon'], + 'type' => SettingsAll::SETTINGS_SIEDBAR_TYPE_INTEGRATION, ]; } @@ -389,6 +402,9 @@ public function getSettingsGlobalData(): array ); } - return $output; + return [ + ...$output, + ...$this->settingsTroubleshooting->getOutputGlobalTroubleshooting(SettingsGreenhouse::SETTINGS_TYPE_KEY), + ]; } } diff --git a/src/Integrations/Hubspot/SettingsHubspot.php b/src/Integrations/Hubspot/SettingsHubspot.php index 497bdc944..651a772bd 100644 --- a/src/Integrations/Hubspot/SettingsHubspot.php +++ b/src/Integrations/Hubspot/SettingsHubspot.php @@ -19,7 +19,9 @@ use EightshiftForms\Integrations\Clearbit\SettingsClearbitDataInterface; use EightshiftForms\Integrations\ClientInterface; use EightshiftForms\Integrations\MapperInterface; +use EightshiftForms\Settings\Settings\SettingsAll; use EightshiftForms\Settings\Settings\SettingsDataInterface; +use EightshiftForms\Troubleshooting\SettingsTroubleshootingDataInterface; use EightshiftFormsVendor\EightshiftLibs\Services\ServiceInterface; /** @@ -135,6 +137,13 @@ class SettingsHubspot implements SettingsDataInterface, ServiceInterface */ protected $hubspot; + /** + * Instance variable for Troubleshooting settings. + * + * @var SettingsTroubleshootingDataInterface + */ + protected $settingsTroubleshooting; + /** * Create a new instance. * @@ -142,17 +151,20 @@ class SettingsHubspot implements SettingsDataInterface, ServiceInterface * @param SettingsClearbitDataInterface $settingsClearbit Inject Clearbit which holds Clearbit settings data. * @param HubspotClientInterface $hubspotClient Inject Hubspot which holds Hubspot connect data. * @param MapperInterface $hubspot Inject HubSpot which holds HubSpot form data. + * @param SettingsTroubleshootingDataInterface $settingsTroubleshooting Inject Troubleshooting which holds Troubleshooting settings data. */ public function __construct( ClearbitClientInterface $clearbitClient, SettingsClearbitDataInterface $settingsClearbit, HubspotClientInterface $hubspotClient, - MapperInterface $hubspot + MapperInterface $hubspot, + SettingsTroubleshootingDataInterface $settingsTroubleshooting ) { $this->clearbitClient = $clearbitClient; $this->settingsClearbit = $settingsClearbit; $this->hubspotClient = $hubspotClient; $this->hubspot = $hubspot; + $this->settingsTroubleshooting = $settingsTroubleshooting; } /** @@ -218,6 +230,7 @@ public function getSettingsSidebar(): array 'label' => \__('HubSpot', 'eightshift-forms'), 'value' => self::SETTINGS_TYPE_KEY, 'icon' => Filters::ALL[self::SETTINGS_TYPE_KEY]['icon'], + 'type' => SettingsAll::SETTINGS_SIEDBAR_TYPE_INTEGRATION, ]; } @@ -379,10 +392,11 @@ public function getSettingsGlobalData(): array ); } - return \array_merge( - $output, - $outputValid - ); + return [ + ...$output, + ...$outputValid, + ...$this->settingsTroubleshooting->getOutputGlobalTroubleshooting(SettingsHubspot::SETTINGS_TYPE_KEY), + ]; } /** diff --git a/src/Integrations/Mailchimp/SettingsMailchimp.php b/src/Integrations/Mailchimp/SettingsMailchimp.php index a74ca5b00..d9fd83d6e 100644 --- a/src/Integrations/Mailchimp/SettingsMailchimp.php +++ b/src/Integrations/Mailchimp/SettingsMailchimp.php @@ -18,7 +18,9 @@ use EightshiftForms\Integrations\ClientInterface; use EightshiftForms\Integrations\MapperInterface; use EightshiftForms\Settings\GlobalSettings\SettingsGlobalDataInterface; +use EightshiftForms\Settings\Settings\SettingsAll; use EightshiftForms\Settings\Settings\SettingsDataInterface; +use EightshiftForms\Troubleshooting\SettingsTroubleshootingDataInterface; use EightshiftFormsVendor\EightshiftLibs\Services\ServiceInterface; /** @@ -105,18 +107,28 @@ class SettingsMailchimp implements SettingsDataInterface, SettingsGlobalDataInte */ protected $mailchimp; + /** + * Instance variable for Troubleshooting settings. + * + * @var SettingsTroubleshootingDataInterface + */ + protected $settingsTroubleshooting; + /** * Create a new instance. * * @param MailchimpClientInterface $mailchimpClient Inject Mailchimp which holds Mailchimp connect data. * @param MapperInterface $mailchimp Inject Mailchimp which holds Mailchimp form data. + * @param SettingsTroubleshootingDataInterface $settingsTroubleshooting Inject Troubleshooting which holds Troubleshooting settings data. */ public function __construct( MailchimpClientInterface $mailchimpClient, - MapperInterface $mailchimp + MapperInterface $mailchimp, + SettingsTroubleshootingDataInterface $settingsTroubleshooting ) { $this->mailchimpClient = $mailchimpClient; $this->mailchimp = $mailchimp; + $this->settingsTroubleshooting = $settingsTroubleshooting; } /** @@ -182,6 +194,7 @@ public function getSettingsSidebar(): array 'label' => \__('Mailchimp', 'eightshift-forms'), 'value' => self::SETTINGS_TYPE_KEY, 'icon' => Filters::ALL[self::SETTINGS_TYPE_KEY]['icon'], + 'type' => SettingsAll::SETTINGS_SIEDBAR_TYPE_INTEGRATION, ]; } @@ -491,6 +504,9 @@ public function getSettingsGlobalData(): array ); } - return $output; + return [ + ...$output, + ...$this->settingsTroubleshooting->getOutputGlobalTroubleshooting(SettingsMailchimp::SETTINGS_TYPE_KEY), + ]; } } diff --git a/src/Integrations/Mailerlite/SettingsMailerlite.php b/src/Integrations/Mailerlite/SettingsMailerlite.php index 157eb7d53..31a0a1dd4 100644 --- a/src/Integrations/Mailerlite/SettingsMailerlite.php +++ b/src/Integrations/Mailerlite/SettingsMailerlite.php @@ -17,7 +17,9 @@ use EightshiftForms\Hooks\Variables; use EightshiftForms\Integrations\ClientInterface; use EightshiftForms\Integrations\MapperInterface; +use EightshiftForms\Settings\Settings\SettingsAll; use EightshiftForms\Settings\Settings\SettingsDataInterface; +use EightshiftForms\Troubleshooting\SettingsTroubleshootingDataInterface; use EightshiftFormsVendor\EightshiftLibs\Services\ServiceInterface; /** @@ -89,18 +91,28 @@ class SettingsMailerlite implements SettingsDataInterface, ServiceInterface */ protected $mailerlite; + /** + * Instance variable for Troubleshooting settings. + * + * @var SettingsTroubleshootingDataInterface + */ + protected $settingsTroubleshooting; + /** * Create a new instance. * * @param ClientInterface $mailerliteClient Inject Mailerlite which holds Mailerlite connect data. * @param MapperInterface $mailerlite Inject Mailerlite which holds Mailerlite form data. + * @param SettingsTroubleshootingDataInterface $settingsTroubleshooting Inject Troubleshooting which holds Troubleshooting settings data. */ public function __construct( ClientInterface $mailerliteClient, - MapperInterface $mailerlite + MapperInterface $mailerlite, + SettingsTroubleshootingDataInterface $settingsTroubleshooting ) { $this->mailerliteClient = $mailerliteClient; $this->mailerlite = $mailerlite; + $this->settingsTroubleshooting = $settingsTroubleshooting; } /** * Register all the hooks @@ -165,6 +177,7 @@ public function getSettingsSidebar(): array 'label' => \__('MailerLite', 'eightshift-forms'), 'value' => self::SETTINGS_TYPE_KEY, 'icon' => Filters::ALL[self::SETTINGS_TYPE_KEY]['icon'], + 'type' => SettingsAll::SETTINGS_SIEDBAR_TYPE_INTEGRATION, ]; } @@ -356,6 +369,9 @@ public function getSettingsGlobalData(): array ); } - return $output; + return [ + ...$output, + ...$this->settingsTroubleshooting->getOutputGlobalTroubleshooting(SettingsMailerlite::SETTINGS_TYPE_KEY), + ]; } } diff --git a/src/Mailer/Mailer.php b/src/Mailer/Mailer.php index 24be8c7de..1fc851d13 100644 --- a/src/Mailer/Mailer.php +++ b/src/Mailer/Mailer.php @@ -143,11 +143,18 @@ public function fallbackEmail(array $data): bool } $to = $this->getOptionValue(SettingsTroubleshooting::SETTINGS_TROUBLESHOOTING_FALLBACK_EMAIL_KEY); + $cc = $this->getOptionValue(SettingsTroubleshooting::SETTINGS_TROUBLESHOOTING_FALLBACK_EMAIL_KEY . '-' . $integration); // translators: %1$s replaces the integration name and %2$s formId. $subject = \sprintf(\__('Your %1$s form failed: %2$s', 'eightshift-forms'), $integration, $formId); - $headers = $this->getType(); // translators: %s replaces the parameters list html. $templateHtml = \sprintf(\__("

    It looks like something went wrong with the users form submition, here is all the data to debug.

    %s", 'eightshift-forms'), $paramsOutput); + $headers = [ + $this->getType() + ]; + + if ($cc) { + $headers[] = "Cc: {$cc}"; + } // Send email. return \wp_mail($to, $subject, $templateHtml, $headers, $filesOutput); diff --git a/src/Mailer/SettingsMailer.php b/src/Mailer/SettingsMailer.php index a47baded5..b0717819f 100644 --- a/src/Mailer/SettingsMailer.php +++ b/src/Mailer/SettingsMailer.php @@ -12,6 +12,7 @@ use EightshiftForms\Helpers\Helper; use EightshiftForms\Hooks\Filters; +use EightshiftForms\Settings\Settings\SettingsAll; use EightshiftForms\Settings\SettingsHelper; use EightshiftForms\Settings\Settings\SettingsDataInterface; use EightshiftFormsVendor\EightshiftLibs\Services\ServiceInterface; @@ -135,6 +136,7 @@ public function getSettingsSidebar(): array 'label' => \__('Mailer', 'eightshift-forms'), 'value' => self::SETTINGS_TYPE_KEY, 'icon' => Filters::ALL[self::SETTINGS_TYPE_KEY]['icon'], + 'type' => SettingsAll::SETTINGS_SIEDBAR_TYPE_GENERAL, ]; } diff --git a/src/Rest/ApiHelper.php b/src/Rest/ApiHelper.php index fe75a469a..06566ae91 100644 --- a/src/Rest/ApiHelper.php +++ b/src/Rest/ApiHelper.php @@ -11,6 +11,8 @@ namespace EightshiftForms\Rest; use EightshiftForms\Helpers\Helper; +use EightshiftForms\Settings\SettingsHelper; +use EightshiftForms\Troubleshooting\SettingsTroubleshooting; use EightshiftFormsVendor\EightshiftLibs\Helpers\Components; /** @@ -18,6 +20,11 @@ */ trait ApiHelper { + /** + * Use general helper trait. + */ + use SettingsHelper; + /** * Return API response array details. * @@ -80,7 +87,9 @@ public function getApiReponseDetails( */ public function getApiErrorOutput(array $details, string $msg): array { - Helper::logger($details); + if ($this->isCheckboxOptionChecked(SettingsTroubleshooting::SETTINGS_TROUBLESHOOTING_LOG_MODE_KEY, SettingsTroubleshooting::SETTINGS_TROUBLESHOOTING_DEBUGGING_KEY)) { + Helper::logger($details); + } return [ 'status' => 'error', diff --git a/src/Rest/Routes/AbstractFormSubmit.php b/src/Rest/Routes/AbstractFormSubmit.php index ef8873913..07a755772 100644 --- a/src/Rest/Routes/AbstractFormSubmit.php +++ b/src/Rest/Routes/AbstractFormSubmit.php @@ -14,7 +14,7 @@ use EightshiftForms\Settings\SettingsHelper; use EightshiftForms\Helpers\UploadHelper; use EightshiftForms\Hooks\Filters; -use EightshiftForms\Hooks\Variables; +use EightshiftForms\Troubleshooting\SettingsTroubleshooting; use WP_REST_Request; /** @@ -81,7 +81,7 @@ public function routeCallback(WP_REST_Request $request) $formData = isset(Filters::ALL[$formType]['fields']) ? \apply_filters(Filters::ALL[$formType]['fields'], $formId) : []; // Validate request. - if (!Variables::skipFormValidation()) { + if (!$this->isCheckboxOptionChecked(SettingsTroubleshooting::SETTINGS_TROUBLESHOOTING_SKIP_VALIDATION_KEY, SettingsTroubleshooting::SETTINGS_TROUBLESHOOTING_DEBUGGING_KEY)) { $this->verifyRequest( $params, $request->get_file_params(), diff --git a/src/Rest/Routes/FormSettingsSubmitRoute.php b/src/Rest/Routes/FormSettingsSubmitRoute.php index 8012f385b..7642cc738 100644 --- a/src/Rest/Routes/FormSettingsSubmitRoute.php +++ b/src/Rest/Routes/FormSettingsSubmitRoute.php @@ -14,7 +14,8 @@ use EightshiftForms\Cache\SettingsCache; use EightshiftForms\Exception\UnverifiedRequestException; use EightshiftForms\Hooks\Filters; -use EightshiftForms\Hooks\Variables; +use EightshiftForms\Settings\SettingsHelper; +use EightshiftForms\Troubleshooting\SettingsTroubleshooting; use EightshiftForms\Validation\ValidatorInterface; use EightshiftFormsVendor\EightshiftLibs\Helpers\Components; use WP_REST_Request; @@ -24,6 +25,11 @@ */ class FormSettingsSubmitRoute extends AbstractBaseRoute { + /** + * Use general helper trait. + */ + use SettingsHelper; + /** * Instance variable of ValidatorInterface data. * @@ -103,7 +109,7 @@ public function routeCallback(WP_REST_Request $request) $formData = isset(Filters::ALL[$formType][$formInternalType]) ? \apply_filters(Filters::ALL[$formType][$formInternalType], $formId) : []; // Validate request. - if (!Variables::skipFormValidation()) { + if (!$this->isCheckboxOptionChecked(SettingsTroubleshooting::SETTINGS_TROUBLESHOOTING_SKIP_VALIDATION_KEY, SettingsTroubleshooting::SETTINGS_TROUBLESHOOTING_DEBUGGING_KEY)) { $this->verifyRequest( $params, $request->get_file_params(), diff --git a/src/Settings/Settings/SettingsAll.php b/src/Settings/Settings/SettingsAll.php index e5c531391..afa038747 100644 --- a/src/Settings/Settings/SettingsAll.php +++ b/src/Settings/Settings/SettingsAll.php @@ -19,6 +19,46 @@ */ class SettingsAll extends AbstractFormBuilder implements SettingsAllInterface { + /** + * Settings sidebar type - general + * + * @var string + */ + public const SETTINGS_SIEDBAR_TYPE_GENERAL = 'general'; + + /** + * Settings sidebar type - integration + * + * @var string + */ + public const SETTINGS_SIEDBAR_TYPE_INTEGRATION = 'integration'; + + /** + * Settings sidebar type - troubleshooting + * + * @var string + */ + public const SETTINGS_SIEDBAR_TYPE_TROUBLESHOOTING = 'troubleshooting'; + + /** + * Settings sidebar type - develop + * + * @var string + */ + public const SETTINGS_SIEDBAR_TYPE_DEVELOP = 'develop'; + + /** + * Sidebar Sort order. + * + * @var array + */ + public const SIDEBAR_SORT_ORDER = [ + self::SETTINGS_SIEDBAR_TYPE_GENERAL, + self::SETTINGS_SIEDBAR_TYPE_INTEGRATION, + self::SETTINGS_SIEDBAR_TYPE_TROUBLESHOOTING, + self::SETTINGS_SIEDBAR_TYPE_DEVELOP + ]; + /** * Get all settings sidebar array for building settings page. * diff --git a/src/Settings/Settings/SettingsGeneral.php b/src/Settings/Settings/SettingsGeneral.php index bc51e6f82..0676df974 100644 --- a/src/Settings/Settings/SettingsGeneral.php +++ b/src/Settings/Settings/SettingsGeneral.php @@ -101,6 +101,7 @@ public function getSettingsSidebar(): array 'label' => \__('General', 'eightshift-forms'), 'value' => self::SETTINGS_TYPE_KEY, 'icon' => Filters::ALL[self::SETTINGS_TYPE_KEY]['icon'], + 'type' => SettingsAll::SETTINGS_SIEDBAR_TYPE_GENERAL, ]; } diff --git a/src/Settings/Settings/SettingsLocation.php b/src/Settings/Settings/SettingsLocation.php index 925ea4700..73ef67f0e 100644 --- a/src/Settings/Settings/SettingsLocation.php +++ b/src/Settings/Settings/SettingsLocation.php @@ -62,6 +62,7 @@ public function getSettingsSidebar(): array 'label' => \__('Display locations', 'eightshift-forms'), 'value' => self::SETTINGS_TYPE_KEY, 'icon' => Filters::ALL[self::SETTINGS_TYPE_KEY]['icon'], + 'type' => SettingsAll::SETTINGS_SIEDBAR_TYPE_TROUBLESHOOTING, ]; } diff --git a/src/Settings/Settings/SettingsTest.php b/src/Settings/Settings/SettingsTest.php index 27acbd384..374f92de6 100644 --- a/src/Settings/Settings/SettingsTest.php +++ b/src/Settings/Settings/SettingsTest.php @@ -61,6 +61,7 @@ public function getSettingsSidebar(): array 'label' => \__('Test', 'eightshift-forms'), 'value' => self::SETTINGS_TYPE_KEY, 'icon' => Filters::ALL[self::SETTINGS_TYPE_KEY]['icon'], + 'type' => SettingsAll::SETTINGS_SIEDBAR_TYPE_DEVELOP, ]; } diff --git a/src/Troubleshooting/SettingsTroubleshooting.php b/src/Troubleshooting/SettingsTroubleshooting.php index e4219b1c4..8bc9cbddd 100644 --- a/src/Troubleshooting/SettingsTroubleshooting.php +++ b/src/Troubleshooting/SettingsTroubleshooting.php @@ -11,14 +11,14 @@ namespace EightshiftForms\Troubleshooting; use EightshiftForms\Hooks\Filters; +use EightshiftForms\Settings\Settings\SettingsAll; use EightshiftForms\Settings\SettingsHelper; -use EightshiftForms\Settings\Settings\SettingsDataInterface; use EightshiftFormsVendor\EightshiftLibs\Services\ServiceInterface; /** * SettingsTroubleshooting class. */ -class SettingsTroubleshooting implements SettingsDataInterface, ServiceInterface +class SettingsTroubleshooting implements ServiceInterface, SettingsTroubleshootingDataInterface { /** * Use general helper trait. @@ -55,6 +55,14 @@ class SettingsTroubleshooting implements SettingsDataInterface, ServiceInterface */ public const SETTINGS_TROUBLESHOOTING_FALLBACK_EMAIL_KEY = 'troubleshooting-fallback-email'; + /** + * Troubleshooting debugging key. + */ + public const SETTINGS_TROUBLESHOOTING_DEBUGGING_KEY = 'troubleshooting-debugging'; + public const SETTINGS_TROUBLESHOOTING_SKIP_VALIDATION_KEY = 'skip-validation'; + public const SETTINGS_TROUBLESHOOTING_SKIP_RESET_KEY = 'skip-reset'; + public const SETTINGS_TROUBLESHOOTING_LOG_MODE_KEY = 'log-mode'; + /** * Register all the hooks * @@ -95,6 +103,7 @@ public function getSettingsSidebar(): array 'label' => \__('Troubleshooting', 'eightshift-forms'), 'value' => self::SETTINGS_TYPE_KEY, 'icon' => Filters::ALL[self::SETTINGS_TYPE_KEY]['icon'], + 'type' => SettingsAll::SETTINGS_SIEDBAR_TYPE_TROUBLESHOOTING, ]; } @@ -121,7 +130,7 @@ public function getSettingsGlobalData(): array [ 'component' => 'intro', 'introTitle' => \__('Fallback emails', 'eightshift-forms'), - 'introSubtitle' => \__('Your forms will send email fallbacks with all the data if there is any kind of error. This can email can be used to debug or provide manual input of the data to any integration.', 'eightshift-forms'), + 'introSubtitle' => \__('Your forms will send email fallbacks with all the data if there is any kind of error. This email can be used to debug or provide manual input of the data to any integration.', 'eightshift-forms'), ], [ 'component' => 'checkboxes', @@ -148,14 +157,91 @@ public function getSettingsGlobalData(): array 'inputName' => $this->getSettingsName(self::SETTINGS_TROUBLESHOOTING_FALLBACK_EMAIL_KEY), 'inputId' => $this->getSettingsName(self::SETTINGS_TROUBLESHOOTING_FALLBACK_EMAIL_KEY), 'inputFieldLabel' => \__('Fallback e-mail', 'eightshift-forms'), - 'inputFieldHelp' => \__('Set email where all fallback emails will be sent.', 'eightshift-forms'), + 'inputFieldHelp' => \__('Set email where all fallback emails will be sent. Use comma to separate multiple emails.', 'eightshift-forms'), 'inputType' => 'text', - 'inputIsEmail' => true, 'inputIsRequired' => true, 'inputValue' => $this->getOptionValue(self::SETTINGS_TROUBLESHOOTING_FALLBACK_EMAIL_KEY), ]; } - return $output; + $outputDebugging = [ + [ + 'component' => 'divider', + ], + [ + 'component' => 'intro', + 'introTitle' => \__('Debugging', 'eightshift-forms'), + 'introSubtitle' => \__('Settings used for debugging forms. USE WITH CAUTION!', 'eightshift-forms'), + ], + [ + 'component' => 'checkboxes', + 'checkboxesFieldLabel' => '', + 'checkboxesName' => $this->getSettingsName(self::SETTINGS_TROUBLESHOOTING_DEBUGGING_KEY), + 'checkboxesId' => $this->getSettingsName(self::SETTINGS_TROUBLESHOOTING_DEBUGGING_KEY), + 'checkboxesContent' => [ + [ + 'component' => 'checkbox', + 'checkboxLabel' => \__('Skip validation', 'eightshift-forms'), + 'checkboxIsChecked' => $this->isCheckboxOptionChecked(self::SETTINGS_TROUBLESHOOTING_SKIP_VALIDATION_KEY, self::SETTINGS_TROUBLESHOOTING_DEBUGGING_KEY), + 'checkboxValue' => self::SETTINGS_TROUBLESHOOTING_SKIP_VALIDATION_KEY, + ], + [ + 'component' => 'checkbox', + 'checkboxLabel' => \__('Skip form reset after submit', 'eightshift-forms'), + 'checkboxIsChecked' => $this->isCheckboxOptionChecked(self::SETTINGS_TROUBLESHOOTING_SKIP_RESET_KEY, self::SETTINGS_TROUBLESHOOTING_DEBUGGING_KEY), + 'checkboxValue' => self::SETTINGS_TROUBLESHOOTING_SKIP_RESET_KEY, + ], + [ + 'component' => 'checkbox', + 'checkboxLabel' => \__('Output logs', 'eightshift-forms'), + 'checkboxIsChecked' => $this->isCheckboxOptionChecked(self::SETTINGS_TROUBLESHOOTING_LOG_MODE_KEY, self::SETTINGS_TROUBLESHOOTING_DEBUGGING_KEY), + 'checkboxValue' => self::SETTINGS_TROUBLESHOOTING_LOG_MODE_KEY, + ] + ] + ], + ]; + + return [ + ...$output, + ...$outputDebugging, + ]; + } + + /** + * Output array settings for form. + * + * @param string $integration Integration name used for troubleshooting. + * + * @return array>|bool|string>> + */ + public function getOutputGlobalTroubleshooting(string $integration): array + { + $isValid = $this->isSettingsGlobalValid(); + + if (!$isValid) { + return []; + } + + return [ + [ + 'component' => 'divider', + ], + [ + 'component' => 'intro', + 'introTitle' => \__('Troubleshooting', 'eightshift-forms'), + 'introSubtitle' => \__('Your forms will send email fallbacks with all the data if there is any kind of error. This email can be used to debug or provide manual input of the data to any integration.', 'eightshift-forms'), + 'introTitleSize' => 'medium', + ], + [ + 'component' => 'input', + 'inputName' => $this->getSettingsName(self::SETTINGS_TROUBLESHOOTING_FALLBACK_EMAIL_KEY . '-' . $integration), + 'inputId' => $this->getSettingsName(self::SETTINGS_TROUBLESHOOTING_FALLBACK_EMAIL_KEY . '-' . $integration), + 'inputFieldLabel' => \__('Fallback e-mail', 'eightshift-forms'), + 'inputFieldHelp' => \__('Set email where this integration fallback emails will be sent. This field will be used as "cc", main "from" field will be used from the main Troubleshooting global setting page. Use comma to separate multiple emails.', 'eightshift-forms'), + 'inputType' => 'text', + 'inputIsRequired' => true, + 'inputValue' => $this->getOptionValue(self::SETTINGS_TROUBLESHOOTING_FALLBACK_EMAIL_KEY . '-' . $integration), + ], + ]; } } diff --git a/src/Troubleshooting/SettingsTroubleshootingDataInterface.php b/src/Troubleshooting/SettingsTroubleshootingDataInterface.php new file mode 100644 index 000000000..4f977666e --- /dev/null +++ b/src/Troubleshooting/SettingsTroubleshootingDataInterface.php @@ -0,0 +1,28 @@ +>|bool|string>> + */ + public function getOutputGlobalTroubleshooting(string $integration): array; +} diff --git a/src/Validation/SettingsCaptcha.php b/src/Validation/SettingsCaptcha.php index ead1a9f08..f9a0d540f 100644 --- a/src/Validation/SettingsCaptcha.php +++ b/src/Validation/SettingsCaptcha.php @@ -14,6 +14,7 @@ use EightshiftForms\Hooks\Variables; use EightshiftForms\Settings\SettingsHelper; use EightshiftForms\Labels\LabelsInterface; +use EightshiftForms\Settings\Settings\SettingsAll; use EightshiftForms\Settings\Settings\SettingsDataInterface; use EightshiftFormsVendor\EightshiftLibs\Services\ServiceInterface; @@ -130,6 +131,7 @@ public function getSettingsSidebar(): array 'label' => \__('Captcha', 'eightshift-forms'), 'value' => self::SETTINGS_TYPE_KEY, 'icon' => Filters::ALL[self::SETTINGS_TYPE_KEY]['icon'], + 'type' => SettingsAll::SETTINGS_SIEDBAR_TYPE_GENERAL, ]; } diff --git a/src/Validation/SettingsValidation.php b/src/Validation/SettingsValidation.php index 4b88def7f..71189980d 100644 --- a/src/Validation/SettingsValidation.php +++ b/src/Validation/SettingsValidation.php @@ -15,6 +15,7 @@ use EightshiftForms\Settings\SettingsHelper; use EightshiftForms\Labels\LabelsInterface; use EightshiftForms\Helpers\Helper; +use EightshiftForms\Settings\Settings\SettingsAll; use EightshiftForms\Settings\Settings\SettingsDataInterface; use EightshiftFormsVendor\EightshiftLibs\Services\ServiceInterface; @@ -101,6 +102,7 @@ public function getSettingsSidebar(): array 'label' => \__('Validation', 'eightshift-forms'), 'value' => self::SETTINGS_TYPE_KEY, 'icon' => Filters::ALL[self::SETTINGS_TYPE_KEY]['icon'], + 'type' => SettingsAll::SETTINGS_SIEDBAR_TYPE_GENERAL, ]; } From 9f058792ca8c9c41f6106077d94f641a4386dd06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20Ru=C5=BEevi=C4=87?= Date: Mon, 5 Sep 2022 16:26:09 +0200 Subject: [PATCH 08/12] Update src/Integrations/Goodbits/GoodbitsClient.php Co-authored-by: Karlo Volf <46056662+volfkarlo@users.noreply.github.com> --- src/Integrations/Goodbits/GoodbitsClient.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Integrations/Goodbits/GoodbitsClient.php b/src/Integrations/Goodbits/GoodbitsClient.php index 6ba49f498..a6cf55f01 100644 --- a/src/Integrations/Goodbits/GoodbitsClient.php +++ b/src/Integrations/Goodbits/GoodbitsClient.php @@ -213,7 +213,7 @@ private function prepareParams(array $params): array $customFields = \array_flip(Components::flattenArray(AbstractBaseRoute::CUSTOM_FORM_PARAMS)); foreach ($params as $key => $param) { - // Remove unecesery fields. + // Remove unnecessary fields. if (isset($customFields[$key])) { continue; } From 96666c38cd8c4dc787c2df0df5ba642f6dc23259 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20Ru=C5=BEevi=C4=87?= Date: Tue, 6 Sep 2022 08:37:40 +0200 Subject: [PATCH 09/12] Update src/AdminMenus/FormGlobalSettingsAdminSubMenu.php MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Denis Žoljom --- src/AdminMenus/FormGlobalSettingsAdminSubMenu.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/AdminMenus/FormGlobalSettingsAdminSubMenu.php b/src/AdminMenus/FormGlobalSettingsAdminSubMenu.php index 4d9d1c560..5aa51a6bd 100644 --- a/src/AdminMenus/FormGlobalSettingsAdminSubMenu.php +++ b/src/AdminMenus/FormGlobalSettingsAdminSubMenu.php @@ -175,7 +175,8 @@ protected function processAttributes($attr): array $settingsSidebarOutput = []; foreach ($this->settingsGlobal->getSettingsSidebar($type) as $item) { - $settingsSidebarOutput[$item['type'] ?? 'general'][] = $item; + $sidebarType = $item['type'] ?? 'general'; + $settingsSidebarOutput[$sidebarType][] = $item; } return [ From 1b3d417edb68689142a1e9b815ef6e984564c8d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20Ruz=CC=8Cevic=CC=81?= Date: Tue, 6 Sep 2022 08:47:08 +0200 Subject: [PATCH 10/12] pr fixes --- .../FormGlobalSettingsAdminSubMenu.php | 3 +- src/AdminMenus/FormSettingsAdminSubMenu.php | 4 +- .../partials/sidebar-section.php | 52 +++++++++---------- src/Hooks/FiltersTracking.md | 10 ++-- 4 files changed, 36 insertions(+), 33 deletions(-) diff --git a/src/AdminMenus/FormGlobalSettingsAdminSubMenu.php b/src/AdminMenus/FormGlobalSettingsAdminSubMenu.php index 5aa51a6bd..73d03a420 100644 --- a/src/AdminMenus/FormGlobalSettingsAdminSubMenu.php +++ b/src/AdminMenus/FormGlobalSettingsAdminSubMenu.php @@ -13,6 +13,7 @@ use EightshiftFormsVendor\EightshiftLibs\Helpers\Components; use EightshiftForms\Helpers\Helper; use EightshiftForms\Settings\GlobalSettings\SettingsGlobalInterface; +use EightshiftForms\Settings\Settings\SettingsAll; use EightshiftForms\Settings\Settings\SettingsGeneral; use EightshiftFormsVendor\EightshiftLibs\AdminMenus\AbstractAdminSubMenu; @@ -175,7 +176,7 @@ protected function processAttributes($attr): array $settingsSidebarOutput = []; foreach ($this->settingsGlobal->getSettingsSidebar($type) as $item) { - $sidebarType = $item['type'] ?? 'general'; + $sidebarType = $item['type'] ?? SettingsAll::SETTINGS_SIEDBAR_TYPE_GENERAL; $settingsSidebarOutput[$sidebarType][] = $item; } diff --git a/src/AdminMenus/FormSettingsAdminSubMenu.php b/src/AdminMenus/FormSettingsAdminSubMenu.php index 7ebaed0b5..c93907572 100644 --- a/src/AdminMenus/FormSettingsAdminSubMenu.php +++ b/src/AdminMenus/FormSettingsAdminSubMenu.php @@ -12,6 +12,7 @@ use EightshiftFormsVendor\EightshiftLibs\Helpers\Components; use EightshiftForms\Helpers\Helper; +use EightshiftForms\Settings\Settings\SettingsAll; use EightshiftForms\Settings\Settings\SettingsAllInterface; use EightshiftForms\Settings\Settings\SettingsGeneral; use EightshiftFormsVendor\EightshiftLibs\AdminMenus\AbstractAdminSubMenu; @@ -188,7 +189,8 @@ protected function processAttributes($attr): array $settingsSidebarOutput = []; foreach ($this->settingsAll->getSettingsSidebar($formId, $type) as $item) { - $settingsSidebarOutput[$item['type'] ?? 'general'][] = $item; + $sidebarType = $item['type'] ?? SettingsAll::SETTINGS_SIEDBAR_TYPE_GENERAL; + $settingsSidebarOutput[$sidebarType][] = $item; } return [ diff --git a/src/Blocks/components/admin-settings/partials/sidebar-section.php b/src/Blocks/components/admin-settings/partials/sidebar-section.php index f0d5eabae..343e8197b 100644 --- a/src/Blocks/components/admin-settings/partials/sidebar-section.php +++ b/src/Blocks/components/admin-settings/partials/sidebar-section.php @@ -24,7 +24,7 @@ // Provide order we want on output. $sortOrder = SettingsAll::SIDEBAR_SORT_ORDER; uksort($items, function ($key1, $key2) use ($sortOrder) { - return ((array_search($key1, $sortOrder, true) > array_search($key2, $sortOrder, true)) ? 1 : -1); + return array_search($key1, $sortOrder, true) <=> array_search($key2, $sortOrder, true); }); foreach ($items as $key => $innerItems) { @@ -44,32 +44,32 @@ } ?> -
    "> -
    "> -
    "> - +
    "> +
    "> +
    "> + +
    +
    -
    -
    true, + 'utm_content' => true, + 'utm_campaign' => true, + ]; foreach ($storage as $key => $param) { if (isset($allowedTags[$key]) && isset($originalParams[$key])) { From 194fdfd881197b2fbde7461d3a9ea3887cf90b7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20Ru=C5=BEevi=C4=87?= Date: Tue, 6 Sep 2022 08:48:53 +0200 Subject: [PATCH 11/12] Apply suggestions from code review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Denis Žoljom --- src/Enqueue/Blocks/EnqueueBlocks.php | 2 +- src/Geolocation/Geolocation.php | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Enqueue/Blocks/EnqueueBlocks.php b/src/Enqueue/Blocks/EnqueueBlocks.php index e6069de4a..71fe652e5 100644 --- a/src/Enqueue/Blocks/EnqueueBlocks.php +++ b/src/Enqueue/Blocks/EnqueueBlocks.php @@ -230,7 +230,7 @@ protected function getLocalizations(): array SettingsGeneral::SETTINGS_GENERAL_DISABLE_DEFAULT_ENQUEUE_KEY ); $output['formResetOnSuccess'] = !$this->isCheckboxOptionChecked(SettingsTroubleshooting::SETTINGS_TROUBLESHOOTING_SKIP_RESET_KEY, SettingsTroubleshooting::SETTINGS_TROUBLESHOOTING_DEBUGGING_KEY); - $output['formServerErrorMsg'] = \esc_html__('An server error occurred while submitting your form. Please try again.', 'eightshift-forms'); + $output['formServerErrorMsg'] = \esc_html__('A server error occurred while submitting your form. Please try again.', 'eightshift-forms'); $output['captcha'] = ''; $output['storageConfig'] = ''; diff --git a/src/Geolocation/Geolocation.php b/src/Geolocation/Geolocation.php index 85317c8ae..87ddc8ed7 100644 --- a/src/Geolocation/Geolocation.php +++ b/src/Geolocation/Geolocation.php @@ -122,7 +122,7 @@ public function isUserGeolocated(string $formId, array $defaultLocations, array if (\has_filter($filterName) && \apply_filters($filterName, null)) { if ($useLogger) { Helper::logger([ - 'geolocation' => 'Filter disabled active, skip geolocation.', + 'geolocation' => 'Disable filter is active, skipping geolocation.', 'formIdOriginal' => $formId, 'formIdUsed' => $formId, 'userLocation' => '', @@ -194,7 +194,7 @@ function ($location) use ($userLocation) { if ($matchDefaultLocations) { if ($useLogger) { Helper::logger([ - 'geolocation' => 'Locations doesn\'t match or exist, default location match. Outputing new form.', + 'geolocation' => 'Locations don\'t match or exist, default location selected. Outputting new form.', 'formIdOriginal' => $formId, 'formIdUsed' => $formId, 'userLocation' => $userLocation, @@ -206,7 +206,7 @@ function ($location) use ($userLocation) { // If we have set default locations but no match return empty form. if ($useLogger) { Helper::logger([ - 'geolocation' => 'Locations doesn\'t exists, default location doesn\'t match. Outputing nothing.', + 'geolocation' => 'Locations don\'t exists, default location doesn\'t match. Outputting nothing.', 'formIdOriginal' => $formId, 'formIdUsed' => '', 'userLocation' => $userLocation, From 7496d9747fcf76a972aaa3b9bf560ad162221925 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20Ruz=CC=8Cevic=CC=81?= Date: Tue, 6 Sep 2022 12:43:43 +0200 Subject: [PATCH 12/12] updating frontend-libs --- package-lock.json | 579 +++++++++++++++++++++++++--------------------- package.json | 2 +- 2 files changed, 312 insertions(+), 269 deletions(-) diff --git a/package-lock.json b/package-lock.json index 736035f64..9fdd44f9a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "@eightshift/eightshift-forms", - "version": "1.3.1-alpha", + "version": "1.4.0", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -38,25 +38,25 @@ } }, "@babel/compat-data": { - "version": "7.18.13", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.18.13.tgz", - "integrity": "sha512-5yUzC5LqyTFp2HLmDoxGQelcdYgSpP9xsnMWBphAscOdFrHSAVbLNzWiy32sVNDqJRDiJK6klfDnAgu6PAGSHw==" + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.19.0.tgz", + "integrity": "sha512-y5rqgTTPTmaF5e2nVhOxw+Ur9HDJLsWb6U/KpgUzRZEdPfE6VOubXBKLdbcUTijzRptednSBDQbYZBOSqJxpJw==" }, "@babel/core": { - "version": "7.18.13", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.18.13.tgz", - "integrity": "sha512-ZisbOvRRusFktksHSG6pjj1CSvkPkcZq/KHD45LAkVP/oiHJkNBZWfpvlLmX8OtHDG8IuzsFlVRWo08w7Qxn0A==", + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.19.0.tgz", + "integrity": "sha512-reM4+U7B9ss148rh2n1Qs9ASS+w94irYXga7c2jaQv9RVzpS7Mv1a9rnYYwuDa45G+DkORt9g6An2k/V4d9LbQ==", "requires": { "@ampproject/remapping": "^2.1.0", "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.18.13", - "@babel/helper-compilation-targets": "^7.18.9", - "@babel/helper-module-transforms": "^7.18.9", - "@babel/helpers": "^7.18.9", - "@babel/parser": "^7.18.13", + "@babel/generator": "^7.19.0", + "@babel/helper-compilation-targets": "^7.19.0", + "@babel/helper-module-transforms": "^7.19.0", + "@babel/helpers": "^7.19.0", + "@babel/parser": "^7.19.0", "@babel/template": "^7.18.10", - "@babel/traverse": "^7.18.13", - "@babel/types": "^7.18.13", + "@babel/traverse": "^7.19.0", + "@babel/types": "^7.19.0", "convert-source-map": "^1.7.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -97,11 +97,11 @@ } }, "@babel/generator": { - "version": "7.18.13", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.18.13.tgz", - "integrity": "sha512-CkPg8ySSPuHTYPJYo7IRALdqyjM9HCbt/3uOBEFbzyGVP6Mn8bwFPB0jX6982JVNBlYzM1nnPkfjuXSOPtQeEQ==", + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.19.0.tgz", + "integrity": "sha512-S1ahxf1gZ2dpoiFgA+ohK9DIpz50bJ0CWs7Zlzb54Z4sG8qmdIrGrVqmy1sAtTVRb+9CU6U8VqT9L0Zj7hxHVg==", "requires": { - "@babel/types": "^7.18.13", + "@babel/types": "^7.19.0", "@jridgewell/gen-mapping": "^0.3.2", "jsesc": "^2.5.1" }, @@ -136,11 +136,11 @@ } }, "@babel/helper-compilation-targets": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.18.9.tgz", - "integrity": "sha512-tzLCyVmqUiFlcFoAPLA/gL9TeYrF61VLNtb+hvkuVaB5SUjW7jcfrglBIX1vUIoT7CLP3bBlIMeyEsIl2eFQNg==", + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.19.0.tgz", + "integrity": "sha512-Ai5bNWXIvwDvWM7njqsG3feMlL9hCVQsPYXodsZyLwshYkZVJt59Gftau4VrE8S9IT9asd2uSP1hG6wCNw+sXA==", "requires": { - "@babel/compat-data": "^7.18.8", + "@babel/compat-data": "^7.19.0", "@babel/helper-validator-option": "^7.18.6", "browserslist": "^4.20.2", "semver": "^6.3.0" @@ -154,13 +154,13 @@ } }, "@babel/helper-create-class-features-plugin": { - "version": "7.18.13", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.18.13.tgz", - "integrity": "sha512-hDvXp+QYxSRL+23mpAlSGxHMDyIGChm0/AwTfTAAK5Ufe40nCsyNdaYCGuK91phn/fVu9kqayImRDkvNAgdrsA==", + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.19.0.tgz", + "integrity": "sha512-NRz8DwF4jT3UfrmUoZjd0Uph9HQnP30t7Ash+weACcyNkiYTywpIjDBgReJMKgr+n86sn2nPVVmJ28Dm053Kqw==", "requires": { "@babel/helper-annotate-as-pure": "^7.18.6", "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-function-name": "^7.18.9", + "@babel/helper-function-name": "^7.19.0", "@babel/helper-member-expression-to-functions": "^7.18.9", "@babel/helper-optimise-call-expression": "^7.18.6", "@babel/helper-replace-supers": "^7.18.9", @@ -168,9 +168,9 @@ } }, "@babel/helper-create-regexp-features-plugin": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.18.6.tgz", - "integrity": "sha512-7LcpH1wnQLGrI+4v+nPp+zUvIkF9x0ddv1Hkdue10tg3gmRnLy97DXh4STiOf1qeIInyD69Qv5kKSZzKD8B/7A==", + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.19.0.tgz", + "integrity": "sha512-htnV+mHX32DF81amCDrwIDr8nrp1PTm+3wfBN9/v8QJOLEioOCOG7qNyq0nHeFiWbT3Eb7gsPwEmV64UCQ1jzw==", "requires": { "@babel/helper-annotate-as-pure": "^7.18.6", "regexpu-core": "^5.1.0" @@ -220,12 +220,12 @@ } }, "@babel/helper-function-name": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.18.9.tgz", - "integrity": "sha512-fJgWlZt7nxGksJS9a0XdSaI4XvpExnNIgRP+rVefWh5U7BL8pPuir6SJUmFKRfjWQ51OtWSzwOxhaH/EBWWc0A==", + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.19.0.tgz", + "integrity": "sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w==", "requires": { - "@babel/template": "^7.18.6", - "@babel/types": "^7.18.9" + "@babel/template": "^7.18.10", + "@babel/types": "^7.19.0" } }, "@babel/helper-hoist-variables": { @@ -253,18 +253,18 @@ } }, "@babel/helper-module-transforms": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.18.9.tgz", - "integrity": "sha512-KYNqY0ICwfv19b31XzvmI/mfcylOzbLtowkw+mfvGPAQ3kfCnMLYbED3YecL5tPd8nAYFQFAd6JHp2LxZk/J1g==", + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.19.0.tgz", + "integrity": "sha512-3HBZ377Fe14RbLIA+ac3sY4PTgpxHVkFrESaWhoI5PuyXPBBX8+C34qblV9G89ZtycGJCmCI/Ut+VUDK4bltNQ==", "requires": { "@babel/helper-environment-visitor": "^7.18.9", "@babel/helper-module-imports": "^7.18.6", "@babel/helper-simple-access": "^7.18.6", "@babel/helper-split-export-declaration": "^7.18.6", "@babel/helper-validator-identifier": "^7.18.6", - "@babel/template": "^7.18.6", - "@babel/traverse": "^7.18.9", - "@babel/types": "^7.18.9" + "@babel/template": "^7.18.10", + "@babel/traverse": "^7.19.0", + "@babel/types": "^7.19.0" } }, "@babel/helper-optimise-call-expression": { @@ -276,9 +276,9 @@ } }, "@babel/helper-plugin-utils": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.18.9.tgz", - "integrity": "sha512-aBXPT3bmtLryXaoJLyYPXPlSD4p1ld9aYeR+sJNOZjJJGiOpb+fKfh3NkcCu7J54nUJwCERPBExCCpyCOHnu/w==" + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.19.0.tgz", + "integrity": "sha512-40Ryx7I8mT+0gaNxm8JGTZFUITNqdLAgdg0hXzeVZxVD6nFsdhQvip6v8dqkRHzsz1VFpFAaOCHNn0vKBL7Czw==" }, "@babel/helper-remap-async-to-generator": { "version": "7.18.9", @@ -343,24 +343,24 @@ "integrity": "sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==" }, "@babel/helper-wrap-function": { - "version": "7.18.11", - "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.18.11.tgz", - "integrity": "sha512-oBUlbv+rjZLh2Ks9SKi4aL7eKaAXBWleHzU89mP0G6BMUlRxSckk9tSIkgDGydhgFxHuGSlBQZfnaD47oBEB7w==", + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.19.0.tgz", + "integrity": "sha512-txX8aN8CZyYGTwcLhlk87KRqncAzhh5TpQamZUa0/u3an36NtDpUP6bQgBCBcLeBs09R/OwQu3OjK0k/HwfNDg==", "requires": { - "@babel/helper-function-name": "^7.18.9", + "@babel/helper-function-name": "^7.19.0", "@babel/template": "^7.18.10", - "@babel/traverse": "^7.18.11", - "@babel/types": "^7.18.10" + "@babel/traverse": "^7.19.0", + "@babel/types": "^7.19.0" } }, "@babel/helpers": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.18.9.tgz", - "integrity": "sha512-Jf5a+rbrLoR4eNdUmnFu8cN5eNJT6qdTdOg5IHIzq87WwyRw9PwguLFOWYgktN/60IP4fgDUawJvs7PjQIzELQ==", + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.19.0.tgz", + "integrity": "sha512-DRBCKGwIEdqY3+rPJgG/dKfQy9+08rHIAJx8q2p+HSWP87s2HCrQmaAMMyMll2kIXKCW0cO1RdQskx15Xakftg==", "requires": { - "@babel/template": "^7.18.6", - "@babel/traverse": "^7.18.9", - "@babel/types": "^7.18.9" + "@babel/template": "^7.18.10", + "@babel/traverse": "^7.19.0", + "@babel/types": "^7.19.0" } }, "@babel/highlight": { @@ -420,9 +420,9 @@ } }, "@babel/parser": { - "version": "7.18.13", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.18.13.tgz", - "integrity": "sha512-dgXcIfMuQ0kgzLB2b9tRZs7TTFFaGM2AbtA4fJgUUYukzGH4jwsS7hzQHEGs67jdehpm22vkgKwvbU+aEflgwg==" + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.19.0.tgz", + "integrity": "sha512-74bEXKX2h+8rrfQUfsBfuZZHzsEs6Eql4pqy/T4Nn6Y9wNPggQOqD6z6pn5Bl8ZfysKouFZT/UXEH94ummEeQw==" }, "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { "version": "7.18.6", @@ -443,12 +443,12 @@ } }, "@babel/plugin-proposal-async-generator-functions": { - "version": "7.18.10", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.18.10.tgz", - "integrity": "sha512-1mFuY2TOsR1hxbjCo4QL+qlIjV07p4H4EUYw2J/WCqsvFV6V9X9z9YhXbWndc/4fw+hYGlDT7egYxliMp5O6Ew==", + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.19.0.tgz", + "integrity": "sha512-nhEByMUTx3uZueJ/QkJuSlCfN4FGg+xy+vRsfGQGzSauq5ks2Deid2+05Q3KhfaUjvec1IGhw/Zm3cFm8JigTQ==", "requires": { "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-plugin-utils": "^7.18.9", + "@babel/helper-plugin-utils": "^7.19.0", "@babel/helper-remap-async-to-generator": "^7.18.9", "@babel/plugin-syntax-async-generators": "^7.8.4" } @@ -473,15 +473,15 @@ } }, "@babel/plugin-proposal-decorators": { - "version": "7.18.10", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.18.10.tgz", - "integrity": "sha512-wdGTwWF5QtpTY/gbBtQLAiCnoxfD4qMbN87NYZle1dOZ9Os8Y6zXcKrIaOU8W+TIvFUWVGG9tUgNww3CjXRVVw==", + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.19.0.tgz", + "integrity": "sha512-Bo5nOSjiJccjv00+BrDkmfeBLBi2B0qe8ygj24KdL8VdwtZz+710NCwehF+x/Ng+0mkHx5za2eAofmvVFLF4Fg==", "requires": { - "@babel/helper-create-class-features-plugin": "^7.18.9", - "@babel/helper-plugin-utils": "^7.18.9", + "@babel/helper-create-class-features-plugin": "^7.19.0", + "@babel/helper-plugin-utils": "^7.19.0", "@babel/helper-replace-supers": "^7.18.9", "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/plugin-syntax-decorators": "^7.18.6" + "@babel/plugin-syntax-decorators": "^7.19.0" } }, "@babel/plugin-proposal-dynamic-import": { @@ -632,11 +632,11 @@ } }, "@babel/plugin-syntax-decorators": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.18.6.tgz", - "integrity": "sha512-fqyLgjcxf/1yhyZ6A+yo1u9gJ7eleFQod2lkaUsF9DQ7sbbY3Ligym3L0+I2c0WmqNKDpoD9UTb1AKP3qRMOAQ==", + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.19.0.tgz", + "integrity": "sha512-xaBZUEDntt4faL1yN8oIFlhfXeQAWJW7CLKYsHTUqriCUbj8xOra8bfxxKGi/UwExPFBuPdH4XfHc9rGQhrVkQ==", "requires": { - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/helper-plugin-utils": "^7.19.0" } }, "@babel/plugin-syntax-dynamic-import": { @@ -802,15 +802,16 @@ } }, "@babel/plugin-transform-classes": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.18.9.tgz", - "integrity": "sha512-EkRQxsxoytpTlKJmSPYrsOMjCILacAjtSVkd4gChEe2kXjFCun3yohhW5I7plXJhCemM0gKsaGMcO8tinvCA5g==", + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.19.0.tgz", + "integrity": "sha512-YfeEE9kCjqTS9IitkgfJuxjcEtLUHMqa8yUJ6zdz8vR7hKuo6mOy2C05P0F1tdMmDCeuyidKnlrw/iTppHcr2A==", "requires": { "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-compilation-targets": "^7.19.0", "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-function-name": "^7.18.9", + "@babel/helper-function-name": "^7.19.0", "@babel/helper-optimise-call-expression": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.9", + "@babel/helper-plugin-utils": "^7.19.0", "@babel/helper-replace-supers": "^7.18.9", "@babel/helper-split-export-declaration": "^7.18.6", "globals": "^11.1.0" @@ -866,11 +867,11 @@ } }, "@babel/plugin-transform-flow-strip-types": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.18.9.tgz", - "integrity": "sha512-+G6rp2zRuOAInY5wcggsx4+QVao1qPM0osC9fTUVlAV3zOrzTCnrMAFVnR6+a3T8wz1wFIH7KhYMcMB3u1n80A==", + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.19.0.tgz", + "integrity": "sha512-sgeMlNaQVbCSpgLSKP4ZZKfsJVnFnNQlUSk6gPYzR/q7tzCgQF2t8RBKAP6cKJeZdveei7Q7Jm527xepI8lNLg==", "requires": { - "@babel/helper-plugin-utils": "^7.18.9", + "@babel/helper-plugin-utils": "^7.19.0", "@babel/plugin-syntax-flow": "^7.18.6" } }, @@ -930,13 +931,13 @@ } }, "@babel/plugin-transform-modules-systemjs": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.18.9.tgz", - "integrity": "sha512-zY/VSIbbqtoRoJKo2cDTewL364jSlZGvn0LKOf9ntbfxOvjfmyrdtEEOAdswOswhZEb8UH3jDkCKHd1sPgsS0A==", + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.19.0.tgz", + "integrity": "sha512-x9aiR0WXAWmOWsqcsnrzGR+ieaTMVyGyffPVA7F8cXAGt/UxefYv6uSHZLkAFChN5M5Iy1+wjE+xJuPt22H39A==", "requires": { "@babel/helper-hoist-variables": "^7.18.6", - "@babel/helper-module-transforms": "^7.18.9", - "@babel/helper-plugin-utils": "^7.18.9", + "@babel/helper-module-transforms": "^7.19.0", + "@babel/helper-plugin-utils": "^7.19.0", "@babel/helper-validator-identifier": "^7.18.6", "babel-plugin-dynamic-import-node": "^2.3.3" } @@ -951,12 +952,12 @@ } }, "@babel/plugin-transform-named-capturing-groups-regex": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.18.6.tgz", - "integrity": "sha512-UmEOGF8XgaIqD74bC8g7iV3RYj8lMf0Bw7NJzvnS9qQhM4mg+1WHKotUIdjxgD2RGrgFLZZPCFPFj3P/kVDYhg==", + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.19.0.tgz", + "integrity": "sha512-HDSuqOQzkU//kfGdiHBt71/hkDTApw4U/cMVgKgX7PqfB3LOaK+2GtCEsBu1dL9CkswDm0Gwehht1dCr421ULQ==", "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/helper-create-regexp-features-plugin": "^7.19.0", + "@babel/helper-plugin-utils": "^7.19.0" } }, "@babel/plugin-transform-new-target": { @@ -1001,15 +1002,15 @@ } }, "@babel/plugin-transform-react-jsx": { - "version": "7.18.10", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.18.10.tgz", - "integrity": "sha512-gCy7Iikrpu3IZjYZolFE4M1Sm+nrh1/6za2Ewj77Z+XirT4TsbJcvOFOyF+fRPwU6AKKK136CZxx6L8AbSFG6A==", + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.19.0.tgz", + "integrity": "sha512-UVEvX3tXie3Szm3emi1+G63jyw1w5IcMY0FSKM+CRnKRI5Mr1YbCNgsSTwoTwKphQEG9P+QqmuRFneJPZuHNhg==", "requires": { "@babel/helper-annotate-as-pure": "^7.18.6", "@babel/helper-module-imports": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.9", + "@babel/helper-plugin-utils": "^7.19.0", "@babel/plugin-syntax-jsx": "^7.18.6", - "@babel/types": "^7.18.10" + "@babel/types": "^7.19.0" } }, "@babel/plugin-transform-react-jsx-development": { @@ -1055,11 +1056,11 @@ } }, "@babel/plugin-transform-spread": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.18.9.tgz", - "integrity": "sha512-39Q814wyoOPtIB/qGopNIL9xDChOE1pNU0ZY5dO0owhiVt/5kFm4li+/bBtwc7QotG0u5EPzqhZdjMtmqBqyQA==", + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.19.0.tgz", + "integrity": "sha512-RsuMk7j6n+r752EtzyScnWkQyuJdli6LdO5Klv8Yx0OfPVTcQkIUfS8clx5e9yHXzlnhOZF3CbQ8C2uP5j074w==", "requires": { - "@babel/helper-plugin-utils": "^7.18.9", + "@babel/helper-plugin-utils": "^7.19.0", "@babel/helper-skip-transparent-expression-wrappers": "^7.18.9" } }, @@ -1088,12 +1089,12 @@ } }, "@babel/plugin-transform-typescript": { - "version": "7.18.12", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.18.12.tgz", - "integrity": "sha512-2vjjam0cum0miPkenUbQswKowuxs/NjMwIKEq0zwegRxXk12C9YOF9STXnaUptITOtOJHKHpzvvWYOjbm6tc0w==", + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.19.0.tgz", + "integrity": "sha512-DOOIywxPpkQHXijXv+s9MDAyZcLp12oYRl3CMWZ6u7TjSoCBq/KqHR/nNFR3+i2xqheZxoF0H2XyL7B6xeSRuA==", "requires": { - "@babel/helper-create-class-features-plugin": "^7.18.9", - "@babel/helper-plugin-utils": "^7.18.9", + "@babel/helper-create-class-features-plugin": "^7.19.0", + "@babel/helper-plugin-utils": "^7.19.0", "@babel/plugin-syntax-typescript": "^7.18.6" } }, @@ -1115,17 +1116,17 @@ } }, "@babel/preset-env": { - "version": "7.18.10", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.18.10.tgz", - "integrity": "sha512-wVxs1yjFdW3Z/XkNfXKoblxoHgbtUF7/l3PvvP4m02Qz9TZ6uZGxRVYjSQeR87oQmHco9zWitW5J82DJ7sCjvA==", + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.19.0.tgz", + "integrity": "sha512-1YUju1TAFuzjIQqNM9WsF4U6VbD/8t3wEAlw3LFYuuEr+ywqLRcSXxFKz4DCEj+sN94l/XTDiUXYRrsvMpz9WQ==", "requires": { - "@babel/compat-data": "^7.18.8", - "@babel/helper-compilation-targets": "^7.18.9", - "@babel/helper-plugin-utils": "^7.18.9", + "@babel/compat-data": "^7.19.0", + "@babel/helper-compilation-targets": "^7.19.0", + "@babel/helper-plugin-utils": "^7.19.0", "@babel/helper-validator-option": "^7.18.6", "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.18.6", "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.18.9", - "@babel/plugin-proposal-async-generator-functions": "^7.18.10", + "@babel/plugin-proposal-async-generator-functions": "^7.19.0", "@babel/plugin-proposal-class-properties": "^7.18.6", "@babel/plugin-proposal-class-static-block": "^7.18.6", "@babel/plugin-proposal-dynamic-import": "^7.18.6", @@ -1159,9 +1160,9 @@ "@babel/plugin-transform-async-to-generator": "^7.18.6", "@babel/plugin-transform-block-scoped-functions": "^7.18.6", "@babel/plugin-transform-block-scoping": "^7.18.9", - "@babel/plugin-transform-classes": "^7.18.9", + "@babel/plugin-transform-classes": "^7.19.0", "@babel/plugin-transform-computed-properties": "^7.18.9", - "@babel/plugin-transform-destructuring": "^7.18.9", + "@babel/plugin-transform-destructuring": "^7.18.13", "@babel/plugin-transform-dotall-regex": "^7.18.6", "@babel/plugin-transform-duplicate-keys": "^7.18.9", "@babel/plugin-transform-exponentiation-operator": "^7.18.6", @@ -1171,9 +1172,9 @@ "@babel/plugin-transform-member-expression-literals": "^7.18.6", "@babel/plugin-transform-modules-amd": "^7.18.6", "@babel/plugin-transform-modules-commonjs": "^7.18.6", - "@babel/plugin-transform-modules-systemjs": "^7.18.9", + "@babel/plugin-transform-modules-systemjs": "^7.19.0", "@babel/plugin-transform-modules-umd": "^7.18.6", - "@babel/plugin-transform-named-capturing-groups-regex": "^7.18.6", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.19.0", "@babel/plugin-transform-new-target": "^7.18.6", "@babel/plugin-transform-object-super": "^7.18.6", "@babel/plugin-transform-parameters": "^7.18.8", @@ -1181,14 +1182,14 @@ "@babel/plugin-transform-regenerator": "^7.18.6", "@babel/plugin-transform-reserved-words": "^7.18.6", "@babel/plugin-transform-shorthand-properties": "^7.18.6", - "@babel/plugin-transform-spread": "^7.18.9", + "@babel/plugin-transform-spread": "^7.19.0", "@babel/plugin-transform-sticky-regex": "^7.18.6", "@babel/plugin-transform-template-literals": "^7.18.9", "@babel/plugin-transform-typeof-symbol": "^7.18.9", "@babel/plugin-transform-unicode-escapes": "^7.18.10", "@babel/plugin-transform-unicode-regex": "^7.18.6", "@babel/preset-modules": "^0.1.5", - "@babel/types": "^7.18.10", + "@babel/types": "^7.19.0", "babel-plugin-polyfill-corejs2": "^0.3.2", "babel-plugin-polyfill-corejs3": "^0.5.3", "babel-plugin-polyfill-regenerator": "^0.4.0", @@ -1319,9 +1320,9 @@ } }, "@babel/runtime-corejs3": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.18.9.tgz", - "integrity": "sha512-qZEWeccZCrHA2Au4/X05QW5CMdm4VjUDCrGq5gf1ZDcM4hRqreKrtwAn7yci9zfgAS9apvnsFXiGBHBAxZdK9A==", + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.19.0.tgz", + "integrity": "sha512-JyXXoCu1N8GLuKc2ii8y5RGma5FMpFeO2nAQIe0Yzrbq+rQnN+sFj47auLblR5ka6aHNGPDgv8G/iI2Grb0ldQ==", "requires": { "core-js-pure": "^3.20.2", "regenerator-runtime": "^0.13.4" @@ -1338,18 +1339,18 @@ } }, "@babel/traverse": { - "version": "7.18.13", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.18.13.tgz", - "integrity": "sha512-N6kt9X1jRMLPxxxPYWi7tgvJRH/rtoU+dbKAPDM44RFHiMH8igdsaSBgFeskhSl/kLWLDUvIh1RXCrTmg0/zvA==", + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.19.0.tgz", + "integrity": "sha512-4pKpFRDh+utd2mbRC8JLnlsMUii3PMHjpL6a0SZ4NMZy7YFP9aXORxEhdMVOc9CpWtDF09IkciQLEhK7Ml7gRA==", "requires": { "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.18.13", + "@babel/generator": "^7.19.0", "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-function-name": "^7.18.9", + "@babel/helper-function-name": "^7.19.0", "@babel/helper-hoist-variables": "^7.18.6", "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/parser": "^7.18.13", - "@babel/types": "^7.18.13", + "@babel/parser": "^7.19.0", + "@babel/types": "^7.19.0", "debug": "^4.1.0", "globals": "^11.1.0" }, @@ -1362,9 +1363,9 @@ } }, "@babel/types": { - "version": "7.18.13", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.18.13.tgz", - "integrity": "sha512-ePqfTihzW0W6XAU+aMw2ykilisStJfDnsejDCXRchCcMJ4O0+8DhPXf2YUbZ6wjBlsEmZwLK/sPweWtu8hcJYQ==", + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.19.0.tgz", + "integrity": "sha512-YuGopBq3ke25BVSiS6fgF49Ul9gH1x70Bcr6bqRLjWCkcX8Hre1/5+z+IiWOIerRMSSEfGZVB9z9kyq7wVs9YA==", "requires": { "@babel/helper-string-parser": "^7.18.10", "@babel/helper-validator-identifier": "^7.18.6", @@ -1381,14 +1382,62 @@ "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==" }, - "@eightshift/frontend-libs": { + "@dnd-kit/accessibility": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@dnd-kit/accessibility/-/accessibility-3.0.1.tgz", + "integrity": "sha512-HXRrwS9YUYQO9lFRc/49uO/VICbM+O+ZRpFDe9Pd1rwVv2PCNkRiTZRdxrDgng/UkvdC3Re9r2vwPpXXrWeFzg==", + "requires": { + "tslib": "^2.0.0" + } + }, + "@dnd-kit/core": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/@dnd-kit/core/-/core-6.0.5.tgz", + "integrity": "sha512-3nL+Zy5cT+1XwsWdlXIvGIFvbuocMyB4NBxTN74DeBaBqeWdH9JsnKwQv7buZQgAHmAH+eIENfS1ginkvW6bCw==", + "requires": { + "@dnd-kit/accessibility": "^3.0.0", + "@dnd-kit/utilities": "^3.2.0", + "tslib": "^2.0.0" + } + }, + "@dnd-kit/modifiers": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@dnd-kit/modifiers/-/modifiers-6.0.0.tgz", + "integrity": "sha512-V3+JSo6/BTcgPRHiNUTSKgqVv/doKXg+T4Z0QvKiiXp+uIyJTUtPkQOBRQApUWi3ApBhnoWljyt/3xxY4fTd0Q==", + "requires": { + "@dnd-kit/utilities": "^3.2.0", + "tslib": "^2.0.0" + } + }, + "@dnd-kit/sortable": { "version": "7.0.1", - "resolved": "https://registry.npmjs.org/@eightshift/frontend-libs/-/frontend-libs-7.0.1.tgz", - "integrity": "sha512-6m0WXy6fMVpH3L/+i0qkEBfq+77wQx+JZIYAOsG3aeYr1hZTxe4qjAWKZaRkl3Cu5cyoqRalLmr7XO83qpw9Mg==", + "resolved": "https://registry.npmjs.org/@dnd-kit/sortable/-/sortable-7.0.1.tgz", + "integrity": "sha512-n77qAzJQtMMywu25sJzhz3gsHnDOUlEjTtnRl8A87rWIhnu32zuP+7zmFjwGgvqfXmRufqiHOSlH7JPC/tnJ8Q==", + "requires": { + "@dnd-kit/utilities": "^3.2.0", + "tslib": "^2.0.0" + } + }, + "@dnd-kit/utilities": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@dnd-kit/utilities/-/utilities-3.2.0.tgz", + "integrity": "sha512-h65/pn2IPCCIWwdlR2BMLqRkDxpTEONA+HQW3n765HBijLYGyrnTCLa2YQt8VVjjSQD6EfFlTE6aS2Q/b6nb2g==", + "requires": { + "tslib": "^2.0.0" + } + }, + "@eightshift/frontend-libs": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@eightshift/frontend-libs/-/frontend-libs-7.1.0.tgz", + "integrity": "sha512-RYHK+HJ6j18k9Aez/a83YGe4HLApIO0/7vpuhEXOgUcjXJi9WYUZKLXA16dCDp16hE3kTUXcMAxIog+r4M0G/A==", "requires": { "@babel/cli": "^7.18.6", "@babel/eslint-parser": "^7.18.2", "@babel/eslint-plugin": "^7.17.7", + "@dnd-kit/core": "^6.0.5", + "@dnd-kit/modifiers": "^6.0.0", + "@dnd-kit/sortable": "^7.0.1", + "@dnd-kit/utilities": "^3.2.0", "@infinumjs/eslint-config-react-js": "^3.3.1", "@wordpress/api-fetch": "^6.9.0", "@wordpress/dependency-extraction-webpack-plugin": "^3.6.0", @@ -1469,9 +1518,9 @@ } }, "@emotion/cache": { - "version": "11.10.2", - "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.10.2.tgz", - "integrity": "sha512-GPR4PovENRvYDbCEnDRecPZYJzWdNMsM+Jn+13MC5uImVNbMyKwzv95DUHy5PDcgfPtKoDtfLU6emF1grrbQDg==", + "version": "11.10.3", + "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.10.3.tgz", + "integrity": "sha512-Psmp/7ovAa8appWh3g51goxu/z3iVms7JXOreq136D8Bbn6dYraPnmL6mdM8GThEx9vwSn92Fz+mGSjBzN8UPQ==", "requires": { "@emotion/memoize": "^0.8.0", "@emotion/sheet": "^1.2.0", @@ -1491,14 +1540,15 @@ "integrity": "sha512-G/YwXTkv7Den9mXDO7AhLWkE3q+I92B+VqAE+dYG4NGPaHZGvt3G8Q0p9vmE+sq7rTGphUbAvmQ9YpbfMQGGlA==" }, "@emotion/react": { - "version": "11.10.0", - "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.10.0.tgz", - "integrity": "sha512-K6z9zlHxxBXwN8TcpwBKcEsBsOw4JWCCmR+BeeOWgqp8GIU1yA2Odd41bwdAAr0ssbQrbJbVnndvv7oiv1bZeQ==", + "version": "11.10.4", + "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.10.4.tgz", + "integrity": "sha512-j0AkMpr6BL8gldJZ6XQsQ8DnS9TxEQu1R+OGmDZiWjBAJtCcbt0tS3I/YffoqHXxH6MjgI7KdMbYKw3MEiU9eA==", "requires": { "@babel/runtime": "^7.18.3", "@emotion/babel-plugin": "^11.10.0", "@emotion/cache": "^11.10.0", "@emotion/serialize": "^1.1.0", + "@emotion/use-insertion-effect-with-fallbacks": "^1.0.0", "@emotion/utils": "^1.2.0", "@emotion/weak-memoize": "^0.3.0", "hoist-non-react-statics": "^3.3.1" @@ -1526,6 +1576,11 @@ "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.8.0.tgz", "integrity": "sha512-VINS5vEYAscRl2ZUDiT3uMPlrFQupiKgHz5AA4bCH1miKBg4qtwkim1qPmJj/4WG6TreYMY111rEFsjupcOKHw==" }, + "@emotion/use-insertion-effect-with-fallbacks": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.0.0.tgz", + "integrity": "sha512-1eEgUGmkaljiBnRMTdksDV1W4kUnmwgp7X9G8B++9GYwl1lUdqSndSriIrTJ0N7LQaoauY9JJ2yhiOYK5+NI4A==" + }, "@emotion/utils": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.2.0.tgz", @@ -1537,13 +1592,13 @@ "integrity": "sha512-AHPmaAx+RYfZz0eYu6Gviiagpmiyw98ySSlQvCUhVGDRtDFe4DBS0x1bSjdF3gqUDYOczB+yYvBTtEylYSdRhg==" }, "@eslint/eslintrc": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.0.tgz", - "integrity": "sha512-UWW0TMTmk2d7hLcWD1/e2g5HDM/HQ3csaLSqXCfqwh4uNDuNqlaKWXmEsL4Cs41Z0KnILNvwbHAah3C2yt06kw==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.1.tgz", + "integrity": "sha512-OhSY22oQQdw3zgPOOwdoj01l/Dzl1Z+xyUP33tkSN+aqyEhymJCcPHyXt+ylW8FSe0TfRC2VG+ROQOapD0aZSQ==", "requires": { "ajv": "^6.12.4", "debug": "^4.3.2", - "espree": "^9.3.2", + "espree": "^9.4.0", "globals": "^13.15.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", @@ -1567,6 +1622,11 @@ "resolved": "https://registry.npmjs.org/@humanwhocodes/gitignore-to-minimatch/-/gitignore-to-minimatch-1.0.2.tgz", "integrity": "sha512-rSqmMJDdLFUsyxR6FMtD00nfQKKLFb1kv+qBbOVKqErvloEIJLo5bDTJTQNTYgeyp78JsA7u/NPi5jT1GR/MuA==" }, + "@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==" + }, "@humanwhocodes/object-schema": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", @@ -1911,9 +1971,9 @@ } }, "@types/node": { - "version": "16.11.54", - "resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.54.tgz", - "integrity": "sha512-ryOpwe15+BtTUxKFfzABjaI/EtXLPBSBEW4B6D5ygWNcORLVKG/1/FC3WwAr5d7t6lCnlVPRsCY0NH680QT+Pg==" + "version": "16.11.57", + "resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.57.tgz", + "integrity": "sha512-diBb5AE2V8h9Fs9zEDtBwSeLvIACng/aAkdZ3ujMV+cGuIQ9Nc/V+wQqurk9HJp8ni5roBxQHW21z/ZYbGDivg==" }, "acorn": { "version": "6.4.2", @@ -2533,11 +2593,6 @@ "resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz", "integrity": "sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==" }, - "@types/component-emitter": { - "version": "1.2.11", - "resolved": "https://registry.npmjs.org/@types/component-emitter/-/component-emitter-1.2.11.tgz", - "integrity": "sha512-SRXjM+tfsSlA9VuG8hGO2nft2p8zjXCK1VcC6N4NXbBbYbSia9kzCChYQajIjzIqOOOuh5Ock6MmV2oux4jDZQ==" - }, "@types/cookie": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz", @@ -2617,9 +2672,9 @@ "integrity": "sha512-vXOTGVSLR2jMw440moWTC7H19iUyLtP3Z1YTj7cSsubOICinjMxFeb/V57v9QdyyPGbbWolUFSSmSiRSn94tFw==" }, "@types/minimatch": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.5.tgz", - "integrity": "sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ==" + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-5.1.2.tgz", + "integrity": "sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==" }, "@types/minimist": { "version": "1.2.2", @@ -2662,9 +2717,9 @@ "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==" }, "@types/react": { - "version": "17.0.48", - "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.48.tgz", - "integrity": "sha512-zJ6IYlJ8cYYxiJfUaZOQee4lh99mFihBoqkOSEGV+dFi9leROW6+PgstzQ+w3gWTnUfskALtQPGHK6dYmPj+2A==", + "version": "17.0.49", + "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.49.tgz", + "integrity": "sha512-CCBPMZaPhcKkYUTqFs/hOWqKjPxhTEmnZWjlHHgIMop67DsXywf9B5Os9Hz8KSacjNOgIdnZVJamwl232uxoPg==", "requires": { "@types/prop-types": "*", "@types/scheduler": "*", @@ -2895,13 +2950,13 @@ "integrity": "sha512-oxnCNGj88fL+xzV+dacXs44HcDwf1ovs3AuEzvP7mqXw7fQntqIhQ1BRmynh4qEKQSSSRSWVyXRjmTbZIX9V2Q==" }, "@wordpress/api-fetch": { - "version": "6.12.0", - "resolved": "https://registry.npmjs.org/@wordpress/api-fetch/-/api-fetch-6.12.0.tgz", - "integrity": "sha512-5zfpvmAd1Fx+89R+ldBfA+mbHxatmpNWxH9BRdF8tFXIFcJhKLFvGK7NsJuqnTu4DH0pr1tAzQyf+QcF4UkV9A==", + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/@wordpress/api-fetch/-/api-fetch-6.13.0.tgz", + "integrity": "sha512-PwVhZI64naytQFmMc2veQYz6jA3DyAPe3cv3L499iKgigNt41fNHZpEz5tgZmpLJA0Avp9Ldy+izCzt9A0PKcQ==", "requires": { "@babel/runtime": "^7.16.0", - "@wordpress/i18n": "^4.15.0", - "@wordpress/url": "^3.16.0" + "@wordpress/i18n": "^4.16.0", + "@wordpress/url": "^3.17.0" } }, "@wordpress/dependency-extraction-webpack-plugin": { @@ -2914,51 +2969,58 @@ } }, "@wordpress/dom-ready": { - "version": "3.15.0", - "resolved": "https://registry.npmjs.org/@wordpress/dom-ready/-/dom-ready-3.15.0.tgz", - "integrity": "sha512-sP6M/nBFvN7cK0jnEQmNDwXPyoPSd35e178vE8zWxu070/6YZkCne0sT9MPvW3Q7LA8VZLles6PgXe4Kg1rgXw==", + "version": "3.16.0", + "resolved": "https://registry.npmjs.org/@wordpress/dom-ready/-/dom-ready-3.16.0.tgz", + "integrity": "sha512-l4tQ65Y1lNMNypjM8Shi08NsxwS3D/lxFYwOznx+JNZzGU6IU39xHDIzCZYyFOkGvO2NkY7AjyITVnvVNkYY5Q==", "requires": { "@babel/runtime": "^7.16.0" } }, "@wordpress/element": { - "version": "4.13.0", - "resolved": "https://registry.npmjs.org/@wordpress/element/-/element-4.13.0.tgz", - "integrity": "sha512-oxTEiK7y0bLva9SMbt/xrp90VgDMFcLSOSPz1lS8wSrC+Hy8NyN0v5rku3DdIUf07kYtcOfiQ1jmsmwDWNvodg==", + "version": "4.14.0", + "resolved": "https://registry.npmjs.org/@wordpress/element/-/element-4.14.0.tgz", + "integrity": "sha512-puH6E1sY5HYcU9MTnwpvwmlGqs0prxNd0JuT2/WcHAd/qwDC2wQPB/7fDaffjB0+gIYUt6WBl8kCWkqQ7g6cbQ==", "requires": { "@babel/runtime": "^7.16.0", "@types/react": "^17.0.37", "@types/react-dom": "^17.0.11", - "@wordpress/escape-html": "^2.15.0", + "@wordpress/escape-html": "^2.16.0", "change-case": "^4.1.2", - "is-plain-obj": "^4.1.0", + "is-plain-object": "^5.0.0", "react": "^17.0.2", "react-dom": "^17.0.2" + }, + "dependencies": { + "is-plain-object": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", + "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==" + } } }, "@wordpress/escape-html": { - "version": "2.15.0", - "resolved": "https://registry.npmjs.org/@wordpress/escape-html/-/escape-html-2.15.0.tgz", - "integrity": "sha512-eW655uSjCK835/eBt1lgCBtLFfgxSX4MiMTe7Dxo8pqZmP5cwh9zNJuirEnVnaamjAjfIVRel4awNGZebflJeg==", + "version": "2.16.0", + "resolved": "https://registry.npmjs.org/@wordpress/escape-html/-/escape-html-2.16.0.tgz", + "integrity": "sha512-63SfsnkGTIFBXQWy+vAjlb2PJp9A59R0wsTv4TIS/DBJq6EtAox9GjBbswGzX6l0VksobUcga1FqOua9+i3EyA==", "requires": { "@babel/runtime": "^7.16.0" } }, "@wordpress/hooks": { - "version": "3.15.0", - "resolved": "https://registry.npmjs.org/@wordpress/hooks/-/hooks-3.15.0.tgz", - "integrity": "sha512-w0kFs8xX4C+ofTszaNaggdvs+cuVl4wOCPULncOfXLEWo4MBwUpx82BFTeV5ql44oOF6iEEKHcR75gOOXCXOVQ==", + "version": "3.16.0", + "resolved": "https://registry.npmjs.org/@wordpress/hooks/-/hooks-3.16.0.tgz", + "integrity": "sha512-KpY8KFp2/3TX6lKmffNmdkeaH9c4CN1iJ8SiCufjGgRCnVWmWe/HcEJ5OjhUvBnRkhsLMY7pvlXMU8Mh7nLxyA==", "requires": { "@babel/runtime": "^7.16.0" } }, "@wordpress/i18n": { - "version": "4.15.0", - "resolved": "https://registry.npmjs.org/@wordpress/i18n/-/i18n-4.15.0.tgz", - "integrity": "sha512-nqazvRbtrhuykmZXnMxyumqP6duiCWxf2YAgHCBhoZIpwOmmbu+S7CtYWNx+EHIAa6cSdon6loRACc90Mx6PZg==", + "version": "4.16.0", + "resolved": "https://registry.npmjs.org/@wordpress/i18n/-/i18n-4.16.0.tgz", + "integrity": "sha512-N7BChVVaQpt63e2Wgc0ST+ahUuhSjd6bqHqgIBnxZ4LU3c8tzd/etYjBqSM8RPcI9gSOM32ddlTnJgAxgntKaA==", "requires": { "@babel/runtime": "^7.16.0", - "@wordpress/hooks": "^3.15.0", + "@wordpress/hooks": "^3.16.0", "gettext-parser": "^1.3.1", "lodash": "^4.17.21", "memize": "^1.1.0", @@ -2967,29 +3029,29 @@ } }, "@wordpress/icons": { - "version": "9.6.0", - "resolved": "https://registry.npmjs.org/@wordpress/icons/-/icons-9.6.0.tgz", - "integrity": "sha512-vQwoqWzPuYmJZS2h0+0fXRfpBRSA95juq6Pj1EmUJZodlSLX2NTV3EiDsDwj2cRmXR+BLmLBledm8uYo7BsjRA==", + "version": "9.7.0", + "resolved": "https://registry.npmjs.org/@wordpress/icons/-/icons-9.7.0.tgz", + "integrity": "sha512-QW9FHBx4Yof7bnxZA2MzZNwc/eJOtFcGjnAcSdY72uOset9n6vCMVkEYZe5wX5ZKsRSRCcpXkNrDw2vTcWCOSQ==", "requires": { "@babel/runtime": "^7.16.0", - "@wordpress/element": "^4.13.0", - "@wordpress/primitives": "^3.13.0" + "@wordpress/element": "^4.14.0", + "@wordpress/primitives": "^3.14.0" } }, "@wordpress/primitives": { - "version": "3.13.0", - "resolved": "https://registry.npmjs.org/@wordpress/primitives/-/primitives-3.13.0.tgz", - "integrity": "sha512-bNBbK30ZUq24G9ltZWsOPiRB0rP75BDgZTQObXogfeh+nSP7rNPsisYozxJ7FSiX5xhLMpQMOgv294XaV9Syhg==", + "version": "3.14.0", + "resolved": "https://registry.npmjs.org/@wordpress/primitives/-/primitives-3.14.0.tgz", + "integrity": "sha512-rHibruWLgp5aIWqIJEBDozsVK+JWGjy2EIwusINVqPN5BL6ahajEJtOmmUJmYZwUzj5g2MVS6fRdzQUS9oKGRQ==", "requires": { "@babel/runtime": "^7.16.0", - "@wordpress/element": "^4.13.0", + "@wordpress/element": "^4.14.0", "classnames": "^2.3.1" } }, "@wordpress/url": { - "version": "3.16.0", - "resolved": "https://registry.npmjs.org/@wordpress/url/-/url-3.16.0.tgz", - "integrity": "sha512-5hlT8KfioKrmfqQAHihj2pWqc8oMUFNae3n5/Wlu8H60Btf5h+cBfxr6eiOXPEVX9Ko9NskLjmAqCxxoiNviqg==", + "version": "3.17.0", + "resolved": "https://registry.npmjs.org/@wordpress/url/-/url-3.17.0.tgz", + "integrity": "sha512-817geMi/DA5cPXO9tPHJB8g+MtI3xpA0s2/26paAciD5rPa/Y9BgTtfvPiR/pzKk+hQOxjNSw6dwb1bPGTmB1A==", "requires": { "@babel/runtime": "^7.16.0", "remove-accents": "^0.4.2" @@ -4515,14 +4577,14 @@ "integrity": "sha512-XgZ0pFcakEUlbwQEVNg3+QAis1FyTL3Qel9FYy8pSkQqoG3PNoT0bOCQtOXcOkur21r2Eq2kI+IE+gsmAEVlYw==" }, "core-js": { - "version": "3.24.1", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.24.1.tgz", - "integrity": "sha512-0QTBSYSUZ6Gq21utGzkfITDylE8jWC9Ne1D2MrhvlsZBI1x39OdDIVbzSqtgMndIy6BlHxBXpMGqzZmnztg2rg==" + "version": "3.25.0", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.25.0.tgz", + "integrity": "sha512-CVU1xvJEfJGhyCpBrzzzU1kjCfgsGUxhEvwUV2e/cOedYWHdmluamx+knDnmhqALddMG16fZvIqvs9aijsHHaA==" }, "core-js-compat": { - "version": "3.24.1", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.24.1.tgz", - "integrity": "sha512-XhdNAGeRnTpp8xbD+sR/HFDK9CbeeeqXT6TuofXh3urqEevzkWmLRgrVoykodsw8okqo2pu1BOmuCKrHx63zdw==", + "version": "3.25.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.25.0.tgz", + "integrity": "sha512-extKQM0g8/3GjFx9US12FAgx8KJawB7RCQ5y8ipYLbmfzEzmFRWdDjIlxDx82g7ygcNG85qMVUSRyABouELdow==", "requires": { "browserslist": "^4.21.3", "semver": "7.0.0" @@ -4536,9 +4598,9 @@ } }, "core-js-pure": { - "version": "3.24.1", - "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.24.1.tgz", - "integrity": "sha512-r1nJk41QLLPyozHUUPmILCEMtMw24NG4oWK6RbsDdjzQgg9ZvrUsPBj1MnG0wXXp1DCDU6j+wUvEmBSrtRbLXg==" + "version": "3.25.0", + "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.25.0.tgz", + "integrity": "sha512-IeHpLwk3uoci37yoI2Laty59+YqH9x5uR65/yiA0ARAJrTrN4YU0rmauLWfvqOuk77SlNJXj2rM6oT/dBD87+A==" }, "core-util-is": { "version": "1.0.3", @@ -4641,9 +4703,9 @@ "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==" }, "css-declaration-sorter": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-6.3.0.tgz", - "integrity": "sha512-OGT677UGHJTAVMRhPO+HJ4oKln3wkBTwtDFH0ojbqm+MJm6xuDMHp2nkhh/ThaBqq20IbraBQSWKfSLNHQO9Og==" + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-6.3.1.tgz", + "integrity": "sha512-fBffmak0bPAnyqc/HO8C3n2sHrp9wcqQz6ES9koRF2/mLOVAx9zIQ3Y7R29sYCteTPqMCwns4WYQoCX91Xl3+w==" }, "css-functions-list": { "version": "3.1.0", @@ -5350,15 +5412,15 @@ } }, "es-abstract": { - "version": "1.20.1", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.20.1.tgz", - "integrity": "sha512-WEm2oBhfoI2sImeM4OF2zE2V3BYdSF+KnSi9Sidz51fQHd7+JuF8Xgcj9/0o+OWeIeIS/MiuNnlruQrJf16GQA==", + "version": "1.20.2", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.20.2.tgz", + "integrity": "sha512-XxXQuVNrySBNlEkTYJoDNFe5+s2yIOpzq80sUHEdPdQr0S5nTLz4ZPPPswNIpKseDDUS5yghX1gfLIHQZ1iNuQ==", "requires": { "call-bind": "^1.0.2", "es-to-primitive": "^1.2.1", "function-bind": "^1.1.1", "function.prototype.name": "^1.1.5", - "get-intrinsic": "^1.1.1", + "get-intrinsic": "^1.1.2", "get-symbol-description": "^1.0.0", "has": "^1.0.3", "has-property-descriptors": "^1.0.0", @@ -5370,9 +5432,9 @@ "is-shared-array-buffer": "^1.0.2", "is-string": "^1.0.7", "is-weakref": "^1.0.2", - "object-inspect": "^1.12.0", + "object-inspect": "^1.12.2", "object-keys": "^1.1.1", - "object.assign": "^4.1.2", + "object.assign": "^4.1.4", "regexp.prototype.flags": "^1.4.3", "string.prototype.trimend": "^1.0.5", "string.prototype.trimstart": "^1.0.5", @@ -5423,13 +5485,14 @@ "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==" }, "eslint": { - "version": "8.22.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.22.0.tgz", - "integrity": "sha512-ci4t0sz6vSRKdmkOGmprBo6fmI4PrphDFMy5JEq/fNS0gQkJM3rLmrqcp8ipMcdobH3KtUP40KniAE9W19S4wA==", + "version": "8.23.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.23.0.tgz", + "integrity": "sha512-pBG/XOn0MsJcKcTRLr27S5HpzQo4kLr+HjLQIyK4EiCsijDl/TB+h5uEuJU6bQ8Edvwz1XWOjpaP2qgnXGpTcA==", "requires": { - "@eslint/eslintrc": "^1.3.0", + "@eslint/eslintrc": "^1.3.1", "@humanwhocodes/config-array": "^0.10.4", "@humanwhocodes/gitignore-to-minimatch": "^1.0.2", + "@humanwhocodes/module-importer": "^1.0.1", "ajv": "^6.10.0", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", @@ -5439,7 +5502,7 @@ "eslint-scope": "^7.1.1", "eslint-utils": "^3.0.0", "eslint-visitor-keys": "^3.3.0", - "espree": "^9.3.3", + "espree": "^9.4.0", "esquery": "^1.4.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", @@ -5464,8 +5527,7 @@ "regexpp": "^3.2.0", "strip-ansi": "^6.0.1", "strip-json-comments": "^3.1.0", - "text-table": "^0.2.0", - "v8-compile-cache": "^2.0.3" + "text-table": "^0.2.0" }, "dependencies": { "ansi-regex": { @@ -5629,9 +5691,9 @@ } }, "eslint-plugin-react": { - "version": "7.30.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.30.1.tgz", - "integrity": "sha512-NbEvI9jtqO46yJA3wcRF9Mo0lF9T/jhdHqhCHXiXtD+Zcb98812wvokjWpU7Q4QH5edo6dmqrukxVvWWXHlsUg==", + "version": "7.31.7", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.31.7.tgz", + "integrity": "sha512-8NldBTeYp/kQoTV1uT0XF6HcmDqbgZ0lNPkN0wlRw8DJKXEnaWu+oh/6gt3xIhzvQ35wB2Y545fJhIbJSZ2NNw==", "requires": { "array-includes": "^3.1.5", "array.prototype.flatmap": "^1.3.0", @@ -5702,9 +5764,9 @@ "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==" }, "espree": { - "version": "9.3.3", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.3.3.tgz", - "integrity": "sha512-ORs1Rt/uQTqUKjDdGCyrtYxbazf5umATSf/K4qxjmZHORR6HJk+2s/2Pqe+Kk49HHINC/xNIrGfgh8sZcll0ng==", + "version": "9.4.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.4.0.tgz", + "integrity": "sha512-DQmnRpLj7f6TgN/NYb0MTzJXL+vJF9h3pHy4JhCIs3zwcgez8xmGg3sXHcEO97BrmO2OSvCwMdfdlyl+E9KjOw==", "requires": { "acorn": "^8.8.0", "acorn-jsx": "^5.3.2", @@ -6332,9 +6394,9 @@ "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==" }, "flow-parser": { - "version": "0.185.1", - "resolved": "https://registry.npmjs.org/flow-parser/-/flow-parser-0.185.1.tgz", - "integrity": "sha512-nbtJZFMGgJVCRBlE/66p7L6IWF+wy6Nbd65sVwyrH7WsnZgeef8m263uxN4xah+8BZwuGndU8HKlt8cHIpTwew==" + "version": "0.186.0", + "resolved": "https://registry.npmjs.org/flow-parser/-/flow-parser-0.186.0.tgz", + "integrity": "sha512-QaPJczRxNc/yvp3pawws439VZ/vHGq+i1/mZ3bEdSaRy8scPgZgiWklSB6jN7y5NR9sfgL4GGIiBcMXTj3Opqg==" }, "flush-write-stream": { "version": "1.1.1", @@ -7677,9 +7739,9 @@ } }, "is-plain-obj": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", - "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==" + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", + "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==" }, "is-plain-object": { "version": "2.0.4", @@ -10075,9 +10137,9 @@ } }, "rc-util": { - "version": "5.23.0", - "resolved": "https://registry.npmjs.org/rc-util/-/rc-util-5.23.0.tgz", - "integrity": "sha512-lgm6diJ/pLgyfoZY59Vz7sW4mSoQCgozqbBye9IJ7/mb5w5h4T7h+i2JpXAx/UBQxscBZe68q0sP7EW+qfkKUg==", + "version": "5.24.2", + "resolved": "https://registry.npmjs.org/rc-util/-/rc-util-5.24.2.tgz", + "integrity": "sha512-MWd0ZEV7xSwN4HM9jz9BwpnMzwCPjYJ7K90lePsrdgAkrmm8U7b4BOTIsv/84BQsaF7N3ejNkcrZ3AfEwc9HXA==", "requires": { "@babel/runtime": "^7.18.3", "react-is": "^16.12.0", @@ -10662,9 +10724,9 @@ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, "sass": { - "version": "1.54.5", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.54.5.tgz", - "integrity": "sha512-p7DTOzxkUPa/63FU0R3KApkRHwcVZYC0PLnLm5iyZACyp15qSi32x7zVUhRdABAATmkALqgGrjCJAcWvobmhHw==", + "version": "1.54.8", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.54.8.tgz", + "integrity": "sha512-ib4JhLRRgbg6QVy6bsv5uJxnJMTS2soVcCp9Y88Extyy13A8vV0G1fAwujOzmNkFQbR3LvedudAMbtuNRPbQww==", "requires": { "chokidar": ">=3.0.0 <4.0.0", "immutable": "^4.0.0", @@ -11149,28 +11211,16 @@ } }, "socket.io": { - "version": "4.5.1", - "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.5.1.tgz", - "integrity": "sha512-0y9pnIso5a9i+lJmsCdtmTTgJFFSvNQKDnPQRz28mGNnxbmqYg2QPtJTLFxhymFZhAIn50eHAKzJeiNaKr+yUQ==", + "version": "4.5.2", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.5.2.tgz", + "integrity": "sha512-6fCnk4ARMPZN448+SQcnn1u8OHUC72puJcNtSgg2xS34Cu7br1gQ09YKkO1PFfDn/wyUE9ZgMAwosJed003+NQ==", "requires": { "accepts": "~1.3.4", "base64id": "~2.0.0", "debug": "~4.3.2", "engine.io": "~6.2.0", "socket.io-adapter": "~2.4.0", - "socket.io-parser": "~4.0.4" - }, - "dependencies": { - "socket.io-parser": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.0.5.tgz", - "integrity": "sha512-sNjbT9dX63nqUFIOv95tTVm6elyIU4RvB1m8dOeZt+IgWwcWklFDOdmGcfo3zSiRsnR/3pJkjY5lfoGqEe4Eig==", - "requires": { - "@types/component-emitter": "^1.2.10", - "component-emitter": "~1.3.0", - "debug": "~4.3.1" - } - } + "socket.io-parser": "~4.2.0" } }, "socket.io-adapter": { @@ -11179,9 +11229,9 @@ "integrity": "sha512-W4N+o69rkMEGVuk2D/cvca3uYsvGlMwsySWV447y99gUPghxq42BxqLNMndb+a1mm/5/7NeXVQS7RLa2XyXvYg==" }, "socket.io-client": { - "version": "4.5.1", - "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.5.1.tgz", - "integrity": "sha512-e6nLVgiRYatS+AHXnOnGi4ocOpubvOUCGhyWw8v+/FxW8saHkinG6Dfhi9TU0Kt/8mwJIAASxvw6eujQmjdZVA==", + "version": "4.5.2", + "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.5.2.tgz", + "integrity": "sha512-naqYfFu7CLDiQ1B7AlLhRXKX3gdeaIMfgigwavDzgJoIUYulc1qHH5+2XflTsXTPY7BlPH5rppJyUjhjrKQKLg==", "requires": { "@socket.io/component-emitter": "~3.1.0", "debug": "~4.3.2", @@ -11876,9 +11926,9 @@ "integrity": "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==" }, "supports-hyperlinks": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.2.0.tgz", - "integrity": "sha512-6sXEzV5+I5j8Bmq9/vUphGRM/RJNT9SCURJLjwfOg51heRtguGWDzcaBlgAzKhQa0EVNpPEKzQuBwZ8S8WaCeQ==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.3.0.tgz", + "integrity": "sha512-RpsAZlpWcDwOPQA22aCH4J0t7L8JmAvsCxfOSEwm7cQs3LshN36QaTkwd70DnBOXDWGssw2eUoc8CaRWT0XunA==", "requires": { "has-flag": "^4.0.0", "supports-color": "^7.0.0" @@ -12276,9 +12326,9 @@ } }, "typescript": { - "version": "4.7.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.4.tgz", - "integrity": "sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==" + "version": "4.8.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.2.tgz", + "integrity": "sha512-C0I1UsrrDHo2fYI5oaCGbSejwX4ch+9Y5jTQELvovfmFkK3HHSZJB8MSJcWLmCUBzQBchCrZ9rMRV6GuNrvGtw==" }, "ua-parser-js": { "version": "1.0.2", @@ -12351,13 +12401,6 @@ "is-plain-obj": "^2.0.0", "trough": "^1.0.0", "vfile": "^4.0.0" - }, - "dependencies": { - "is-plain-obj": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", - "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==" - } } }, "union-value": { diff --git a/package.json b/package.json index 74ccbf341..77c9908b7 100644 --- a/package.json +++ b/package.json @@ -33,7 +33,7 @@ "webpack-cli": "^4.10.0" }, "dependencies": { - "@eightshift/frontend-libs": "^7.0.0", + "@eightshift/frontend-libs": "^7.1.0", "autosize": "^5.0.1", "choices.js": "^10.1.0", "dropzone": "^6.0.0-beta.1"