1002 lines
30 KiB
PHP
1002 lines
30 KiB
PHP
|
|
<?php
|
||
|
|
/**
|
||
|
|
* Gravity Flow Step Webhook
|
||
|
|
*
|
||
|
|
* @package GravityFlow
|
||
|
|
* @subpackage Classes/Gravity_Flow_Step_Webhook
|
||
|
|
* @copyright Copyright (c) 2015-2018, Steven Henty S.L.
|
||
|
|
* @license http://opensource.org/licenses/gpl-2.0.php GNU Public License
|
||
|
|
* @since 1.0
|
||
|
|
*/
|
||
|
|
|
||
|
|
if ( ! class_exists( 'GFForms' ) ) {
|
||
|
|
die();
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Class Gravity_Flow_Step_Webhook
|
||
|
|
*/
|
||
|
|
class Gravity_Flow_Step_Webhook extends Gravity_Flow_Step {
|
||
|
|
|
||
|
|
/**
|
||
|
|
* The step type.
|
||
|
|
*
|
||
|
|
* @var string
|
||
|
|
*/
|
||
|
|
public $_step_type = 'webhook';
|
||
|
|
|
||
|
|
/**
|
||
|
|
* The temporary credentials.
|
||
|
|
*
|
||
|
|
* @var array
|
||
|
|
*/
|
||
|
|
protected $temporary_credentials = array();
|
||
|
|
|
||
|
|
/**
|
||
|
|
* The OAuth1 Client
|
||
|
|
*
|
||
|
|
* @var Gravity_Flow_Oauth1_Client
|
||
|
|
*/
|
||
|
|
protected $oauth1_client;
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Returns the step label.
|
||
|
|
*
|
||
|
|
* @return string
|
||
|
|
*/
|
||
|
|
public function get_label() {
|
||
|
|
return esc_html__( 'Outgoing Webhook', 'gravityflow' );
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Returns the HTML for the step icon.
|
||
|
|
*
|
||
|
|
* @return string
|
||
|
|
*/
|
||
|
|
public function get_icon_url() {
|
||
|
|
return '<i class="fa fa-external-link"></i>';
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Returns an array of settings for this step type.
|
||
|
|
*
|
||
|
|
* @return array
|
||
|
|
*/
|
||
|
|
public function get_settings() {
|
||
|
|
$connected_apps = gravityflow_connected_apps()->get_connected_apps();
|
||
|
|
$connected_apps_options = array(
|
||
|
|
array(
|
||
|
|
'label' => esc_html__( 'Select a Connected App', 'gravityflow' ),
|
||
|
|
'value' => '',
|
||
|
|
),
|
||
|
|
);
|
||
|
|
foreach ( $connected_apps as $key => $app ) {
|
||
|
|
$connected_apps_options[ $key ] = array(
|
||
|
|
'label' => $app['app_name'],
|
||
|
|
'value' => $app['app_id'],
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
$settings = array(
|
||
|
|
'title' => esc_html__( 'Outgoing Webhook', 'gravityflow' ),
|
||
|
|
'fields' => array(
|
||
|
|
array(
|
||
|
|
'name' => 'url',
|
||
|
|
'class' => 'large',
|
||
|
|
'label' => esc_html__( 'Outgoing Webhook URL', 'gravityflow' ),
|
||
|
|
'type' => 'text',
|
||
|
|
),
|
||
|
|
array(
|
||
|
|
'name' => 'method',
|
||
|
|
'label' => esc_html__( 'Request Method', 'gravityflow' ),
|
||
|
|
'type' => 'select',
|
||
|
|
'default_value' => 'post',
|
||
|
|
'onchange' => "jQuery(this).closest('form').submit();",
|
||
|
|
'choices' => array(
|
||
|
|
array(
|
||
|
|
'label' => 'POST',
|
||
|
|
'value' => 'post',
|
||
|
|
),
|
||
|
|
array(
|
||
|
|
'label' => 'GET',
|
||
|
|
'value' => 'get',
|
||
|
|
),
|
||
|
|
array(
|
||
|
|
'label' => 'PUT',
|
||
|
|
'value' => 'put',
|
||
|
|
),
|
||
|
|
array(
|
||
|
|
'label' => 'DELETE',
|
||
|
|
'value' => 'delete',
|
||
|
|
),
|
||
|
|
array(
|
||
|
|
'label' => 'PATCH',
|
||
|
|
'value' => 'patch',
|
||
|
|
),
|
||
|
|
),
|
||
|
|
),
|
||
|
|
array(
|
||
|
|
'name' => 'authentication',
|
||
|
|
'label' => esc_html__( 'Request Authentication Type', 'gravityflow' ),
|
||
|
|
'type' => 'select',
|
||
|
|
'onchange' => "jQuery(this).closest('form').submit();",
|
||
|
|
'default_value' => '',
|
||
|
|
'choices' => array(
|
||
|
|
array(
|
||
|
|
'label' => 'None',
|
||
|
|
'value' => '',
|
||
|
|
),
|
||
|
|
array(
|
||
|
|
'label' => 'Basic',
|
||
|
|
'value' => 'basic',
|
||
|
|
),
|
||
|
|
array(
|
||
|
|
'label' => 'Connected App',
|
||
|
|
'value' => 'connected_app',
|
||
|
|
),
|
||
|
|
),
|
||
|
|
),
|
||
|
|
array(
|
||
|
|
'name' => 'basic_username',
|
||
|
|
'label' => esc_html__( 'Username', 'gravityflow' ),
|
||
|
|
'type' => 'text',
|
||
|
|
'dependency' => array(
|
||
|
|
'field' => 'authentication',
|
||
|
|
'values' => array( 'basic' ),
|
||
|
|
),
|
||
|
|
),
|
||
|
|
array(
|
||
|
|
'name' => 'basic_password',
|
||
|
|
'label' => esc_html__( 'Password', 'gravityflow' ),
|
||
|
|
'type' => 'text',
|
||
|
|
'dependency' => array(
|
||
|
|
'field' => 'authentication',
|
||
|
|
'values' => array( 'basic' ),
|
||
|
|
),
|
||
|
|
),
|
||
|
|
array(
|
||
|
|
'name' => 'connected_app',
|
||
|
|
'label' => esc_html__( 'Connected App', 'gravityflow' ),
|
||
|
|
'type' => 'select',
|
||
|
|
'tooltip' => esc_html__( 'Manage your Connected Apps in the Workflow->Settings->Connected Apps page. ', 'gravityflow' ),
|
||
|
|
'dependency' => array(
|
||
|
|
'field' => 'authentication',
|
||
|
|
'values' => array(
|
||
|
|
'connected_app',
|
||
|
|
),
|
||
|
|
),
|
||
|
|
'choices' => $connected_apps_options,
|
||
|
|
),
|
||
|
|
array(
|
||
|
|
'label' => esc_html__( 'Request Headers', 'gravityflow' ),
|
||
|
|
'name' => 'requestHeaders',
|
||
|
|
'type' => 'generic_map',
|
||
|
|
'required' => false,
|
||
|
|
'merge_tags' => true,
|
||
|
|
'tooltip' => sprintf(
|
||
|
|
'<h6>%s</h6>%s',
|
||
|
|
esc_html__( 'Request Headers', 'gravityflow' ),
|
||
|
|
esc_html__( 'Setup the HTTP headers to be sent with the webhook request.', 'gravityflow' )
|
||
|
|
),
|
||
|
|
'key_choices' => $this->get_header_choices(),
|
||
|
|
// The Add-On Framework now contains the generic map field but with a slight difference
|
||
|
|
// The key_field and value_field elements are included here for when Gravity Flow removes the generic map field.
|
||
|
|
'key_field' => array(
|
||
|
|
'choices' => $this->get_header_choices(),
|
||
|
|
'custom_value' => true,
|
||
|
|
'title' => esc_html__( 'Name', 'gravityflow' ),
|
||
|
|
),
|
||
|
|
'value_field' => array(
|
||
|
|
'choices' => 'form_fields',
|
||
|
|
'custom_value' => true,
|
||
|
|
),
|
||
|
|
),
|
||
|
|
array(
|
||
|
|
'name' => 'body',
|
||
|
|
'label' => esc_html__( 'Request Body', 'gravityflow' ),
|
||
|
|
'type' => 'radio',
|
||
|
|
'default_value' => 'select',
|
||
|
|
'horizontal' => true,
|
||
|
|
'onchange' => "jQuery(this).closest('form').submit();",
|
||
|
|
'choices' => array(
|
||
|
|
array(
|
||
|
|
'label' => __( 'Select Fields', 'gravityflow' ),
|
||
|
|
'value' => 'select',
|
||
|
|
),
|
||
|
|
array(
|
||
|
|
'label' => __( 'Raw request', 'gravityflow' ),
|
||
|
|
'value' => 'raw',
|
||
|
|
),
|
||
|
|
),
|
||
|
|
'dependency' => array(
|
||
|
|
'field' => 'method',
|
||
|
|
'values' => array( '', 'post', 'put', 'patch' ),
|
||
|
|
),
|
||
|
|
),
|
||
|
|
),
|
||
|
|
);
|
||
|
|
if ( in_array( $this->get_setting( 'method' ), array( 'post', 'put', 'patch', '' ) ) ) {
|
||
|
|
|
||
|
|
if ( $this->get_setting( 'body' ) == 'raw' ) {
|
||
|
|
global $_gaddon_posted_settings;
|
||
|
|
|
||
|
|
if ( ! empty( $_gaddon_posted_settings ) ) {
|
||
|
|
$this->set_posted_raw_body_value();
|
||
|
|
}
|
||
|
|
|
||
|
|
$settings['fields'][] = array(
|
||
|
|
'name' => 'raw_body',
|
||
|
|
'label' => esc_html__( 'Raw Body', 'gravityflow' ),
|
||
|
|
'type' => 'textarea',
|
||
|
|
'class' => 'fieldwidth-3 fieldheight-2',
|
||
|
|
'save_callback' => array( $this, 'save_callback_raw_body' ),
|
||
|
|
);
|
||
|
|
} else {
|
||
|
|
|
||
|
|
$settings['fields'][] = array(
|
||
|
|
'name' => 'format',
|
||
|
|
'label' => esc_html__( 'Format', 'gravityflow' ),
|
||
|
|
'type' => 'select',
|
||
|
|
'tooltip' => esc_html__( 'If JSON is selected then the Content-Type header will be set to application/json', 'gravityflow' ),
|
||
|
|
'onchange' => "jQuery(this).closest('form').submit();",
|
||
|
|
'default_value' => 'json',
|
||
|
|
'choices' => array(
|
||
|
|
array(
|
||
|
|
'label' => 'JSON',
|
||
|
|
'value' => 'json',
|
||
|
|
),
|
||
|
|
array(
|
||
|
|
'label' => 'FORM',
|
||
|
|
'value' => 'form',
|
||
|
|
),
|
||
|
|
),
|
||
|
|
);
|
||
|
|
$settings['fields'][] = array(
|
||
|
|
'name' => 'body_type',
|
||
|
|
'label' => esc_html__( 'Body Content', 'gravityflow' ),
|
||
|
|
'type' => 'radio',
|
||
|
|
'default_value' => 'all_fields',
|
||
|
|
'horizontal' => true,
|
||
|
|
'onchange' => "jQuery(this).closest('form').submit();",
|
||
|
|
'choices' => array(
|
||
|
|
array(
|
||
|
|
'label' => __( 'All Fields', 'gravityflow' ),
|
||
|
|
'value' => 'all_fields',
|
||
|
|
),
|
||
|
|
array(
|
||
|
|
'label' => __( 'Select Fields', 'gravityflow' ),
|
||
|
|
'value' => 'select_fields',
|
||
|
|
),
|
||
|
|
),
|
||
|
|
'dependency' => array(
|
||
|
|
'field' => 'body',
|
||
|
|
'values' => array( 'select', '' ),
|
||
|
|
),
|
||
|
|
);
|
||
|
|
$settings['fields'][] = array(
|
||
|
|
'name' => 'mappings',
|
||
|
|
'label' => esc_html__( 'Field Values', 'gravityflow' ),
|
||
|
|
'type' => 'generic_map',
|
||
|
|
'enable_custom_key' => false,
|
||
|
|
'enable_custom_value' => true,
|
||
|
|
'key_field_title' => esc_html__( 'Key', 'gravityflow' ),
|
||
|
|
'value_field_title' => esc_html__( 'Value', 'gravityflow' ),
|
||
|
|
'value_choices' => $this->value_mappings(),
|
||
|
|
'tooltip' => '<h6>' . esc_html__( 'Mapping', 'gravityflow' ) . '</h6>' . esc_html__( 'Map the fields of this form to the selected form. Values from this form will be saved in the entry in the selected form', 'gravityflow' ),
|
||
|
|
'dependency' => array(
|
||
|
|
'field' => 'body_type',
|
||
|
|
'values' => array( 'select_fields' ),
|
||
|
|
),
|
||
|
|
);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return $settings;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Returns an array of statuses and their properties.
|
||
|
|
*
|
||
|
|
* @return array
|
||
|
|
*/
|
||
|
|
public function get_status_config() {
|
||
|
|
return array(
|
||
|
|
array(
|
||
|
|
'status' => 'complete',
|
||
|
|
'status_label' => __( 'Success', 'gravityflow' ),
|
||
|
|
'destination_setting_label' => esc_html__( 'Next Step if Success', 'gravityflow' ),
|
||
|
|
'default_destination' => 'next',
|
||
|
|
),
|
||
|
|
array(
|
||
|
|
'status' => 'error_client',
|
||
|
|
'status_label' => __( 'Error - Client', 'gravityflow' ),
|
||
|
|
'destination_setting_label' => esc_html__( 'Next Step if Client Error', 'gravityflow' ),
|
||
|
|
'default_destination' => 'complete',
|
||
|
|
),
|
||
|
|
array(
|
||
|
|
'status' => 'error_server',
|
||
|
|
'status_label' => __( 'Error - Server', 'gravityflow' ),
|
||
|
|
'destination_setting_label' => esc_html__( 'Next Step if Server Error', 'gravityflow' ),
|
||
|
|
'default_destination' => 'complete',
|
||
|
|
),
|
||
|
|
array(
|
||
|
|
'status' => 'error',
|
||
|
|
'status_label' => __( 'Error - Other', 'gravityflow' ),
|
||
|
|
'destination_setting_label' => esc_html__( 'Next step if Other Error', 'gravityflow' ),
|
||
|
|
'default_destination' => 'complete',
|
||
|
|
),
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Prepares common HTTP header names as choices.
|
||
|
|
*
|
||
|
|
* @since 1.0
|
||
|
|
* @access public
|
||
|
|
*
|
||
|
|
* @return array
|
||
|
|
*/
|
||
|
|
public function get_header_choices() {
|
||
|
|
|
||
|
|
return array(
|
||
|
|
array(
|
||
|
|
'label' => esc_html__( 'Select a Name', 'gravityformswebhooks' ),
|
||
|
|
'value' => '',
|
||
|
|
),
|
||
|
|
array(
|
||
|
|
'label' => 'Accept',
|
||
|
|
'value' => 'Accept',
|
||
|
|
),
|
||
|
|
array(
|
||
|
|
'label' => 'Accept-Charset',
|
||
|
|
'value' => 'Accept-Charset',
|
||
|
|
),
|
||
|
|
array(
|
||
|
|
'label' => 'Accept-Encoding',
|
||
|
|
'value' => 'Accept-Encoding',
|
||
|
|
),
|
||
|
|
array(
|
||
|
|
'label' => 'Accept-Language',
|
||
|
|
'value' => 'Accept-Language',
|
||
|
|
),
|
||
|
|
array(
|
||
|
|
'label' => 'Accept-Datetime',
|
||
|
|
'value' => 'Accept-Datetime',
|
||
|
|
),
|
||
|
|
array(
|
||
|
|
'label' => 'Cache-Control',
|
||
|
|
'value' => 'Cache-Control',
|
||
|
|
),
|
||
|
|
array(
|
||
|
|
'label' => 'Connection',
|
||
|
|
'value' => 'Connection',
|
||
|
|
),
|
||
|
|
array(
|
||
|
|
'label' => 'Cookie',
|
||
|
|
'value' => 'Cookie',
|
||
|
|
),
|
||
|
|
array(
|
||
|
|
'label' => 'Content-Length',
|
||
|
|
'value' => 'Content-Length',
|
||
|
|
),
|
||
|
|
array(
|
||
|
|
'label' => 'Content-Type',
|
||
|
|
'value' => 'Content-Type',
|
||
|
|
),
|
||
|
|
array(
|
||
|
|
'label' => 'Date',
|
||
|
|
'value' => 'Date',
|
||
|
|
),
|
||
|
|
array(
|
||
|
|
'label' => 'Expect',
|
||
|
|
'value' => 'Expect',
|
||
|
|
),
|
||
|
|
array(
|
||
|
|
'label' => 'Forwarded',
|
||
|
|
'value' => 'Forwarded',
|
||
|
|
),
|
||
|
|
array(
|
||
|
|
'label' => 'From',
|
||
|
|
'value' => 'From',
|
||
|
|
),
|
||
|
|
array(
|
||
|
|
'label' => 'Host',
|
||
|
|
'value' => 'Host',
|
||
|
|
),
|
||
|
|
array(
|
||
|
|
'label' => 'If-Match',
|
||
|
|
'value' => 'If-Match',
|
||
|
|
),
|
||
|
|
array(
|
||
|
|
'label' => 'If-Modified-Since',
|
||
|
|
'value' => 'If-Modified-Since',
|
||
|
|
),
|
||
|
|
array(
|
||
|
|
'label' => 'If-None-Match',
|
||
|
|
'value' => 'If-None-Match',
|
||
|
|
),
|
||
|
|
array(
|
||
|
|
'label' => 'If-Range',
|
||
|
|
'value' => 'If-Range',
|
||
|
|
),
|
||
|
|
array(
|
||
|
|
'label' => 'If-Unmodified-Since',
|
||
|
|
'value' => 'If-Unmodified-Since',
|
||
|
|
),
|
||
|
|
array(
|
||
|
|
'label' => 'Max-Forwards',
|
||
|
|
'value' => 'Max-Forwards',
|
||
|
|
),
|
||
|
|
array(
|
||
|
|
'label' => 'Origin',
|
||
|
|
'value' => 'Origin',
|
||
|
|
),
|
||
|
|
array(
|
||
|
|
'label' => 'Pragma',
|
||
|
|
'value' => 'Pragma',
|
||
|
|
),
|
||
|
|
array(
|
||
|
|
'label' => 'Proxy-Authorization',
|
||
|
|
'value' => 'Proxy-Authorization',
|
||
|
|
),
|
||
|
|
array(
|
||
|
|
'label' => 'Range',
|
||
|
|
'value' => 'Range',
|
||
|
|
),
|
||
|
|
array(
|
||
|
|
'label' => 'Referer',
|
||
|
|
'value' => 'Referer',
|
||
|
|
),
|
||
|
|
array(
|
||
|
|
'label' => 'TE',
|
||
|
|
'value' => 'TE',
|
||
|
|
),
|
||
|
|
array(
|
||
|
|
'label' => 'User-Agent',
|
||
|
|
'value' => 'User-Agent',
|
||
|
|
),
|
||
|
|
array(
|
||
|
|
'label' => 'Upgrade',
|
||
|
|
'value' => 'Upgrade',
|
||
|
|
),
|
||
|
|
array(
|
||
|
|
'label' => 'Via',
|
||
|
|
'value' => 'Via',
|
||
|
|
),
|
||
|
|
array(
|
||
|
|
'label' => 'Warning',
|
||
|
|
'value' => 'Warning',
|
||
|
|
),
|
||
|
|
);
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Settings are JSON decoded so this callback resets the value to the raw value and strips scripts if the current
|
||
|
|
* user cannot unfiltered_html. This circumvents the automatic parsing of JSON values by the add-on framework.
|
||
|
|
*
|
||
|
|
* @since 1.8.1
|
||
|
|
*
|
||
|
|
* @param array $field The setting properties.
|
||
|
|
* @param mixed $field_setting The setting value.
|
||
|
|
*
|
||
|
|
* @return string
|
||
|
|
*/
|
||
|
|
function save_callback_raw_body( $field, $field_setting ) {
|
||
|
|
return $this->set_posted_raw_body_value();
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Sets the value of the raw_body setting in the $_gaddon_posted_settings global and strips scripts if the current
|
||
|
|
* user cannot unfiltered_html. This circumvents the automatic parsing of JSON values by the add-on framework.
|
||
|
|
*
|
||
|
|
* @since 1.8.1
|
||
|
|
*
|
||
|
|
* @return string the raw value
|
||
|
|
*/
|
||
|
|
protected function set_posted_raw_body_value() {
|
||
|
|
global $_gaddon_posted_settings;
|
||
|
|
|
||
|
|
$raw_value = rgpost( '_gaddon_setting_raw_body' );
|
||
|
|
|
||
|
|
if ( ! current_user_can( 'unfiltered_html' ) ) {
|
||
|
|
$raw_value = wp_kses_post( $raw_value );
|
||
|
|
}
|
||
|
|
|
||
|
|
$_gaddon_posted_settings['raw_body'] = $raw_value;
|
||
|
|
|
||
|
|
return $raw_value;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Process the step. For example, assign to a user, send to a service, send a notification or do nothing. Return (bool) $complete.
|
||
|
|
*
|
||
|
|
* @return bool Is the step complete?
|
||
|
|
*/
|
||
|
|
function process() {
|
||
|
|
|
||
|
|
$step_status = $this->send_webhook();
|
||
|
|
|
||
|
|
//Ensure webhook steps defined / last updated prior to v2.0.2 (w/o 4xx, 5xx, other response code config) continue to process
|
||
|
|
$destination_status_key = 'destination_' . $step_status;
|
||
|
|
if ( ! isset( $this->{$destination_status_key} ) ) {
|
||
|
|
$step_status = 'complete';
|
||
|
|
}
|
||
|
|
|
||
|
|
$this->update_step_status( $step_status );
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Processes the webhook request.
|
||
|
|
*
|
||
|
|
* @return string The step status.
|
||
|
|
*/
|
||
|
|
function send_webhook() {
|
||
|
|
|
||
|
|
$entry = $this->get_entry();
|
||
|
|
|
||
|
|
$url = $this->url;
|
||
|
|
|
||
|
|
$this->log_debug( __METHOD__ . '() - url before replacing variables: ' . $url );
|
||
|
|
|
||
|
|
$url = GFCommon::replace_variables( $url, $this->get_form(), $entry, true, false, false, 'text' );
|
||
|
|
|
||
|
|
$this->log_debug( __METHOD__ . '() - url after replacing variables: ' . $url );
|
||
|
|
|
||
|
|
$method = strtoupper( $this->method );
|
||
|
|
|
||
|
|
$body = null;
|
||
|
|
|
||
|
|
// Get request headers.
|
||
|
|
$headers = gravity_flow()->get_generic_map_fields( $this->get_feed_meta(), 'requestHeaders', $this->get_form(), $entry );
|
||
|
|
|
||
|
|
// Remove request headers with undefined name.
|
||
|
|
unset( $headers[ null ] );
|
||
|
|
|
||
|
|
if ( $this->authentication == 'basic' ) {
|
||
|
|
$auth_string = sprintf( '%s:%s', $this->basic_username, $this->basic_password );
|
||
|
|
$headers['Authorization'] = sprintf( 'Basic %s', base64_encode( $auth_string ) );
|
||
|
|
}
|
||
|
|
$this->log_debug( __METHOD__ . '() - log body setting ' . $this->body . ' :: ' . $this->raw_body );
|
||
|
|
if ( $this->body == 'raw' ) {
|
||
|
|
$body = $this->raw_body;
|
||
|
|
$body = GFCommon::replace_variables( $body, $this->get_form(), $entry, false, false, false, 'text' );
|
||
|
|
$this->log_debug( __METHOD__ . '() - got body after replace vars: ' . $body );
|
||
|
|
} elseif ( in_array( $method, array( 'POST', 'PUT', 'PATCH' ) ) ) {
|
||
|
|
$body = $this->get_request_body();
|
||
|
|
if ( $this->format == 'json' ) {
|
||
|
|
$headers['Content-type'] = 'application/json';
|
||
|
|
$body = json_encode( $body );
|
||
|
|
} else {
|
||
|
|
$headers = array();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if ( $this->authentication == 'connected_app' ) {
|
||
|
|
$app_id = $this->get_setting( 'connected_app' );
|
||
|
|
$connected_app = gravityflow_connected_apps()->get_app( $app_id );
|
||
|
|
if ( empty( $connected_app ) ) {
|
||
|
|
$this->log_debug( __METHOD__ . '() - Connected app not found: ' . $app_id );
|
||
|
|
}
|
||
|
|
$access_credentials = $connected_app['access_creds'];
|
||
|
|
|
||
|
|
require_once( dirname( __FILE__ ) . '/../class-oauth1-client.php' );
|
||
|
|
$this->oauth1_client = new Gravity_Flow_Oauth1_Client(
|
||
|
|
array(
|
||
|
|
'consumer_key' => $connected_app['consumer_key'],
|
||
|
|
'consumer_secret' => $connected_app['consumer_secret'],
|
||
|
|
'token' => $access_credentials['oauth_token'],
|
||
|
|
'token_secret' => $access_credentials['oauth_token_secret'],
|
||
|
|
),
|
||
|
|
'gravi_flow_' . $connected_app['consumer_key'],
|
||
|
|
$this->get_setting( 'url' )
|
||
|
|
);
|
||
|
|
|
||
|
|
if ( ! is_array( $access_credentials ) ) {
|
||
|
|
$this->log_debug( __METHOD__ . '() - No access credentials: ' . print_r( $access_credentials, true ) );
|
||
|
|
} else {
|
||
|
|
$this->oauth1_client->config['token'] = $access_credentials['oauth_token'];
|
||
|
|
$this->oauth1_client->config['token_secret'] = $access_credentials['oauth_token_secret'];
|
||
|
|
}
|
||
|
|
// Note we don't send the final $options[] parameter in here because our request is always sent in the body.
|
||
|
|
$headers['Authorization'] = $this->oauth1_client->get_full_request_header( $this->get_setting( 'url' ), $method );
|
||
|
|
}
|
||
|
|
|
||
|
|
$args = array(
|
||
|
|
'method' => $method,
|
||
|
|
'timeout' => 45,
|
||
|
|
'redirection' => 3,
|
||
|
|
'blocking' => true,
|
||
|
|
'headers' => $headers,
|
||
|
|
'body' => $body,
|
||
|
|
'cookies' => array(),
|
||
|
|
);
|
||
|
|
|
||
|
|
$args = apply_filters( 'gravityflow_webhook_args', $args, $entry, $this );
|
||
|
|
$args = apply_filters( 'gravityflow_webhook_args_' . $this->get_form_id(), $args, $entry, $this );
|
||
|
|
|
||
|
|
$response = wp_remote_request( $url, $args );
|
||
|
|
$this->log_debug( __METHOD__ . '() - request: ' . print_r( $args, true ) );
|
||
|
|
$this->log_debug( __METHOD__ . '() - response: ' . print_r( $response, true ) );
|
||
|
|
|
||
|
|
if ( is_wp_error( $response ) ) {
|
||
|
|
$step_status = 'error';
|
||
|
|
$http_response_message = ' (WP Error)';
|
||
|
|
} else {
|
||
|
|
if ( isset( $response['response']['code'] ) ) {
|
||
|
|
$http_response_code = intval( $response['response']['code'] );
|
||
|
|
switch ( true ) {
|
||
|
|
case in_array( $http_response_code, range( 200,299 ) ):
|
||
|
|
$http_response_message = $response['response']['code'] . ' ' . $response['response']['message'] . ' (Success)';
|
||
|
|
$step_status = 'complete';
|
||
|
|
break;
|
||
|
|
case in_array( $http_response_code, range( 400,499 ) ):
|
||
|
|
$step_status = 'error_client';
|
||
|
|
$http_response_message = $response['response']['code'] . ' ' . $response['response']['message'] . ' (Client Error)';
|
||
|
|
break;
|
||
|
|
case in_array( $http_response_code, range( 500,599 ) ):
|
||
|
|
$step_status = 'error_server';
|
||
|
|
$http_response_message = $response['response']['code'] . ' ' . $response['response']['message'] . ' (Server Error)';
|
||
|
|
break;
|
||
|
|
default:
|
||
|
|
$step_status = 'error';
|
||
|
|
$http_response_message = $response['response']['code'] . ' ' . $response['response']['message'] . ' (Error)';
|
||
|
|
}
|
||
|
|
} else {
|
||
|
|
$step_status = 'error';
|
||
|
|
$http_response_message = ' (Error)';
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Allow the step status to be modified on the webhook step.
|
||
|
|
*
|
||
|
|
* @param string $step_status The step status derived from webhook response
|
||
|
|
* @param array $response The response returned from webhook.
|
||
|
|
* @param array $args The arguments used for executing the webhook request
|
||
|
|
* @param array $entry The current entry.
|
||
|
|
* @param Gravity_Flow_Step $this The current step.
|
||
|
|
*
|
||
|
|
* @return string
|
||
|
|
*/
|
||
|
|
$step_status = apply_filters( 'gravityflow_step_status_webhook', $step_status, $response, $args, $entry, $this );
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Allow the message logged to the timeline following webhook step to be modified
|
||
|
|
*
|
||
|
|
* @param string $http_response_message The status message derived from webhook response
|
||
|
|
* @param string $step_status The step status derived from webhook response
|
||
|
|
* @param array $response The response returned from webhook.
|
||
|
|
* @param array $args The arguments used for executing the webhook request
|
||
|
|
* @param array $entry The current entry.
|
||
|
|
* @param Gravity_Flow_Step $this The current step.
|
||
|
|
*
|
||
|
|
* @return string
|
||
|
|
*/
|
||
|
|
$custom_response_message = apply_filters( 'gravityflow_response_message_webhook', $http_response_message, $step_status, $response, $args, $entry, $this );
|
||
|
|
|
||
|
|
if ( $custom_response_message == $http_response_message ) {
|
||
|
|
/* Translators: 1st placeholders is URL provided by user in step settings, 2nd placeholder is response codes from webhook execution */
|
||
|
|
$this->add_note( sprintf( esc_html__( 'Webhook sent. URL: %1$s. RESPONSE: %2$s', 'gravityflow' ), $url, $http_response_message ) );
|
||
|
|
$this->log_debug( __METHOD__ . '() - result: ' . $http_response_message );
|
||
|
|
} else {
|
||
|
|
$this->add_note( esc_html( $custom_response_message ) );
|
||
|
|
$this->log_debug( __METHOD__ . '() - result: ' . $custom_response_message );
|
||
|
|
}
|
||
|
|
|
||
|
|
do_action( 'gravityflow_post_webhook', $response, $args, $entry, $this );
|
||
|
|
|
||
|
|
return $step_status;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Determines the current status of the step.
|
||
|
|
*
|
||
|
|
* @return string
|
||
|
|
*/
|
||
|
|
public function status_evaluation() {
|
||
|
|
$step_status = $this->get_status();
|
||
|
|
|
||
|
|
return $step_status;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Determines if the current step has been completed.
|
||
|
|
*
|
||
|
|
* @return bool
|
||
|
|
*/
|
||
|
|
public function is_complete() {
|
||
|
|
$status = $this->evaluate_status();
|
||
|
|
|
||
|
|
return ! in_array( $status, array( 'pending', 'queued' ) );
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Prepare value map.
|
||
|
|
*
|
||
|
|
* @return array
|
||
|
|
*/
|
||
|
|
public function value_mappings() {
|
||
|
|
|
||
|
|
$form = $this->get_form();
|
||
|
|
|
||
|
|
$fields = $this->get_field_map_choices( $form );
|
||
|
|
return $fields;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Returns the choices for the source field mappings.
|
||
|
|
*
|
||
|
|
* @param array $form The current form.
|
||
|
|
* @param null|string $field_type Field types to include as choices. Defaults to null.
|
||
|
|
* @param null|array $exclude_field_types Field types to exclude as choices. Defaults to null.
|
||
|
|
*
|
||
|
|
* @return array
|
||
|
|
*/
|
||
|
|
public function get_field_map_choices( $form, $field_type = null, $exclude_field_types = null ) {
|
||
|
|
|
||
|
|
$fields = array();
|
||
|
|
|
||
|
|
// Setup first choice.
|
||
|
|
if ( rgblank( $field_type ) || ( is_array( $field_type ) && count( $field_type ) > 1 ) ) {
|
||
|
|
|
||
|
|
$first_choice_label = __( 'Select a Field', 'gravityflow' );
|
||
|
|
|
||
|
|
} else {
|
||
|
|
|
||
|
|
$type = is_array( $field_type ) ? $field_type[0] : $field_type;
|
||
|
|
$type = ucfirst( GF_Fields::get( $type )->get_form_editor_field_title() );
|
||
|
|
|
||
|
|
/* Translators: Placeholder is for the field type which should be selected */
|
||
|
|
$first_choice_label = sprintf( __( 'Select a %s Field', 'gravityflow' ), $type );
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
$fields[] = array(
|
||
|
|
'value' => '',
|
||
|
|
'label' => $first_choice_label,
|
||
|
|
);
|
||
|
|
|
||
|
|
// If field types not restricted add the default fields and entry meta.
|
||
|
|
if ( is_null( $field_type ) ) {
|
||
|
|
$fields[] = array( 'value' => 'id', 'label' => esc_html__( 'Entry ID', 'gravityflow' ) );
|
||
|
|
$fields[] = array( 'value' => 'date_created', 'label' => esc_html__( 'Entry Date', 'gravityflow' ) );
|
||
|
|
$fields[] = array( 'value' => 'ip', 'label' => esc_html__( 'User IP', 'gravityflow' ) );
|
||
|
|
$fields[] = array( 'value' => 'source_url', 'label' => esc_html__( 'Source Url', 'gravityflow' ) );
|
||
|
|
$fields[] = array( 'value' => 'created_by', 'label' => esc_html__( 'Created By', 'gravityflow' ) );
|
||
|
|
|
||
|
|
$entry_meta = GFFormsModel::get_entry_meta( $form['id'] );
|
||
|
|
foreach ( $entry_meta as $meta_key => $meta ) {
|
||
|
|
$fields[] = array(
|
||
|
|
'value' => $meta_key,
|
||
|
|
'label' => rgars( $entry_meta, "{$meta_key}/label" ),
|
||
|
|
);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// Populate form fields.
|
||
|
|
if ( is_array( $form['fields'] ) ) {
|
||
|
|
foreach ( $form['fields'] as $field ) {
|
||
|
|
$input_type = $field->get_input_type();
|
||
|
|
$inputs = $field->get_entry_inputs();
|
||
|
|
$field_is_valid_type = ( empty( $field_type ) || ( is_array( $field_type ) && in_array( $input_type, $field_type ) ) || ( ! empty( $field_type ) && $input_type == $field_type ) );
|
||
|
|
|
||
|
|
if ( is_null( $exclude_field_types ) ) {
|
||
|
|
$exclude_field = false;
|
||
|
|
} elseif ( is_array( $exclude_field_types ) ) {
|
||
|
|
if ( in_array( $input_type, $exclude_field_types ) ) {
|
||
|
|
$exclude_field = true;
|
||
|
|
} else {
|
||
|
|
$exclude_field = false;
|
||
|
|
}
|
||
|
|
} else {
|
||
|
|
// Not array, so should be single string.
|
||
|
|
if ( $input_type == $exclude_field_types ) {
|
||
|
|
$exclude_field = true;
|
||
|
|
} else {
|
||
|
|
$exclude_field = false;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
if ( is_array( $inputs ) && $field_is_valid_type && ! $exclude_field ) {
|
||
|
|
// If this is an address field, add full name to the list.
|
||
|
|
if ( $input_type == 'address' ) {
|
||
|
|
$fields[] = array(
|
||
|
|
'value' => $field->id,
|
||
|
|
'label' => GFCommon::get_label( $field ) . ' (' . esc_html__( 'Full', 'gravityflow' ) . ')',
|
||
|
|
);
|
||
|
|
}
|
||
|
|
// If this is a name field, add full name to the list.
|
||
|
|
if ( $input_type == 'name' ) {
|
||
|
|
$fields[] = array(
|
||
|
|
'value' => $field->id,
|
||
|
|
'label' => GFCommon::get_label( $field ) . ' (' . esc_html__( 'Full', 'gravityflow' ) . ')',
|
||
|
|
);
|
||
|
|
}
|
||
|
|
// If this is a checkbox field, add to the list.
|
||
|
|
if ( $input_type == 'checkbox' ) {
|
||
|
|
$fields[] = array(
|
||
|
|
'value' => $field->id,
|
||
|
|
'label' => GFCommon::get_label( $field ) . ' (' . esc_html__( 'Selected', 'gravityflow' ) . ')',
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
foreach ( $inputs as $input ) {
|
||
|
|
$fields[] = array(
|
||
|
|
'value' => $input['id'],
|
||
|
|
'label' => GFCommon::get_label( $field, $input['id'] ),
|
||
|
|
);
|
||
|
|
}
|
||
|
|
} elseif ( $input_type == 'list' && $field->enableColumns && $field_is_valid_type && ! $exclude_field ) {
|
||
|
|
$fields[] = array(
|
||
|
|
'value' => $field->id,
|
||
|
|
'label' => GFCommon::get_label( $field ) . ' (' . esc_html__( 'Full', 'gravityflow' ) . ')',
|
||
|
|
);
|
||
|
|
$col_index = 0;
|
||
|
|
foreach ( $field->choices as $column ) {
|
||
|
|
$fields[] = array(
|
||
|
|
'value' => $field->id . '.' . $col_index,
|
||
|
|
'label' => GFCommon::get_label( $field ) . ' (' . esc_html( rgar( $column, 'text' ) ) . ')',
|
||
|
|
);
|
||
|
|
$col_index ++;
|
||
|
|
}
|
||
|
|
} elseif ( ! rgar( $field, 'displayOnly' ) && $field_is_valid_type && ! $exclude_field ) {
|
||
|
|
$fields[] = array(
|
||
|
|
'value' => $field->id,
|
||
|
|
'label' => GFCommon::get_label( $field ),
|
||
|
|
);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return $fields;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Returns the request body.
|
||
|
|
*
|
||
|
|
* @return array|null The request body.
|
||
|
|
*/
|
||
|
|
public function get_request_body() {
|
||
|
|
$entry = $this->get_entry();
|
||
|
|
if ( empty( $this->body_type ) || $this->body_type == 'all_fields' ) {
|
||
|
|
return $entry;
|
||
|
|
}
|
||
|
|
|
||
|
|
return $this->do_request_body_mapping();
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Performs the body's response mappings.
|
||
|
|
*/
|
||
|
|
public function do_request_body_mapping() {
|
||
|
|
$body = array();
|
||
|
|
|
||
|
|
if ( ! is_array( $this->mappings ) ) {
|
||
|
|
|
||
|
|
return $body;
|
||
|
|
}
|
||
|
|
|
||
|
|
foreach ( $this->mappings as $mapping ) {
|
||
|
|
if ( rgblank( $mapping['key'] ) ) {
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
|
||
|
|
$body = $this->add_mapping_to_body( $mapping, $body );
|
||
|
|
}
|
||
|
|
|
||
|
|
return $body;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Add the mapped value to the body.
|
||
|
|
*
|
||
|
|
* @param array $mapping The properties for the mapping being processed.
|
||
|
|
* @param array $body The body to sent.
|
||
|
|
*
|
||
|
|
* @return array
|
||
|
|
*/
|
||
|
|
public function add_mapping_to_body( $mapping, $body ) {
|
||
|
|
$target_field_id = trim( $mapping['custom_key'] );
|
||
|
|
|
||
|
|
$source_field_id = (string) $mapping['value'];
|
||
|
|
|
||
|
|
$entry = $this->get_entry();
|
||
|
|
|
||
|
|
$form = $this->get_form();
|
||
|
|
|
||
|
|
$source_field = GFFormsModel::get_field( $form, $source_field_id );
|
||
|
|
|
||
|
|
if ( is_object( $source_field ) ) {
|
||
|
|
$is_full_source = $source_field_id === (string) intval( $source_field_id );
|
||
|
|
$source_field_inputs = $source_field->get_entry_inputs();
|
||
|
|
|
||
|
|
if ( $is_full_source && is_array( $source_field_inputs ) ) {
|
||
|
|
$body[ $target_field_id ] = $source_field->get_value_export( $entry, $source_field_id, true );
|
||
|
|
} else {
|
||
|
|
$body[ $target_field_id ] = $this->get_source_field_value( $entry, $source_field, $source_field_id );
|
||
|
|
}
|
||
|
|
} elseif ( $source_field_id == 'gf_custom' ) {
|
||
|
|
$body[ $target_field_id ] = GFCommon::replace_variables( $mapping['custom_value'], $form, $entry, false, false, false, 'text' );
|
||
|
|
} else {
|
||
|
|
$body[ $target_field_id ] = $entry[ $source_field_id ];
|
||
|
|
}
|
||
|
|
|
||
|
|
return $body;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Get the source field value.
|
||
|
|
*
|
||
|
|
* Returns the choice text instead of the unique value for choice based poll, quiz and survey fields.
|
||
|
|
*
|
||
|
|
* The source field choice unique value will not match the target field unique value.
|
||
|
|
*
|
||
|
|
* @param array $entry The entry being processed by this step.
|
||
|
|
* @param GF_Field $source_field The source field being processed.
|
||
|
|
* @param string $source_field_id The ID of the source field or input.
|
||
|
|
*
|
||
|
|
* @return string
|
||
|
|
*/
|
||
|
|
public function get_source_field_value( $entry, $source_field, $source_field_id ) {
|
||
|
|
$field_value = $entry[ $source_field_id ];
|
||
|
|
|
||
|
|
if ( in_array( $source_field->type, array( 'poll', 'quiz', 'survey' ) ) ) {
|
||
|
|
if ( $source_field->inputType == 'rank' ) {
|
||
|
|
$values = explode( ',', $field_value );
|
||
|
|
foreach ( $values as &$value ) {
|
||
|
|
$value = $this->get_source_choice_text( $value, $source_field );
|
||
|
|
}
|
||
|
|
|
||
|
|
return implode( ',', $values );
|
||
|
|
}
|
||
|
|
|
||
|
|
if ( $source_field->inputType == 'likert' && $source_field->gsurveyLikertEnableMultipleRows ) {
|
||
|
|
list( $row_value, $field_value ) = rgexplode( ':', $field_value, 2 );
|
||
|
|
}
|
||
|
|
|
||
|
|
return $this->get_source_choice_text( $field_value, $source_field );
|
||
|
|
}
|
||
|
|
|
||
|
|
return $field_value;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Gets the choice text for the supplied choice value.
|
||
|
|
*
|
||
|
|
* @param string $selected_choice The choice value from the source field.
|
||
|
|
* @param GF_Field $source_field The source field being processed.
|
||
|
|
*
|
||
|
|
* @return string
|
||
|
|
*/
|
||
|
|
public function get_source_choice_text( $selected_choice, $source_field ) {
|
||
|
|
return $this->get_choice_property( $selected_choice, $source_field->choices, 'value', 'text' );
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Helper to get the specified choice property for the selected choice.
|
||
|
|
*
|
||
|
|
* @param string $selected_choice The selected choice value or text.
|
||
|
|
* @param array $choices The field choices.
|
||
|
|
* @param string $compare_property The choice property the $selected_choice is to be compared against.
|
||
|
|
* @param string $return_property The choice property to be returned.
|
||
|
|
*
|
||
|
|
* @return string
|
||
|
|
*/
|
||
|
|
public function get_choice_property( $selected_choice, $choices, $compare_property, $return_property ) {
|
||
|
|
if ( $selected_choice && is_array( $choices ) ) {
|
||
|
|
foreach ( $choices as $choice ) {
|
||
|
|
if ( $choice[ $compare_property ] == $selected_choice ) {
|
||
|
|
return $choice[ $return_property ];
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return $selected_choice;
|
||
|
|
}
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
Gravity_Flow_Steps::register( new Gravity_Flow_Step_Webhook() );
|