plugin install
This commit is contained in:
@@ -0,0 +1,3 @@
|
||||
#gfwebapi-qrcode-container{
|
||||
padding:5px;
|
||||
}
|
||||
1
wp/wp-content/plugins/gravityforms/includes/webapi/css/gfwebapi_settings.min.css
vendored
Normal file
1
wp/wp-content/plugins/gravityforms/includes/webapi/css/gfwebapi_settings.min.css
vendored
Normal file
@@ -0,0 +1 @@
|
||||
#gfwebapi-qrcode-container{padding:5px}
|
||||
@@ -0,0 +1,2 @@
|
||||
<?php
|
||||
//Nothing to see here
|
||||
@@ -0,0 +1,168 @@
|
||||
<?php
|
||||
|
||||
require_once( ABSPATH . '/wp-admin/includes/class-wp-list-table.php' );
|
||||
|
||||
class GF_API_Keys_Table extends WP_List_Table {
|
||||
|
||||
public function __construct( $args = array() ) {
|
||||
parent::__construct( $args );
|
||||
|
||||
}
|
||||
|
||||
protected function get_table_classes() {
|
||||
return array( 'widefat', 'striped', 'feeds', 'api_key_table' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of columns to be included in the list table.
|
||||
*
|
||||
* @since 2.4
|
||||
* @since 2.4.22 Removed the key column.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
function get_columns() {
|
||||
|
||||
return array(
|
||||
'description' => esc_html__( 'Description', 'gravityforms' ),
|
||||
'user' => esc_html__( 'User', 'gravityforms' ),
|
||||
'permissions' => esc_html__( 'Permissions', 'gravityforms' ),
|
||||
'last_access' => esc_html__( 'Last Access', 'gravityforms' ),
|
||||
);
|
||||
}
|
||||
|
||||
function prepare_items() {
|
||||
|
||||
$this->_column_headers = array( $this->get_columns(), array(), array() );
|
||||
$this->items = GFWebAPI::get_api_keys();
|
||||
}
|
||||
|
||||
function process_action() {
|
||||
|
||||
$action = rgget( 'single_action' );
|
||||
|
||||
if ( $action !== 'revoke' ) {
|
||||
return;
|
||||
}
|
||||
|
||||
check_admin_referer( 'gforms_revoke_key' );
|
||||
|
||||
$this->delete_api_key( rgget( 'key_id' ) );
|
||||
}
|
||||
|
||||
function column_default( $item, $column_name ) {
|
||||
return $item[ $column_name ];
|
||||
}
|
||||
|
||||
function column_description( $item ) {
|
||||
|
||||
// create a nonce
|
||||
$revoke_nonce = wp_create_nonce( 'gforms_revoke_key' );
|
||||
|
||||
$description = $item['description'];
|
||||
|
||||
$confirm = "javascript: if( ! confirm('WARNING: You are about to revoke this API Key. \'Cancel\' to stop, \'OK\' to revoke.')){ event.stopPropagation(); return false } ";
|
||||
$nonce_url = wp_nonce_url( '?page=gf_settings&subview=gravityformswebapi', 'gf_revoke_key' );
|
||||
|
||||
$actions = array(
|
||||
'edit' => '<a href="javascript:editKey( ' . $item['key_id'] . ' );">' . esc_html__( 'Edit', 'gravityforms' ) . '</a>',
|
||||
'delete' => sprintf( '<a data-wp-lists="delete:the-list:key_row_%d::status=delete&action=delete_key&key=%d" onclick="%s" href="%s" class="submitdelete">Revoke</a>', absint( $item['key_id'] ), absint( $item['key_id'] ), $confirm, $nonce_url ),
|
||||
);
|
||||
|
||||
return $description . $this->row_actions( $actions );
|
||||
}
|
||||
|
||||
function get_edit_url( $key_id ) {
|
||||
return sprintf( '?page=gf_settings&subview=gravityformswebapi&action=edit&key_id=%s', absint( $key_id ) );
|
||||
}
|
||||
|
||||
function column_last_access( $item ) {
|
||||
return empty( $item['last_access'] ) ? __( 'Never Accessed', 'gravityforms' ) : GFCommon::format_date( $item['last_access'], true, '', true );
|
||||
}
|
||||
|
||||
function column_permissions( $item ) {
|
||||
|
||||
if ( $item['permissions'] == 'read_write' ) {
|
||||
return 'Read/Write';
|
||||
} else {
|
||||
return ucwords( $item['permissions'] );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function no_items() {
|
||||
echo '<div style="padding:10px;">' . sprintf( esc_html__( 'You don\'t have any API keys. Let\'s go %1$screate one%2$s!', 'gravityforms' ), '<a href="javascript:editKey( 0 );">', '</a>' ) . '</div>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the table
|
||||
*
|
||||
* @since 3.1.0
|
||||
*/
|
||||
public function display() {
|
||||
$singular = $this->_args['singular'];
|
||||
|
||||
$this->screen->render_screen_reader_content( 'heading_list' );
|
||||
?>
|
||||
|
||||
<input type="hidden" name="single_action"/> <input type="hidden" name="action_args"/>
|
||||
<table class="wp-list-table <?php echo implode( ' ', $this->get_table_classes() ); ?>">
|
||||
<thead>
|
||||
<tr>
|
||||
<?php $this->print_column_headers(); ?>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody id="the-list"<?php
|
||||
if ( $singular ) {
|
||||
echo " data-wp-lists='list:$singular'";
|
||||
} ?>>
|
||||
<?php $this->display_rows_or_placeholder(); ?>
|
||||
</tbody>
|
||||
|
||||
</table>
|
||||
<div>
|
||||
<a class="button" id="add_setting_button" href="javascript:editKey( 0 );">Add Key</a>
|
||||
</div>
|
||||
<?php
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates content for a single row of the table
|
||||
*
|
||||
* @since 3.1.0
|
||||
*
|
||||
* @param object $item The current item
|
||||
*/
|
||||
public function single_row( $item ) {
|
||||
echo "<tr id='key_row_{$item['key_id']}' >";
|
||||
$this->single_row_columns( $item );
|
||||
echo '</tr>';
|
||||
}
|
||||
|
||||
public function output_styles() {
|
||||
?>
|
||||
<style>
|
||||
table.gforms_form_settings .api_key_table td { padding-left: 10px; vertical-align: top; }
|
||||
#add_setting_button { margin-top: 10px; }
|
||||
tr:hover .row-actions { position: relative; }
|
||||
.api_key_table tr:hover .row-actions { position: static; }
|
||||
</style>
|
||||
<?php
|
||||
}
|
||||
|
||||
public function output_scripts() {
|
||||
?>
|
||||
<script type="text/javascript">
|
||||
|
||||
jQuery(document).ready(function () {
|
||||
|
||||
jQuery("#the-list").wpList();
|
||||
|
||||
});
|
||||
|
||||
</script>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
<?php
|
||||
//Nothing to see here
|
||||
8
wp/wp-content/plugins/gravityforms/includes/webapi/js/enc-base64-min.js
vendored
Normal file
8
wp/wp-content/plugins/gravityforms/includes/webapi/js/enc-base64-min.js
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
/*
|
||||
CryptoJS v3.1.2
|
||||
code.google.com/p/crypto-js
|
||||
(c) 2009-2013 by Jeff Mott. All rights reserved.
|
||||
code.google.com/p/crypto-js/wiki/License
|
||||
*/
|
||||
(function(){var h=CryptoJS,j=h.lib.WordArray;h.enc.Base64={stringify:function(b){var e=b.words,f=b.sigBytes,c=this._map;b.clamp();b=[];for(var a=0;a<f;a+=3)for(var d=(e[a>>>2]>>>24-8*(a%4)&255)<<16|(e[a+1>>>2]>>>24-8*((a+1)%4)&255)<<8|e[a+2>>>2]>>>24-8*((a+2)%4)&255,g=0;4>g&&a+0.75*g<f;g++)b.push(c.charAt(d>>>6*(3-g)&63));if(e=c.charAt(64))for(;b.length%4;)b.push(e);return b.join("")},parse:function(b){var e=b.length,f=this._map,c=f.charAt(64);c&&(c=b.indexOf(c),-1!=c&&(e=c));for(var c=[],a=0,d=0;d<
|
||||
e;d++)if(d%4){var g=f.indexOf(b.charAt(d-1))<<2*(d%4),h=f.indexOf(b.charAt(d))>>>6-2*(d%4);c[a>>>2]|=(g|h)<<24-8*(a%4);a++}return j.create(c,a)},_map:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="}})();
|
||||
1
wp/wp-content/plugins/gravityforms/includes/webapi/js/enc-base64-min.min.js
vendored
Normal file
1
wp/wp-content/plugins/gravityforms/includes/webapi/js/enc-base64-min.min.js
vendored
Normal file
@@ -0,0 +1 @@
|
||||
!function(){var r=CryptoJS,h=r.lib.WordArray;r.enc.Base64={stringify:function(r){var a=r.words,t=r.sigBytes,n=this._map;r.clamp(),r=[];for(var i=0;i<t;i+=3)for(var e=(a[i>>>2]>>>24-i%4*8&255)<<16|(a[i+1>>>2]>>>24-(i+1)%4*8&255)<<8|a[i+2>>>2]>>>24-(i+2)%4*8&255,f=0;f<4&&i+.75*f<t;f++)r.push(n.charAt(e>>>6*(3-f)&63));if(a=n.charAt(64))for(;r.length%4;)r.push(a);return r.join("")},parse:function(r){var a=r.length,t=this._map;(e=t.charAt(64))&&-1!=(e=r.indexOf(e))&&(a=e);for(var n,i,e=[],f=0,c=0;c<a;c++)c%4&&(n=t.indexOf(r.charAt(c-1))<<c%4*2,i=t.indexOf(r.charAt(c))>>>6-c%4*2,e[f>>>2]|=(n|i)<<24-f%4*8,f++);return h.create(e,f)},_map:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="}}();
|
||||
@@ -0,0 +1,214 @@
|
||||
function gfapiCalculateSig(stringToSign, privateKey) {
|
||||
var hash = CryptoJS.HmacSHA1(stringToSign, privateKey);
|
||||
var base64 = hash.toString(CryptoJS.enc.Base64);
|
||||
return encodeURIComponent(base64);
|
||||
}
|
||||
|
||||
jQuery(document).ready(function () {
|
||||
|
||||
jQuery("#gfwebapi-qrbutton").click(function () {
|
||||
jQuery("#gfwebapi-qrcode-container").toggle();
|
||||
var $img = jQuery('#gfwebapi-qrcode');
|
||||
if ($img.length > 0)
|
||||
$img.attr('src', ajaxurl + '?action=gfwebapi_qrcode&rnd=' + Date.now());
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
jQuery("#public_key, #private_key").on("keyup", function () {
|
||||
jQuery("#gfwebapi-qrcode-container").html("The keys have changes. Please save the changes and try again.")
|
||||
});
|
||||
|
||||
jQuery("#gfapi-url-builder-button").click(function (e) {
|
||||
e.preventDefault();
|
||||
var publicKey, privateKey, expiration, method, route, stringToSign, url, sig;
|
||||
publicKey = jQuery("#public_key").val();
|
||||
privateKey = jQuery("#private_key").val();
|
||||
expiration = parseInt(jQuery("#gfapi-url-builder-expiration").val());
|
||||
method = jQuery("#gfapi-url-builder-method").val();
|
||||
route = jQuery("#gfapi-url-builder-route").val();
|
||||
route = route.replace(/\/$/, ""); // remove trailing slash
|
||||
var d = new Date;
|
||||
var unixtime = parseInt(d.getTime() / 1000);
|
||||
var future_unixtime = unixtime + expiration;
|
||||
|
||||
stringToSign = publicKey + ":" + method + ":" + route + ":" + future_unixtime;
|
||||
sig = gfapiCalculateSig(stringToSign, privateKey);
|
||||
url = gfapiBaseUrl + "/" + route + "/?api_key=" + publicKey + "&signature=" + sig + "&expires=" + future_unixtime;
|
||||
jQuery('#gfapi-url-builder-generated-url').val(url);
|
||||
return false;
|
||||
});
|
||||
var gfapiTesterAjaxRequest;
|
||||
jQuery("#gfapi-url-tester-button").click(function (e) {
|
||||
var $button = jQuery(this);
|
||||
var $loading = jQuery("#gfapi-url-tester-loading");
|
||||
var $results = jQuery("#gfapi-url-tester-results");
|
||||
var url = jQuery('#gfapi-url-tester-url').val();
|
||||
var method = jQuery('#gfapi-url-tester-method').val();
|
||||
gfapiTesterAjaxRequest = jQuery.ajax({
|
||||
url : url + "&test=1",
|
||||
type : method,
|
||||
dataType : 'json',
|
||||
data : {},
|
||||
beforeSend: function (xhr, opts) {
|
||||
$button.attr('disabled', 'disabled');
|
||||
$loading.show();
|
||||
}
|
||||
})
|
||||
.done(function (data, textStatus, xhr) {
|
||||
$button.removeAttr('disabled');
|
||||
$loading.hide();
|
||||
$results.html(xhr.status);
|
||||
$results.fadeTo("fast", 1);
|
||||
})
|
||||
.fail(function (jqXHR) {
|
||||
|
||||
$button.removeAttr('disabled');
|
||||
$loading.hide();
|
||||
$results.fadeTo("fast", 1);
|
||||
var msg;
|
||||
$loading.hide();
|
||||
if (msg == "abort") {
|
||||
msg = "Request cancelled";
|
||||
} else {
|
||||
msg = jqXHR.status + ": " + jqXHR.statusText;
|
||||
}
|
||||
$results.html(msg);
|
||||
});
|
||||
return false;
|
||||
});
|
||||
|
||||
// Reload page when modal is closed.
|
||||
jQuery( 'body' ).on( 'thickbox:removed', function( e ) {
|
||||
|
||||
if ( modalSubmitted ) {
|
||||
jQuery( '#gform-settings' ).submit();
|
||||
}
|
||||
|
||||
} );
|
||||
|
||||
});
|
||||
|
||||
var modalSubmitted = false;
|
||||
|
||||
// Update key.
|
||||
function saveKey() {
|
||||
|
||||
var requestData = {
|
||||
action: 'gfwebapi_edit_key',
|
||||
nonce: jQuery( '#gform-webapi-edit input[name="_wpnonce"]' ).val(),
|
||||
key_id: jQuery( '#gform-webapi-key' ).val(),
|
||||
description: jQuery( '#gform-webapi-description' ).val(),
|
||||
user_id: jQuery( '#gform-webapi-user' ).val(),
|
||||
permissions: jQuery( '#gform-webapi-permissions' ).val()
|
||||
};
|
||||
|
||||
// Attempt to save key, display response.
|
||||
jQuery.ajax(
|
||||
{
|
||||
url: ajaxurl,
|
||||
type: 'POST',
|
||||
dataType: 'json',
|
||||
data: requestData,
|
||||
success: function ( response ) {
|
||||
|
||||
// Get alert class.
|
||||
var alertClass = response.success ? 'success' : 'error';
|
||||
|
||||
// Remove existing alert, add new alert.
|
||||
jQuery( '#gform-webapi-edit .alert', document ).remove();
|
||||
jQuery( '#gform-webapi-edit' ).prepend( '<div class="alert ' + alertClass + '">' + response.data.message + '</div>' );
|
||||
|
||||
// Display consumer key, secret.
|
||||
if ( response.data.key ) {
|
||||
jQuery( '#gform-webapi-description, #gform-webapi-user, #gform-webapi-permissions, #gform-webapi-truncated-key, #gform-webapi-last-access' ).parent().hide();
|
||||
jQuery( '#gform-webapi-consumer-key' ).val( response.data.key.consumer_key ).parent().show();
|
||||
jQuery( '#gform-webapi-consumer-secret' ).val( response.data.key.consumer_secret ).parent().show();
|
||||
jQuery( '#gform-webapi-edit button' ).hide();
|
||||
} else {
|
||||
jQuery( '#gform-webapi-consumer-key' ).val( '' ).parent().hide();
|
||||
jQuery( '#gform-webapi-consumer-secret' ).val( '' ).parent().hide();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
modalSubmitted = true;
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
// Open edit key modal.
|
||||
function editKey( keyId ) {
|
||||
|
||||
modalSubmitted = false;
|
||||
|
||||
// Remove existing alert, hide consumer key/secret, show button.
|
||||
jQuery( '#gform-webapi-edit .alert', document ).remove();
|
||||
jQuery( '#gform-webapi-consumer-key, #gform-webapi-consumer-secret' ).parent().hide();
|
||||
jQuery( '#gform-webapi-edit button' ).show();
|
||||
|
||||
// If this is a new key, reset the form and open modal.
|
||||
if ( keyId == 0 ) {
|
||||
|
||||
jQuery( '#gform-webapi-key' ).val( keyId );
|
||||
jQuery( '#gform-webapi-description' ).val( '' );
|
||||
jQuery( '#gform-webapi-user' ).val( jQuery( '#gform-webapi-user option:first-child' ).val() );
|
||||
jQuery( '#gform-webapi-permissions' ).val( jQuery( '#gform-webapi-permissions option:first-child' ).val() );
|
||||
|
||||
jQuery( '#gform-webapi-edit button' ).html( jQuery( '#gform-webapi-edit button' ).data( 'add' ) );
|
||||
|
||||
jQuery( '#gform-webapi-key, #gform-webapi-description, #gform-webapi-user, #gform-webapi-permissions' ).parent().show();
|
||||
jQuery( '#gform-webapi-truncated-key, #gform-webapi-last-access' ).parent().hide();
|
||||
|
||||
tb_show( 'Add New Key', '#TB_inline?width=375&height=330&inlineId=gform-webapi-edit-container' );
|
||||
|
||||
jQuery( '#gform-webapi-edit', document ).on( 'submit', saveKey );
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
// Get key details, open modal.
|
||||
jQuery.ajax(
|
||||
{
|
||||
url: ajaxurl,
|
||||
type: 'GET',
|
||||
dataType: 'json',
|
||||
data: {
|
||||
action: 'gfwebapi_edit_key',
|
||||
key_id: keyId,
|
||||
nonce: jQuery( '#gform-webapi-edit input[name="_wpnonce"]' ).val(),
|
||||
},
|
||||
success: function ( response ) {
|
||||
|
||||
// If key could not be retrieve, display error.
|
||||
if ( ! response.success ) {
|
||||
alert( response.data.message );
|
||||
return;
|
||||
}
|
||||
|
||||
var key = response.data.key;
|
||||
|
||||
jQuery( '#gform-webapi-key' ).val( key.key_id );
|
||||
jQuery( '#gform-webapi-description' ).val( key.description );
|
||||
jQuery( '#gform-webapi-user' ).val( key.user_id );
|
||||
jQuery( '#gform-webapi-permissions' ).val( key.permissions );
|
||||
jQuery( '#gform-webapi-truncated-key' ).html( key.consumer_key ).parent().show();
|
||||
jQuery( '#gform-webapi-last-access' ).html( key.last_access ).parent().show();
|
||||
|
||||
jQuery( '#gform-webapi-edit button' ).html( jQuery( '#gform-webapi-edit button' ).data( 'edit' ) );
|
||||
|
||||
jQuery( '#gform-webapi-description, #gform-webapi-user, #gform-webapi-permissions, #gform-webapi-truncated-key, #gform-webapi-last-access' ).parent().show();
|
||||
|
||||
tb_show( 'Edit Key', '#TB_inline?width=375&height=445&inlineId=gform-webapi-edit-container' );
|
||||
|
||||
jQuery( '#gform-webapi-edit', document ).on( 'submit', saveKey );
|
||||
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
}
|
||||
1
wp/wp-content/plugins/gravityforms/includes/webapi/js/gfwebapi_settings.min.js
vendored
Normal file
1
wp/wp-content/plugins/gravityforms/includes/webapi/js/gfwebapi_settings.min.js
vendored
Normal file
@@ -0,0 +1 @@
|
||||
function gfapiCalculateSig(e,r){e=CryptoJS.HmacSHA1(e,r).toString(CryptoJS.enc.Base64);return encodeURIComponent(e)}jQuery(document).ready(function(){jQuery("#gfwebapi-qrbutton").click(function(){jQuery("#gfwebapi-qrcode-container").toggle();var e=jQuery("#gfwebapi-qrcode");return 0<e.length&&e.attr("src",ajaxurl+"?action=gfwebapi_qrcode&rnd="+Date.now()),!1}),jQuery("#public_key, #private_key").on("keyup",function(){jQuery("#gfwebapi-qrcode-container").html("The keys have changes. Please save the changes and try again.")}),jQuery("#gfapi-url-builder-button").click(function(e){e.preventDefault(),e=jQuery("#public_key").val(),r=jQuery("#private_key").val(),t=parseInt(jQuery("#gfapi-url-builder-expiration").val()),o=jQuery("#gfapi-url-builder-method").val(),a=(a=jQuery("#gfapi-url-builder-route").val()).replace(/\/$/,"");var r,a,i=new Date,i=parseInt(i.getTime()/1e3)+t,t=gfapiCalculateSig(e+":"+o+":"+a+":"+i,r),o=gfapiBaseUrl+"/"+a+"/?api_key="+e+"&signature="+t+"&expires="+i;return jQuery("#gfapi-url-builder-generated-url").val(o),!1}),jQuery("#gfapi-url-tester-button").click(function(e){var i=jQuery(this),t=jQuery("#gfapi-url-tester-loading"),o=jQuery("#gfapi-url-tester-results"),r=jQuery("#gfapi-url-tester-url").val(),a=jQuery("#gfapi-url-tester-method").val();return jQuery.ajax({url:r+"&test=1",type:a,dataType:"json",data:{},beforeSend:function(e,r){i.attr("disabled","disabled"),t.show()}}).done(function(e,r,a){i.removeAttr("disabled"),t.hide(),o.html(a.status),o.fadeTo("fast",1)}).fail(function(e){var r;i.removeAttr("disabled"),t.hide(),o.fadeTo("fast",1),t.hide(),r="abort"==r?"Request cancelled":e.status+": "+e.statusText,o.html(r)}),!1}),jQuery("body").on("thickbox:removed",function(e){modalSubmitted&&jQuery("#gform-settings").submit()})});var modalSubmitted=!1;function saveKey(){var e={action:"gfwebapi_edit_key",nonce:jQuery('#gform-webapi-edit input[name="_wpnonce"]').val(),key_id:jQuery("#gform-webapi-key").val(),description:jQuery("#gform-webapi-description").val(),user_id:jQuery("#gform-webapi-user").val(),permissions:jQuery("#gform-webapi-permissions").val()};return jQuery.ajax({url:ajaxurl,type:"POST",dataType:"json",data:e,success:function(e){var r=e.success?"success":"error";jQuery("#gform-webapi-edit .alert",document).remove(),jQuery("#gform-webapi-edit").prepend('<div class="alert '+r+'">'+e.data.message+"</div>"),(e.data.key?(jQuery("#gform-webapi-description, #gform-webapi-user, #gform-webapi-permissions, #gform-webapi-truncated-key, #gform-webapi-last-access").parent().hide(),jQuery("#gform-webapi-consumer-key").val(e.data.key.consumer_key).parent().show(),jQuery("#gform-webapi-consumer-secret").val(e.data.key.consumer_secret).parent().show(),jQuery("#gform-webapi-edit button")):(jQuery("#gform-webapi-consumer-key").val("").parent().hide(),jQuery("#gform-webapi-consumer-secret").val("").parent())).hide()}}),!(modalSubmitted=!0)}function editKey(e){modalSubmitted=!1,jQuery("#gform-webapi-edit .alert",document).remove(),jQuery("#gform-webapi-consumer-key, #gform-webapi-consumer-secret").parent().hide(),jQuery("#gform-webapi-edit button").show(),0==e?(jQuery("#gform-webapi-key").val(e),jQuery("#gform-webapi-description").val(""),jQuery("#gform-webapi-user").val(jQuery("#gform-webapi-user option:first-child").val()),jQuery("#gform-webapi-permissions").val(jQuery("#gform-webapi-permissions option:first-child").val()),jQuery("#gform-webapi-edit button").html(jQuery("#gform-webapi-edit button").data("add")),jQuery("#gform-webapi-key, #gform-webapi-description, #gform-webapi-user, #gform-webapi-permissions").parent().show(),jQuery("#gform-webapi-truncated-key, #gform-webapi-last-access").parent().hide(),tb_show("Add New Key","#TB_inline?width=375&height=330&inlineId=gform-webapi-edit-container"),jQuery("#gform-webapi-edit",document).on("submit",saveKey)):jQuery.ajax({url:ajaxurl,type:"GET",dataType:"json",data:{action:"gfwebapi_edit_key",key_id:e,nonce:jQuery('#gform-webapi-edit input[name="_wpnonce"]').val()},success:function(e){var r;e.success?(r=e.data.key,jQuery("#gform-webapi-key").val(r.key_id),jQuery("#gform-webapi-description").val(r.description),jQuery("#gform-webapi-user").val(r.user_id),jQuery("#gform-webapi-permissions").val(r.permissions),jQuery("#gform-webapi-truncated-key").html(r.consumer_key).parent().show(),jQuery("#gform-webapi-last-access").html(r.last_access).parent().show(),jQuery("#gform-webapi-edit button").html(jQuery("#gform-webapi-edit button").data("edit")),jQuery("#gform-webapi-description, #gform-webapi-user, #gform-webapi-permissions, #gform-webapi-truncated-key, #gform-webapi-last-access").parent().show(),tb_show("Edit Key","#TB_inline?width=375&height=445&inlineId=gform-webapi-edit-container"),jQuery("#gform-webapi-edit",document).on("submit",saveKey)):alert(e.data.message)}})}
|
||||
17
wp/wp-content/plugins/gravityforms/includes/webapi/js/hmac-sha1.min.js
vendored
Normal file
17
wp/wp-content/plugins/gravityforms/includes/webapi/js/hmac-sha1.min.js
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
CryptoJS v3.1.2
|
||||
code.google.com/p/crypto-js
|
||||
(c) 2009-2013 by Jeff Mott. All rights reserved.
|
||||
code.google.com/p/crypto-js/wiki/License
|
||||
*/
|
||||
var CryptoJS=CryptoJS||function(g,l){var e={},d=e.lib={},m=function(){},k=d.Base={extend:function(a){m.prototype=this;var c=new m;a&&c.mixIn(a);c.hasOwnProperty("init")||(c.init=function(){c.$super.init.apply(this,arguments)});c.init.prototype=c;c.$super=this;return c},create:function(){var a=this.extend();a.init.apply(a,arguments);return a},init:function(){},mixIn:function(a){for(var c in a)a.hasOwnProperty(c)&&(this[c]=a[c]);a.hasOwnProperty("toString")&&(this.toString=a.toString)},clone:function(){return this.init.prototype.extend(this)}},
|
||||
p=d.WordArray=k.extend({init:function(a,c){a=this.words=a||[];this.sigBytes=c!=l?c:4*a.length},toString:function(a){return(a||n).stringify(this)},concat:function(a){var c=this.words,q=a.words,f=this.sigBytes;a=a.sigBytes;this.clamp();if(f%4)for(var b=0;b<a;b++)c[f+b>>>2]|=(q[b>>>2]>>>24-8*(b%4)&255)<<24-8*((f+b)%4);else if(65535<q.length)for(b=0;b<a;b+=4)c[f+b>>>2]=q[b>>>2];else c.push.apply(c,q);this.sigBytes+=a;return this},clamp:function(){var a=this.words,c=this.sigBytes;a[c>>>2]&=4294967295<<
|
||||
32-8*(c%4);a.length=g.ceil(c/4)},clone:function(){var a=k.clone.call(this);a.words=this.words.slice(0);return a},random:function(a){for(var c=[],b=0;b<a;b+=4)c.push(4294967296*g.random()|0);return new p.init(c,a)}}),b=e.enc={},n=b.Hex={stringify:function(a){var c=a.words;a=a.sigBytes;for(var b=[],f=0;f<a;f++){var d=c[f>>>2]>>>24-8*(f%4)&255;b.push((d>>>4).toString(16));b.push((d&15).toString(16))}return b.join("")},parse:function(a){for(var c=a.length,b=[],f=0;f<c;f+=2)b[f>>>3]|=parseInt(a.substr(f,
|
||||
2),16)<<24-4*(f%8);return new p.init(b,c/2)}},j=b.Latin1={stringify:function(a){var c=a.words;a=a.sigBytes;for(var b=[],f=0;f<a;f++)b.push(String.fromCharCode(c[f>>>2]>>>24-8*(f%4)&255));return b.join("")},parse:function(a){for(var c=a.length,b=[],f=0;f<c;f++)b[f>>>2]|=(a.charCodeAt(f)&255)<<24-8*(f%4);return new p.init(b,c)}},h=b.Utf8={stringify:function(a){try{return decodeURIComponent(escape(j.stringify(a)))}catch(c){throw Error("Malformed UTF-8 data");}},parse:function(a){return j.parse(unescape(encodeURIComponent(a)))}},
|
||||
r=d.BufferedBlockAlgorithm=k.extend({reset:function(){this._data=new p.init;this._nDataBytes=0},_append:function(a){"string"==typeof a&&(a=h.parse(a));this._data.concat(a);this._nDataBytes+=a.sigBytes},_process:function(a){var c=this._data,b=c.words,f=c.sigBytes,d=this.blockSize,e=f/(4*d),e=a?g.ceil(e):g.max((e|0)-this._minBufferSize,0);a=e*d;f=g.min(4*a,f);if(a){for(var k=0;k<a;k+=d)this._doProcessBlock(b,k);k=b.splice(0,a);c.sigBytes-=f}return new p.init(k,f)},clone:function(){var a=k.clone.call(this);
|
||||
a._data=this._data.clone();return a},_minBufferSize:0});d.Hasher=r.extend({cfg:k.extend(),init:function(a){this.cfg=this.cfg.extend(a);this.reset()},reset:function(){r.reset.call(this);this._doReset()},update:function(a){this._append(a);this._process();return this},finalize:function(a){a&&this._append(a);return this._doFinalize()},blockSize:16,_createHelper:function(a){return function(b,d){return(new a.init(d)).finalize(b)}},_createHmacHelper:function(a){return function(b,d){return(new s.HMAC.init(a,
|
||||
d)).finalize(b)}}});var s=e.algo={};return e}(Math);
|
||||
(function(){var g=CryptoJS,l=g.lib,e=l.WordArray,d=l.Hasher,m=[],l=g.algo.SHA1=d.extend({_doReset:function(){this._hash=new e.init([1732584193,4023233417,2562383102,271733878,3285377520])},_doProcessBlock:function(d,e){for(var b=this._hash.words,n=b[0],j=b[1],h=b[2],g=b[3],l=b[4],a=0;80>a;a++){if(16>a)m[a]=d[e+a]|0;else{var c=m[a-3]^m[a-8]^m[a-14]^m[a-16];m[a]=c<<1|c>>>31}c=(n<<5|n>>>27)+l+m[a];c=20>a?c+((j&h|~j&g)+1518500249):40>a?c+((j^h^g)+1859775393):60>a?c+((j&h|j&g|h&g)-1894007588):c+((j^h^
|
||||
g)-899497514);l=g;g=h;h=j<<30|j>>>2;j=n;n=c}b[0]=b[0]+n|0;b[1]=b[1]+j|0;b[2]=b[2]+h|0;b[3]=b[3]+g|0;b[4]=b[4]+l|0},_doFinalize:function(){var d=this._data,e=d.words,b=8*this._nDataBytes,g=8*d.sigBytes;e[g>>>5]|=128<<24-g%32;e[(g+64>>>9<<4)+14]=Math.floor(b/4294967296);e[(g+64>>>9<<4)+15]=b;d.sigBytes=4*e.length;this._process();return this._hash},clone:function(){var e=d.clone.call(this);e._hash=this._hash.clone();return e}});g.SHA1=d._createHelper(l);g.HmacSHA1=d._createHmacHelper(l)})();
|
||||
(function(){var g=CryptoJS,l=g.enc.Utf8;g.algo.HMAC=g.lib.Base.extend({init:function(e,d){e=this._hasher=new e.init;"string"==typeof d&&(d=l.parse(d));var g=e.blockSize,k=4*g;d.sigBytes>k&&(d=e.finalize(d));d.clamp();for(var p=this._oKey=d.clone(),b=this._iKey=d.clone(),n=p.words,j=b.words,h=0;h<g;h++)n[h]^=1549556828,j[h]^=909522486;p.sigBytes=b.sigBytes=k;this.reset()},reset:function(){var e=this._hasher;e.reset();e.update(this._iKey)},update:function(e){this._hasher.update(e);return this},finalize:function(e){var d=
|
||||
this._hasher;e=d.finalize(e);d.reset();return d.finalize(this._oKey.clone().concat(e))}})})();
|
||||
@@ -0,0 +1,2 @@
|
||||
<?php
|
||||
//Nothing to see here
|
||||
2193
wp/wp-content/plugins/gravityforms/includes/webapi/v2/README.md
Normal file
2193
wp/wp-content/plugins/gravityforms/includes/webapi/v2/README.md
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,76 @@
|
||||
<?php
|
||||
|
||||
if ( ! class_exists( 'GFForms' ) ) {
|
||||
die();
|
||||
}
|
||||
|
||||
class GF_REST_API {
|
||||
/**
|
||||
* Contains an instance of this class, if available.
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
* @var object $_instance If available, contains an instance of this class
|
||||
*/
|
||||
private static $_instance = null;
|
||||
|
||||
/**
|
||||
* Returns an instance of this class, and stores it in the $_instance property.
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
* @return GF_REST_API $_instance An instance of the GF_REST_API class
|
||||
*/
|
||||
public static function get_instance() {
|
||||
if ( self::$_instance == null ) {
|
||||
self::$_instance = new GF_REST_API();
|
||||
}
|
||||
|
||||
return self::$_instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 2.4-beta-1
|
||||
*/
|
||||
private function __clone() {
|
||||
} /* do nothing */
|
||||
|
||||
/**
|
||||
* GF_REST_API constructor.
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*/
|
||||
public function __construct() {
|
||||
add_action( 'rest_api_init', array( $this, 'register_rest_routes' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Register REST API routes
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*/
|
||||
public function register_rest_routes() {
|
||||
$controllers = array(
|
||||
'GF_REST_Entries_Controller',
|
||||
'GF_REST_Entry_Properties_Controller',
|
||||
'GF_REST_Entry_Notifications_Controller',
|
||||
'GF_REST_Notes_Controller',
|
||||
'GF_REST_Entry_Notes_Controller',
|
||||
'GF_REST_Form_Entries_Controller',
|
||||
'GF_REST_Form_Results_Controller',
|
||||
'GF_REST_Form_Submissions_Controller',
|
||||
'GF_REST_Form_Submissions_Validation_Controller',
|
||||
'GF_REST_Forms_Controller',
|
||||
'GF_REST_Feeds_Controller',
|
||||
'GF_REST_Form_Feeds_Controller',
|
||||
'GF_REST_Form_Field_Filters_Controller',
|
||||
'GF_REST_Feed_Properties_Controller',
|
||||
);
|
||||
|
||||
foreach ( $controllers as $controller ) {
|
||||
$controller_obj = new $controller();
|
||||
$controller_obj->register_routes();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,896 @@
|
||||
<?php
|
||||
/**
|
||||
* REST API Authentication
|
||||
*
|
||||
* @since 2.4.0
|
||||
*/
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
/**
|
||||
* REST API authentication class.
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*/
|
||||
class GF_REST_Authentication {
|
||||
|
||||
/**
|
||||
* Authentication error.
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
* @var WP_Error
|
||||
*/
|
||||
protected $error = null;
|
||||
|
||||
/**
|
||||
* Logged in user data.
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
* @var stdClass
|
||||
*/
|
||||
protected $user = null;
|
||||
|
||||
/**
|
||||
* Current auth method.
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $auth_method = '';
|
||||
|
||||
/**
|
||||
* Initialize authentication actions.
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*/
|
||||
public function __construct() {
|
||||
|
||||
$this->init();
|
||||
}
|
||||
|
||||
/***
|
||||
* Initializes REST authentication by adding appropriate filters
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*/
|
||||
public function init() {
|
||||
|
||||
add_filter( 'determine_current_user', array( $this, 'authenticate' ), 15 );
|
||||
add_filter( 'rest_authentication_errors', array( $this, 'authentication_fallback' ) );
|
||||
add_filter( 'rest_authentication_errors', array( $this, 'check_authentication_error' ), 99 );
|
||||
add_filter( 'rest_pre_dispatch', array( $this, 'check_user_permissions' ), 99, 3 );
|
||||
add_filter( 'rest_post_dispatch', array( $this, 'send_unauthorized_headers' ), 50 );
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* If request is to our API and we did not set any authentication errors, override authentication errors that may
|
||||
* be set by other REST API authenticators.
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
* @deprecated 2.4.22
|
||||
*
|
||||
* @param $errors
|
||||
*
|
||||
* @return null
|
||||
*/
|
||||
public function override_rest_authentication_errors( $errors ) {
|
||||
_deprecated_function( __METHOD__, '2.4.22', 'GF_REST_Authentication::check_authentication_error' );
|
||||
|
||||
if ( $this->is_request_to_rest_api() && ! $this->get_error() ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $errors;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Check if is request to Gravity Forms REST API.
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
* @return bool Returns true if this is a request to the Gravity Forms REST API. False otherwise
|
||||
*/
|
||||
protected function is_request_to_rest_api() {
|
||||
if ( empty( $_SERVER['REQUEST_URI'] ) || ! ( defined( 'REST_REQUEST' ) && REST_REQUEST ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$rest_prefix = trailingslashit( rest_get_url_prefix() );
|
||||
|
||||
// Check if our endpoint.
|
||||
$is_gf_endpoint = ( strpos( $_SERVER['REQUEST_URI'], $rest_prefix . 'gf/' ) !== false );
|
||||
|
||||
// Allow third party plugins use our authentication methods.
|
||||
$third_party = ( false !== strpos( $_SERVER['REQUEST_URI'], $rest_prefix . 'gf-' ) );
|
||||
|
||||
if ( has_filter( 'gform_is_request_to_rest_api' ) ) {
|
||||
$this->log_debug( __METHOD__ . '(): Executing functions hooked to gform_is_request_to_rest_api.' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows filtering of whether or not the current request is a request to the Gravity Forms REST API.
|
||||
*
|
||||
* @param bool $is_rest_api_request True if this is a request to the Gravity Forms REST API. False if not.
|
||||
*/
|
||||
return apply_filters( 'gform_is_request_to_rest_api', $is_gf_endpoint || $third_party );
|
||||
}
|
||||
|
||||
/**
|
||||
* Authenticate user.
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
* @param int|false $user_id User ID if one has been determined, false otherwise.
|
||||
* @return int|false Returns the User ID of the authenticated user.
|
||||
*/
|
||||
public function authenticate( $user_id ) {
|
||||
if ( ! $this->is_request_to_rest_api() ) {
|
||||
return $user_id;
|
||||
}
|
||||
|
||||
if ( ! empty( $user_id ) ) {
|
||||
$this->log_debug( __METHOD__ . sprintf( '(): User #%d already authenticated.', $user_id ) );
|
||||
|
||||
return $user_id;
|
||||
}
|
||||
|
||||
$this->clear_errors();
|
||||
$this->log_debug( __METHOD__ . '(): Running.' );
|
||||
|
||||
if ( is_ssl() ) {
|
||||
$user_id = $this->perform_basic_authentication();
|
||||
if ( $user_id ) {
|
||||
return $user_id;
|
||||
}
|
||||
|
||||
$user_id = $this->perform_application_password_authentication();
|
||||
if ( $user_id ) {
|
||||
return $user_id;
|
||||
}
|
||||
}
|
||||
|
||||
return $this->perform_oauth_authentication();
|
||||
}
|
||||
|
||||
/**
|
||||
* Authenticate the user if authentication wasn't performed during the determine_current_user action.
|
||||
*
|
||||
* Necessary in cases where wp_get_current_user() is called before Gravity Forms is loaded.
|
||||
*
|
||||
* @since 2.4.22
|
||||
*
|
||||
* @param WP_Error|null|bool $error Error data.
|
||||
*
|
||||
* @return WP_Error|null|bool
|
||||
*/
|
||||
public function authentication_fallback( $error ) {
|
||||
if ( ! empty( $error ) ) {
|
||||
// Another plugin has already declared a failure.
|
||||
return $error;
|
||||
}
|
||||
|
||||
if ( empty( $this->error ) && empty( $this->auth_method ) && empty( $this->user ) && 0 === get_current_user_id() ) {
|
||||
// Authentication hasn't occurred during `determine_current_user`, so check auth.
|
||||
$user_id = $this->authenticate( false );
|
||||
if ( $user_id ) {
|
||||
wp_set_current_user( $user_id );
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return $error;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check for authentication error.
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
* @param WP_Error|null|bool $error Error data.
|
||||
*
|
||||
* @return WP_Error|null|bool
|
||||
*/
|
||||
public function check_authentication_error( $error ) {
|
||||
if ( ! $this->is_request_to_rest_api() || $_SERVER['REQUEST_METHOD'] === 'OPTIONS' ) {
|
||||
// Pass through OPTIONS requests or those to non-GF endpoints.
|
||||
return $error;
|
||||
}
|
||||
|
||||
$error = $this->get_error();
|
||||
if ( empty( $error ) ) {
|
||||
// rest_handle_options_request() will be called by $this->check_user_permissions().
|
||||
remove_filter( 'rest_pre_dispatch', 'rest_handle_options_request' );
|
||||
|
||||
// Indicate auth succeeded.
|
||||
return true;
|
||||
}
|
||||
|
||||
return $error;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set authentication error.
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
* @param WP_Error $error Authentication error data.
|
||||
*/
|
||||
protected function set_error( $error ) {
|
||||
// Reset user.
|
||||
$this->user = null;
|
||||
|
||||
$this->error = $error;
|
||||
|
||||
$this->log_error( __METHOD__ . '(): ' . json_encode( $error ) );
|
||||
}
|
||||
|
||||
/***
|
||||
* Clears all authentication errors and resets user.
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*/
|
||||
protected function clear_errors() {
|
||||
|
||||
// Reset user.
|
||||
$this->user = null;
|
||||
|
||||
$this->error = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get authentication error.
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
* @return WP_Error|null.
|
||||
*/
|
||||
protected function get_error() {
|
||||
return $this->error;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the user property for the authenticated user and clears the error property.
|
||||
*
|
||||
* @since 2.4.22
|
||||
*
|
||||
* @param object $user An object containing the user id and some other optional properties.
|
||||
*
|
||||
* @return int The ID of the authenticated user.
|
||||
*/
|
||||
protected function set_user( $user ) {
|
||||
$this->user = $user;
|
||||
$this->error = null;
|
||||
|
||||
return $this->user->user_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to authenticate the request using the application password feature introduced in WordPress 5.6.
|
||||
*
|
||||
* @since 2.4.22
|
||||
*
|
||||
* @return false|int False or the ID of the authenticated user.
|
||||
*/
|
||||
private function perform_application_password_authentication() {
|
||||
if ( ! function_exists( 'wp_validate_application_password' ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->log_debug( __METHOD__ . '(): Running.' );
|
||||
$this->auth_method = 'application_password';
|
||||
$user_id = wp_validate_application_password( false );
|
||||
|
||||
if ( empty( $user_id ) ) {
|
||||
global $wp_rest_application_password_status;
|
||||
if ( is_wp_error( $wp_rest_application_password_status ) ) {
|
||||
$this->set_error( new WP_Error( 'gform_rest_authentication_error', $wp_rest_application_password_status->get_error_message(), array( 'status' => 401 ) ) );
|
||||
}
|
||||
|
||||
$this->log_error( __METHOD__ . '(): Aborting; user not found.' );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->log_debug( __METHOD__ . '(): Valid.' );
|
||||
|
||||
return $this->set_user( (object) array( 'user_id' => $user_id ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Basic Authentication.
|
||||
*
|
||||
* SSL-encrypted requests are not subject to sniffing or man-in-the-middle
|
||||
* attacks, so the request can be authenticated by simply looking up the user
|
||||
* associated with the given consumer key and confirming the consumer secret
|
||||
* provided is valid.
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
* @return int|bool Returs the authenticated user's User ID if successfull. Otherwise, returns false.
|
||||
*/
|
||||
private function perform_basic_authentication() {
|
||||
$this->log_debug( __METHOD__ . '(): Running.' );
|
||||
|
||||
$this->auth_method = 'basic_auth';
|
||||
$consumer_key = '';
|
||||
$consumer_secret = '';
|
||||
|
||||
// If the $_GET parameters are present, use those first.
|
||||
if ( ! empty( $_GET['consumer_key'] ) && ! empty( $_GET['consumer_secret'] ) ) {
|
||||
$consumer_key = $_GET['consumer_key']; // WPCS: sanitization ok.
|
||||
$consumer_secret = $_GET['consumer_secret']; // WPCS: sanitization ok.
|
||||
}
|
||||
|
||||
// If the above is not present, we will do full basic auth.
|
||||
if ( ! $consumer_key && ! empty( $_SERVER['PHP_AUTH_USER'] ) && ! empty( $_SERVER['PHP_AUTH_PW'] ) ) {
|
||||
$consumer_key = $_SERVER['PHP_AUTH_USER']; // WPCS: sanitization ok.
|
||||
$consumer_secret = $_SERVER['PHP_AUTH_PW']; // WPCS: sanitization ok.
|
||||
}
|
||||
|
||||
// Stop if don't have any key.
|
||||
if ( ! $consumer_key || ! $consumer_secret ) {
|
||||
$this->log_error( __METHOD__ . '(): Aborting; credentials not found.' );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get user data.
|
||||
$user = $this->get_user_data_by_consumer_key( $consumer_key );
|
||||
if ( empty( $user ) ) {
|
||||
$this->log_error( __METHOD__ . '(): Aborting; user not found.' );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Validate user secret.
|
||||
if ( ! hash_equals( $user->consumer_secret, $consumer_secret ) ) {
|
||||
$this->set_error( new WP_Error( 'gform_rest_authentication_error', __( 'Consumer secret is invalid.', 'gravityforms' ), array( 'status' => 401 ) ) );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->log_debug( __METHOD__ . '(): Valid.' );
|
||||
|
||||
return $this->set_user( $user );
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the Authorization header into parameters.
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
* @param string $header Authorization header value (not including "Authorization: " prefix).
|
||||
*
|
||||
* @return array Map of parameter values.
|
||||
*/
|
||||
public function parse_header( $header ) {
|
||||
if ( 'OAuth ' !== substr( $header, 0, 6 ) ) {
|
||||
return array();
|
||||
}
|
||||
|
||||
// From OAuth PHP library, used under MIT license.
|
||||
$params = array();
|
||||
if ( preg_match_all( '/(oauth_[a-z_-]*)=(:?"([^"]*)"|([^,]*))/', $header, $matches ) ) {
|
||||
foreach ( $matches[1] as $i => $h ) {
|
||||
$params[ $h ] = urldecode( empty( $matches[3][ $i ] ) ? $matches[4][ $i ] : $matches[3][ $i ] );
|
||||
}
|
||||
if ( isset( $params['realm'] ) ) {
|
||||
unset( $params['realm'] );
|
||||
}
|
||||
}
|
||||
|
||||
return $params;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the authorization header.
|
||||
*
|
||||
* On certain systems and configurations, the Authorization header will be
|
||||
* stripped out by the server or PHP. Typically this is then used to
|
||||
* generate `PHP_AUTH_USER`/`PHP_AUTH_PASS` but not passed on. We use
|
||||
* `getallheaders` here to try and grab it out instead.
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
* @return string Authorization header if set.
|
||||
*/
|
||||
public function get_authorization_header() {
|
||||
if ( ! empty( $_SERVER['HTTP_AUTHORIZATION'] ) ) {
|
||||
return wp_unslash( $_SERVER['HTTP_AUTHORIZATION'] ); // WPCS: sanitization ok.
|
||||
}
|
||||
|
||||
if ( function_exists( 'getallheaders' ) ) {
|
||||
$headers = getallheaders();
|
||||
// Check for the authoization header case-insensitively.
|
||||
foreach ( $headers as $key => $value ) {
|
||||
if ( 'authorization' === strtolower( $key ) ) {
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get oAuth parameters from $_GET, $_POST or request header.
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
* @return array|WP_Error
|
||||
*/
|
||||
public function get_oauth_parameters() {
|
||||
$params = array_merge( $_GET, $_POST ); // WPCS: CSRF ok.
|
||||
$params = wp_unslash( $params );
|
||||
$header = $this->get_authorization_header();
|
||||
|
||||
if ( ! empty( $header ) ) {
|
||||
// Trim leading spaces.
|
||||
$header = trim( $header );
|
||||
$header_params = $this->parse_header( $header );
|
||||
|
||||
if ( ! empty( $header_params ) ) {
|
||||
$params = array_merge( $params, $header_params );
|
||||
}
|
||||
}
|
||||
|
||||
$param_names = array(
|
||||
'oauth_consumer_key',
|
||||
'oauth_timestamp',
|
||||
'oauth_nonce',
|
||||
'oauth_signature',
|
||||
'oauth_signature_method',
|
||||
);
|
||||
|
||||
$errors = array();
|
||||
$have_one = false;
|
||||
|
||||
// Check for required OAuth parameters.
|
||||
foreach ( $param_names as $param_name ) {
|
||||
if ( empty( $params[ $param_name ] ) ) {
|
||||
$errors[] = $param_name;
|
||||
} else {
|
||||
$have_one = true;
|
||||
}
|
||||
}
|
||||
|
||||
// All keys are missing, so we're probably not even trying to use OAuth.
|
||||
if ( ! $have_one ) {
|
||||
return array();
|
||||
}
|
||||
|
||||
// If we have at least one supplied piece of data, and we have an error,
|
||||
// then it's a failed authentication.
|
||||
if ( ! empty( $errors ) ) {
|
||||
$message = sprintf(
|
||||
/* translators: %s: amount of errors */
|
||||
_n( 'Missing OAuth parameter %s', 'Missing OAuth parameters %s', count( $errors ), 'gravityforms' ),
|
||||
implode( ', ', $errors )
|
||||
);
|
||||
|
||||
$this->set_error( new WP_Error( 'gform_rest_authentication_missing_parameter', $message, array( 'status' => 401 ) ) );
|
||||
|
||||
return array();
|
||||
}
|
||||
|
||||
return $params;
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform OAuth 1.0a "one-legged" (http://oauthbible.com/#oauth-10a-one-legged) authentication for non-SSL requests.
|
||||
*
|
||||
* This is required so API credentials cannot be sniffed or intercepted when making API requests over plain HTTP.
|
||||
*
|
||||
* This follows the spec for simple OAuth 1.0a authentication (RFC 5849) as closely as possible, with two exceptions:
|
||||
*
|
||||
* 1) There is no token associated with request/responses, only consumer keys/secrets are used.
|
||||
*
|
||||
* 2) The OAuth parameters are included as part of the request query string instead of part of the Authorization header,
|
||||
* This is because there is no cross-OS function within PHP to get the raw Authorization header.
|
||||
*
|
||||
* @link http://tools.ietf.org/html/rfc5849 for the full spec.
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
* @return int|bool
|
||||
*/
|
||||
private function perform_oauth_authentication() {
|
||||
$this->log_debug( __METHOD__ . '(): Running.' );
|
||||
|
||||
$this->auth_method = 'oauth1';
|
||||
|
||||
$params = $this->get_oauth_parameters();
|
||||
if ( empty( $params ) ) {
|
||||
$this->log_error( __METHOD__ . '(): Aborting; OAuth parameters not found.' );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Fetch WP user by consumer key.
|
||||
$user = $this->get_user_data_by_consumer_key( $params['oauth_consumer_key'] );
|
||||
|
||||
if ( empty( $user ) ) {
|
||||
$this->set_error( new WP_Error( 'gform_rest_authentication_error', __( 'Consumer key is invalid.', 'gravityforms' ), array( 'status' => 401 ) ) );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Perform OAuth validation.
|
||||
$signature = $this->check_oauth_signature( $user, $params );
|
||||
if ( is_wp_error( $signature ) ) {
|
||||
$this->set_error( $signature );
|
||||
return false;
|
||||
}
|
||||
|
||||
$timestamp_and_nonce = $this->check_oauth_timestamp_and_nonce( $user, $params['oauth_timestamp'], $params['oauth_nonce'] );
|
||||
if ( is_wp_error( $timestamp_and_nonce ) ) {
|
||||
$this->set_error( $timestamp_and_nonce );
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->log_debug( __METHOD__ . '(): Valid.' );
|
||||
|
||||
return $this->set_user( $user );
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that the consumer-provided request signature matches our generated signature,
|
||||
* this ensures the consumer has a valid key/secret.
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
* @param stdClass $user User data.
|
||||
* @param array $params The request parameters.
|
||||
* @return true|WP_Error
|
||||
*/
|
||||
private function check_oauth_signature( $user, $params ) {
|
||||
$http_method = isset( $_SERVER['REQUEST_METHOD'] ) ? strtoupper( $_SERVER['REQUEST_METHOD'] ) : ''; // WPCS: sanitization ok.
|
||||
$request_path = isset( $_SERVER['REQUEST_URI'] ) ? parse_url( $_SERVER['REQUEST_URI'], PHP_URL_PATH ) : ''; // WPCS: sanitization ok.
|
||||
$wp_base = get_home_url( null, '/', 'relative' );
|
||||
if ( substr( $request_path, 0, strlen( $wp_base ) ) === $wp_base ) {
|
||||
$request_path = substr( $request_path, strlen( $wp_base ) );
|
||||
}
|
||||
$base_request_uri = rawurlencode( get_home_url( null, $request_path, is_ssl() ? 'https' : 'http' ) );
|
||||
|
||||
// Get the signature provided by the consumer and remove it from the parameters prior to checking the signature.
|
||||
$consumer_signature = rawurldecode( str_replace( ' ', '+', $params['oauth_signature'] ) );
|
||||
unset( $params['oauth_signature'] );
|
||||
|
||||
// Sort parameters.
|
||||
if ( ! uksort( $params, 'strcmp' ) ) {
|
||||
return new WP_Error( 'gform_rest_authentication_error', __( 'Invalid signature - failed to sort parameters.', 'gravityforms' ), array( 'status' => 401 ) );
|
||||
}
|
||||
|
||||
// Normalize parameter key/values.
|
||||
$params = $this->normalize_parameters( $params );
|
||||
$query_string = implode( '%26', $this->join_with_equals_sign( $params ) ); // Join with ampersand.
|
||||
$string_to_sign = $http_method . '&' . $base_request_uri . '&' . $query_string;
|
||||
|
||||
if ( 'HMAC-SHA1' !== $params['oauth_signature_method'] && 'HMAC-SHA256' !== $params['oauth_signature_method'] ) {
|
||||
return new WP_Error( 'gform_rest_authentication_error', __( 'Invalid signature - signature method is invalid.', 'gravityforms' ), array( 'status' => 401 ) );
|
||||
}
|
||||
|
||||
$hash_algorithm = strtolower( str_replace( 'HMAC-', '', $params['oauth_signature_method'] ) );
|
||||
$secret = $user->consumer_secret . '&';
|
||||
$signature = base64_encode( hash_hmac( $hash_algorithm, $string_to_sign, $secret, true ) );
|
||||
|
||||
if ( ! hash_equals( $signature, $consumer_signature ) ) {
|
||||
$this->log_debug( __METHOD__ . '(): Signature base: ' . $string_to_sign );
|
||||
|
||||
return new WP_Error( 'gform_rest_authentication_error', __( 'Invalid signature - provided signature does not match.', 'gravityforms' ), array( 'status' => 401 ) );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an array of urlencoded strings out of each array key/value pairs.
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
* @param array $params Array of parameters to convert.
|
||||
* @param array $query_params Array to extend.
|
||||
* @param string $key Optional Array key to append.
|
||||
* @return string Array of urlencoded strings.
|
||||
*/
|
||||
private function join_with_equals_sign( $params, $query_params = array(), $key = '' ) {
|
||||
foreach ( $params as $param_key => $param_value ) {
|
||||
if ( $key ) {
|
||||
$param_key = $key . '%5B' . $param_key . '%5D'; // Handle multi-dimensional array.
|
||||
}
|
||||
|
||||
if ( is_array( $param_value ) ) {
|
||||
$query_params = $this->join_with_equals_sign( $param_value, $query_params, $param_key );
|
||||
} else {
|
||||
$string = $param_key . '=' . $param_value; // Join with equals sign.
|
||||
$query_params[] = $this->urlencode_rfc3986( $string );
|
||||
}
|
||||
}
|
||||
|
||||
return $query_params;
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalize each parameter by assuming each parameter may have already been
|
||||
* encoded, so attempt to decode, and then re-encode according to RFC 3986.
|
||||
*
|
||||
* Note both the key and value is normalized so a filter param like:
|
||||
*
|
||||
* 'filter[period]' => 'week'
|
||||
*
|
||||
* is encoded to:
|
||||
*
|
||||
* 'filter%255Bperiod%255D' => 'week'
|
||||
*
|
||||
* This conforms to the OAuth 1.0a spec which indicates the entire query string
|
||||
* should be URL encoded.
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
* @see rawurlencode()
|
||||
* @param array $parameters Un-normalized parameters.
|
||||
* @return array Normalized parameters.
|
||||
*/
|
||||
private function normalize_parameters( $parameters ) {
|
||||
$keys = $this->urlencode_rfc3986( array_keys( $parameters ) );
|
||||
$values = $this->urlencode_rfc3986( array_values( $parameters ) );
|
||||
$parameters = array_combine( $keys, $values );
|
||||
|
||||
return $parameters;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that the timestamp and nonce provided with the request are valid. This prevents replay attacks where
|
||||
* an attacker could attempt to re-send an intercepted request at a later time.
|
||||
*
|
||||
* - A timestamp is valid if it is within 15 minutes of now.
|
||||
* - A nonce is valid if it has not been used within the last 15 minutes.
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
* @param stdClass $user User data.
|
||||
* @param int $timestamp The unix timestamp for when the request was made.
|
||||
* @param string $nonce A unique (for the given user) 32 alphanumeric string, consumer-generated.
|
||||
* @return bool|WP_Error
|
||||
*/
|
||||
private function check_oauth_timestamp_and_nonce( $user, $timestamp, $nonce ) {
|
||||
global $wpdb;
|
||||
|
||||
$valid_window = 15 * 60; // 15 minute window.
|
||||
|
||||
if ( ( $timestamp < time() - $valid_window ) || ( $timestamp > time() + $valid_window ) ) {
|
||||
return new WP_Error( 'gform_rest_authentication_error', __( 'Invalid timestamp.', 'gravityforms' ), array( 'status' => 401 ) );
|
||||
}
|
||||
|
||||
$used_nonces = maybe_unserialize( $user->nonces );
|
||||
|
||||
if ( empty( $used_nonces ) ) {
|
||||
$used_nonces = array();
|
||||
}
|
||||
|
||||
if ( in_array( $nonce, $used_nonces ) ) {
|
||||
return new WP_Error( 'gform_rest_authentication_error', __( 'Invalid nonce - nonce has already been used.', 'gravityforms' ), array( 'status' => 401 ) );
|
||||
}
|
||||
|
||||
$used_nonces[ $timestamp ] = $nonce;
|
||||
|
||||
// Remove expired nonces.
|
||||
foreach ( $used_nonces as $nonce_timestamp => $nonce ) {
|
||||
if ( $nonce_timestamp < ( time() - $valid_window ) ) {
|
||||
unset( $used_nonces[ $nonce_timestamp ] );
|
||||
}
|
||||
}
|
||||
|
||||
$used_nonces = maybe_serialize( $used_nonces );
|
||||
|
||||
$wpdb->update(
|
||||
$wpdb->prefix . 'gf_rest_api_keys',
|
||||
array( 'nonces' => $used_nonces ),
|
||||
array( 'key_id' => $user->key_id ),
|
||||
array( '%s' ),
|
||||
array( '%d' )
|
||||
);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the user data for the given consumer_key.
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
* @param string $consumer_key Consumer key.
|
||||
* @return array
|
||||
*/
|
||||
private function get_user_data_by_consumer_key( $consumer_key ) {
|
||||
global $wpdb;
|
||||
|
||||
$consumer_key = GFWebAPI::api_hash( sanitize_text_field( $consumer_key ) );
|
||||
$user = $wpdb->get_row(
|
||||
$wpdb->prepare(
|
||||
"
|
||||
SELECT key_id, user_id, permissions, consumer_key, consumer_secret, nonces
|
||||
FROM {$wpdb->prefix}gf_rest_api_keys
|
||||
WHERE consumer_key = %s
|
||||
", $consumer_key
|
||||
)
|
||||
);
|
||||
|
||||
return $user;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Check that the API keys provided have the proper key-specific permissions to either read or write API resources.
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
* @param string $method Request method.
|
||||
* @return bool|WP_Error
|
||||
*/
|
||||
private function check_permissions( $method ) {
|
||||
if ( ! $this->is_gf_auth_method() ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$permissions = $this->user->permissions;
|
||||
|
||||
switch ( $method ) {
|
||||
case 'HEAD':
|
||||
case 'GET':
|
||||
if ( 'read' !== $permissions && 'read_write' !== $permissions ) {
|
||||
return new WP_Error( 'gform_rest_authentication_error', __( 'The API key provided does not have read permissions.', 'gravityforms' ), array( 'status' => 401 ) );
|
||||
}
|
||||
break;
|
||||
case 'POST':
|
||||
case 'PUT':
|
||||
case 'PATCH':
|
||||
case 'DELETE':
|
||||
if ( 'write' !== $permissions && 'read_write' !== $permissions ) {
|
||||
return new WP_Error( 'gform_rest_authentication_error', __( 'The API key provided does not have write permissions.', 'gravityforms' ), array( 'status' => 401 ) );
|
||||
}
|
||||
break;
|
||||
case 'OPTIONS':
|
||||
return true;
|
||||
|
||||
default:
|
||||
return new WP_Error( 'gform_rest_authentication_error', __( 'Unknown request method.', 'gravityforms' ), array( 'status' => 401 ) );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updated API Key last access datetime.
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
*/
|
||||
private function update_last_access() {
|
||||
if ( ! $this->is_gf_auth_method() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
global $wpdb;
|
||||
|
||||
$wpdb->update(
|
||||
$wpdb->prefix . 'gf_rest_api_keys',
|
||||
array( 'last_access' => current_time( 'mysql' ) ),
|
||||
array( 'key_id' => $this->user->key_id ),
|
||||
array( '%s' ),
|
||||
array( '%d' )
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* If the consumer_key and consumer_secret $_GET parameters are NOT provided
|
||||
* and the Basic auth headers are either not present or the consumer secret does not match the consumer
|
||||
* key provided, then return the correct Basic headers and an error message.
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
* @param WP_REST_Response $response Current response being served.
|
||||
* @return WP_REST_Response
|
||||
*/
|
||||
public function send_unauthorized_headers( $response ) {
|
||||
if ( is_wp_error( $this->get_error() ) && 'basic_auth' === $this->auth_method ) {
|
||||
$auth_message = __( 'Gravity Forms API. Use a consumer key in the username field and a consumer secret in the password field.', 'gravityforms' );
|
||||
$response->header( 'WWW-Authenticate', 'Basic realm="' . $auth_message . '"', true );
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check for user permissions and register last access.
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
* @param mixed $result Response to replace the requested version with.
|
||||
* @param WP_REST_Server $server Server instance.
|
||||
* @param WP_REST_Request $request Request used to generate the response.
|
||||
* @return mixed
|
||||
*/
|
||||
public function check_user_permissions( $result, $server, $request ) {
|
||||
if ( ! $this->user ) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
$this->log_debug( sprintf( '%s(): Running for user #%d.', __METHOD__, $this->user->user_id ) );
|
||||
|
||||
// Check API Key permissions.
|
||||
$allowed = $this->check_permissions( $request->get_method() );
|
||||
if ( is_wp_error( $allowed ) ) {
|
||||
$this->log_error( __METHOD__ . '(): ' . print_r( $allowed, true ) );
|
||||
|
||||
return $allowed;
|
||||
}
|
||||
|
||||
// Register last access.
|
||||
$this->update_last_access();
|
||||
$this->log_debug( __METHOD__ . '(): Permissions valid.' );
|
||||
|
||||
return rest_handle_options_request( null, $server, $request );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Encodes a value according to RFC 3986.
|
||||
* Supports multidimensional arrays.
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
* @param string|array $value The value to encode.
|
||||
* @return string|array Encoded values.
|
||||
*/
|
||||
public function urlencode_rfc3986( $value ) {
|
||||
if ( is_array( $value ) ) {
|
||||
return array_map( array( $this, 'urlencode_rfc3986' ), $value );
|
||||
} else {
|
||||
return str_replace( array( '+', '%7E' ), array( ' ', '~' ), rawurlencode( $value ) );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Write an error message to the Gravity Forms API log.
|
||||
*
|
||||
* @since 2.4.11
|
||||
*
|
||||
* @param string $message The message to be logged.
|
||||
*/
|
||||
public function log_error( $message ) {
|
||||
GFAPI::log_error( $message );
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a debug message to the Gravity Forms API log.
|
||||
*
|
||||
* @since 2.4.11
|
||||
*
|
||||
* @param string $message The message to be logged.
|
||||
*/
|
||||
public function log_debug( $message ) {
|
||||
GFAPI::log_debug( $message );
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the request is authenticated using credentials generated by Gravity Forms.
|
||||
*
|
||||
* @since 2.4.22
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function is_gf_auth_method() {
|
||||
return in_array( $this->auth_method, array( 'basic_auth', 'oauth1' ) );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
new GF_REST_Authentication();
|
||||
@@ -0,0 +1,884 @@
|
||||
<?php
|
||||
|
||||
if ( ! class_exists( 'GFForms' ) ) {
|
||||
die();
|
||||
}
|
||||
|
||||
/**
|
||||
* Manages the entry results cache expiry and rebuild.
|
||||
*
|
||||
* GF_Results_Cache::get_results() will attempt to calculate the results inside the time_limit arg.
|
||||
* If incomplete then a WP Cron task is kicked off.
|
||||
* If the cron task is unable to finish within time_limit_cron then another task is scheduled until the results are complete.
|
||||
*
|
||||
* @package Gravity Forms
|
||||
* @subpackage GF_Results_Cache
|
||||
* @access public
|
||||
*/
|
||||
class GF_Results_Cache {
|
||||
|
||||
/**
|
||||
* GF_Results_Cache constructor.
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*/
|
||||
public function __construct() {
|
||||
if ( defined( 'DOING_CRON' ) && DOING_CRON ) {
|
||||
add_action( 'gravityforms_results_cron', array( $this, 'results_cron' ), 10, 4 );
|
||||
return;
|
||||
}
|
||||
|
||||
add_action( 'gform_entry_created', array( $this, 'entry_created' ), 10, 2 );
|
||||
add_action( 'gform_after_update_entry', array( $this, 'entry_updated' ), 10, 2 );
|
||||
add_action( 'gform_update_status', array( $this, 'update_entry_status' ), 10, 2 );
|
||||
add_action( 'gform_after_save_form', array( $this, 'after_save_form' ), 10, 2 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Contains an instance of this class, if available.
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
* @var GF_Results_Cache $_instance If available, contains an instance of this class.
|
||||
*/
|
||||
private static $_instance = null;
|
||||
|
||||
/**
|
||||
* Returns an instance of this class, and stores it in the $_instance property.
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
* @return GF_Results_Cache $_instance
|
||||
*/
|
||||
public static function get_instance() {
|
||||
if ( self::$_instance == null ) {
|
||||
self::$_instance = new GF_Results_Cache();
|
||||
}
|
||||
|
||||
return self::$_instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the default args for the results cache process.
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
* time_limit - Max seconds allowed per batch.
|
||||
* time_limit_cron - Max seconds allowed per batch while inside the cron task.
|
||||
* page_size - Page size for each batch search results.
|
||||
* callbacks - An array of callbacks. One supported callback: 'calculation' $cache_data, $form, $fields, $entries
|
||||
* wait - Time in seconds to wait between each cron task.
|
||||
* field_ids - An array of field IDs to include in the results.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_default_args() {
|
||||
return array(
|
||||
'time_limit' => 15, // Max seconds for the initial attempt.
|
||||
'time_limit_cron' => 15, // Max seconds for the cron task.
|
||||
'page_size' => 100,
|
||||
'callbacks' => array(),
|
||||
'wait' => 10,
|
||||
'field_ids' => false,
|
||||
'labels' => true,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Callback for the gform_update_status action.
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
* @param $entry_id
|
||||
*/
|
||||
public function update_entry_status( $entry_id ) {
|
||||
$entry = GFAPI::get_entry( $entry_id );
|
||||
$form_id = $entry['form_id'];
|
||||
$form = GFFormsModel::get_form_meta( $form_id );
|
||||
$this->maybe_update_results_cache_meta( $form );
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback for the gform_after_update_entry action.
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
* @param $form
|
||||
* @param $entry_id
|
||||
*/
|
||||
public function entry_updated( $form, $entry_id ) {
|
||||
$this->maybe_update_results_cache_meta( $form );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Callback for the gform_entry_created action.
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
* @param $entry
|
||||
* @param $form
|
||||
*/
|
||||
public function entry_created( $entry, $form ) {
|
||||
$this->maybe_update_results_cache_meta( $form );
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback for the gform_after_save_form action.
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
* @param $form
|
||||
* @param $is_new
|
||||
*/
|
||||
public function after_save_form( $form, $is_new ) {
|
||||
if ( $is_new ) {
|
||||
return;
|
||||
}
|
||||
$form_id = $form['id'];
|
||||
|
||||
// only need to update the cache meta when cached results exist
|
||||
if ( ! $this->cached_results_exists( $form_id ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$fields = rgar( $form, 'fields' );
|
||||
$current_fields_hash = wp_hash( json_encode( $fields ) );
|
||||
|
||||
$cache_meta = $this->get_results_cache_meta( $form_id );
|
||||
$cached_fields_hash = rgar( $cache_meta, 'fields_hash' );
|
||||
|
||||
if ( ! hash_equals( $current_fields_hash, $cached_fields_hash ) ) {
|
||||
// delete the meta for this form
|
||||
$this->delete_results_cache_meta( $form_id );
|
||||
// delete all cached results for this form
|
||||
$this->delete_cached_results( $form_id );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* When entries are added or updated the cache needs to be expired and rebuilt.
|
||||
*
|
||||
* This cache meta records the last updated time for each form and a hash of the fields array.
|
||||
* Each time results are requested this value is checked to make sure the cache is still valid.
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
* @param $form
|
||||
*/
|
||||
private function maybe_update_results_cache_meta( $form ) {
|
||||
$form_id = $form['id'];
|
||||
|
||||
// Only need to update the cache meta when cached results exist.
|
||||
if ( ! $this->cached_results_exists( $form_id ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->update_results_cache_meta( $form_id, rgar( $form, 'fields' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the results cache meta containing a hash of the all the fields and a timestamp.
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
* @param $form_id
|
||||
* @param $fields
|
||||
*/
|
||||
private function update_results_cache_meta( $form_id, $fields ) {
|
||||
|
||||
$data = array(
|
||||
'fields_hash' => wp_hash( json_encode( $fields ) ),
|
||||
'timestamp' => time(),
|
||||
);
|
||||
|
||||
$key = $this->get_results_cache_meta_key( $form_id );
|
||||
|
||||
$this->update_results_cache( $key, $data );
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes the cache meta.
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
*
|
||||
* @param $form_id
|
||||
*/
|
||||
private function delete_results_cache_meta( $form_id ) {
|
||||
|
||||
$key = $this->get_results_cache_meta_key( $form_id );
|
||||
|
||||
delete_option( $key );
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the cache meta key.
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
* @param $form_id
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function get_results_cache_meta_key( $form_id ) {
|
||||
$key = 'gf-results-cache-meta-form-' . $form_id;
|
||||
|
||||
return $key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the cache meta.
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
* @param $form_id
|
||||
*
|
||||
* @return mixed|void
|
||||
*/
|
||||
private function get_results_cache_meta( $form_id ) {
|
||||
|
||||
$key = $this->get_results_cache_meta_key( $form_id );
|
||||
$cache_meta = get_option( $key );
|
||||
|
||||
return $cache_meta;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the results cache.
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
* @param $key
|
||||
* @param $data
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function update_results_cache( $key, $data ) {
|
||||
|
||||
/* From: https://codex.wordpress.org/Function_Reference/add_option
|
||||
*
|
||||
* Until version 4.2, you could not specify autoload='no' if you use update_option().
|
||||
* If you need to specify autoload='no', and you are not sure whether the option already exists,
|
||||
* then call delete_option() first before calling add_option().
|
||||
*/
|
||||
|
||||
delete_option( $key );
|
||||
|
||||
$result = add_option( $key, $data, '', 'no' );
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether a cache exists for the given form ID.
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
* @param $form_id
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function cached_results_exists( $form_id ) {
|
||||
global $wpdb;
|
||||
|
||||
$key = $this->get_results_cache_key_prefix( $form_id );
|
||||
|
||||
$key = '%' . GFCommon::esc_like( $key ) . '%';
|
||||
|
||||
$sql = $wpdb->prepare( "SELECT count(option_id) FROM $wpdb->options WHERE option_name LIKE %s", $key );
|
||||
|
||||
$result = $wpdb->get_var( $sql );
|
||||
|
||||
return $result > 0;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes all the cached results for the given form ID.
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
* @param $form_id
|
||||
*
|
||||
* @return false|int|void
|
||||
*/
|
||||
public function delete_cached_results( $form_id ) {
|
||||
global $wpdb;
|
||||
|
||||
$form = GFAPI::get_form( $form_id );
|
||||
if ( ! ( $form ) || ! is_array( $form ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$key = $this->get_results_cache_key_prefix( $form_id );
|
||||
|
||||
$key = '%' . GFCommon::esc_like( $key ) . '%';
|
||||
|
||||
$sql = $wpdb->prepare( "DELETE FROM $wpdb->options WHERE option_name LIKE %s", $key );
|
||||
|
||||
$result = $wpdb->query( $sql );
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the prefix for the results cache option name.
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
* @param $form_id
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_results_cache_key_prefix( $form_id ) {
|
||||
|
||||
$key = sprintf( 'gf-results-cache-%s-', $form_id );
|
||||
|
||||
// The option_name column in the options table has a max length of 64 chars.
|
||||
// Truncate the key if it's too long for column and allow space for the 'tmp' prefix
|
||||
$key = substr( $key, 0, 60 );
|
||||
|
||||
return $key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a unique key for the cache meta based on form ID, fields and
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
* @param $form_id
|
||||
* @param $search_criteria
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_results_cache_key( $form_id, $search_criteria = array() ) {
|
||||
|
||||
$key = $this->get_results_cache_key_prefix( $form_id );
|
||||
$key .= wp_hash( json_encode( $search_criteria ) );
|
||||
|
||||
return $key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursive wp_cron task to continue the calculation of results.
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
* @param $form_id
|
||||
* @param $search_criteria
|
||||
* @param $args
|
||||
*/
|
||||
public function results_cron( $form_id, $search_criteria, $args ) {
|
||||
|
||||
$args = wp_parse_args( $args, $this->get_default_args() );
|
||||
|
||||
$form = GFAPI::get_form( $form_id );
|
||||
$key = $this->get_results_cache_key( $form_id, $search_criteria );
|
||||
$key_tmp = 'tmp' . $key;
|
||||
$state = get_option( $key_tmp, array() );
|
||||
|
||||
if ( ! empty( $state ) ) {
|
||||
$results = $this->calculate( $form, $search_criteria, $state, $args );
|
||||
if ( 'complete' == $results['status'] ) {
|
||||
if ( isset( $results['progress'] ) ) {
|
||||
unset( $results['progress'] );
|
||||
}
|
||||
$this->update_results_cache( $key, $results );
|
||||
if ( false == empty( $state ) ) {
|
||||
delete_option( $key_tmp );
|
||||
}
|
||||
} else {
|
||||
$this->update_results_cache( $key_tmp, $results );
|
||||
|
||||
$data = get_option( $key );
|
||||
if ( $data ) {
|
||||
$data['progress'] = $results['progress'];
|
||||
$this->update_results_cache( $key, $data );
|
||||
}
|
||||
|
||||
$this->schedule_results_cron( $form_id, $search_criteria, $args );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Schedules the cron task.
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
* @param $form_id
|
||||
* @param $search_criteria
|
||||
* @param $args
|
||||
*/
|
||||
private function schedule_results_cron( $form_id, $search_criteria, $args ) {
|
||||
$args = wp_parse_args( $args, $this->get_default_args() );
|
||||
|
||||
$cron_args = array( $form_id, $search_criteria, $args );
|
||||
$delay_in_seconds = $args['wait'];
|
||||
wp_schedule_single_event( time() + $delay_in_seconds, $this->get_results_cron_hook(), $cron_args );
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the results cron job is currently scheduled
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
* @param $form_id
|
||||
* @param $search_criteria
|
||||
* @param $args
|
||||
*
|
||||
* @return false|int
|
||||
*/
|
||||
public function results_cron_is_scheduled( $form_id, $search_criteria, $args ) {
|
||||
$args = wp_parse_args( $args, $this->get_default_args() );
|
||||
$cron_args = array( $form_id, $search_criteria, $args );
|
||||
|
||||
return wp_next_scheduled( $this->get_results_cron_hook(), $cron_args );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returs the results cron hook name
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_results_cron_hook() {
|
||||
return 'gravityforms_results_cron';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array with the results for all the fields in the form.
|
||||
*
|
||||
* If the results can be calculated within the time allowed in GFResults then the results are returned and nothing is cached.
|
||||
* If the calculation has not finished then a single recursive wp_cron task will be scheduled for immediate execution.
|
||||
* While the cache is being built by the wp_cron task this function will return the expired cache results if available or the latest step in the cache build.
|
||||
* Add-On-specific results are not included e.g. grade frequencies in the Quiz Add-On.
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
* @param int $form_id
|
||||
* @param array $search_criteria
|
||||
* @param array $args
|
||||
*
|
||||
* @return array|mixed|void
|
||||
*/
|
||||
public function get_results( $form_id, $search_criteria = array(), $args = array() ) {
|
||||
|
||||
$args = wp_parse_args( $args, $this->get_default_args() );
|
||||
|
||||
$form = GFAPI::get_form( $form_id );
|
||||
|
||||
if ( ! $form ) {
|
||||
return new WP_Error( 'not_found', __( 'Form not found', 'gravityforms' ) );
|
||||
}
|
||||
|
||||
$fields = rgar( $form, 'fields' );
|
||||
|
||||
$form_id = $form['id'];
|
||||
$key = $this->get_results_cache_key( $form_id, $search_criteria );
|
||||
$key_tmp = 'tmp' . $key;
|
||||
|
||||
$data = get_option( $key, array() );
|
||||
|
||||
$cache_meta = $this->get_results_cache_meta( $form_id );
|
||||
|
||||
// add the cache meta early so form editor updates can test for valid field hash
|
||||
if ( empty( $cache_meta ) ) {
|
||||
$this->update_results_cache_meta( $form_id, $fields );
|
||||
}
|
||||
|
||||
$cache_expiry = rgar( $cache_meta, 'timestamp' );
|
||||
$cache_timestamp = isset( $data['timestamp'] ) ? $data['timestamp'] : 0;
|
||||
$cache_expired = $cache_expiry ? $cache_expiry > $cache_timestamp : false;
|
||||
|
||||
// check for valid cached results first
|
||||
if ( ! empty( $data ) && 'complete' == rgar( $data, 'status' ) && ! $cache_expired ) {
|
||||
$results = $data;
|
||||
if ( isset( $results['progress'] ) ) {
|
||||
unset( $results['progress'] );
|
||||
}
|
||||
} else {
|
||||
|
||||
$state = get_option( $key_tmp );
|
||||
|
||||
if ( empty( $state ) || ( 'complete' == rgar( $data, 'status' ) && $cache_expired ) ) {
|
||||
|
||||
$results = $this->calculate( $form, $search_criteria, $state, $args );
|
||||
|
||||
if ( rgar( $results, 'status' ) == 'complete' ) {
|
||||
if ( false == empty( $state ) ) {
|
||||
delete_option( $key_tmp );
|
||||
}
|
||||
} else {
|
||||
|
||||
if ( ! empty( $data ) && rgar( $data, 'status' ) == 'complete' && $cache_expired ) {
|
||||
$data['status'] = 'expired';
|
||||
$data['progress'] = $results['progress'];
|
||||
$this->update_results_cache( $key, $data );
|
||||
}
|
||||
|
||||
$this->update_results_cache( $key_tmp, $results );
|
||||
|
||||
$this->schedule_results_cron( $form_id, $search_criteria, $args );
|
||||
|
||||
if ( $data ) {
|
||||
$results = $data;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
// The cron task is recursive, not periodic, so system restarts, script timeouts and memory issues can prevent the cron from restarting.
|
||||
// Check timestamp and kick off the cron again if it appears to have stopped
|
||||
$state_timestamp = rgar( $state, 'timestamp' );
|
||||
$state_age = time() - $state_timestamp;
|
||||
if ( $state_age > 180 && ! $this->results_cron_is_scheduled( $form, $search_criteria, $args ) ) {
|
||||
$this->schedule_results_cron( $form_id, $search_criteria, $args );
|
||||
}
|
||||
|
||||
if ( ! empty( $data ) && rgar( $data, 'status' ) == 'expired' ) {
|
||||
$results = $data;
|
||||
} else {
|
||||
$results = $state;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$field_data = rgar( $results, 'field_data' );
|
||||
|
||||
if ( ! empty( $field_data ) && $args['labels'] ) {
|
||||
// add choice labels to the results so the client doesn't need to cross-reference with the form object
|
||||
$results['labels'] = $this->get_labels( $form, $args );
|
||||
}
|
||||
|
||||
return $results;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate a batch of entry results.
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
* @param $form
|
||||
* @param array $search_criteria
|
||||
* @param array $state_array
|
||||
* @param array $args
|
||||
*
|
||||
* @return array|mixed
|
||||
*/
|
||||
public function calculate( $form, $search_criteria = array(), $state_array = array(), $args = array() ) {
|
||||
|
||||
$args = wp_parse_args( $args, $this->get_default_args() );
|
||||
|
||||
$max_execution_time = defined( 'DOING_CRON' ) && DOING_CRON ? $args['time_limit_cron'] : $args['time_limit'];
|
||||
$page_size = $args['page_size'];
|
||||
$callbacks = $args['callbacks'];
|
||||
|
||||
$time_start = microtime( true );
|
||||
|
||||
$form_id = $form['id'];
|
||||
$data = array();
|
||||
$offset = 0;
|
||||
$entry_count = 0;
|
||||
$field_data = array();
|
||||
|
||||
$fields = $this->filter_fields( $form, $args['field_ids'] );
|
||||
|
||||
if ( $state_array ) {
|
||||
// get counts from state
|
||||
$data = $state_array;
|
||||
$offset = (int) rgar( $data, 'offset' );
|
||||
|
||||
unset( $data['offset'] );
|
||||
$entry_count = $offset;
|
||||
$field_data = rgar( $data, 'field_data' );
|
||||
} else {
|
||||
// initialize counts
|
||||
foreach ( $fields as $field ) {
|
||||
/* @var GF_Field $field */
|
||||
$field_type = $field->get_input_type();
|
||||
if ( ! isset( $field->choices ) ) {
|
||||
$field_data[ $field->id ] = 0;
|
||||
continue;
|
||||
}
|
||||
$choices = $field->choices;
|
||||
|
||||
if ( $field_type == 'likert' && $field->gsurveyLikertEnableMultipleRows ) {
|
||||
foreach ( $field->gsurveyLikertRows as $row ) {
|
||||
foreach ( $choices as $choice ) {
|
||||
$field_data[ $field->id ][ $row['value'] ][ $choice['value'] ] = 0;
|
||||
}
|
||||
if ( $field->gsurveyLikertEnableScoring ) {
|
||||
$field_data[ $field->id ][ $row['value'] ]['row_score_sum'] = 0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if ( ! empty( $choices ) && is_array( $choices ) ) {
|
||||
foreach ( $choices as $choice ) {
|
||||
$field_data[ $field->id ][ $choice['value'] ] = 0;
|
||||
}
|
||||
} else {
|
||||
$field_data[ $field->id ] = 0;
|
||||
}
|
||||
}
|
||||
if ( $field_type == 'likert' && rgar( $field, 'gsurveyLikertEnableScoring' ) ) {
|
||||
$field_data[ $field->id ]['sum_of_scores'] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$count_search_entries = GFAPI::count_entries( $form_id, $search_criteria );
|
||||
$data['entry_count'] = $count_search_entries;
|
||||
|
||||
if ( $count_search_entries == 0 ) {
|
||||
$data['status'] = 'complete';
|
||||
}
|
||||
|
||||
$entries_left = $count_search_entries - $offset;
|
||||
|
||||
while ( $entries_left > 0 ) {
|
||||
|
||||
$paging = array(
|
||||
'offset' => $offset,
|
||||
'page_size' => $page_size,
|
||||
);
|
||||
|
||||
$search_entries_time_start = microtime( true );
|
||||
$entries = GFAPI::get_entries( $form_id, $search_criteria, null, $paging );
|
||||
$search_entries_time_end = microtime( true );
|
||||
$search_entries_time = $search_entries_time_end - $search_entries_time_start;
|
||||
|
||||
$entries_in_search = count( $entries );
|
||||
|
||||
$entry_count += $entries_in_search;
|
||||
$entries_processed = 0;
|
||||
foreach ( $entries as $entry ) {
|
||||
|
||||
$entry_time_start = microtime( true );
|
||||
foreach ( $fields as $field ) {
|
||||
$field_type = $field->get_input_type();
|
||||
$field_id = $field->id;
|
||||
|
||||
$value = GFFormsModel::get_lead_field_value( $entry, $field );
|
||||
|
||||
if ( $field_type == 'likert' && rgar( $field, 'gsurveyLikertEnableMultipleRows' ) ) {
|
||||
|
||||
if ( empty( $value ) ) {
|
||||
continue;
|
||||
}
|
||||
foreach ( $value as $value_vector ) {
|
||||
if ( empty( $value_vector ) ) {
|
||||
continue;
|
||||
}
|
||||
list( $row_val, $col_val ) = explode( ':', $value_vector, 2 );
|
||||
if ( isset( $field_data[ $field->id ][ $row_val ] ) && isset( $field_data[ $field->id ][ $row_val ][ $col_val ] ) ) {
|
||||
$field_data[ $field->id ][ $row_val ][ $col_val ] ++;
|
||||
if ( $field->gsurveyLikertEnableScoring ) {
|
||||
$field_data[ $field->id ][ $row_val ]['row_score_sum'] += $this->get_likert_row_score( $row_val, $field, $entry );
|
||||
}
|
||||
}
|
||||
}
|
||||
} elseif ( $field_type == 'rank' ) {
|
||||
$score = count( rgar( $field, 'choices' ) );
|
||||
$values = explode( ',', $value );
|
||||
foreach ( $values as $ranked_value ) {
|
||||
$field_data[ $field->id ][ $ranked_value ] += $score;
|
||||
$score --;
|
||||
}
|
||||
} else {
|
||||
|
||||
if ( empty( $field->choices ) ) {
|
||||
if ( ( ! is_array( $value ) && ! empty( $value ) ) || ( is_array( $value ) && ! GFCommon::is_empty_array( $value ) ) ) {
|
||||
$field_data[ $field_id ] ++;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
$choices = $field->choices;
|
||||
|
||||
foreach ( $choices as $choice ) {
|
||||
$choice_is_selected = false;
|
||||
if ( is_array( $value ) ) {
|
||||
$choice_value = rgar( $choice, 'value' );
|
||||
if ( in_array( $choice_value, $value ) ) {
|
||||
$choice_is_selected = true;
|
||||
}
|
||||
} else {
|
||||
if ( GFFormsModel::choice_value_match( $field, $choice, $value ) ) {
|
||||
$choice_is_selected = true;
|
||||
}
|
||||
}
|
||||
if ( $choice_is_selected ) {
|
||||
$field_data[ $field_id ][ $choice['value'] ] ++;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( $field_type == 'likert' && rgar( $field, 'gsurveyLikertEnableScoring' ) ) {
|
||||
$field_data[ $field->id ]['sum_of_scores'] += $this->get_likert_score( $field, $entry );
|
||||
}
|
||||
}
|
||||
$entries_processed ++;
|
||||
$entry_time_end = microtime( true );
|
||||
$total_execution_time = $entry_time_end - $search_entries_time_start;
|
||||
$entry_execution_time = $entry_time_end - $entry_time_start;
|
||||
if ( $total_execution_time + $entry_execution_time > $max_execution_time ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
$data['field_data'] = $field_data;
|
||||
if ( isset( $callbacks['calculation'] ) && is_callable( $callbacks['calculation'] ) ) {
|
||||
$data = call_user_func( $callbacks['calculation'], $data, $form, $fields, $entries );
|
||||
$field_data = $data['field_data'];
|
||||
}
|
||||
$offset += $entries_processed;
|
||||
$entries_left -= $entries_processed;
|
||||
|
||||
$time_end = microtime( true );
|
||||
$execution_time = ( $time_end - $time_start );
|
||||
|
||||
if ( $entries_left > 0 && $execution_time + $search_entries_time > $max_execution_time ) {
|
||||
$data['status'] = 'incomplete';
|
||||
$data['offset'] = $offset;
|
||||
$progress = $data['entry_count'] > 0 ? round( $data['offset'] / $data['entry_count'] * 100 ) : 0;
|
||||
$data['progress'] = $progress;
|
||||
break;
|
||||
}
|
||||
|
||||
if ( $entries_left <= 0 ) {
|
||||
$data['status'] = 'complete';
|
||||
}
|
||||
}
|
||||
|
||||
$data['timestamp'] = time();
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the likert field row score
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
*
|
||||
* @param $row_val
|
||||
* @param $field
|
||||
* @param $entry
|
||||
*
|
||||
* @return float|int
|
||||
*/
|
||||
private function get_likert_row_score( $row_val, $field, $entry ) {
|
||||
return is_callable( array(
|
||||
'GFSurvey',
|
||||
'get_likert_row_score',
|
||||
) ) ? GFSurvey::get_likert_row_score( $row_val, $field, $entry ) : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the likert field score
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
*
|
||||
* @param $field
|
||||
* @param $entry
|
||||
*
|
||||
* @return float|int
|
||||
*/
|
||||
private function get_likert_score( $field, $entry ) {
|
||||
return is_callable( array(
|
||||
'GFSurvey',
|
||||
'get_field_score',
|
||||
) ) ? GFSurvey::get_field_score( $field, $entry ) : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array with field labels and choice labels
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
*
|
||||
* @param $form
|
||||
* @param $args
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function get_labels( $form, $args ) {
|
||||
|
||||
$args = wp_parse_args( $args, $this->get_default_args() );
|
||||
|
||||
$fields = $this->filter_fields( $form, $args['field_ids'] );
|
||||
|
||||
$labels = array();
|
||||
|
||||
// replace the values/ids with text labels
|
||||
foreach ( $fields as $field ) {
|
||||
$field_id = $field->id;
|
||||
$field = GFFormsModel::get_field( $form, $field_id );
|
||||
|
||||
if ( is_array( $field->choices ) ) {
|
||||
$label = array();
|
||||
$choice_labels = array();
|
||||
foreach ( $field->choices as $choice ) {
|
||||
$choice_labels[ $choice['value'] ] = $choice['text'];
|
||||
}
|
||||
|
||||
if ( $field instanceof GF_Field_Likert && $field->gsurveyLikertEnableMultipleRows ) {
|
||||
/* @var GF_Field_Likert $field */
|
||||
$label = array(
|
||||
'label' => $field->label,
|
||||
'cols' => $choice_labels,
|
||||
'rows' => array(),
|
||||
);
|
||||
foreach ( $field->gsurveyLikertRows as $row ) {
|
||||
$label['rows'][ $row['value'] ] = $row['text'];
|
||||
}
|
||||
} else {
|
||||
$label['label'] = $field->label;
|
||||
$label['choices'] = $choice_labels;
|
||||
}
|
||||
} else {
|
||||
$label = $field['label'];
|
||||
}
|
||||
|
||||
$labels[ $field->id ] = $label;
|
||||
}
|
||||
|
||||
return $labels;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters the form array, returning only the fields matching the specified list of $field_ids
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
* @param $form The form array to be filtered
|
||||
* @param $field_ids The list of field ids to be returned
|
||||
*
|
||||
* @return array Returns a filtered form array only containing fields that match the $field_ids list
|
||||
*/
|
||||
private function filter_fields( $form, $field_ids ) {
|
||||
$fields = $form['fields'];
|
||||
if ( is_array( $field_ids ) && ! empty( $field_ids ) ) {
|
||||
foreach ( $fields as $key => $field ) {
|
||||
if ( ! in_array( $field->id, $field_ids ) ) {
|
||||
unset( $fields[ $key ] );
|
||||
}
|
||||
}
|
||||
$fields = array_values( $fields );
|
||||
}
|
||||
return $fields;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return GF_Results_Cache
|
||||
*/
|
||||
function gf_results_cache() {
|
||||
return GF_Results_Cache::get_instance();
|
||||
}
|
||||
|
||||
gf_results_cache();
|
||||
@@ -0,0 +1,369 @@
|
||||
<?php
|
||||
if ( ! class_exists( 'GFForms' ) ) {
|
||||
die();
|
||||
}
|
||||
|
||||
|
||||
class GF_REST_Entries_Controller extends GF_REST_Form_Entries_Controller {
|
||||
|
||||
/**
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $rest_base = 'entries';
|
||||
|
||||
/**
|
||||
* Register the routes for the objects of the controller.
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
*/
|
||||
public function register_routes() {
|
||||
|
||||
$namespace = $this->namespace;
|
||||
|
||||
$base = $this->rest_base;
|
||||
|
||||
register_rest_route( $namespace, '/' . $base, array(
|
||||
array(
|
||||
'methods' => WP_REST_Server::READABLE,
|
||||
'callback' => array( $this, 'get_items' ),
|
||||
'permission_callback' => array( $this, 'get_items_permissions_check' ),
|
||||
'args' => $this->get_collection_params(),
|
||||
),
|
||||
array(
|
||||
'methods' => WP_REST_Server::CREATABLE,
|
||||
'callback' => array( $this, 'create_item' ),
|
||||
'permission_callback' => array( $this, 'create_item_permissions_check' ),
|
||||
'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::CREATABLE ),
|
||||
),
|
||||
) );
|
||||
|
||||
register_rest_route( $namespace, '/' . $base . '/(?P<entry_id>[\d]+)', array(
|
||||
array(
|
||||
'methods' => WP_REST_Server::READABLE,
|
||||
'callback' => array( $this, 'get_item' ),
|
||||
'permission_callback' => array( $this, 'get_item_permissions_check' ),
|
||||
'args' => array(),
|
||||
),
|
||||
array(
|
||||
'methods' => 'PUT',
|
||||
'callback' => array( $this, 'update_item' ),
|
||||
'permission_callback' => array( $this, 'update_item_permissions_check' ),
|
||||
'args' => $this->get_endpoint_args_for_item_schema( false ),
|
||||
),
|
||||
array(
|
||||
'methods' => WP_REST_Server::DELETABLE,
|
||||
'callback' => array( $this, 'delete_item' ),
|
||||
'permission_callback' => array( $this, 'delete_item_permissions_check' ),
|
||||
'args' => array(),
|
||||
),
|
||||
) );
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a collection of entries
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
* @param WP_REST_Request $request Full data about the request.
|
||||
*
|
||||
* @return WP_Error|WP_REST_Response
|
||||
*/
|
||||
public function get_items( $request ) {
|
||||
return parent::get_items( $request );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get one item from the collection
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
* @param WP_REST_Request $request Full data about the request.
|
||||
*
|
||||
* @return WP_Error|WP_REST_Response
|
||||
*/
|
||||
public function get_item( $request ) {
|
||||
|
||||
$entry_id = $request->get_param( 'entry_id' );
|
||||
$entry = GFAPI::get_entry( $entry_id );
|
||||
|
||||
if ( is_wp_error( $entry ) ) {
|
||||
return new WP_Error( 'gf_entry_invalid_id', __( 'Invalid entry id.', 'gravityforms' ), array( 'status' => 404 ) );
|
||||
}
|
||||
|
||||
// Get form id here, it could be removed when _field_ids are specified.
|
||||
$form_id = $entry['form_id'];
|
||||
|
||||
$field_ids = $request['_field_ids'];
|
||||
if ( ! empty( $field_ids ) ) {
|
||||
$field_ids = (array) explode( ',', $request['_field_ids'] );
|
||||
$field_ids = array_map( 'trim', $field_ids );
|
||||
if ( ! empty( $field_ids ) ) {
|
||||
$entry = $this->filter_entry_fields( $entry, $field_ids );
|
||||
}
|
||||
}
|
||||
|
||||
$labels = $request['_labels'];
|
||||
|
||||
if ( $labels ) {
|
||||
|
||||
$form = GFAPI::get_form( $form_id );
|
||||
|
||||
$entry['_labels'] = $this->get_entry_labels( $form, compact( 'field_ids' ) );
|
||||
}
|
||||
|
||||
$data = $this->prepare_item_for_response( $entry, $request );
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create one item from the collection
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
* @param WP_REST_Request $request Full data about the request.
|
||||
*
|
||||
* @return WP_Error|WP_REST_Request
|
||||
*/
|
||||
public function create_item( $request ) {
|
||||
return parent::create_item( $request );
|
||||
}
|
||||
|
||||
/**
|
||||
* Update one item from the collection
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
* @param WP_REST_Request $request Full data about the request.
|
||||
*
|
||||
* @return WP_Error|WP_REST_Response
|
||||
*/
|
||||
public function update_item( $request ) {
|
||||
$entry = $this->prepare_item_for_database( $request );
|
||||
|
||||
if ( is_wp_error( $entry ) ) {
|
||||
return $entry;
|
||||
}
|
||||
|
||||
$result = GFAPI::update_entry( $entry );
|
||||
|
||||
if ( is_wp_error( $result ) ) {
|
||||
$status = $this->get_error_status( $result );
|
||||
return new WP_Error( $result->get_error_code(), $result->get_error_message(), array( 'status' => $status ) );
|
||||
}
|
||||
|
||||
|
||||
$updated_entry = GFAPI::get_entry( $entry['id'] );
|
||||
|
||||
$response = $this->prepare_item_for_response( $updated_entry, $request );
|
||||
|
||||
return rest_ensure_response( $response );
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete one item from the collection
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
* @param WP_REST_Request $request Full data about the request.
|
||||
*
|
||||
* @return WP_Error|WP_REST_Response
|
||||
*/
|
||||
public function delete_item( $request ) {
|
||||
$entry_id = $request['entry_id'];
|
||||
|
||||
$entry = GFAPI::get_entry( $entry_id );
|
||||
if ( is_wp_error( $entry ) ) {
|
||||
return new WP_Error( 'gf_entry_invalid_id', __( 'Invalid entry id.', 'gravityforms' ), array( 'status' => 404 ) );
|
||||
}
|
||||
|
||||
$force = isset( $request['force'] ) ? (bool) $request['force'] : false;
|
||||
|
||||
if ( $force ) {
|
||||
$result = GFAPI::delete_entry( $entry_id );
|
||||
|
||||
if ( is_wp_error( $result ) ) {
|
||||
$message = $result->get_error_message();
|
||||
return new WP_Error( 'gf_cannot_delete', $message, array( 'status' => 500 ) );
|
||||
}
|
||||
|
||||
$previous = $this->prepare_item_for_response( $entry, $request );
|
||||
$response = new WP_REST_Response();
|
||||
$response->set_data( array( 'deleted' => true, 'previous' => $previous->get_data() ) );
|
||||
} else {
|
||||
if ( rgar( $entry, 'status' ) == 'trash' ) {
|
||||
$message = __( 'The entry has already been deleted.', 'gravityforms' );
|
||||
return new WP_Error( 'gf_already_trashed', $message, array( 'status' => 410 ) );
|
||||
}
|
||||
|
||||
// Trash the entry
|
||||
GFAPI::update_entry_property( $entry_id, 'status', 'trash' );
|
||||
|
||||
$entry = GFAPI::get_entry( $entry_id );
|
||||
$response = rest_ensure_response( $entry );
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a given request has access to get items
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
* @param WP_REST_Request $request Full data about the request.
|
||||
*
|
||||
* @return WP_Error|bool
|
||||
*/
|
||||
public function get_items_permissions_check( $request ) {
|
||||
|
||||
/**
|
||||
* Filters the capability required to get entries via the REST API.
|
||||
*
|
||||
* @since 2.4
|
||||
*
|
||||
* @param string|array $capability The capability required for this endpoint.
|
||||
* @param WP_REST_Request $request Full data about the request.
|
||||
*/
|
||||
$capability = apply_filters( 'gform_rest_api_capability_get_entries', 'gravityforms_view_entries', $request );
|
||||
|
||||
return $this->current_user_can_any( $capability, $request );
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a given request has access to get a specific item
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
* @param WP_REST_Request $request Full data about the request.
|
||||
*
|
||||
* @return WP_Error|bool
|
||||
*/
|
||||
public function get_item_permissions_check( $request ) {
|
||||
return $this->get_items_permissions_check( $request );
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a given request has access to create items
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
* @param WP_REST_Request $request Full data about the request.
|
||||
*
|
||||
* @return WP_Error|bool
|
||||
*/
|
||||
public function create_item_permissions_check( $request ) {
|
||||
|
||||
/**
|
||||
* Filters the capability required to create entries via the REST API.
|
||||
*
|
||||
* @since 2.4
|
||||
*
|
||||
* @param string|array $capability The capability required for this endpoint.
|
||||
* @param WP_REST_Request $request Full data about the request.
|
||||
*/
|
||||
$capability = apply_filters( 'gform_rest_api_capability_post_entries', 'gravityforms_edit_entries', $request );
|
||||
|
||||
return $this->current_user_can_any( $capability, $request );
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a given request has access to update a specific item
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
* @param WP_REST_Request $request Full data about the request.
|
||||
*
|
||||
* @return WP_Error|bool
|
||||
*/
|
||||
public function update_item_permissions_check( $request ) {
|
||||
|
||||
/**
|
||||
* Filters the capability required to update entries via the REST API.
|
||||
*
|
||||
* @since 2.4
|
||||
*
|
||||
* @param string|array $capability The capability required for this endpoint.
|
||||
* @param WP_REST_Request $request Full data about the request.
|
||||
*/
|
||||
$capability = apply_filters( 'gform_rest_api_capability_put_entries', 'gravityforms_edit_entries', $request );
|
||||
|
||||
return $this->current_user_can_any( $capability, $request );
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a given request has access to delete a specific item
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
* @param WP_REST_Request $request Full data about the request.
|
||||
*
|
||||
* @return WP_Error|bool
|
||||
*/
|
||||
public function delete_item_permissions_check( $request ) {
|
||||
|
||||
/**
|
||||
* Filters the capability required to delete entries via the REST API.
|
||||
*
|
||||
* @since 2.4
|
||||
*
|
||||
* @param string|array $capability The capability required for this endpoint.
|
||||
* @param WP_REST_Request $request Full data about the request.
|
||||
*/
|
||||
$capability = apply_filters( 'gform_rest_api_capability_delete_entries', 'gravityforms_delete_entries', $request );
|
||||
|
||||
return $this->current_user_can_any( $capability, $request );
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare the item for create or update operation
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
* @param WP_REST_Request $request Request object
|
||||
*
|
||||
* @return WP_Error|array $prepared_item
|
||||
*/
|
||||
protected function prepare_item_for_database( $request ) {
|
||||
|
||||
$entry = $request->get_json_params();
|
||||
|
||||
if ( empty( $entry ) ) {
|
||||
return new WP_Error( 'missing_entry', __( 'Missing entry JSON', 'gravityforms' ) );
|
||||
}
|
||||
|
||||
$entry_id = $request['entry_id'];
|
||||
|
||||
if ( ! empty( $entry_id ) ) {
|
||||
$entry['id'] = $entry_id;
|
||||
}
|
||||
|
||||
$entry = $this->maybe_json_encode_applicable_fields( $entry );
|
||||
$entry = $this->maybe_serialize_list_fields( $entry );
|
||||
|
||||
return $entry;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare the item for the REST response
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
* @param mixed $item WordPress representation of the item.
|
||||
* @param WP_REST_Request $request Request object.
|
||||
*
|
||||
* @return WP_REST_Response Returns the item wrapped in a WP_REST_Response object
|
||||
*/
|
||||
public function prepare_item_for_response( $item, $request ) {
|
||||
|
||||
$item = $this->prepare_entry_for_response( $item );
|
||||
|
||||
$response = new WP_REST_Response( $item, 200 );
|
||||
return $response;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,307 @@
|
||||
<?php
|
||||
if ( ! class_exists( 'GFForms' ) ) {
|
||||
die();
|
||||
}
|
||||
|
||||
|
||||
class GF_REST_Entry_Notes_Controller extends GF_REST_Controller {
|
||||
|
||||
/**
|
||||
* @var string Base for the REST request.
|
||||
*/
|
||||
public $rest_base = 'entries/(?P<entry_id>[\d]+)/notes';
|
||||
|
||||
/**
|
||||
* Register the routes for the objects of the controller.
|
||||
*/
|
||||
public function register_routes() {
|
||||
|
||||
$namespace = $this->namespace;
|
||||
|
||||
$base = $this->rest_base;
|
||||
|
||||
register_rest_route(
|
||||
$namespace,
|
||||
'/' . $base,
|
||||
array(
|
||||
array(
|
||||
'methods' => WP_REST_Server::READABLE,
|
||||
'callback' => array( $this, 'get_items' ),
|
||||
'permission_callback' => array( $this, 'get_items_permissions_check' ),
|
||||
'args' => $this->get_collection_params(),
|
||||
),
|
||||
array(
|
||||
'methods' => WP_REST_Server::CREATABLE,
|
||||
'callback' => array( $this, 'create_item' ),
|
||||
'permission_callback' => array( $this, 'create_item_permissions_check' ),
|
||||
'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::CREATABLE ),
|
||||
),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all notes for one entry.
|
||||
*
|
||||
* @since 2.4.18
|
||||
*
|
||||
* @param WP_REST_Request $request Full data about the request.
|
||||
*
|
||||
* @return WP_Error|WP_REST_Response
|
||||
*/
|
||||
public function get_items( $request ) {
|
||||
|
||||
$entry_id = $request->get_param( 'entry_id' );
|
||||
|
||||
if ( ! GFAPI::entry_exists( $entry_id ) ) {
|
||||
return new WP_Error( 'gf_entry_invalid_id', __( 'Invalid entry id.', 'gravityforms' ), array( 'status' => 404 ) );
|
||||
}
|
||||
|
||||
$criteria = $request->get_params();
|
||||
|
||||
$allowed_criteria = array(
|
||||
'user_id',
|
||||
'note_type',
|
||||
'sub_type',
|
||||
'user_name'
|
||||
);
|
||||
|
||||
foreach ( $criteria as $key => $value ) {
|
||||
if ( in_array( $key, $allowed_criteria ) ) {
|
||||
$criteria[$key] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
$criteria['entry_id'] = $entry_id;
|
||||
|
||||
$sorting = '';
|
||||
if ( isset( $criteria['sorting'] ) ) {
|
||||
$sorting = $criteria['sorting'];
|
||||
unset( $criteria['sorting'] );
|
||||
}
|
||||
|
||||
$notes = GFAPI::get_notes( $criteria, $sorting );
|
||||
|
||||
if ( is_wp_error( $notes ) ) {
|
||||
return new WP_Error( 'gf_entry_invalid_notes', __( 'Error retrieving notes.', 'gravityforms' ), array( 'status' => 404 ) );
|
||||
}
|
||||
|
||||
if ( ! is_array( $notes ) || empty( $notes ) ) {
|
||||
return array();
|
||||
}
|
||||
|
||||
$data = array();
|
||||
|
||||
foreach ( $notes as $note ) {
|
||||
$data[ $note->id ] = $note;
|
||||
}
|
||||
|
||||
$response = new WP_REST_Response( $data, 200 );
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create one note.
|
||||
*
|
||||
* @since 2.4.18
|
||||
*
|
||||
* @param WP_REST_Request $request Full data about the request.
|
||||
*
|
||||
* @return WP_Error|WP_REST_Request
|
||||
*/
|
||||
public function create_item( $request ) {
|
||||
|
||||
$note = $this->prepare_item_for_database( $request );
|
||||
$entry_id = $request->get_param( 'entry_id' );
|
||||
|
||||
if ( is_wp_error( $note ) ) {
|
||||
return $note;
|
||||
}
|
||||
|
||||
$note_id = GFAPI::add_note( $entry_id, $note['user_id'], $note['user_name'], $note['note'] );
|
||||
|
||||
if ( is_wp_error( $note_id ) ) {
|
||||
$status = $this->get_error_status( $note_id );
|
||||
return new WP_Error( $note_id->get_error_code(), $note_id->get_error_message(), array( 'status' => $status ) );
|
||||
}
|
||||
|
||||
$note['id'] = $note_id;
|
||||
|
||||
$note = $this->prepare_note_for_response( $note_id );
|
||||
$response = rest_ensure_response( $note );
|
||||
$response->set_status( 201 );
|
||||
$base = sprintf( 'entries/%d/notes/', $note_id );
|
||||
$response->header( 'Location', rest_url( sprintf( '%s/%s/%d', $this->namespace, $base, $note_id ) ) );
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a given request has access to get items.
|
||||
*
|
||||
* @since 2.4.18
|
||||
*
|
||||
* @param WP_REST_Request $request Full data about the request.
|
||||
*
|
||||
* @return WP_Error|bool
|
||||
*/
|
||||
public function get_items_permissions_check( $request ) {
|
||||
|
||||
/**
|
||||
* Filters the capability required to get entries via the REST API.
|
||||
*
|
||||
* @param string|array $capability The capability required for this endpoint.
|
||||
* @param WP_REST_Request $request Full data about the request.
|
||||
*/
|
||||
$capability = apply_filters( 'gform_rest_api_capability_get_notes', 'gravityforms_view_entry_notes', $request );
|
||||
|
||||
return $this->current_user_can_any( $capability, $request );
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a given request has access to get a specific item.
|
||||
*
|
||||
* @since 2.4.18
|
||||
*
|
||||
* @param WP_REST_Request $request Full data about the request.
|
||||
*
|
||||
* @return WP_Error|bool
|
||||
*/
|
||||
public function get_item_permissions_check( $request ) {
|
||||
return $this->get_items_permissions_check( $request );
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a given request has access to create items.
|
||||
*
|
||||
* @since 2.4.18
|
||||
*
|
||||
* @param WP_REST_Request $request Full data about the request.
|
||||
*
|
||||
* @return WP_Error|bool
|
||||
*/
|
||||
public function create_item_permissions_check( $request ) {
|
||||
|
||||
/**
|
||||
* Filters the capability required to create entries via the REST API.
|
||||
*
|
||||
* @since 2.4.18
|
||||
*
|
||||
* @param string|array $capability The capability required for this endpoint.
|
||||
* @param WP_REST_Request $request Full data about the request.
|
||||
*/
|
||||
$capability = apply_filters( 'gform_rest_api_capability_post_notes', 'gravityforms_edit_entry_notes', $request );
|
||||
|
||||
return $this->current_user_can_any( $capability, $request );
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare the item for create or update operation.
|
||||
*
|
||||
* @since 2.4.18
|
||||
*
|
||||
* @param WP_REST_Request $request Request object.
|
||||
*
|
||||
* @return WP_Error|array $prepared_item.
|
||||
*/
|
||||
protected function prepare_item_for_database( $request ) {
|
||||
|
||||
$note = $request->get_json_params();
|
||||
|
||||
if ( empty( $note ) ) {
|
||||
return new WP_Error( 'missing_entry', __( 'Missing entry JSON', 'gravityforms' ) );
|
||||
}
|
||||
|
||||
$note['user_id'] = intval( $note['user_id'] );
|
||||
$note['note'] = wp_kses_post( $note['value'] );
|
||||
|
||||
return $note;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare the item for the REST response.
|
||||
*
|
||||
* @since 2.4.18
|
||||
*
|
||||
* @param mixed $item WordPress representation of the item.
|
||||
* @param WP_REST_Request $request Request object.
|
||||
*
|
||||
* @return WP_REST_Response Returns the item wrapped in a WP_REST_Response object
|
||||
*/
|
||||
public function prepare_item_for_response( $item, $request ) {
|
||||
|
||||
$item = $this->prepare_note_for_response( $item->id );
|
||||
|
||||
$response = new WP_REST_Response( $item, 200 );
|
||||
return $response;
|
||||
}
|
||||
|
||||
/***
|
||||
* Prepares note for REST API response, decoding or unserializing appropriate fields.
|
||||
*
|
||||
* @since 2.4.18
|
||||
*
|
||||
* @param int $note_id The note id.
|
||||
*
|
||||
* @return bool|array Returns the entry array ready to be send in the REST API response.
|
||||
*/
|
||||
public function prepare_note_for_response( $note_id ) {
|
||||
|
||||
$note = GFAPI::get_note( $note_id );
|
||||
|
||||
if ( is_wp_error( $note ) || ! isset( $note->ID ) ) {
|
||||
return $note;
|
||||
}
|
||||
|
||||
return $note;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a given request has access to update a specific item.
|
||||
*
|
||||
* @since 2.4.18
|
||||
*
|
||||
* @param WP_REST_Request $request Full data about the request.
|
||||
*
|
||||
* @return WP_Error|bool
|
||||
*/
|
||||
public function update_item_permissions_check( $request ) {
|
||||
|
||||
/**
|
||||
* Filters the capability required to update entries via the REST API.
|
||||
*
|
||||
* @since 2.4
|
||||
*
|
||||
* @param string|array $capability The capability required for this endpoint.
|
||||
* @param WP_REST_Request $request Full data about the request.
|
||||
*/
|
||||
$capability = apply_filters( 'gform_rest_api_capability_put_notes', 'gravityforms_edit_entries', $request );
|
||||
|
||||
return $this->current_user_can_any( $capability, $request );
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a given request has access to delete a specific item.
|
||||
*
|
||||
* @since 2.4.18
|
||||
*
|
||||
* @param WP_REST_Request $request Full data about the request.
|
||||
*
|
||||
* @return WP_Error|bool
|
||||
*/
|
||||
public function delete_item_permissions_check( $request ) {
|
||||
/**
|
||||
* Filters the capability required to delete entries via the REST API.
|
||||
*
|
||||
* @since 2.4.18
|
||||
*
|
||||
* @param string|array $capability The capability required for this endpoint.
|
||||
* @param WP_REST_Request $request Full data about the request.
|
||||
*/
|
||||
$capability = apply_filters( 'gform_rest_api_capability_delete_notes', 'gravityforms_edit_entry_notes', $request );
|
||||
|
||||
return $this->current_user_can_any( $capability, $request );
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,128 @@
|
||||
<?php
|
||||
if ( ! class_exists( 'GFForms' ) ) {
|
||||
die();
|
||||
}
|
||||
|
||||
|
||||
class GF_REST_Entry_Notifications_Controller extends GF_REST_Controller {
|
||||
|
||||
/**
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $rest_base = 'entries/(?P<entry_id>[\d]+)/notifications';
|
||||
|
||||
/**
|
||||
* Register the routes for the objects of the controller.
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
*/
|
||||
public function register_routes() {
|
||||
|
||||
$namespace = $this->namespace;
|
||||
|
||||
$base = $this->rest_base;
|
||||
|
||||
register_rest_route( $namespace, '/' . $base, array(
|
||||
array(
|
||||
'methods' => WP_REST_Server::CREATABLE,
|
||||
'callback' => array( $this, 'create_item' ),
|
||||
'permission_callback' => array( $this, 'create_item_permissions_check' ),
|
||||
'args' => $this->get_collection_params(),
|
||||
),
|
||||
) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Re-sends notifications for an entry.
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
* @param WP_REST_Request $request Full data about the request.
|
||||
*
|
||||
* @return WP_Error|WP_REST_Response
|
||||
*/
|
||||
public function create_item( $request ) {
|
||||
$entry_id = $request['entry_id'];
|
||||
|
||||
$entry = GFAPI::get_entry( $entry_id );
|
||||
|
||||
if ( is_wp_error( $entry ) ) {
|
||||
return $entry;
|
||||
}
|
||||
|
||||
$form_id = $entry['form_id'];
|
||||
|
||||
$form = GFAPI::get_form( $form_id );
|
||||
|
||||
if ( empty( $form ) ) {
|
||||
return new WP_Error( __( 'Form not found.', 'gravityforms' ) );
|
||||
}
|
||||
|
||||
$notification_ids = $request['_notifications'];
|
||||
|
||||
if ( ! empty( $notification_ids ) ) {
|
||||
$notification_ids = (array) explode( ',', $request['_notifications'] );
|
||||
$notification_ids = array_map( 'trim', $notification_ids );
|
||||
}
|
||||
|
||||
$event = isset( $request['_event'] ) ? $request['_event'] : 'form_submission';
|
||||
|
||||
if ( empty( $notification_ids ) ) {
|
||||
$notification_ids = GFAPI::send_notifications( $form, $entry, $event );
|
||||
} else {
|
||||
foreach ( $notification_ids as $notification_id ) {
|
||||
if ( empty( $form['notifications'][ $notification_id ] ) ) {
|
||||
/* translators: %s: The notification id */
|
||||
return new WP_Error( __( sprintf( 'Notification %s not found.', $notification_id ), 'gravityforms' ) );
|
||||
}
|
||||
|
||||
GFCommon::send_notification( $form['notifications'][ $notification_id ], $form, $entry );
|
||||
}
|
||||
}
|
||||
|
||||
return new WP_REST_Response( $notification_ids, 200 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a given request has permission to send notifications.
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
* @param WP_REST_Request $request Full data about the request.
|
||||
*
|
||||
* @return WP_Error|bool
|
||||
*/
|
||||
public function create_item_permissions_check( $request ) {
|
||||
/**
|
||||
* Filters the capability required to re-send notifications via the REST API.
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
* @param string|array $capability The capability required for this endpoint.
|
||||
* @param WP_REST_Request $request Full data about the request.
|
||||
*/
|
||||
$capability = apply_filters( 'gform_rest_api_capability_post_entries_notifications', 'gravityforms_edit_entries', $request );
|
||||
return $this->current_user_can_any( $capability, $request );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the query params for collections
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_collection_params() {
|
||||
return array(
|
||||
'include' => array(
|
||||
'description' => 'Limit the notifications to specific IDs.',
|
||||
),
|
||||
'event' => array(
|
||||
'description' => 'The event to trigger. Default: form_submission.',
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,140 @@
|
||||
<?php
|
||||
if ( ! class_exists( 'GFForms' ) ) {
|
||||
die();
|
||||
}
|
||||
|
||||
|
||||
class GF_REST_Entry_Properties_Controller extends GF_REST_Form_Entries_Controller {
|
||||
|
||||
/**
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $rest_base = 'entries/(?P<entry_id>[\d]+)/properties';
|
||||
|
||||
/**
|
||||
* Register the routes for the objects of the controller.
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
*/
|
||||
public function register_routes() {
|
||||
|
||||
$namespace = $this->namespace;
|
||||
|
||||
$base = $this->rest_base;
|
||||
|
||||
register_rest_route( $namespace, '/' . $base, array(
|
||||
array(
|
||||
'methods' => 'PUT',
|
||||
'callback' => array( $this, 'update_items' ),
|
||||
'permission_callback' => array( $this, 'update_item_permissions_check' ),
|
||||
'args' => $this->get_endpoint_args_for_item_schema( true ),
|
||||
),
|
||||
) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Update one item from the collection
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
*
|
||||
* @param WP_REST_Request $request Full data about the request.
|
||||
*
|
||||
* @return WP_Error|WP_REST_Response
|
||||
*/
|
||||
public function update_items( $request ) {
|
||||
$entry_id = $request['entry_id'];
|
||||
$key_value_pairs = $this->prepare_item_for_database( $request );
|
||||
|
||||
if ( empty( $key_value_pairs ) ) {
|
||||
$message = __( 'No property values were found in the request body', 'gravityforms' );
|
||||
return new WP_REST_Response( $message, 400 );
|
||||
} elseif ( ! is_array( $key_value_pairs ) ) {
|
||||
$message = __( 'Property values should be sent as an array', 'gravityforms' );
|
||||
return new WP_REST_Response( $message, 400 );
|
||||
}
|
||||
|
||||
$result = false;
|
||||
foreach ( $key_value_pairs as $key => $property_value ) {
|
||||
$result = GFAPI::update_entry_property( $entry_id, $key, $property_value );
|
||||
if ( is_wp_error( $result ) ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( is_wp_error( $result ) ) {
|
||||
$status = $this->get_error_status( $result );
|
||||
return new WP_Error( $result->get_error_code(), $result->get_error_message(), array( 'status' => $status ) );
|
||||
}
|
||||
|
||||
$message = __( 'Entry updated successfully', 'gravityforms' );
|
||||
|
||||
return new WP_REST_Response( $message, 200 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a given request has access to update a specific item
|
||||
*
|
||||
* @since 2.4
|
||||
*
|
||||
* @param WP_REST_Request $request Full data about the request.
|
||||
*
|
||||
* @return WP_Error|bool
|
||||
*/
|
||||
public function update_item_permissions_check( $request ) {
|
||||
/**
|
||||
* Filters the capability required to update entries via the REST API.
|
||||
*
|
||||
* @since 2.4
|
||||
*
|
||||
* @param string|array $capability The capability required for this endpoint.
|
||||
* @param WP_REST_Request $request Full data about the request.
|
||||
*/
|
||||
$capability = apply_filters( 'gform_rest_api_capability_put_entries', 'gravityforms_edit_entries', $request );
|
||||
return $this->current_user_can_any( $capability, $request );
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare the item for create or update operation
|
||||
*
|
||||
* @since 2.4
|
||||
*
|
||||
* @param WP_REST_Request $request Request object
|
||||
*
|
||||
* @return WP_Error|array $prepared_item
|
||||
*/
|
||||
protected function prepare_item_for_database( $request ) {
|
||||
$properties = $request->get_json_params();
|
||||
if ( empty( $properties ) ) {
|
||||
return new WP_Error( 'missing_properties', __( 'Missing Key Value Pairs JSON', 'gravityforms' ) );
|
||||
}
|
||||
|
||||
return $properties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the query params for collections
|
||||
*
|
||||
* @since 2.4
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_collection_params() {
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Entry Property schema, conforming to JSON Schema.
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_item_schema() {
|
||||
return array();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
<?php
|
||||
if ( ! class_exists( 'GFForms' ) ) {
|
||||
die();
|
||||
}
|
||||
|
||||
|
||||
class GF_REST_Feed_Properties_Controller extends GF_REST_Feeds_Controller {
|
||||
|
||||
/**
|
||||
* The base of this controller's route.
|
||||
*
|
||||
* @since 2.4.24
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $rest_base = 'feeds/(?P<feed_id>[\d]+)/properties';
|
||||
|
||||
/**
|
||||
* Register the routes for the objects of the controller.
|
||||
*
|
||||
* @since 2.4.24
|
||||
*/
|
||||
public function register_routes() {
|
||||
register_rest_route( $this->namespace, '/' . $this->rest_base, array(
|
||||
array(
|
||||
'methods' => 'PUT',
|
||||
'callback' => array( $this, 'update_items' ),
|
||||
'permission_callback' => array( $this, 'update_item_permissions_check' ),
|
||||
'args' => $this->get_endpoint_args_for_item_schema( true ),
|
||||
),
|
||||
) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the specified feed with the given properties.
|
||||
*
|
||||
* @since 2.4.24
|
||||
*
|
||||
* @param WP_REST_Request $request Full data about the request.
|
||||
*
|
||||
* @return WP_Error|WP_REST_Response
|
||||
*/
|
||||
public function update_items( $request ) {
|
||||
$properties = $this->prepare_item_for_database( $request );
|
||||
|
||||
if ( is_wp_error( $properties ) ) {
|
||||
return $properties;
|
||||
}
|
||||
|
||||
$result = $this->update_feed_properties( $request['feed_id'], $properties );
|
||||
if ( is_wp_error( $result ) ) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
return new WP_REST_Response( __( 'Feed updated successfully', 'gravityforms' ), 200 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the properties from the request body.
|
||||
*
|
||||
* @since 2.4.24
|
||||
*
|
||||
* @param WP_REST_Request $request Request object
|
||||
*
|
||||
* @return WP_Error|array
|
||||
*/
|
||||
protected function prepare_item_for_database( $request ) {
|
||||
$properties = $request->get_json_params();
|
||||
if ( empty( $properties ) ) {
|
||||
return new WP_Error( 'missing_properties', __( 'Invalid JSON. Properties should be sent as key value pairs.', 'gravityforms' ), array( 'status' => 400 ) );
|
||||
}
|
||||
|
||||
return $properties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the query params for collections
|
||||
*
|
||||
* @since 2.4.24
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_collection_params() {
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Feed schema, conforming to JSON Schema.
|
||||
*
|
||||
* @since 2.4.24
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_item_schema() {
|
||||
return array(
|
||||
'$schema' => 'http://json-schema.org/draft-04/schema#',
|
||||
'title' => 'feed',
|
||||
'type' => 'object',
|
||||
'properties' => array(
|
||||
'id' => array(
|
||||
'description' => __( 'Unique identifier for the feed.', 'gravityforms' ),
|
||||
'type' => 'integer',
|
||||
'readonly' => true,
|
||||
),
|
||||
'form_id' => array(
|
||||
'description' => __( 'The Form ID for the feed.', 'gravityforms' ),
|
||||
'type' => 'integer',
|
||||
),
|
||||
'is_active' => array(
|
||||
'description' => __( 'Indicates if the feed is active or inactive.', 'gravityforms' ),
|
||||
'type' => 'boolean',
|
||||
),
|
||||
'feed_order' => array(
|
||||
'description' => __( 'The position of the feed on the feeds list page and when processed; for add-ons which support feed ordering.', 'gravityforms' ),
|
||||
'type' => 'integer',
|
||||
),
|
||||
'meta' => array(
|
||||
'description' => __( 'The JSON string containing the feed meta.', 'gravityforms' ),
|
||||
'type' => 'object',
|
||||
),
|
||||
'addon_slug' => array(
|
||||
'description' => __( 'The add-on the feed belongs to.', 'gravityforms' ),
|
||||
'type' => 'string',
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,363 @@
|
||||
<?php
|
||||
if ( ! class_exists( 'GFForms' ) ) {
|
||||
die();
|
||||
}
|
||||
|
||||
|
||||
class GF_REST_Feeds_Controller extends GF_REST_Form_Feeds_Controller {
|
||||
|
||||
/**
|
||||
* @since 2.4
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $rest_base = 'feeds';
|
||||
|
||||
/**
|
||||
* Register the routes for the objects of the controller.
|
||||
*
|
||||
* @since 2.4
|
||||
*
|
||||
*/
|
||||
public function register_routes() {
|
||||
|
||||
$namespace = $this->namespace;
|
||||
|
||||
$base = $this->rest_base;
|
||||
|
||||
register_rest_route( $namespace, '/' . $base, array(
|
||||
array(
|
||||
'methods' => WP_REST_Server::READABLE,
|
||||
'callback' => array( $this, 'get_items' ),
|
||||
'permission_callback' => array( $this, 'get_items_permissions_check' ),
|
||||
'args' => $this->get_collection_params(),
|
||||
),
|
||||
array(
|
||||
'methods' => WP_REST_Server::CREATABLE,
|
||||
'callback' => array( $this, 'create_item' ),
|
||||
'permission_callback' => array( $this, 'create_item_permissions_check' ),
|
||||
'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::CREATABLE ),
|
||||
),
|
||||
) );
|
||||
|
||||
register_rest_route( $namespace, '/' . $base . '/(?P<feed_id>[\d]+)', array(
|
||||
array(
|
||||
'methods' => WP_REST_Server::READABLE,
|
||||
'callback' => array( $this, 'get_item' ),
|
||||
'permission_callback' => array( $this, 'get_item_permissions_check' ),
|
||||
'args' => array(),
|
||||
),
|
||||
array(
|
||||
'methods' => 'PUT,PATCH',
|
||||
'callback' => array( $this, 'update_item' ),
|
||||
'permission_callback' => array( $this, 'update_item_permissions_check' ),
|
||||
'args' => $this->get_endpoint_args_for_item_schema( false ),
|
||||
),
|
||||
array(
|
||||
'methods' => WP_REST_Server::DELETABLE,
|
||||
'callback' => array( $this, 'delete_item' ),
|
||||
'permission_callback' => array( $this, 'delete_item_permissions_check' ),
|
||||
'args' => array(),
|
||||
),
|
||||
) );
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a collection of feeds.
|
||||
*
|
||||
* @since 2.4
|
||||
*
|
||||
* @param WP_REST_Request $request Full data about the request.
|
||||
*
|
||||
* @return WP_Error|WP_REST_Response
|
||||
*/
|
||||
public function get_items( $request ) {
|
||||
$feed_ids = $request['include'];
|
||||
|
||||
if ( ! empty( $feed_ids ) ) {
|
||||
if ( ! is_array( $feed_ids ) ) {
|
||||
$feed_ids = array( $feed_ids );
|
||||
}
|
||||
$feed_ids = array_map( 'absint', $feed_ids );
|
||||
}
|
||||
|
||||
$addon_slug = $request['addon'];
|
||||
|
||||
$feeds = GFAPI::get_feeds( $feed_ids, null, $addon_slug );
|
||||
|
||||
return new WP_REST_Response( $feeds, 200 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get one item from the collection
|
||||
*
|
||||
* @since 2.4
|
||||
*
|
||||
* @param WP_REST_Request $request Full data about the request.
|
||||
*
|
||||
* @return WP_Error|WP_REST_Response
|
||||
*/
|
||||
public function get_item( $request ) {
|
||||
|
||||
$feed_id = $request->get_param( 'feed_id' );
|
||||
|
||||
$feed = GFAPI::get_feed( $feed_id );
|
||||
|
||||
if ( is_wp_error( $feed ) ) {
|
||||
return new WP_Error( 'gf_feed_invalid_id', __( 'Invalid feed id.', 'gravityforms' ), array( 'status' => 404 ) );
|
||||
}
|
||||
|
||||
return $this->prepare_item_for_response( $feed, $request );
|
||||
}
|
||||
|
||||
/**
|
||||
* Create one item from the collection
|
||||
*
|
||||
* @since 2.4
|
||||
*
|
||||
* @param WP_REST_Request $request Full data about the request.
|
||||
*
|
||||
* @return WP_Error|WP_REST_Request
|
||||
*/
|
||||
public function create_item( $request ) {
|
||||
return parent::create_item( $request );
|
||||
}
|
||||
|
||||
/**
|
||||
* Update one item from the collection
|
||||
*
|
||||
* @since 2.4
|
||||
*
|
||||
* @param WP_REST_Request $request Full data about the request.
|
||||
*
|
||||
* @return WP_Error|WP_REST_Response
|
||||
*/
|
||||
public function update_item( $request ) {
|
||||
if ( ! GFAPI::feed_exists( $request['feed_id'] ) ) {
|
||||
return new WP_Error( 'gf_feed_invalid_id', __( 'Invalid feed id.', 'gravityforms' ), array( 'status' => 404 ) );
|
||||
}
|
||||
|
||||
$properties = $this->prepare_item_for_database( $request );
|
||||
if ( is_wp_error( $properties ) ) {
|
||||
return $properties;
|
||||
}
|
||||
|
||||
unset( $properties['id'] );
|
||||
|
||||
$result = $this->update_feed_properties( $request['feed_id'], $properties );
|
||||
if ( is_wp_error( $result ) ) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
return $this->prepare_item_for_response( GFAPI::get_feed( $request['feed_id'] ), $request );
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares the item for the update operation.
|
||||
*
|
||||
* @since 2.4.24
|
||||
*
|
||||
* @param WP_REST_Request $request Request object
|
||||
*
|
||||
* @return WP_Error|array
|
||||
*/
|
||||
protected function prepare_item_for_database( $request ) {
|
||||
if ( $request->get_method() !== 'PATCH' ) {
|
||||
return parent::prepare_item_for_database( $request );
|
||||
}
|
||||
|
||||
$properties = $request->get_json_params();
|
||||
|
||||
if ( empty( $properties ) ) {
|
||||
return new WP_Error( 'missing_properties', __( 'Invalid JSON. Properties should be sent as key value pairs.', 'gravityforms' ), array( 'status' => 400 ) );
|
||||
}
|
||||
|
||||
if ( ! empty( $properties['meta'] ) ) {
|
||||
$feed = GFAPI::get_feed( $request['feed_id'] );
|
||||
$properties['meta'] = $this->patch_array_recursive( $feed['meta'], $properties['meta'] );
|
||||
}
|
||||
|
||||
return $properties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the specified feed with the given property values.
|
||||
*
|
||||
* @since 2.4.24
|
||||
*
|
||||
* @param int $feed_id The ID of the feed being updated.
|
||||
* @param array $properties The feed properties being updated.
|
||||
*
|
||||
* @return bool|WP_Error
|
||||
*/
|
||||
protected function update_feed_properties( $feed_id, $properties ) {
|
||||
foreach ( $properties as $key => $value ) {
|
||||
$result = GFAPI::update_feed_property( $feed_id, $key, $value );
|
||||
if ( is_wp_error( $result ) ) {
|
||||
return new WP_Error(
|
||||
$result->get_error_code(),
|
||||
$result->get_error_message(),
|
||||
array( 'status' => $this->get_error_status( $result ) )
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete one item from the collection
|
||||
*
|
||||
* @since 2.4
|
||||
*
|
||||
* @param WP_REST_Request $request Full data about the request.
|
||||
*
|
||||
* @return WP_Error|WP_REST_Response
|
||||
*/
|
||||
public function delete_item( $request ) {
|
||||
$feed_id = $request['feed_id'];
|
||||
|
||||
$feed = GFAPI::get_feed( $feed_id );
|
||||
if ( is_wp_error( $feed ) ) {
|
||||
return new WP_Error( 'gf_feed_invalid_id', __( 'Invalid feed id.', 'gravityforms' ), array( 'status' => 404 ) );
|
||||
}
|
||||
|
||||
$result = GFAPI::delete_feed( $feed_id );
|
||||
if ( is_wp_error( $result ) ) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
$previous = $this->prepare_item_for_response( $feed, $request );
|
||||
$response = new WP_REST_Response();
|
||||
$response->set_data( array( 'deleted' => true, 'previous' => $previous->get_data() ) );
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a given request has access to get items
|
||||
*
|
||||
* @since 2.4
|
||||
*
|
||||
* @param WP_REST_Request $request Full data about the request.
|
||||
*
|
||||
* @return WP_Error|bool
|
||||
*/
|
||||
public function get_items_permissions_check( $request ) {
|
||||
|
||||
/**
|
||||
* Filters the capability required to get feeds via the REST API.
|
||||
*
|
||||
* @since 2.4
|
||||
*
|
||||
* @param string|array $capability The capability required for this endpoint.
|
||||
* @param WP_REST_Request $request Full data about the request.
|
||||
*/
|
||||
$capability = apply_filters( 'gform_rest_api_capability_get_feeds', 'gravityforms_edit_forms', $request );
|
||||
|
||||
return $this->current_user_can_any( $capability, $request );
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a given request has access to get a specific item
|
||||
*
|
||||
* @since 2.4
|
||||
*
|
||||
* @param WP_REST_Request $request Full data about the request.
|
||||
*
|
||||
* @return WP_Error|bool
|
||||
*/
|
||||
public function get_item_permissions_check( $request ) {
|
||||
return $this->get_items_permissions_check( $request );
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a given request has access to create items
|
||||
*
|
||||
* @since 2.4
|
||||
*
|
||||
* @param WP_REST_Request $request Full data about the request.
|
||||
*
|
||||
* @return WP_Error|bool
|
||||
*/
|
||||
public function create_item_permissions_check( $request ) {
|
||||
|
||||
/**
|
||||
* Filters the capability required to create feeds via the REST API.
|
||||
*
|
||||
* @since 2.4
|
||||
*
|
||||
* @param string|array $capability The capability required for this endpoint.
|
||||
* @param WP_REST_Request $request Full data about the request.
|
||||
*/
|
||||
$capability = apply_filters( 'gform_rest_api_capability_post_feeds', 'gravityforms_edit_forms', $request );
|
||||
|
||||
return $this->current_user_can_any( $capability, $request );
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a given request has access to update a specific item
|
||||
*
|
||||
* @since 2.4
|
||||
*
|
||||
* @param WP_REST_Request $request Full data about the request.
|
||||
*
|
||||
* @return WP_Error|bool
|
||||
*/
|
||||
public function update_item_permissions_check( $request ) {
|
||||
|
||||
/**
|
||||
* Filters the capability required to update feeds via the REST API.
|
||||
*
|
||||
* @since 2.4
|
||||
*
|
||||
* @param string|array $capability The capability required for this endpoint.
|
||||
* @param WP_REST_Request $request Full data about the request.
|
||||
*/
|
||||
$capability = apply_filters( 'gform_rest_api_capability_put_feeds', 'gravityforms_edit_forms', $request );
|
||||
|
||||
return $this->current_user_can_any( $capability, $request );
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a given request has access to delete a specific item
|
||||
*
|
||||
* @since 2.4
|
||||
*
|
||||
* @param WP_REST_Request $request Full data about the request.
|
||||
*
|
||||
* @return WP_Error|bool
|
||||
*/
|
||||
public function delete_item_permissions_check( $request ) {
|
||||
|
||||
/**
|
||||
* Filters the capability required to delete feeds via the REST API.
|
||||
*
|
||||
* @since 2.4
|
||||
*
|
||||
* @param string|array $capability The capability required for this endpoint.
|
||||
* @param WP_REST_Request $request Full data about the request.
|
||||
*/
|
||||
$capability = apply_filters( 'gform_rest_api_capability_delete_feeds', 'gravityforms_edit_forms', $request );
|
||||
|
||||
return $this->current_user_can_any( $capability, $request );
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare the item for the REST response
|
||||
*
|
||||
* @since 2.4
|
||||
*
|
||||
* @param mixed $item WordPress representation of the item.
|
||||
* @param WP_REST_Request $request Request object.
|
||||
*
|
||||
* @return WP_REST_Response Returns the item wrapped in a WP_REST_Response object
|
||||
*/
|
||||
public function prepare_item_for_response( $item, $request ) {
|
||||
|
||||
$response = new WP_REST_Response( $item, 200 );
|
||||
return $response;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,496 @@
|
||||
<?php
|
||||
if ( ! class_exists( 'GFForms' ) ) {
|
||||
die();
|
||||
}
|
||||
|
||||
|
||||
class GF_REST_Form_Entries_Controller extends GF_REST_Controller {
|
||||
|
||||
/**
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $rest_base = 'forms/(?P<form_id>[\d]+)/entries';
|
||||
|
||||
/**
|
||||
* Register the routes for the objects of the controller.
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*/
|
||||
public function register_routes() {
|
||||
|
||||
$namespace = $this->namespace;
|
||||
|
||||
$base = $this->rest_base;
|
||||
|
||||
register_rest_route( $namespace, '/' . $base, array(
|
||||
array(
|
||||
'methods' => WP_REST_Server::READABLE,
|
||||
'callback' => array( $this, 'get_items' ),
|
||||
'permission_callback' => array( $this, 'get_items_permissions_check' ),
|
||||
'args' => $this->get_collection_params(),
|
||||
),
|
||||
array(
|
||||
'methods' => WP_REST_Server::CREATABLE,
|
||||
'callback' => array( $this, 'create_item' ),
|
||||
'permission_callback' => array( $this, 'create_item_permissions_check' ),
|
||||
'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::CREATABLE ),
|
||||
),
|
||||
) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a collection of entries
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
* @param WP_REST_Request $request Full data about the request.
|
||||
*
|
||||
* @return WP_Error|WP_REST_Response
|
||||
*/
|
||||
public function get_items( $request ) {
|
||||
|
||||
$entry_ids = $request['include'];
|
||||
|
||||
if ( ! empty( $entry_ids ) ) {
|
||||
if ( ! is_array( $entry_ids ) ) {
|
||||
$entry_ids = array( $entry_ids );
|
||||
}
|
||||
$entry_ids = array_map( 'absint', $entry_ids );
|
||||
}
|
||||
|
||||
$field_ids = $request['_field_ids'];
|
||||
if ( ! empty( $field_ids ) ) {
|
||||
$field_ids = (array) explode( ',', $request['_field_ids'] );
|
||||
$field_ids = array_map( 'trim', $field_ids );
|
||||
}
|
||||
|
||||
$labels = $request['_labels'];
|
||||
|
||||
$data = array();
|
||||
if ( $entry_ids ) {
|
||||
foreach ( $entry_ids as $id ) {
|
||||
$result = GFAPI::get_entry( $id );
|
||||
if ( ! is_wp_error( $result ) ) {
|
||||
|
||||
$form_id = $result['form_id'];
|
||||
|
||||
$entry = $this->prepare_entry_for_response( $result );
|
||||
|
||||
if ( ! empty( $field_ids ) && ( ! empty( $entry ) ) ) {
|
||||
$entry = $this->filter_entry_fields( $entry, $field_ids );
|
||||
}
|
||||
|
||||
if ( $labels ) {
|
||||
$form = GFAPI::get_form( $form_id );
|
||||
$entry['_labels'] = $this->get_entry_labels( $form, compact( 'field_ids' ) );
|
||||
}
|
||||
|
||||
$data[ $id ] = $entry;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$entry_search_params = $this->parse_entry_search_params( $request );
|
||||
|
||||
$entry_count = 0;
|
||||
|
||||
$form_id = isset( $entry_search_params['form_ids'] ) ? $entry_search_params['form_ids'] : $request['form_id'];
|
||||
|
||||
if ( empty( $form_id ) ) {
|
||||
$form_id = 0;
|
||||
}
|
||||
|
||||
$entries = GFAPI::get_entries( $form_id, $entry_search_params['search_criteria'], $entry_search_params['sorting'], $entry_search_params['paging'], $entry_count );
|
||||
|
||||
$data = array();
|
||||
if ( ! is_wp_error( $entries ) ) {
|
||||
foreach ( $entries as &$entry ) {
|
||||
$form_id_for_entry = $entry['form_id'];
|
||||
$entry = $this->prepare_entry_for_response( $entry );
|
||||
if ( ! empty( $field_ids ) && ! empty( $entry ) ) {
|
||||
$entry = $this->filter_entry_fields( $entry, $field_ids );
|
||||
}
|
||||
if ( $labels && ( empty( $form_id ) || is_array( $form_id ) ) ) {
|
||||
$form = GFAPI::get_form( $form_id_for_entry );
|
||||
$entry['_labels'] = $this->get_entry_labels( $form, compact( 'field_ids' ) );
|
||||
}
|
||||
}
|
||||
$data = array( 'total_count' => $entry_count, 'entries' => $entries );
|
||||
|
||||
if ( $labels && ! empty( $form_id ) && ! is_array( $form_id ) ) {
|
||||
$form = GFAPI::get_form( $form_id );
|
||||
$data['_labels'] = $this->get_entry_labels( $form, compact( 'field_ids' ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new WP_REST_Response( $data, 200 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Create one item from the collection
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
* @param WP_REST_Request $request Full data about the request.
|
||||
*
|
||||
* @return WP_Error|WP_REST_Response
|
||||
*/
|
||||
public function create_item( $request ) {
|
||||
|
||||
$entry = $this->prepare_item_for_database( $request );
|
||||
|
||||
if ( is_wp_error( $entry ) ) {
|
||||
return $entry;
|
||||
}
|
||||
|
||||
$entry_id = GFAPI::add_entry( $entry );
|
||||
|
||||
if ( is_wp_error( $entry_id ) ) {
|
||||
$status = $this->get_error_status( $entry_id );
|
||||
return new WP_Error( $entry_id->get_error_code(), $entry_id->get_error_message(), array( 'status' => $status ) );
|
||||
}
|
||||
|
||||
$entry['id'] = $entry_id;
|
||||
|
||||
$entry = $this->prepare_entry_for_response( $entry );
|
||||
|
||||
$response = rest_ensure_response( $entry );
|
||||
|
||||
$response->set_status( 201 );
|
||||
|
||||
$base = sprintf( 'forms/%d/entries', $entry['form_id'] );
|
||||
|
||||
$response->header( 'Location', rest_url( sprintf( '%s/%s/%d', $this->namespace, $base, $entry_id ) ) );
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a given request has access to get items
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
* @param WP_REST_Request $request Full data about the request.
|
||||
*
|
||||
* @return WP_Error|bool
|
||||
*/
|
||||
public function get_items_permissions_check( $request ) {
|
||||
|
||||
/**
|
||||
* Filters the capability required to get entries via the REST API.
|
||||
*
|
||||
* @since 2.0-beta-2
|
||||
*
|
||||
* @param string|array $capability The capability required for this endpoint.
|
||||
* @param WP_REST_Request $request Full data about the request.
|
||||
*/
|
||||
$capability = apply_filters( 'gform_rest_api_capability_get_entries', 'gravityforms_view_entries', $request );
|
||||
|
||||
return $this->current_user_can_any( $capability, $request );
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a given request has access to create items
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
* @param WP_REST_Request $request Full data about the request.
|
||||
*
|
||||
* @return WP_Error|bool
|
||||
*/
|
||||
public function create_item_permissions_check( $request ) {
|
||||
|
||||
/**
|
||||
* Filters the capability required to create entries via the REST API.
|
||||
*
|
||||
* @since 2.0-beta-2
|
||||
*
|
||||
* @param string|array $capability The capability required for this endpoint.
|
||||
* @param WP_REST_Request $request Full data about the request.
|
||||
*/
|
||||
$capability = apply_filters( 'gform_rest_api_capability_post_entries', 'gravityforms_edit_entries', $request );
|
||||
|
||||
return $this->current_user_can_any( $capability, $request );
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare the item for create or update operation
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
* @param WP_REST_Request $request Request object
|
||||
*
|
||||
* @return WP_Error|array $prepared_item
|
||||
*/
|
||||
protected function prepare_item_for_database( $request ) {
|
||||
$entry = $request->get_json_params();
|
||||
|
||||
if ( empty( $entry ) ) {
|
||||
return new WP_Error( 'missing_entry', __( 'Missing entry JSON', 'gravityforms' ) );
|
||||
}
|
||||
|
||||
$url_params = $request->get_url_params();
|
||||
|
||||
// Check the URL params first
|
||||
$form_id = rgar( $url_params, 'form_id' );
|
||||
|
||||
if ( empty( $form_id ) ) {
|
||||
$form_id = $request->get_param( 'form_id' );
|
||||
}
|
||||
|
||||
if ( $form_id ) {
|
||||
$entry['form_id'] = absint( $form_id );
|
||||
}
|
||||
|
||||
$entry = $this->maybe_json_encode_applicable_fields( $entry );
|
||||
$entry = $this->maybe_serialize_list_fields( $entry );
|
||||
|
||||
return $entry;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the query params for collections
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_collection_params() {
|
||||
return array(
|
||||
'sorting' => array(
|
||||
'description' => 'The sorting criteria.',
|
||||
),
|
||||
'paging' => array(
|
||||
'description' => 'The paging criteria.',
|
||||
),
|
||||
'search' => array(
|
||||
'description' => 'The search criteria.',
|
||||
'type' => 'string',
|
||||
),
|
||||
'include' => array(
|
||||
'description' => __( 'Limit result set to specific IDs.' ),
|
||||
'type' => 'array',
|
||||
'items' => array(
|
||||
'type' => 'integer',
|
||||
),
|
||||
'default' => array(),
|
||||
),
|
||||
'_field_ids' => array(
|
||||
'description' => 'Comma separated list of fields to include in the response.',
|
||||
'type' => 'string',
|
||||
),
|
||||
'_labels' => array(
|
||||
'description' => 'Whether to include the labels in the response.',
|
||||
'type' => 'integer',
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Entry schema, conforming to JSON Schema.
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_item_schema() {
|
||||
$schema = array(
|
||||
'$schema' => 'http://json-schema.org/draft-04/schema#',
|
||||
'title' => 'entry',
|
||||
'type' => 'object',
|
||||
'properties' => array(
|
||||
'id' => array(
|
||||
'description' => __( 'Unique identifier for the resource.', 'gravityforms' ),
|
||||
'type' => 'integer',
|
||||
'readonly' => true,
|
||||
),
|
||||
'form_id' => array(
|
||||
'description' => __( 'The Form ID for the entry.', 'gravityforms' ),
|
||||
'type' => 'integer',
|
||||
'required' => true,
|
||||
'readonly' => false,
|
||||
),
|
||||
'date_created' => array(
|
||||
'description' => __( 'The date the entry was created, in UTC.', 'gravityforms' ),
|
||||
'type' => 'string',
|
||||
'readonly' => false,
|
||||
),
|
||||
'date_updated' => array(
|
||||
'description' => __( 'The date the entry was updated, in UTC.', 'gravityforms' ),
|
||||
'type' => 'string',
|
||||
'readonly' => false,
|
||||
),
|
||||
'is_starred' => array(
|
||||
'description' => __( 'Whether the entry is starred.', 'gravityforms' ),
|
||||
'type' => 'integer',
|
||||
'readonly' => false,
|
||||
),
|
||||
'is_read' => array(
|
||||
'description' => __( 'Whether the entry has been read.', 'gravityforms' ),
|
||||
'type' => 'integer',
|
||||
'readonly' => false,
|
||||
),
|
||||
'ip' => array(
|
||||
'description' => __( 'The IP address of the entry creator.', 'gravityforms' ),
|
||||
'type' => 'string',
|
||||
'readonly' => false,
|
||||
),
|
||||
'source_url' => array(
|
||||
'description' => __( 'The URL where the form was embedded.', 'gravityforms' ),
|
||||
'type' => 'string',
|
||||
'readonly' => false,
|
||||
),
|
||||
'user_agent' => array(
|
||||
'description' => __( 'The user agent string for the browser used to submit the entry.', 'gravityforms' ),
|
||||
'type' => 'string',
|
||||
'readonly' => false,
|
||||
),
|
||||
'payment_status' => array(
|
||||
'description' => __( 'The status of the payment, if applicable.', 'gravityforms' ),
|
||||
'type' => 'string',
|
||||
'readonly' => false,
|
||||
),
|
||||
'payment_date' => array(
|
||||
'description' => __( 'The date of the payment, if applicable.', 'gravityforms' ),
|
||||
'type' => 'string',
|
||||
'readonly' => false,
|
||||
),
|
||||
'payment_amount' => array(
|
||||
'description' => __( 'The amount of the payment, if applicable.', 'gravityforms' ),
|
||||
'type' => 'string',
|
||||
'readonly' => false,
|
||||
),
|
||||
'payment_method' => array(
|
||||
'description' => __( 'The payment method for the payment, if applicable.', 'gravityforms' ),
|
||||
'type' => 'string',
|
||||
'readonly' => false,
|
||||
),
|
||||
'transaction_id' => array(
|
||||
'description' => __( 'The transaction ID for the payment, if applicable.', 'gravityforms' ),
|
||||
'type' => 'string',
|
||||
'readonly' => false,
|
||||
),
|
||||
'is_fulfilled' => array(
|
||||
'description' => __( 'Whether the transaction has been fulfilled, if applicable.', 'gravityforms' ),
|
||||
'type' => 'string',
|
||||
'readonly' => false,
|
||||
),
|
||||
'created_by' => array(
|
||||
'description' => __( 'The user ID of the entry submitter.', 'gravityforms' ),
|
||||
'type' => 'integer',
|
||||
'readonly' => false,
|
||||
),
|
||||
'transaction_type' => array(
|
||||
'description' => __( 'The type of the transaction, if applicable.', 'gravityforms' ),
|
||||
'type' => 'string',
|
||||
'readonly' => false,
|
||||
),
|
||||
'status' => array(
|
||||
'description' => __( 'The status of the entry.', 'gravityforms' ),
|
||||
'type' => 'string',
|
||||
'readonly' => false,
|
||||
),
|
||||
),
|
||||
);
|
||||
return $schema;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array with field labels and choice labels
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
* @param $form
|
||||
* @param array $args
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function get_entry_labels( $form, $args = array() ) {
|
||||
$defaults = array(
|
||||
'field_ids' => false,
|
||||
);
|
||||
|
||||
$args = wp_parse_args( $args, $defaults );
|
||||
|
||||
$fields = $this->filter_fields( $form, $args['field_ids'] );
|
||||
|
||||
$labels = array();
|
||||
|
||||
// replace the values/ids with text labels
|
||||
foreach ( $fields as $field ) {
|
||||
/* @var GF_Field $field */
|
||||
$field_id = $field->id;
|
||||
$field = GFFormsModel::get_field( $form, $field_id );
|
||||
$input_type = $field->get_input_type();
|
||||
if ( in_array( $input_type , array( 'likert', 'rank', 'rating' ) ) ) {
|
||||
$label = array();
|
||||
$choice_labels = array();
|
||||
foreach ( $field->choices as $choice ) {
|
||||
$choice_labels[ $choice['value'] ] = $choice['text'];
|
||||
}
|
||||
if ( $input_type = 'likert' && $field->gsurveyLikertEnableMultipleRows ) {
|
||||
/* @var GF_Field_Likert $field */
|
||||
$label = array(
|
||||
'label' => $field->label,
|
||||
'cols' => $choice_labels,
|
||||
'rows' => array(),
|
||||
);
|
||||
foreach ( $field->gsurveyLikertRows as $row ) {
|
||||
$label['rows'][ $row['value'] ] = $row['text'];
|
||||
}
|
||||
} else {
|
||||
$label['label'] = $field->label;
|
||||
$label['choices'] = $choice_labels;
|
||||
}
|
||||
} else {
|
||||
$inputs = $field->get_entry_inputs();
|
||||
|
||||
if ( empty( $inputs ) ) {
|
||||
$label = $field->get_field_label( false, null );
|
||||
} else {
|
||||
$label = array();
|
||||
$label[ (string) $field->id ] = $field->get_field_label( false, null );
|
||||
foreach ( $inputs as $input ) {
|
||||
$label[ (string) $input['id'] ] = $input['label'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$labels[ $field->id ] = $label;
|
||||
}
|
||||
|
||||
return $labels;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters the form array, returning only the fields matching the specified list of $field_ids
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
* @param array $form The form array
|
||||
* @param array $field_ids The list of fields to be returned
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function filter_fields( $form, $field_ids ) {
|
||||
$fields = $form['fields'];
|
||||
if ( is_array( $field_ids ) && ! empty( $field_ids ) ) {
|
||||
foreach ( $fields as $key => $field ) {
|
||||
$found = false;
|
||||
foreach ( $field_ids as $field_id ) {
|
||||
if ( intval( $field_id ) == $field->id ) {
|
||||
$found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( ! $found ) {
|
||||
unset( $fields[ $key ] );
|
||||
}
|
||||
}
|
||||
$fields = array_values( $fields );
|
||||
}
|
||||
return $fields;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,281 @@
|
||||
<?php
|
||||
if ( ! class_exists( 'GFForms' ) ) {
|
||||
die();
|
||||
}
|
||||
|
||||
|
||||
class GF_REST_Form_Feeds_Controller extends GF_REST_Controller {
|
||||
|
||||
/**
|
||||
* @since 2.4
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $rest_base = 'forms/(?P<form_id>[\d]+)/feeds';
|
||||
|
||||
/**
|
||||
* Register the routes for the objects of the controller.
|
||||
*
|
||||
* @since 2.4
|
||||
*/
|
||||
public function register_routes() {
|
||||
|
||||
$namespace = $this->namespace;
|
||||
|
||||
$base = $this->rest_base;
|
||||
|
||||
register_rest_route( $namespace, '/' . $base, array(
|
||||
array(
|
||||
'methods' => WP_REST_Server::READABLE,
|
||||
'callback' => array( $this, 'get_items' ),
|
||||
'permission_callback' => array( $this, 'get_items_permissions_check' ),
|
||||
'args' => $this->get_collection_params(),
|
||||
),
|
||||
array(
|
||||
'methods' => WP_REST_Server::CREATABLE,
|
||||
'callback' => array( $this, 'create_item' ),
|
||||
'permission_callback' => array( $this, 'create_item_permissions_check' ),
|
||||
'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::CREATABLE ),
|
||||
),
|
||||
) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a collection of feeds for the form.
|
||||
*
|
||||
* @since 2.4
|
||||
*
|
||||
* @param WP_REST_Request $request Full data about the request.
|
||||
*
|
||||
* @return WP_Error|WP_REST_Response
|
||||
*/
|
||||
public function get_items( $request ) {
|
||||
|
||||
$form_id = $request['form_id'];
|
||||
|
||||
$addon_slug = $request['addon'];
|
||||
|
||||
$feed_ids = $request['include'];
|
||||
|
||||
if ( ! empty( $feed_ids ) ) {
|
||||
if ( ! is_array( $feed_ids ) ) {
|
||||
$feed_ids = array( $feed_ids );
|
||||
}
|
||||
$feed_ids = array_map( 'absint', $feed_ids );
|
||||
}
|
||||
|
||||
$feeds = GFAPI::get_feeds( $feed_ids, $form_id, $addon_slug );
|
||||
|
||||
if ( is_wp_error( $feeds ) ) {
|
||||
return $feeds;
|
||||
}
|
||||
|
||||
return new WP_REST_Response( $feeds, 200 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Create one feed for the form.
|
||||
*
|
||||
* @since 2.4
|
||||
*
|
||||
* @param WP_REST_Request $request Full data about the request.
|
||||
*
|
||||
* @return WP_Error|WP_REST_Response
|
||||
*/
|
||||
public function create_item( $request ) {
|
||||
|
||||
$feed = $this->prepare_item_for_database( $request );
|
||||
|
||||
if ( is_wp_error( $feed ) ) {
|
||||
return $feed;
|
||||
}
|
||||
|
||||
$form_id = $feed['form_id'];
|
||||
|
||||
$feed_id = GFAPI::add_feed( $form_id, $feed['meta'], $feed['addon_slug'] );
|
||||
if ( is_wp_error( $feed_id ) ) {
|
||||
$feed_id->add_data( array( 'status' => $this->get_error_status( $feed_id ) ) );
|
||||
|
||||
return $feed_id;
|
||||
}
|
||||
|
||||
$feed['id'] = $feed_id;
|
||||
|
||||
$response = $this->prepare_item_for_response( $feed, $request );
|
||||
|
||||
$response->set_status( 201 );
|
||||
|
||||
$base = sprintf( 'forms/%d/feeds', $form_id );
|
||||
|
||||
$response->header( 'Location', rest_url( sprintf( '%s/%s/%d', $this->namespace, $base, $feed_id ) ) );
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare the item for the REST response.
|
||||
*
|
||||
* @since 2.4
|
||||
*
|
||||
*
|
||||
* @param mixed $item WordPress representation of the item.
|
||||
* @param WP_REST_Request $request Request object.
|
||||
*
|
||||
* @return WP_REST_Response $response
|
||||
*/
|
||||
public function prepare_item_for_response( $item, $request ) {
|
||||
return rest_ensure_response( $item );
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a given request has access to get items
|
||||
*
|
||||
* @since 2.4
|
||||
*
|
||||
* @param WP_REST_Request $request Full data about the request.
|
||||
*
|
||||
* @return WP_Error|bool
|
||||
*/
|
||||
public function get_items_permissions_check( $request ) {
|
||||
|
||||
/**
|
||||
* Filters the capability required to get feeds via the REST API.
|
||||
*
|
||||
* @since 2.4
|
||||
*
|
||||
* @param string|array $capability The capability required for this endpoint.
|
||||
* @param WP_REST_Request $request Full data about the request.
|
||||
*/
|
||||
$capability = apply_filters( 'gform_rest_api_capability_get_feeds', 'gravityforms_edit_forms', $request );
|
||||
|
||||
return $this->current_user_can_any( $capability, $request );
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a given request has access to create items
|
||||
*
|
||||
* @since 2.4
|
||||
*
|
||||
* @param WP_REST_Request $request Full data about the request.
|
||||
*
|
||||
* @return WP_Error|bool
|
||||
*/
|
||||
public function create_item_permissions_check( $request ) {
|
||||
|
||||
/**
|
||||
* Filters the capability required to create feeds via the REST API.
|
||||
*
|
||||
* @since 2.0-beta-2
|
||||
*
|
||||
* @param string|array $capability The capability required for this endpoint.
|
||||
* @param WP_REST_Request $request Full data about the request.
|
||||
*/
|
||||
$capability = apply_filters( 'gform_rest_api_capability_post_feeds', 'gravityforms_edit_forms', $request );
|
||||
|
||||
return $this->current_user_can_any( $capability, $request );
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare the item for create or update operation
|
||||
*
|
||||
* @since 2.4
|
||||
*
|
||||
* @param WP_REST_Request $request Request object
|
||||
*
|
||||
* @return WP_Error|array $prepared_item
|
||||
*/
|
||||
protected function prepare_item_for_database( $request ) {
|
||||
|
||||
$feed = $request->get_json_params();
|
||||
|
||||
if ( empty( $feed ) ) {
|
||||
return new WP_Error( 'missing_feed', __( 'Missing feed JSON', 'gravityforms' ), array( 'status' => 400 ) );
|
||||
}
|
||||
|
||||
$url_params = $request->get_url_params();
|
||||
|
||||
// Check the URL params first
|
||||
$form_id = rgar( $url_params, 'form_id' );
|
||||
|
||||
if ( empty( $form_id ) ) {
|
||||
$form_id = rgar( $feed, 'form_id' );
|
||||
}
|
||||
|
||||
if ( isset( $form_id ) ) {
|
||||
$feed['form_id'] = absint( $form_id );
|
||||
} else {
|
||||
return new WP_Error( 'missing_form_id', __( 'Missing form id', 'gravityforms' ), array( 'status' => 400 ) );
|
||||
}
|
||||
|
||||
$addon_slug = isset( $feed['addon_slug'] ) ? $feed['addon_slug'] : $request['addon'];
|
||||
if ( empty( $addon_slug ) ) {
|
||||
return new WP_Error( 'missing_addon_slug', __( 'Missing add-on slug', 'gravityforms' ), array( 'status' => 400 ) );
|
||||
}
|
||||
|
||||
|
||||
if ( empty( $feed['meta'] ) ) {
|
||||
return new WP_Error( 'missing_feed_meta', __( 'Missing feed meta', 'gravityforms' ), array( 'status' => 400 ) );
|
||||
}
|
||||
|
||||
return $feed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the query params for collections
|
||||
*
|
||||
* @since 2.4
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_collection_params() {
|
||||
return array(
|
||||
'include' => array(
|
||||
'description' => __( 'Limit result set to specific IDs.' ),
|
||||
'type' => 'array',
|
||||
'items' => array(
|
||||
'type' => 'integer',
|
||||
),
|
||||
'default' => array(),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Feed schema, conforming to JSON Schema.
|
||||
*
|
||||
* @since 2.4
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_item_schema() {
|
||||
$schema = array(
|
||||
'$schema' => 'http://json-schema.org/draft-04/schema#',
|
||||
'title' => 'feed',
|
||||
'type' => 'object',
|
||||
'properties' => array(
|
||||
'id' => array(
|
||||
'description' => __( 'Unique identifier for the feed.', 'gravityforms' ),
|
||||
'type' => 'integer',
|
||||
'readonly' => true,
|
||||
),
|
||||
'form_id' => array(
|
||||
'description' => __( 'The Form ID for the feed.', 'gravityforms' ),
|
||||
'type' => 'integer',
|
||||
'required' => true,
|
||||
'readonly' => true,
|
||||
),
|
||||
'meta' => array(
|
||||
'description' => __( 'The JSON string containing the feed meta.', 'gravityforms' ),
|
||||
'type' => 'object',
|
||||
'readonly' => false,
|
||||
),
|
||||
'addon_slug' => array(
|
||||
'description' => __( 'The add-on the feed belongs to.', 'gravityforms' ),
|
||||
'type' => 'integer',
|
||||
'readonly' => true,
|
||||
),
|
||||
),
|
||||
);
|
||||
return $schema;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
<?php
|
||||
if ( ! class_exists( 'GFForms' ) ) {
|
||||
die();
|
||||
}
|
||||
|
||||
class GF_REST_Form_Field_Filters_Controller extends GF_REST_Controller {
|
||||
|
||||
/**
|
||||
* The base of this controller's route.
|
||||
*
|
||||
* @since 2.4.22
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $rest_base = 'forms/(?P<form_id>[\d]+)/field-filters';
|
||||
|
||||
/**
|
||||
* Register the routes for the objects of the controller.
|
||||
*
|
||||
* @since 2.4.22
|
||||
*/
|
||||
public function register_routes() {
|
||||
register_rest_route( $this->namespace, '/' . $this->rest_base, array(
|
||||
array(
|
||||
'methods' => WP_REST_Server::READABLE,
|
||||
'callback' => array( $this, 'get_items' ),
|
||||
'permission_callback' => array( $this, 'get_items_permissions_check' ),
|
||||
'args' => $this->get_collection_params(),
|
||||
),
|
||||
) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the field filters for the specified form.
|
||||
*
|
||||
* @since 2.4.22
|
||||
*
|
||||
* @param WP_REST_Request $request Full data about the request.
|
||||
*
|
||||
* @return WP_Error|WP_REST_Response
|
||||
*/
|
||||
public function get_items( $request ) {
|
||||
$form = GFAPI::get_form( $request['form_id'] );
|
||||
|
||||
if ( ! $form ) {
|
||||
return new WP_Error( 'gf_not_found', __( 'Form not found', 'gravityforms' ), array( 'status' => 404 ) );
|
||||
}
|
||||
|
||||
if ( ! empty( $request['_admin_labels'] ) ) {
|
||||
/** @var GF_Field $field The field object. */
|
||||
foreach ( $form['fields'] as $field ) {
|
||||
$field->set_context_property( 'use_admin_label', true );
|
||||
}
|
||||
}
|
||||
|
||||
return new WP_REST_Response( GFCommon::get_field_filter_settings( $form ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the user for the current request has permission to get the field filters.
|
||||
*
|
||||
* @since 2.4.22
|
||||
*
|
||||
* @param WP_REST_Request $request Full data about the request.
|
||||
*
|
||||
* @return WP_Error|bool
|
||||
*/
|
||||
public function get_items_permissions_check( $request ) {
|
||||
/**
|
||||
* Filters the capability required to get the field filters via the REST API.
|
||||
*
|
||||
* @since 2.4.22
|
||||
*
|
||||
* @param string|array $capability The capability required for this endpoint.
|
||||
* @param WP_REST_Request $request Full data about the request.
|
||||
*/
|
||||
$capability = apply_filters( 'gform_rest_api_capability_get_field_filters', 'gravityforms_view_entries', $request );
|
||||
|
||||
return $this->current_user_can_any( $capability, $request );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of supported query params for this endpoint.
|
||||
*
|
||||
* @since 2.4.22
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_collection_params() {
|
||||
return array(
|
||||
'_admin_labels' => array(
|
||||
'description' => 'Whether to include the field admin labels in the response, if configured.',
|
||||
'type' => 'integer',
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
<?php
|
||||
if ( ! class_exists( 'GFForms' ) ) {
|
||||
die();
|
||||
}
|
||||
|
||||
|
||||
class GF_REST_Form_Results_Controller extends GF_REST_Controller {
|
||||
|
||||
/**
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $rest_base = 'forms/(?P<form_id>[\d]+)/results';
|
||||
|
||||
/**
|
||||
* Register the routes for the objects of the controller.
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*/
|
||||
public function register_routes() {
|
||||
|
||||
$namespace = $this->namespace;
|
||||
|
||||
$base = $this->rest_base;
|
||||
|
||||
register_rest_route( $namespace, '/' . $base, array(
|
||||
array(
|
||||
'methods' => WP_REST_Server::READABLE,
|
||||
'callback' => array( $this, 'get_items' ),
|
||||
'permission_callback' => array( $this, 'get_items_permissions_check' ),
|
||||
'args' => $this->get_collection_params(),
|
||||
),
|
||||
) );
|
||||
|
||||
register_rest_route( $namespace, '/' . $base . '/schema', array(
|
||||
'methods' => WP_REST_Server::READABLE,
|
||||
'callback' => array( $this, 'get_public_item_schema' ),
|
||||
'permission_callback' => '__return_true',
|
||||
) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a collection of results.
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
* @param WP_REST_Request $request Full data about the request.
|
||||
*
|
||||
* @return WP_Error|WP_REST_Response
|
||||
*/
|
||||
public function get_items( $request ) {
|
||||
$form_id = $request['form_id'];
|
||||
$search_params = $this->parse_entry_search_params( $request );
|
||||
$search_criteria = rgar( $search_params, 'search_criteria' );
|
||||
$args = array(
|
||||
'page_size' => 100,
|
||||
'time_limit' => 5,
|
||||
'wait' => 5,
|
||||
);
|
||||
$data = gf_results_cache()->get_results( $form_id, $search_criteria, $args );
|
||||
$response = $this->prepare_item_for_response( $data, $request );
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a given request has access to get items
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
* @param WP_REST_Request $request Full data about the request.
|
||||
*
|
||||
* @return WP_Error|bool
|
||||
*/
|
||||
public function get_items_permissions_check( $request ) {
|
||||
/**
|
||||
* Filters the capability required to get form results via the web API.
|
||||
*
|
||||
* @since 2.0-beta-2
|
||||
*
|
||||
* @param string|array $capability The capability required for this endpoint.
|
||||
* @param WP_REST_Request $request Full data about the request.
|
||||
*/
|
||||
$capability = apply_filters( 'gform_rest_api_capability_get_results', 'gravityforms_view_entries', $request );
|
||||
return $this->current_user_can_any( $capability, $request );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Prepare the item for the REST response
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
* @param mixed $item WordPress representation of the item.
|
||||
* @param WP_REST_Request $request Request object.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function prepare_item_for_response( $item, $request ) {
|
||||
|
||||
$response = new WP_REST_Response( $item, 200 );
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the query params for collections
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_collection_params() {
|
||||
return array(
|
||||
'search' => array(
|
||||
'description' => 'The search criteria.',
|
||||
'type' => 'string',
|
||||
'sanitize_callback' => 'sanitize_text_field',
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
<?php
|
||||
if ( ! class_exists( 'GFForms' ) ) {
|
||||
die();
|
||||
}
|
||||
|
||||
class GF_REST_Form_Submissions_Validation_Controller extends GF_REST_Controller {
|
||||
|
||||
/**
|
||||
* The base of this controller's route.
|
||||
*
|
||||
* @since 2.6.4
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $rest_base = 'forms/(?P<form_id>[\d]+)/submissions/validation';
|
||||
|
||||
/**
|
||||
* Registers the route.
|
||||
*
|
||||
* @since 2.6.4
|
||||
*/
|
||||
public function register_routes() {
|
||||
register_rest_route( $this->namespace, '/' . $this->rest_base, array(
|
||||
array(
|
||||
'methods' => WP_REST_Server::CREATABLE,
|
||||
'callback' => array( $this, 'validate_form' ),
|
||||
'permission_callback' => array( $this, 'validate_form_permissions_check' ),
|
||||
),
|
||||
) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates submitted values for the specified form.
|
||||
*
|
||||
* @since 2.6.4
|
||||
*
|
||||
* @param WP_REST_Request $request Full data about the request.
|
||||
*
|
||||
* @return WP_Error|WP_REST_Response
|
||||
*/
|
||||
public function validate_form( $request ) {
|
||||
$params = $request->get_json_params();
|
||||
$input_values = $params;
|
||||
|
||||
if ( empty( $params ) ) {
|
||||
$params = $request->get_body_params();
|
||||
$input_values = array(); // The input values are already in $_POST.
|
||||
}
|
||||
|
||||
$field_values = rgar( $params, 'field_values', array() );
|
||||
$target_page = rgar( $params, 'target_page', 0 );
|
||||
$source_page = rgar( $params, 'source_page', 1 );
|
||||
|
||||
$result = GFAPI::validate_form( rgar( $request->get_url_params(), 'form_id' ), $input_values, $field_values, $target_page, $source_page );
|
||||
|
||||
if ( is_wp_error( $result ) ) {
|
||||
return new WP_Error( $result->get_error_code(), $result->get_error_message(), array( 'status' => 400 ) );
|
||||
}
|
||||
|
||||
return $this->prepare_item_for_response( $result, $request );
|
||||
}
|
||||
|
||||
/**
|
||||
* All users can submit values for validation.
|
||||
*
|
||||
* @since 2.6.4
|
||||
*
|
||||
* @param WP_REST_Request $request Full data about the request.
|
||||
*
|
||||
* @return WP_Error|boolean
|
||||
*/
|
||||
public function validate_form_permissions_check( $request ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Prepares the item for the REST response.
|
||||
*
|
||||
* @since 2.6.4
|
||||
*
|
||||
* @param mixed $item WordPress representation of the item.
|
||||
* @param WP_REST_Request $request Request object.
|
||||
*
|
||||
* @return WP_REST_Response
|
||||
*/
|
||||
public function prepare_item_for_response( $item, $request ) {
|
||||
$status = $item['is_valid'] ? 200 : 400;
|
||||
|
||||
return new WP_REST_Response( $item, $status );
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,166 @@
|
||||
<?php
|
||||
if ( ! class_exists( 'GFForms' ) ) {
|
||||
die();
|
||||
}
|
||||
|
||||
|
||||
class GF_REST_Form_Submissions_Controller extends GF_REST_Controller {
|
||||
|
||||
/**
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $rest_base = 'forms/(?P<form_id>[\d]+)/submissions';
|
||||
|
||||
/**
|
||||
* Register the routes for the objects of the controller.
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*/
|
||||
public function register_routes() {
|
||||
|
||||
$namespace = $this->namespace;
|
||||
|
||||
$base = $this->rest_base;
|
||||
|
||||
register_rest_route( $namespace, '/' . $base, array(
|
||||
array(
|
||||
'methods' => WP_REST_Server::CREATABLE,
|
||||
'callback' => array( $this, 'create_item' ),
|
||||
'permission_callback' => array( $this, 'create_item_permissions_check' ),
|
||||
'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::CREATABLE ),
|
||||
),
|
||||
) );
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Create one item from the collection.
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
* @param WP_REST_Request $request Full data about the request.
|
||||
*
|
||||
* @return WP_Error|WP_REST_Response
|
||||
*/
|
||||
public function create_item( $request ) {
|
||||
if ( rgar( $request->get_query_params(), '_validate_only' ) ) {
|
||||
return ( new GF_REST_Form_Submissions_Validation_Controller() )->validate_form( $request );
|
||||
}
|
||||
|
||||
$form_id = $request['form_id'];
|
||||
|
||||
$params = $request->get_json_params();
|
||||
if ( empty( $params ) ) {
|
||||
$input_values = $request->get_body_params();
|
||||
$field_values = isset( $input_values['field_values'] ) ? $input_values['field_values'] : array();
|
||||
$target_page = isset( $input_values['target_page'] ) ? $input_values['target_page'] : 0;
|
||||
$source_page = isset( $input_values['source_page'] ) ? $input_values['source_page'] : 1;
|
||||
$input_values = array(); // The input values are already in $_POST
|
||||
} else {
|
||||
$input_values = $params;
|
||||
$field_values = isset( $params['field_values'] ) ? $params['field_values'] : array();
|
||||
$target_page = isset( $params['target_page'] ) ? $params['target_page'] : 0;
|
||||
$source_page = isset( $params['source_page'] ) ? $params['source_page'] : 1;
|
||||
}
|
||||
|
||||
$result = GFAPI::submit_form( $form_id, $input_values, $field_values, $target_page, $source_page );
|
||||
|
||||
if ( is_wp_error( $result ) ) {
|
||||
return new WP_Error( $result->get_error_code(), $result->get_error_message(), array( 'status' => 400 ) );
|
||||
}
|
||||
|
||||
if ( ! current_user_can( 'gravityforms_view_entries' ) && ! current_user_can( 'gravityforms_edit_entries' ) ) {
|
||||
unset( $result['entry_id'] );
|
||||
}
|
||||
|
||||
$response = $this->prepare_item_for_response( $result, $request );
|
||||
|
||||
if ( isset( $result['confirmation_type'] ) && $result['confirmation_type'] == 'redirect' ) {
|
||||
$response->header( 'Location', $result['confirmation_redirect'] );
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a given request has access to create items.
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
* @param WP_REST_Request $request Full data about the request.
|
||||
*
|
||||
* @return WP_Error|boolean
|
||||
*/
|
||||
public function create_item_permissions_check( $request ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Prepare the item for the REST response
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
* @param mixed $item WordPress representation of the item.
|
||||
* @param WP_REST_Request $request Request object.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function prepare_item_for_response( $item, $request ) {
|
||||
|
||||
$status = $item['is_valid'] ? 200 : 400;
|
||||
|
||||
$response = new WP_REST_Response( $item, $status );
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the query params for collections
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_collection_params() {
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Entry schema, conforming to JSON Schema.
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_item_schema() {
|
||||
$schema = array(
|
||||
'$schema' => 'http://json-schema.org/draft-04/schema#',
|
||||
'title' => 'form-submission',
|
||||
'type' => 'object',
|
||||
'properties' => array(
|
||||
'input_[Field ID]' => array(
|
||||
'description' => __( 'The input values.', 'gravityforms' ),
|
||||
'type' => 'string',
|
||||
),
|
||||
'field_values' => array(
|
||||
'description' => __( 'The field values.', 'gravityforms' ),
|
||||
'type' => array( 'string', 'array' ),
|
||||
),
|
||||
'target_page' => array(
|
||||
'description' => 'The target page number.',
|
||||
'type' => 'integer',
|
||||
),
|
||||
'source_page' => array(
|
||||
'description' => 'The source page number.',
|
||||
'type' => 'integer',
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
return $schema;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,455 @@
|
||||
<?php
|
||||
if ( ! class_exists( 'GFForms' ) ) {
|
||||
die();
|
||||
}
|
||||
|
||||
|
||||
class GF_REST_Forms_Controller extends GF_REST_Controller {
|
||||
|
||||
/**
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $rest_base = 'forms';
|
||||
|
||||
/**
|
||||
* Register the routes for the objects of the controller.
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*/
|
||||
public function register_routes() {
|
||||
|
||||
$namespace = $this->namespace;
|
||||
|
||||
$base = $this->rest_base;
|
||||
|
||||
register_rest_route( $namespace, '/' . $base, array(
|
||||
array(
|
||||
'methods' => WP_REST_Server::READABLE,
|
||||
'callback' => array( $this, 'get_items' ),
|
||||
'permission_callback' => array( $this, 'get_items_permissions_check' ),
|
||||
'args' => array(),
|
||||
),
|
||||
array(
|
||||
'methods' => WP_REST_Server::CREATABLE,
|
||||
'callback' => array( $this, 'create_item' ),
|
||||
'permission_callback' => array( $this, 'create_item_permissions_check' ),
|
||||
'args' => $this->get_endpoint_args_for_item_schema( true ),
|
||||
),
|
||||
) );
|
||||
register_rest_route( $namespace, '/' . $base . '/(?P<id>[\d]+)', array(
|
||||
array(
|
||||
'methods' => WP_REST_Server::READABLE,
|
||||
'callback' => array( $this, 'get_item' ),
|
||||
'permission_callback' => array( $this, 'get_item_permissions_check' ),
|
||||
'args' => array(
|
||||
'context' => array(
|
||||
'default' => 'view',
|
||||
),
|
||||
),
|
||||
),
|
||||
array(
|
||||
'methods' => 'PUT',
|
||||
'callback' => array( $this, 'update_item' ),
|
||||
'permission_callback' => array( $this, 'update_item_permissions_check' ),
|
||||
'args' => $this->get_endpoint_args_for_item_schema( false ),
|
||||
),
|
||||
array(
|
||||
'methods' => WP_REST_Server::DELETABLE,
|
||||
'callback' => array( $this, 'delete_item' ),
|
||||
'permission_callback' => array( $this, 'delete_item_permissions_check' ),
|
||||
'args' => array(
|
||||
'force' => array(
|
||||
'default' => false,
|
||||
),
|
||||
),
|
||||
),
|
||||
) );
|
||||
|
||||
register_rest_route( $namespace, '/' . $base . '/schema', array(
|
||||
'methods' => WP_REST_Server::READABLE,
|
||||
'callback' => array( $this, 'get_public_item_schema' ),
|
||||
'permission_callback' => '__return_true',
|
||||
) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a collection of items.
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
* @param WP_REST_Request $request Full data about the request.
|
||||
*
|
||||
* @return WP_Error|WP_REST_Response
|
||||
*/
|
||||
public function get_items( $request ) {
|
||||
|
||||
$form_ids = $request['include'];
|
||||
|
||||
if ( ! empty( $form_ids ) ) {
|
||||
if ( ! is_array( $form_ids ) ) {
|
||||
$form_ids = array( $form_ids );
|
||||
}
|
||||
$form_ids = array_map( 'absint', $form_ids );
|
||||
}
|
||||
|
||||
$data = array();
|
||||
if ( $form_ids && is_array( $form_ids ) ) {
|
||||
foreach ( $form_ids as $id ) {
|
||||
$form = GFAPI::get_form( $id );
|
||||
$data[ $id ] = $form;
|
||||
}
|
||||
} else {
|
||||
$forms = GFFormsModel::get_forms( true );
|
||||
foreach ( $forms as $form ) {
|
||||
|
||||
/**
|
||||
* Allows third-party code to omit form totals from the API response. This is useful for increasing
|
||||
* the performance of the endpoint when totals aren't required.
|
||||
*
|
||||
* @since 2.5
|
||||
*
|
||||
* @var bool $include_totals Whether to include totals; defaults to true.
|
||||
* @var object $form The current form object.
|
||||
*/
|
||||
$include_totals = gf_apply_filters( array( 'gform_rest_api_retrieve_form_totals', $form->id ), true, $form );
|
||||
|
||||
$form_id = $form->id;
|
||||
$form_info = array(
|
||||
'id' => $form_id,
|
||||
'title' => $form->title,
|
||||
);
|
||||
|
||||
if ( $include_totals ) {
|
||||
$totals = GFFormsModel::get_form_counts( $form_id );
|
||||
$form_info['entries'] = rgar( $totals, 'total' );
|
||||
}
|
||||
|
||||
$data[ $form_id ] = $form_info;
|
||||
}
|
||||
}
|
||||
|
||||
return new WP_REST_Response( $data, 200 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get one item from the collection.
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
* @param WP_REST_Request $request Full data about the request.
|
||||
*
|
||||
* @return WP_Error|WP_REST_Response
|
||||
*/
|
||||
public function get_item( $request ) {
|
||||
$form_id = $request['id'];
|
||||
$form = GFAPI::get_form( $form_id );
|
||||
|
||||
if ( $form ) {
|
||||
return new WP_REST_Response( $form, 200 );
|
||||
} else {
|
||||
return new WP_Error( 'gf_not_found', __( 'Form not found', 'gravityforms' ) );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create one item from the collection.
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
* @param WP_REST_Request $request Full data about the request.
|
||||
*
|
||||
* @return WP_Error|WP_REST_Request
|
||||
*/
|
||||
public function create_item( $request ) {
|
||||
|
||||
$form = $this->prepare_item_for_database( $request );
|
||||
|
||||
if ( is_wp_error( $form ) ) {
|
||||
return new WP_Error( $form->get_error_code(), $form->get_error_message(), array( 'status' => 400 ) );
|
||||
}
|
||||
|
||||
$form_id = GFAPI::add_form( $form );
|
||||
|
||||
if ( is_wp_error( $form_id ) ) {
|
||||
$status = $this->get_error_status( $form_id );
|
||||
return new WP_Error( $form_id->get_error_code(), $form_id->get_error_message(), array( 'status' => $status ) );
|
||||
}
|
||||
|
||||
$form = GFAPI::get_form( $form_id );
|
||||
|
||||
$response = $this->prepare_item_for_response( $form, $request );
|
||||
|
||||
$response = rest_ensure_response( $response );
|
||||
|
||||
$response->set_status( 201 );
|
||||
$response->header( 'Location', rest_url( sprintf( '%s/%s/%d', $this->namespace, $this->rest_base, $form_id ) ) );
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update one item from the collection
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
* @param WP_REST_Request $request Full data about the request.
|
||||
*
|
||||
* @return WP_Error|WP_REST_Request
|
||||
*/
|
||||
public function update_item( $request ) {
|
||||
$form_id = $request['id'];
|
||||
$form = $this->prepare_item_for_database( $request );
|
||||
|
||||
if ( is_wp_error( $form ) ) {
|
||||
return $form;
|
||||
}
|
||||
|
||||
$result = GFAPI::update_form( $form, $form_id );
|
||||
|
||||
if ( is_wp_error( $result ) ) {
|
||||
$status = $this->get_error_status( $result );
|
||||
return new WP_Error( $result->get_error_code(), $result->get_error_message(), array( 'status' => $status ) );
|
||||
}
|
||||
|
||||
$form = GFAPI::get_form( $form_id );
|
||||
|
||||
$response = $this->prepare_item_for_response( $form, $request );
|
||||
|
||||
return rest_ensure_response( $response );
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete one item from the collection
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
* @param WP_REST_Request $request Full data about the request.
|
||||
*
|
||||
* @return WP_Error|WP_REST_Request
|
||||
*/
|
||||
public function delete_item( $request ) {
|
||||
|
||||
$form_id = $request['id'];
|
||||
|
||||
$form = GFAPI::get_form( $form_id );
|
||||
if ( empty( $form ) ) {
|
||||
return new WP_Error( 'gf_form_invalid_id', __( 'Invalid form id.', 'gravityforms' ), array( 'status' => 404 ) );
|
||||
}
|
||||
|
||||
$force = isset( $request['force'] ) ? (bool) $request['force'] : false;
|
||||
|
||||
if ( $force ) {
|
||||
$result = GFAPI::delete_form( $form_id );
|
||||
|
||||
if ( is_wp_error( $result ) ) {
|
||||
$message = $result->get_error_message();
|
||||
return new WP_Error( 'gf_cannot_delete', $message, array( 'status' => 500 ) );
|
||||
}
|
||||
|
||||
$previous = $this->prepare_item_for_response( $form, $request );
|
||||
$response = new WP_REST_Response();
|
||||
$response->set_data( array( 'deleted' => true, 'previous' => $previous->get_data() ) );
|
||||
|
||||
} else {
|
||||
if ( rgar( $form, 'is_trash' ) ) {
|
||||
$message = __( 'The form has already been deleted.', 'gravityforms' );
|
||||
return new WP_Error( 'gf_already_trashed', $message, array( 'status' => 410 ) );
|
||||
}
|
||||
|
||||
// Trash the form
|
||||
GFAPI::update_form_property( $form_id, 'is_trash', 1 );
|
||||
|
||||
$form = GFAPI::get_form( $form_id );
|
||||
$response = rest_ensure_response( $form );
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a given request has access to get items
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
* @param WP_REST_Request $request Full data about the request.
|
||||
*
|
||||
* @return WP_Error|bool
|
||||
*/
|
||||
public function get_items_permissions_check( $request ) {
|
||||
/**
|
||||
* Filters the capability required to get forms via the REST API.
|
||||
*
|
||||
* @since 2.4
|
||||
*
|
||||
* @param string|array $capability The capability required for this endpoint.
|
||||
* @param WP_REST_Request $request Full data about the request.
|
||||
*/
|
||||
$capability = apply_filters( 'gform_rest_api_capability_get_forms', 'gravityforms_edit_forms', $request );
|
||||
return $this->current_user_can_any( $capability, $request );
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a given request has access to get a specific item
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
* @param WP_REST_Request $request Full data about the request.
|
||||
*
|
||||
* @return WP_Error|bool
|
||||
*/
|
||||
public function get_item_permissions_check( $request ) {
|
||||
/**
|
||||
* Filters the capability required to get forms via the REST API.
|
||||
*
|
||||
* @since 2.4
|
||||
*
|
||||
* @param string|array $capability The capability required for this endpoint.
|
||||
* @param WP_REST_Request $request Full data about the request.
|
||||
*/
|
||||
$capability = apply_filters( 'gform_rest_api_capability_get_forms', 'gravityforms_edit_forms', $request );
|
||||
return $this->current_user_can_any( $capability, $request );
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a given request has access to create items
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
* @param WP_REST_Request $request Full data about the request.
|
||||
*
|
||||
* @return WP_Error|bool
|
||||
*/
|
||||
public function create_item_permissions_check( $request ) {
|
||||
/**
|
||||
* Filters the capability required to create forms via the REST API.
|
||||
*
|
||||
* @since 2.4
|
||||
*
|
||||
* @param string|array $capability The capability required for this endpoint.
|
||||
* @param WP_REST_Request $request Full data about the request.
|
||||
*/
|
||||
$capability = apply_filters( 'gform_rest_api_capability_post_forms', 'gravityforms_create_form', $request );
|
||||
return $this->current_user_can_any( $capability, $request );
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a given request has access to update a specific item.
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
* @param WP_REST_Request $request Full data about the request.
|
||||
*
|
||||
* @return WP_Error|bool
|
||||
*/
|
||||
public function update_item_permissions_check( $request ) {
|
||||
/**
|
||||
* Filters the capability required to update forms via the REST API.
|
||||
*
|
||||
* @since 2.4
|
||||
*
|
||||
* @param string|array $capability The capability required for this endpoint.
|
||||
* @param WP_REST_Request $request Full data about the request.
|
||||
*/
|
||||
$capability = apply_filters( 'gform_rest_api_capability_put_forms', 'gravityforms_create_form', $request );
|
||||
return $this->current_user_can_any( $capability, $request );
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a given request has access to delete a specific item.
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
* @param WP_REST_Request $request Full data about the request.
|
||||
*
|
||||
* @return WP_Error|bool
|
||||
*/
|
||||
public function delete_item_permissions_check( $request ) {
|
||||
/**
|
||||
* Filters the capability required to delete forms via the REST API.
|
||||
*
|
||||
* @since 2.4
|
||||
*
|
||||
* @param string|array $capability The capability required for this endpoint.
|
||||
* @param WP_REST_Request $request Full data about the request.
|
||||
*/
|
||||
$capability = apply_filters( 'gform_rest_api_capability_delete_forms', 'gravityforms_delete_forms', $request );
|
||||
return $this->current_user_can_any( $capability, $request );
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare the item for create or update operation.
|
||||
*
|
||||
* The Form object must be sent as a JSON string in order to preserve boolean values.
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
* @param WP_REST_Request $request Request object
|
||||
*
|
||||
* @return WP_Error|array $prepared_item
|
||||
*/
|
||||
protected function prepare_item_for_database( $request ) {
|
||||
$form_json = $request->get_json_params();
|
||||
if ( ! $form_json ) {
|
||||
|
||||
$form_json = $request->get_body_params();
|
||||
|
||||
if ( empty( $form_json ) || is_array( $form_json ) ) {
|
||||
return new WP_Error( 'missing_form', __( 'The Form object must be sent as a JSON string in the request body with the content-type header set to application/json.', 'gravityforms' ) );
|
||||
}
|
||||
}
|
||||
$form = ( is_string( $form_json ) ) ? json_decode( $form_json, true ) : $form_json;
|
||||
|
||||
$form = GFFormsModel::convert_field_objects( $form );
|
||||
|
||||
$form = GFFormsModel::sanitize_settings( $form );
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare the item for the REST response
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
* @param mixed $item WordPress representation of the item.
|
||||
* @param WP_REST_Request $request Request object.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function prepare_item_for_response( $item, $request ) {
|
||||
|
||||
$response = new WP_REST_Response( $item, 200 );
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the query params for collections
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_collection_params() {
|
||||
return array(
|
||||
'page' => array(
|
||||
'description' => 'Current page of the collection.',
|
||||
'type' => 'integer',
|
||||
'default' => 1,
|
||||
'sanitize_callback' => 'absint',
|
||||
),
|
||||
'per_page' => array(
|
||||
'description' => 'Maximum number of items to be returned in result set.',
|
||||
'type' => 'integer',
|
||||
'default' => 10,
|
||||
'sanitize_callback' => 'absint',
|
||||
),
|
||||
'search' => array(
|
||||
'description' => 'The search criteria.',
|
||||
'type' => 'array',
|
||||
'sanitize_callback' => 'sanitize_text_field',
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,384 @@
|
||||
<?php
|
||||
if ( ! class_exists( 'GFForms' ) ) {
|
||||
die();
|
||||
}
|
||||
|
||||
|
||||
class GF_REST_Notes_Controller extends GF_REST_Entry_Notes_Controller {
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $rest_base = 'notes';
|
||||
|
||||
/**
|
||||
* Register the routes for the objects of the controller.
|
||||
*/
|
||||
public function register_routes() {
|
||||
|
||||
$namespace = $this->namespace;
|
||||
|
||||
$base = $this->rest_base;
|
||||
|
||||
register_rest_route(
|
||||
$namespace,
|
||||
'/' . $base,
|
||||
array(
|
||||
array(
|
||||
'methods' => WP_REST_Server::READABLE,
|
||||
'callback' => array( $this, 'get_items' ),
|
||||
'permission_callback' => array( $this, 'get_items_permissions_check' ),
|
||||
'args' => $this->get_collection_params(),
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
register_rest_route(
|
||||
$namespace,
|
||||
'/' . $base . '/(?P<note_id>[\d]+)',
|
||||
array(
|
||||
array(
|
||||
'methods' => WP_REST_Server::READABLE,
|
||||
'callback' => array( $this, 'get_item' ),
|
||||
'permission_callback' => array( $this, 'get_item_permissions_check' ),
|
||||
'args' => $this->get_collection_params(),
|
||||
),
|
||||
array(
|
||||
'methods' => 'PUT',
|
||||
'callback' => array( $this, 'update_item' ),
|
||||
'permission_callback' => array( $this, 'update_item_permissions_check' ),
|
||||
'args' => $this->get_endpoint_args_for_item_schema( false ),
|
||||
),
|
||||
array(
|
||||
'methods' => WP_REST_Server::DELETABLE,
|
||||
'callback' => array( $this, 'delete_item' ),
|
||||
'permission_callback' => array( $this, 'delete_item_permissions_check' ),
|
||||
'args' => $this->get_collection_params(),
|
||||
),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get one note.
|
||||
*
|
||||
* @since 2.4.18
|
||||
*
|
||||
* @param WP_REST_Request $request Full data about the request.
|
||||
*
|
||||
* @return WP_Error|WP_REST_Response
|
||||
*/
|
||||
public function get_item( $request ) {
|
||||
|
||||
$note_id = $request->get_param( 'note_id' );
|
||||
|
||||
$note = GFAPI::get_note( $note_id );
|
||||
|
||||
if ( is_wp_error( $note ) ) {
|
||||
return new WP_Error( 'gf_note_invalid_id', __( 'Invalid note id.', 'gravityforms' ), array( 'status' => 404 ) );
|
||||
}
|
||||
|
||||
$data = $this->prepare_item_for_response( $note, $request );
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get multiple notes.
|
||||
*
|
||||
* @since 2.4.18
|
||||
*
|
||||
* @param WP_REST_Request $request Full data about the request.
|
||||
*
|
||||
* @return WP_Error|WP_REST_Response
|
||||
*/
|
||||
public function get_items( $request ) {
|
||||
$criteria = $request->get_params();
|
||||
|
||||
$allowed_criteria = array(
|
||||
'entry_id',
|
||||
'user_id',
|
||||
'note_type',
|
||||
'sub_type',
|
||||
'user_name'
|
||||
);
|
||||
|
||||
$search_criteria = array();
|
||||
|
||||
foreach ( $criteria as $key => $value ) {
|
||||
if ( in_array( $key, $allowed_criteria ) ) {
|
||||
$search_criteria[$key] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
$sorting = '';
|
||||
if ( isset( $criteria['sorting'] ) ) {
|
||||
$sorting = $criteria['sorting'];
|
||||
}
|
||||
|
||||
$notes = GFAPI::get_notes( $search_criteria, $sorting );
|
||||
|
||||
if ( is_wp_error( $notes ) ) {
|
||||
return new WP_Error( 'gf_entry_invalid_notes', __( 'Error retrieving notes.', 'gravityforms' ), array( 'status' => 404 ) );
|
||||
}
|
||||
|
||||
if ( ! is_array( $notes ) || empty( $notes ) ) {
|
||||
return array();
|
||||
}
|
||||
|
||||
$data = array();
|
||||
|
||||
foreach ( $notes as $note ) {
|
||||
$data[ $note->id ] = $note;
|
||||
}
|
||||
|
||||
$response = new WP_REST_Response( $data, 200 );
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create one note.
|
||||
*
|
||||
* @since 2.4.18
|
||||
*
|
||||
* @param WP_REST_Request $request Full data about the request.
|
||||
*
|
||||
* @return WP_Error|WP_REST_Request
|
||||
*/
|
||||
public function create_item( $request ) {
|
||||
|
||||
$note = $this->prepare_item_for_database( $request );
|
||||
$entry_id = $request->get_param( 'entry_id' );
|
||||
|
||||
if ( is_wp_error( $note ) ) {
|
||||
return $note;
|
||||
}
|
||||
|
||||
$note_id = GFAPI::add_note( $entry_id, $note['user_id'], $note['user_name'], $note['note'] );
|
||||
|
||||
if ( is_wp_error( $note_id ) ) {
|
||||
$status = $this->get_error_status( $note_id );
|
||||
return new WP_Error( $note_id->get_error_code(), $note_id->get_error_message(), array( 'status' => $status ) );
|
||||
}
|
||||
|
||||
$note['id'] = $note_id;
|
||||
|
||||
$note = $this->prepare_note_for_response( $note_id );
|
||||
$response = rest_ensure_response( $note );
|
||||
$response->set_status( 201 );
|
||||
$base = sprintf( 'entries/%d/notes/', $note_id );
|
||||
$response->header( 'Location', rest_url( sprintf( '%s/%s/%d', $this->namespace, $base, $note_id ) ) );
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update one note.
|
||||
*
|
||||
* @since 2.4.18
|
||||
*
|
||||
* @param WP_REST_Request $request Full data about the request.
|
||||
*
|
||||
* @return WP_Error|WP_REST_Response
|
||||
*/
|
||||
public function update_item( $request ) {
|
||||
$note = $this->prepare_item_for_database( $request );
|
||||
$note['id'] = $request['note_id'];
|
||||
|
||||
if ( is_wp_error( $note ) ) {
|
||||
return $note;
|
||||
}
|
||||
|
||||
$result = GFAPI::update_note( $note, $request->get_param( 'note_id' ) );
|
||||
|
||||
if ( is_wp_error( $result ) ) {
|
||||
$status = $this->get_error_status( $result );
|
||||
return new WP_Error( $result->get_error_code(), $result->get_error_message(), array( 'status' => $status ) );
|
||||
}
|
||||
|
||||
$updated_note = GFAPI::get_note( $note['id'] );
|
||||
|
||||
$response = $this->prepare_item_for_response( $updated_note, $request );
|
||||
$response->set_status( 201 );
|
||||
$base = sprintf( 'entries/%d/notes/', $note['id'] );
|
||||
$response->header( 'Location', rest_url( sprintf( '%s/%s/%d', $this->namespace, $base, $note['id'] ) ) );
|
||||
|
||||
return rest_ensure_response( $response );
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete one note.
|
||||
*
|
||||
* @since 2.4.18
|
||||
*
|
||||
* @param WP_REST_Request $request Full data about the request.
|
||||
*
|
||||
* @return WP_Error|WP_REST_Response
|
||||
*/
|
||||
public function delete_item( $request ) {
|
||||
$note_id = $request['note_id'];
|
||||
|
||||
$note = GFAPI::get_note( $note_id );
|
||||
if ( is_wp_error( $note ) ) {
|
||||
return new WP_Error( 'gf_entry_invalid_id', __( 'Invalid note id.', 'gravityforms' ), array( 'status' => 404 ) );
|
||||
}
|
||||
|
||||
$result = GFAPI::delete_note( $note_id );
|
||||
|
||||
if ( is_wp_error( $result ) ) {
|
||||
$message = $result->get_error_message();
|
||||
return new WP_Error( 'gf_cannot_delete', $message, array( 'status' => 500 ) );
|
||||
}
|
||||
|
||||
$previous = $this->prepare_item_for_response( $note, $request );
|
||||
$response = new WP_REST_Response();
|
||||
$response->set_data(
|
||||
array(
|
||||
'deleted' => true,
|
||||
'previous' => $previous->get_data(),
|
||||
)
|
||||
);
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a given request has access to get items.
|
||||
*
|
||||
* @since 2.4.18
|
||||
*
|
||||
* @param WP_REST_Request $request Full data about the request.
|
||||
*
|
||||
* @return WP_Error|bool
|
||||
*/
|
||||
public function get_items_permissions_check( $request ) {
|
||||
return parent::get_items_permissions_check( $request );
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a given request has access to get a specific item.
|
||||
*
|
||||
* @since 2.4.18
|
||||
*
|
||||
* @param WP_REST_Request $request Full data about the request.
|
||||
*
|
||||
* @return WP_Error|bool
|
||||
*/
|
||||
public function get_item_permissions_check( $request ) {
|
||||
return parent::get_item_permissions_check( $request );
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a given request has access to create items.
|
||||
*
|
||||
* @since 2.4-.18
|
||||
*
|
||||
* @param WP_REST_Request $request Full data about the request.
|
||||
*
|
||||
* @return WP_Error|bool
|
||||
*/
|
||||
public function create_item_permissions_check( $request ) {
|
||||
|
||||
/**
|
||||
* Filters the capability required to create entries via the REST API.
|
||||
*
|
||||
* @since 2.4.18
|
||||
*
|
||||
* @param string|array $capability The capability required for this endpoint.
|
||||
* @param WP_REST_Request $request Full data about the request.
|
||||
*/
|
||||
$capability = apply_filters( 'gform_rest_api_capability_post_notes', 'gravityforms_edit_entry_notes', $request );
|
||||
|
||||
return $this->current_user_can_any( $capability, $request );
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a given request has access to update a specific item.
|
||||
*
|
||||
* @since 2.4.18
|
||||
*
|
||||
* @param WP_REST_Request $request Full data about the request.
|
||||
*
|
||||
* @return WP_Error|bool
|
||||
*/
|
||||
public function update_item_permissions_check( $request ) {
|
||||
return parent::update_item_permissions_check( $request );
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a given request has access to delete a specific item.
|
||||
*
|
||||
* @since 2.4.18
|
||||
*
|
||||
* @param WP_REST_Request $request Full data about the request.
|
||||
*
|
||||
* @return WP_Error|bool
|
||||
*/
|
||||
public function delete_item_permissions_check( $request ) {
|
||||
return parent::delete_item_permissions_check( $request );
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare the item for create or update operation.
|
||||
*
|
||||
* @since 2.4.18
|
||||
*
|
||||
* @param WP_REST_Request $request Request object.
|
||||
*
|
||||
* @return WP_Error|array $prepared_item.
|
||||
*/
|
||||
protected function prepare_item_for_database( $request ) {
|
||||
|
||||
$note = $request->get_json_params();
|
||||
|
||||
if ( empty( $note ) ) {
|
||||
return new WP_Error( 'missing_entry', __( 'Missing entry JSON', 'gravityforms' ) );
|
||||
}
|
||||
|
||||
$note['user_id'] = intval( $note['user_id'] );
|
||||
$note['note'] = wp_kses_post( $note['value'] );
|
||||
|
||||
return $note;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare the item for the REST response.
|
||||
*
|
||||
* @since 2.4.18
|
||||
*
|
||||
* @param mixed $item WordPress representation of the item.
|
||||
* @param WP_REST_Request $request Request object.
|
||||
*
|
||||
* @return WP_REST_Response Returns the item wrapped in a WP_REST_Response object
|
||||
*/
|
||||
public function prepare_item_for_response( $item, $request ) {
|
||||
|
||||
$item = $this->prepare_note_for_response( $item->id );
|
||||
|
||||
$response = new WP_REST_Response( $item, 200 );
|
||||
return $response;
|
||||
}
|
||||
|
||||
/***
|
||||
* Prepares note for REST API response, decoding or unserializing appropriate fields.
|
||||
*
|
||||
* @since 2.4.18
|
||||
*
|
||||
* @param int $note_id The note id.
|
||||
*
|
||||
* @return bool|array Returns the entry array ready to be send in the REST API response.
|
||||
*/
|
||||
public function prepare_note_for_response( $note_id ) {
|
||||
|
||||
$note = GFAPI::get_note( $note_id );
|
||||
|
||||
if ( is_wp_error( $note ) || ! isset( $note->ID ) ) {
|
||||
return $note;
|
||||
}
|
||||
|
||||
return $note;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,436 @@
|
||||
<?php
|
||||
if ( ! class_exists( 'GFForms' ) ) {
|
||||
die();
|
||||
}
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Abstract Rest Controller Class
|
||||
*
|
||||
* @author Rocketgenius
|
||||
* @category API
|
||||
* @package Rocketgenius/Abstracts
|
||||
* @extends WP_REST_Controller
|
||||
*/
|
||||
abstract class GF_REST_Controller extends WP_REST_Controller {
|
||||
/**
|
||||
* Endpoint namespace.
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $namespace = 'gf/v2';
|
||||
|
||||
/**
|
||||
* Route base.
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $rest_base = '';
|
||||
|
||||
/**
|
||||
* Indicates if the capability validation request has been logged.
|
||||
*
|
||||
* Without this the other registered methods for the route will also be logged when rest_send_allow_header() in WP rest-api.php runs.
|
||||
*
|
||||
* @since 2.4.11
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $_validate_caps_logged = false;
|
||||
|
||||
/**
|
||||
* Parses the entry search, sort and paging parameters from the request
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
* @param WP_REST_Request $request Full data about the request.
|
||||
*
|
||||
* @return array Returns an associative array with the "search_criteria", "paging" and "sorting" keys appropriately populated.
|
||||
*/
|
||||
public function parse_entry_search_params( $request ) {
|
||||
|
||||
// Sorting parameters
|
||||
$sorting_param = $request->get_param( 'sorting' );
|
||||
$sort_key = isset( $sorting_param['key'] ) && ! empty( $sorting_param['key'] ) ? $sorting_param['key'] : 'id';
|
||||
$sort_dir = isset( $sorting_param['direction'] ) && ! empty( $sorting_param['direction'] ) ? $sorting_param['direction'] : 'DESC';
|
||||
$sorting = array( 'key' => $sort_key, 'direction' => $sort_dir );
|
||||
if ( isset( $sorting_param['is_numeric'] ) ) {
|
||||
$sorting['is_numeric'] = $sorting_param['is_numeric'];
|
||||
}
|
||||
|
||||
// paging parameters
|
||||
$paging_param = $request->get_param( 'paging' );
|
||||
$page_size = isset( $paging_param['page_size'] ) ? intval( $paging_param['page_size'] ) : 10;
|
||||
if ( isset( $paging_param['current_page'] ) ) {
|
||||
$current_page = intval( $paging_param['current_page'] );
|
||||
$offset = $page_size * ( $current_page - 1 );
|
||||
} else {
|
||||
$offset = isset( $paging_param['offset'] ) ? intval( $paging_param['offset'] ) : 0;
|
||||
}
|
||||
|
||||
$paging = array( 'offset' => $offset, 'page_size' => $page_size );
|
||||
|
||||
$search = $request->get_param( 'search' );
|
||||
if ( isset( $search ) ) {
|
||||
if ( ! is_array( $search ) ) {
|
||||
$search = urldecode( ( stripslashes( $search ) ) );
|
||||
$search = json_decode( $search, true );
|
||||
}
|
||||
} else {
|
||||
$search = array();
|
||||
}
|
||||
|
||||
if ( ! isset( $search['status'] ) ) {
|
||||
$search['status'] = 'active';
|
||||
}
|
||||
|
||||
$params = array(
|
||||
'search_criteria' => $search,
|
||||
'paging' => $paging,
|
||||
'sorting' => $sorting,
|
||||
);
|
||||
|
||||
$form_ids = $request->get_param( 'form_ids' );
|
||||
|
||||
if ( isset( $form_ids ) ) {
|
||||
$params['form_ids'] = $form_ids;
|
||||
}
|
||||
|
||||
return $params;
|
||||
}
|
||||
|
||||
/**
|
||||
* JSON encodes list fields in the specified $entry and returns the new $entry
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
* @param array $entry The entry object
|
||||
*
|
||||
* @return array Returns the $entry array with the list fields json encoded
|
||||
*/
|
||||
public function maybe_json_encode_list_fields( $entry ) {
|
||||
$form_id = $entry['form_id'];
|
||||
$form = GFAPI::get_form( $form_id );
|
||||
if ( ! empty( $form['fields'] ) && is_array( $form['fields'] ) ) {
|
||||
foreach ( $form['fields'] as $field ) {
|
||||
/* @var GF_Field $field */
|
||||
if ( $field->get_input_type() == 'list' ) {
|
||||
$new_value = maybe_unserialize( $entry[ $field->id ] );
|
||||
|
||||
if ( ! $this->is_json( $new_value ) ) {
|
||||
$new_value = json_encode( $new_value );
|
||||
}
|
||||
|
||||
$entry[ $field->id ] = $new_value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $entry;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the specified values is a JSON encoded string
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
* @param mixed $value The value to be checked
|
||||
*
|
||||
* @return bool True if the speficied value is JSON encoded. False otherwise
|
||||
*/
|
||||
public static function is_json( $value ) {
|
||||
if ( is_string( $value ) && in_array( substr( $value, 0, 1 ), array( '{', '[' ) ) && is_array( json_decode( $value, ARRAY_A ) ) ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters an entry, removing fields that aren't in the list of specified $field_ids
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
* @param array $entry The entry to be filtered
|
||||
* @param array $field_ids The field IDs to be kept in the entry
|
||||
*
|
||||
* @return array Returns the entry array, containing only the field_ids specified in the $field_ids array.
|
||||
*/
|
||||
public static function filter_entry_fields( $entry, $field_ids ) {
|
||||
|
||||
if ( ! is_array( $field_ids ) ) {
|
||||
$field_ids = array( $field_ids );
|
||||
}
|
||||
$new_entry = array();
|
||||
foreach ( $entry as $key => $val ) {
|
||||
if ( in_array( $key, $field_ids ) || ( is_numeric( $key ) && in_array( intval( $key ), $field_ids ) ) ) {
|
||||
$new_entry[ $key ] = $val;
|
||||
}
|
||||
}
|
||||
|
||||
return $new_entry;
|
||||
}
|
||||
|
||||
/***
|
||||
* Prepares entry for REST API response, decoding or unserializing appropriate fields
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
* @param array $entry The entry array
|
||||
*
|
||||
* @return bool|array Returns the entry array ready to be send in the REST API response.
|
||||
*/
|
||||
public function prepare_entry_for_response( $entry ) {
|
||||
|
||||
if ( is_wp_error( $entry ) || ! isset( $entry['form_id'] ) ) {
|
||||
return $entry;
|
||||
}
|
||||
|
||||
$form = GFAPI::get_form( $entry['form_id'] );
|
||||
foreach ( $form['fields'] as $field ) {
|
||||
|
||||
if ( empty( $entry[ $field->id ] ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( $field instanceof GF_Field_MultiSelect ) {
|
||||
|
||||
$entry[ $field->id ] = $field->to_array( $entry[ $field->id ] );
|
||||
|
||||
} elseif ( $field instanceof GF_Field_FileUpload && $field->multipleFiles ) {
|
||||
|
||||
$entry[ $field->id ] = json_decode( $entry[ $field->id ] );
|
||||
|
||||
} elseif ( $field instanceof GF_Field_List ) {
|
||||
|
||||
$entry[ $field->id ] = maybe_unserialize( $entry[ $field->id ] );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return $entry;
|
||||
}
|
||||
|
||||
/***
|
||||
* Determines if the value of the specified field is stored in JSON format
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
* @param GF_Field $field The field to be checked
|
||||
*
|
||||
* @return bool Returns true if the specified field's value is stored in JSON format. Retruns false otherwise.
|
||||
*/
|
||||
public function is_field_value_json( $field ) {
|
||||
|
||||
$input_type = $field->get_input_type();
|
||||
|
||||
if ( in_array( $input_type, array( 'multiselect', 'list' ) ) ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ( $input_type == 'fileupload' && $field->multipleFiles ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Serializes list fields in the specified $entry array.
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
* @param array $entry The entry array
|
||||
* @param null $form_id The current form id
|
||||
*
|
||||
* @return array Returns the $entry array with all it's list fields serialized.
|
||||
*/
|
||||
public function maybe_serialize_list_fields( $entry, $form_id = null ) {
|
||||
if ( empty( $form_id ) ) {
|
||||
$form_id = $entry['form_id'];
|
||||
}
|
||||
$form = GFAPI::get_form( $form_id );
|
||||
if ( ! empty( $form['fields'] ) && is_array( $form['fields'] ) ) {
|
||||
foreach ( $form['fields'] as $field ) {
|
||||
/* @var GF_Field $field */
|
||||
if ( $field->get_input_type() == 'list' && isset( $entry[ $field->id ] ) ) {
|
||||
$new_list_value = self::maybe_decode_json( $entry[ $field->id ] );
|
||||
if ( ! is_serialized( $new_list_value ) ) {
|
||||
$new_list_value = serialize( $new_list_value );
|
||||
}
|
||||
$entry[ $field->id ] = $new_list_value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $entry;
|
||||
}
|
||||
|
||||
/**
|
||||
* JSON encodes appropriate fields in the specified $entry array
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
* @param array $entry The entry array.
|
||||
*
|
||||
* @return array Returns the $entry array with all appropriate fields JSON encoded.
|
||||
*/
|
||||
public function maybe_json_encode_applicable_fields( $entry ) {
|
||||
|
||||
$form = GFAPI::get_form( $entry['form_id'] );
|
||||
|
||||
/** @var GF_Field $field */
|
||||
foreach ( $form['fields'] as $field ) {
|
||||
|
||||
if ( empty( $entry[ $field->id ] ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( $field->get_input_type() === 'fileupload' && $field->multipleFiles ) {
|
||||
|
||||
$entry[ $field->id ] = json_encode( $entry[ $field->id ] );
|
||||
|
||||
} elseif ( $field instanceof GF_Field_MultiSelect ) {
|
||||
|
||||
$entry[ $field->id ] = $field->to_string( $entry[ $field->id ] );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return $entry;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes JSON encoded strings.
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
* @param string $value String to be decoded
|
||||
*
|
||||
* @return array|mixed Returns the decoded JSON array. If the specified $value isn't a JSON encoded string, returns
|
||||
* $value.
|
||||
*/
|
||||
public static function maybe_decode_json( $value ) {
|
||||
if ( self::is_json( $value ) ) {
|
||||
return json_decode( $value, ARRAY_A );
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the http error status
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
* @param WP_Error $wp_error
|
||||
*
|
||||
* @return int Returns the http status recored in the specified $wp_error
|
||||
*/
|
||||
public function get_error_status( $wp_error ) {
|
||||
$error_code = $wp_error->get_error_code();
|
||||
$mappings = array(
|
||||
'not_found' => 404,
|
||||
'not_allowed' => 401,
|
||||
);
|
||||
$http_code = isset( $mappings[ $error_code ] ) ? $mappings[ $error_code ] : 400;
|
||||
|
||||
return $http_code;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a message to the log
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
* @param string $message
|
||||
*/
|
||||
public function log_debug( $message ) {
|
||||
GFAPI::log_debug( $message );
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates that the current user has the specified capability.
|
||||
*
|
||||
* @since 2.4.11
|
||||
*
|
||||
* @param string|array $capability The required capability.
|
||||
* @param WP_REST_Request $request Full data about the request.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function current_user_can_any( $capability, $request ) {
|
||||
$result = GFAPI::current_user_can_any( $capability );
|
||||
|
||||
if ( ! $this->_validate_caps_logged ) {
|
||||
$this->log_debug( sprintf( '%s(): method: %s; route: %s; capability: %s; result: %s.', __METHOD__, $request->get_method(), $request->get_route(), json_encode( $capability ), json_encode( $result ) ) );
|
||||
$this->_validate_caps_logged = true;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively patches the given item with the supplied changes (deletions, updates, and additions).
|
||||
*
|
||||
* @since 2.4.24
|
||||
*
|
||||
* @param mixed $current The existing item to be modified (e.g. feed).
|
||||
* @param mixed $changes The changes to be applied.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function patch_array_recursive( $current, $changes ) {
|
||||
if ( ! $this->is_assoc_array( $changes ) ) {
|
||||
return $changes;
|
||||
}
|
||||
|
||||
if ( ! $this->is_assoc_array( $current ) ) {
|
||||
$current = array();
|
||||
}
|
||||
|
||||
foreach ( $changes as $key => $value ) {
|
||||
if ( is_null( $value ) ) {
|
||||
unset( $current[ $key ] );
|
||||
continue;
|
||||
}
|
||||
|
||||
$current[ $key ] = $this->patch_array_recursive( rgar( $current, $key ), $value );
|
||||
}
|
||||
|
||||
return $current;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the passed variable is an associative array.
|
||||
*
|
||||
* @since 2.4.24
|
||||
*
|
||||
* @param mixed $array The variable to be checked.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function is_assoc_array( $array ) {
|
||||
if ( ! is_array( $array ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach ( array_keys( $array ) as $key ) {
|
||||
if ( $key !== (int) $key ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,764 @@
|
||||
<?php
|
||||
if ( ! class_exists( 'GFForms' ) ) {
|
||||
die();
|
||||
}
|
||||
|
||||
/**
|
||||
* This is a copy of WP_REST_Controller which is not currently in the WordPress core.
|
||||
* https://github.com/WP-API/WP-API/blob/develop/lib/endpoints/class-wp-rest-controller.php
|
||||
*
|
||||
* Last updated 17 August 2016
|
||||
*
|
||||
* Class WP_REST_Controller
|
||||
*/
|
||||
|
||||
abstract class WP_REST_Controller {
|
||||
|
||||
/**
|
||||
* The namespace of this controller's route.
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $namespace;
|
||||
|
||||
/**
|
||||
* The base of this controller's route.
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $rest_base;
|
||||
|
||||
/**
|
||||
* Register the routes for the objects of the controller.
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
*/
|
||||
public function register_routes() {
|
||||
_doing_it_wrong( 'WP_REST_Controller::register_routes', __( 'The register_routes() method must be overriden' ), 'WPAPI-2.0' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a given request has access to get items.
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
*
|
||||
* @param WP_REST_Request $request Full data about the request.
|
||||
*
|
||||
* @return WP_Error|boolean
|
||||
*/
|
||||
public function get_items_permissions_check( $request ) {
|
||||
return new WP_Error( 'invalid-method', sprintf( __( "Method '%s' not implemented. Must be over-ridden in subclass." ), __METHOD__ ), array( 'status' => 405 ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a collection of items.
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
*
|
||||
* @param WP_REST_Request $request Full data about the request.
|
||||
*
|
||||
* @return WP_Error|WP_REST_Response
|
||||
*/
|
||||
public function get_items( $request ) {
|
||||
return new WP_Error( 'invalid-method', sprintf( __( "Method '%s' not implemented. Must be over-ridden in subclass." ), __METHOD__ ), array( 'status' => 405 ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a given request has access to get a specific item.
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
*
|
||||
* @param WP_REST_Request $request Full data about the request.
|
||||
*
|
||||
* @return WP_Error|boolean
|
||||
*/
|
||||
public function get_item_permissions_check( $request ) {
|
||||
return new WP_Error( 'invalid-method', sprintf( __( "Method '%s' not implemented. Must be over-ridden in subclass." ), __METHOD__ ), array( 'status' => 405 ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get one item from the collection.
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
*
|
||||
* @param WP_REST_Request $request Full data about the request.
|
||||
*
|
||||
* @return WP_Error|WP_REST_Response
|
||||
*/
|
||||
public function get_item( $request ) {
|
||||
return new WP_Error( 'invalid-method', sprintf( __( "Method '%s' not implemented. Must be over-ridden in subclass." ), __METHOD__ ), array( 'status' => 405 ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a given request has access to create items.
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
*
|
||||
* @param WP_REST_Request $request Full data about the request.
|
||||
*
|
||||
* @return WP_Error|boolean
|
||||
*/
|
||||
public function create_item_permissions_check( $request ) {
|
||||
return new WP_Error( 'invalid-method', sprintf( __( "Method '%s' not implemented. Must be over-ridden in subclass." ), __METHOD__ ), array( 'status' => 405 ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Create one item from the collection.
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
*
|
||||
* @param WP_REST_Request $request Full data about the request.
|
||||
*
|
||||
* @return WP_Error|WP_REST_Response
|
||||
*/
|
||||
public function create_item( $request ) {
|
||||
return new WP_Error( 'invalid-method', sprintf( __( "Method '%s' not implemented. Must be over-ridden in subclass." ), __METHOD__ ), array( 'status' => 405 ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a given request has access to update a specific item.
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
*
|
||||
* @param WP_REST_Request $request Full data about the request.
|
||||
*
|
||||
* @return WP_Error|boolean
|
||||
*/
|
||||
public function update_item_permissions_check( $request ) {
|
||||
return new WP_Error( 'invalid-method', sprintf( __( "Method '%s' not implemented. Must be over-ridden in subclass." ), __METHOD__ ), array( 'status' => 405 ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Update one item from the collection.
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
*
|
||||
* @param WP_REST_Request $request Full data about the request.
|
||||
*
|
||||
* @return WP_Error|WP_REST_Response
|
||||
*/
|
||||
public function update_item( $request ) {
|
||||
return new WP_Error( 'invalid-method', sprintf( __( "Method '%s' not implemented. Must be over-ridden in subclass." ), __METHOD__ ), array( 'status' => 405 ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a given request has access to delete a specific item.
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
*
|
||||
* @param WP_REST_Request $request Full data about the request.
|
||||
*
|
||||
* @return WP_Error|boolean
|
||||
*/
|
||||
public function delete_item_permissions_check( $request ) {
|
||||
return new WP_Error( 'invalid-method', sprintf( __( "Method '%s' not implemented. Must be over-ridden in subclass." ), __METHOD__ ), array( 'status' => 405 ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete one item from the collection.
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
*
|
||||
* @param WP_REST_Request $request Full data about the request.
|
||||
*
|
||||
* @return WP_Error|WP_REST_Response
|
||||
*/
|
||||
public function delete_item( $request ) {
|
||||
return new WP_Error( 'invalid-method', sprintf( __( "Method '%s' not implemented. Must be over-ridden in subclass." ), __METHOD__ ), array( 'status' => 405 ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare the item for create or update operation.
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
*
|
||||
* @param WP_REST_Request $request Request object.
|
||||
*
|
||||
* @return WP_Error|object $prepared_item
|
||||
*/
|
||||
protected function prepare_item_for_database( $request ) {
|
||||
return new WP_Error( 'invalid-method', sprintf( __( "Method '%s' not implemented. Must be over-ridden in subclass." ), __METHOD__ ), array( 'status' => 405 ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare the item for the REST response.
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
*
|
||||
* @param mixed $item WordPress representation of the item.
|
||||
* @param WP_REST_Request $request Request object.
|
||||
*
|
||||
* @return WP_REST_Response $response
|
||||
*/
|
||||
public function prepare_item_for_response( $item, $request ) {
|
||||
return new WP_Error( 'invalid-method', sprintf( __( "Method '%s' not implemented. Must be over-ridden in subclass." ), __METHOD__ ), array( 'status' => 405 ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare a response for inserting into a collection.
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
*
|
||||
* @param WP_REST_Response $response Response object.
|
||||
*
|
||||
* @return array Response data, ready for insertion into collection data.
|
||||
*/
|
||||
public function prepare_response_for_collection( $response ) {
|
||||
if ( ! ( $response instanceof WP_REST_Response ) ) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
$data = (array) $response->get_data();
|
||||
$server = rest_get_server();
|
||||
|
||||
if ( method_exists( $server, 'get_compact_response_links' ) ) {
|
||||
$links = call_user_func( array( $server, 'get_compact_response_links' ), $response );
|
||||
} else {
|
||||
$links = call_user_func( array( $server, 'get_response_links' ), $response );
|
||||
}
|
||||
|
||||
if ( ! empty( $links ) ) {
|
||||
$data['_links'] = $links;
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter a response based on the context defined in the schema.
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
*
|
||||
* @param array $data
|
||||
* @param string $context
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function filter_response_by_context( $data, $context ) {
|
||||
|
||||
$schema = $this->get_item_schema();
|
||||
foreach ( $data as $key => $value ) {
|
||||
if ( empty( $schema['properties'][ $key ] ) || empty( $schema['properties'][ $key ]['context'] ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( ! in_array( $context, $schema['properties'][ $key ]['context'] ) ) {
|
||||
unset( $data[ $key ] );
|
||||
}
|
||||
|
||||
if ( 'object' === $schema['properties'][ $key ]['type'] && ! empty( $schema['properties'][ $key ]['properties'] ) ) {
|
||||
foreach ( $schema['properties'][ $key ]['properties'] as $attribute => $details ) {
|
||||
if ( empty( $details['context'] ) ) {
|
||||
continue;
|
||||
}
|
||||
if ( ! in_array( $context, $details['context'] ) ) {
|
||||
if ( isset( $data[ $key ][ $attribute ] ) ) {
|
||||
unset( $data[ $key ][ $attribute ] );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the item's schema, conforming to JSON Schema.
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_item_schema() {
|
||||
return $this->add_additional_fields_schema( array() );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the item's schema for display / public consumption purposes.
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_public_item_schema() {
|
||||
|
||||
$schema = $this->get_item_schema();
|
||||
|
||||
foreach ( $schema['properties'] as &$property ) {
|
||||
if ( isset( $property['arg_options'] ) ) {
|
||||
unset( $property['arg_options'] );
|
||||
}
|
||||
}
|
||||
|
||||
return $schema;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the query params for collections.
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_collection_params() {
|
||||
return array(
|
||||
'context' => $this->get_context_param(),
|
||||
'page' => array(
|
||||
'description' => __( 'Current page of the collection.' ),
|
||||
'type' => 'integer',
|
||||
'default' => 1,
|
||||
'sanitize_callback' => 'absint',
|
||||
'validate_callback' => 'rest_validate_request_arg',
|
||||
'minimum' => 1,
|
||||
),
|
||||
'per_page' => array(
|
||||
'description' => __( 'Maximum number of items to be returned in result set.' ),
|
||||
'type' => 'integer',
|
||||
'default' => 10,
|
||||
'minimum' => 1,
|
||||
'maximum' => 100,
|
||||
'sanitize_callback' => 'absint',
|
||||
'validate_callback' => 'rest_validate_request_arg',
|
||||
),
|
||||
'search' => array(
|
||||
'description' => __( 'Limit results to those matching a string.' ),
|
||||
'type' => 'string',
|
||||
'sanitize_callback' => 'sanitize_text_field',
|
||||
'validate_callback' => 'rest_validate_request_arg',
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the magical context param.
|
||||
*
|
||||
* Ensures consistent description between endpoints, and populates enum from schema.
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
*
|
||||
* @param array $args
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_context_param( $args = array() ) {
|
||||
$param_details = array(
|
||||
'description' => __( 'Scope under which the request is made; determines fields present in response.' ),
|
||||
'type' => 'string',
|
||||
'sanitize_callback' => 'sanitize_key',
|
||||
'validate_callback' => 'rest_validate_request_arg',
|
||||
);
|
||||
$schema = $this->get_item_schema();
|
||||
if ( empty( $schema['properties'] ) ) {
|
||||
return array_merge( $param_details, $args );
|
||||
}
|
||||
$contexts = array();
|
||||
foreach ( $schema['properties'] as $attributes ) {
|
||||
if ( ! empty( $attributes['context'] ) ) {
|
||||
$contexts = array_merge( $contexts, $attributes['context'] );
|
||||
}
|
||||
}
|
||||
if ( ! empty( $contexts ) ) {
|
||||
$param_details['enum'] = array_unique( $contexts );
|
||||
rsort( $param_details['enum'] );
|
||||
}
|
||||
return array_merge( $param_details, $args );
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the values from additional fields to a data object.
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
*
|
||||
* @param array $object
|
||||
* @param WP_REST_Request $request
|
||||
*
|
||||
* @return array modified object with additional fields.
|
||||
*/
|
||||
protected function add_additional_fields_to_object( $object, $request ) {
|
||||
|
||||
$additional_fields = $this->get_additional_fields();
|
||||
|
||||
foreach ( $additional_fields as $field_name => $field_options ) {
|
||||
|
||||
if ( ! $field_options['get_callback'] ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$object[ $field_name ] = call_user_func( $field_options['get_callback'], $object, $field_name, $request, $this->get_object_type() );
|
||||
}
|
||||
|
||||
return $object;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the values of additional fields added to a data object.
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
*
|
||||
* @param array $object
|
||||
* @param WP_REST_Request $request
|
||||
*/
|
||||
protected function update_additional_fields_for_object( $object, $request ) {
|
||||
|
||||
$additional_fields = $this->get_additional_fields();
|
||||
|
||||
foreach ( $additional_fields as $field_name => $field_options ) {
|
||||
|
||||
if ( ! $field_options['update_callback'] ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Don't run the update callbacks if the data wasn't passed in the request.
|
||||
if ( ! isset( $request[ $field_name ] ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
call_user_func( $field_options['update_callback'], $request[ $field_name ], $object, $field_name, $request, $this->get_object_type() );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the schema from additional fields to an schema array.
|
||||
*
|
||||
* The type of object is inferred from the passed schema.
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
*
|
||||
* @param array $schema Schema array.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function add_additional_fields_schema( $schema ) {
|
||||
if ( empty( $schema['title'] ) ) {
|
||||
return $schema;
|
||||
}
|
||||
|
||||
/**
|
||||
* Can't use $this->get_object_type otherwise we cause an inf loop.
|
||||
*/
|
||||
$object_type = $schema['title'];
|
||||
|
||||
$additional_fields = $this->get_additional_fields( $object_type );
|
||||
|
||||
foreach ( $additional_fields as $field_name => $field_options ) {
|
||||
if ( ! $field_options['schema'] ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$schema['properties'][ $field_name ] = $field_options['schema'];
|
||||
}
|
||||
|
||||
return $schema;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all the registered additional fields for a given object-type.
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
*
|
||||
* @param string $object_type
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function get_additional_fields( $object_type = null ) {
|
||||
|
||||
if ( ! $object_type ) {
|
||||
$object_type = $this->get_object_type();
|
||||
}
|
||||
|
||||
if ( ! $object_type ) {
|
||||
return array();
|
||||
}
|
||||
|
||||
global $wp_rest_additional_fields;
|
||||
|
||||
if ( ! $wp_rest_additional_fields || ! isset( $wp_rest_additional_fields[ $object_type ] ) ) {
|
||||
return array();
|
||||
}
|
||||
|
||||
return $wp_rest_additional_fields[ $object_type ];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the object type this controller is responsible for managing.
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function get_object_type() {
|
||||
$schema = $this->get_item_schema();
|
||||
|
||||
if ( ! $schema || ! isset( $schema['title'] ) ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $schema['title'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an array of endpoint arguments from the item schema for the controller.
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
*
|
||||
* @param string $method HTTP method of the request. The arguments
|
||||
* for `CREATABLE` requests are checked for required
|
||||
* values and may fall-back to a given default, this
|
||||
* is not done on `EDITABLE` requests. Default is
|
||||
* WP_REST_Server::CREATABLE.
|
||||
*
|
||||
* @return array $endpoint_args
|
||||
*/
|
||||
public function get_endpoint_args_for_item_schema( $method = WP_REST_Server::CREATABLE ) {
|
||||
|
||||
$schema = $this->get_item_schema();
|
||||
$schema_properties = ! empty( $schema['properties'] ) ? $schema['properties'] : array();
|
||||
$endpoint_args = array();
|
||||
|
||||
foreach ( $schema_properties as $field_id => $params ) {
|
||||
|
||||
// Arguments specified as `readonly` are not allowed to be set.
|
||||
if ( ! empty( $params['readonly'] ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$endpoint_args[ $field_id ] = array(
|
||||
'validate_callback' => 'rest_validate_request_arg',
|
||||
'sanitize_callback' => 'rest_sanitize_request_arg',
|
||||
);
|
||||
|
||||
if ( isset( $params['description'] ) ) {
|
||||
$endpoint_args[ $field_id ]['description'] = $params['description'];
|
||||
}
|
||||
|
||||
if ( WP_REST_Server::CREATABLE === $method && isset( $params['default'] ) ) {
|
||||
$endpoint_args[ $field_id ]['default'] = $params['default'];
|
||||
}
|
||||
|
||||
if ( WP_REST_Server::CREATABLE === $method && ! empty( $params['required'] ) ) {
|
||||
$endpoint_args[ $field_id ]['required'] = true;
|
||||
}
|
||||
|
||||
foreach ( array( 'type', 'format', 'enum' ) as $schema_prop ) {
|
||||
if ( isset( $params[ $schema_prop ] ) ) {
|
||||
$endpoint_args[ $field_id ][ $schema_prop ] = $params[ $schema_prop ];
|
||||
}
|
||||
}
|
||||
|
||||
// Merge in any options provided by the schema property.
|
||||
if ( isset( $params['arg_options'] ) ) {
|
||||
|
||||
// Only use required / default from arg_options on CREATABLE endpoints.
|
||||
if ( WP_REST_Server::CREATABLE !== $method ) {
|
||||
$params['arg_options'] = array_diff_key( $params['arg_options'], array( 'required' => '', 'default' => '' ) );
|
||||
}
|
||||
|
||||
$endpoint_args[ $field_id ] = array_merge( $endpoint_args[ $field_id ], $params['arg_options'] );
|
||||
}
|
||||
}
|
||||
|
||||
return $endpoint_args;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves post data given a post ID or post object.
|
||||
*
|
||||
* This is a subset of the functionality of the `get_post()` function, with
|
||||
* the additional functionality of having `the_post` action done on the
|
||||
* resultant post object. This is done so that plugins may manipulate the
|
||||
* post that is used in the REST API.
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
*
|
||||
* @see get_post()
|
||||
* @global WP_Query $wp_query
|
||||
*
|
||||
* @param int|WP_Post $post Post ID or post object. Defaults to global $post.
|
||||
*
|
||||
* @return WP_Post|null A `WP_Post` object when successful.
|
||||
*/
|
||||
public function get_post( $post ) {
|
||||
$post_obj = get_post( $post );
|
||||
|
||||
/**
|
||||
* Filter the post.
|
||||
*
|
||||
* Allows plugins to filter the post object as returned by `\WP_REST_Controller::get_post()`.
|
||||
*
|
||||
* @param WP_Post|null $post_obj The post object as returned by `get_post()`.
|
||||
* @param int|WP_Post $post The original value used to obtain the post object.
|
||||
*/
|
||||
$post = apply_filters( 'rest_the_post', $post_obj, $post );
|
||||
|
||||
return $post;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if ( ! function_exists( 'rest_sanitize_request_arg' ) ) {
|
||||
/**
|
||||
* Sanitize a request argument based on details registered to the route.
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
*
|
||||
* @param mixed $value
|
||||
* @param WP_REST_Request $request
|
||||
* @param string $param
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
function rest_sanitize_request_arg( $value, $request, $param ) {
|
||||
|
||||
$attributes = $request->get_attributes();
|
||||
if ( ! isset( $attributes['args'][ $param ] ) || ! is_array( $attributes['args'][ $param ] ) ) {
|
||||
return $value;
|
||||
}
|
||||
$args = $attributes['args'][ $param ];
|
||||
|
||||
if ( 'integer' === $args['type'] ) {
|
||||
return (int) $value;
|
||||
}
|
||||
|
||||
if ( isset( $args['format'] ) ) {
|
||||
switch ( $args['format'] ) {
|
||||
case 'string' :
|
||||
return sanitize_text_field( $value );
|
||||
|
||||
case 'email' :
|
||||
/*
|
||||
* sanitize_email() validates, which would be unexpected
|
||||
*/
|
||||
return sanitize_text_field( $value );
|
||||
|
||||
case 'uri' :
|
||||
return esc_url_raw( $value );
|
||||
}
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if ( ! function_exists( 'rest_validate_request_arg' ) ) {
|
||||
/**
|
||||
* Validate a request argument based on details registered to the route.
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
*
|
||||
* @param mixed $value
|
||||
* @param WP_REST_Request $request
|
||||
* @param string $param
|
||||
*
|
||||
* @return WP_Error|boolean
|
||||
*/
|
||||
function rest_validate_request_arg( $value, $request, $param ) {
|
||||
|
||||
$attributes = $request->get_attributes();
|
||||
if ( ! isset( $attributes['args'][ $param ] ) || ! is_array( $attributes['args'][ $param ] ) ) {
|
||||
return true;
|
||||
}
|
||||
$args = $attributes['args'][ $param ];
|
||||
|
||||
if ( ! empty( $args['enum'] ) ) {
|
||||
if ( ! in_array( $value, $args['enum'] ) ) {
|
||||
return new WP_Error( 'rest_invalid_param', sprintf( __( '%s is not one of %s' ), $param, implode( ', ', $args['enum'] ) ) );
|
||||
}
|
||||
}
|
||||
|
||||
if ( 'integer' === $args['type'] && ! is_numeric( $value ) ) {
|
||||
return new WP_Error( 'rest_invalid_param', sprintf( __( '%s is not of type %s' ), $param, 'integer' ) );
|
||||
}
|
||||
|
||||
if ( 'string' === $args['type'] && ! is_string( $value ) ) {
|
||||
return new WP_Error( 'rest_invalid_param', sprintf( __( '%s is not of type %s' ), $param, 'string' ) );
|
||||
}
|
||||
|
||||
if ( isset( $args['format'] ) ) {
|
||||
switch ( $args['format'] ) {
|
||||
case 'date-time' :
|
||||
if ( ! rest_parse_date( $value ) ) {
|
||||
return new WP_Error( 'rest_invalid_date', __( 'The date you provided is invalid.' ) );
|
||||
}
|
||||
break;
|
||||
|
||||
case 'email' :
|
||||
if ( ! is_email( $value ) ) {
|
||||
return new WP_Error( 'rest_invalid_email', __( 'The email address you provided is invalid.' ) );
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( in_array( $args['type'], array( 'numeric', 'integer' ) ) && ( isset( $args['minimum'] ) || isset( $args['maximum'] ) ) ) {
|
||||
if ( isset( $args['minimum'] ) && ! isset( $args['maximum'] ) ) {
|
||||
if ( ! empty( $args['exclusiveMinimum'] ) && $value <= $args['minimum'] ) {
|
||||
return new WP_Error( 'rest_invalid_param', sprintf( __( '%s must be greater than %d (exclusive)' ), $param, $args['minimum'] ) );
|
||||
} else if ( empty( $args['exclusiveMinimum'] ) && $value < $args['minimum'] ) {
|
||||
return new WP_Error( 'rest_invalid_param', sprintf( __( '%s must be greater than %d (inclusive)' ), $param, $args['minimum'] ) );
|
||||
}
|
||||
} else if ( isset( $args['maximum'] ) && ! isset( $args['minimum'] ) ) {
|
||||
if ( ! empty( $args['exclusiveMaximum'] ) && $value >= $args['maximum'] ) {
|
||||
return new WP_Error( 'rest_invalid_param', sprintf( __( '%s must be less than %d (exclusive)' ), $param, $args['maximum'] ) );
|
||||
} else if ( empty( $args['exclusiveMaximum'] ) && $value > $args['maximum'] ) {
|
||||
return new WP_Error( 'rest_invalid_param', sprintf( __( '%s must be less than %d (inclusive)' ), $param, $args['maximum'] ) );
|
||||
}
|
||||
} else if ( isset( $args['maximum'] ) && isset( $args['minimum'] ) ) {
|
||||
if ( ! empty( $args['exclusiveMinimum'] ) && ! empty( $args['exclusiveMaximum'] ) ) {
|
||||
if ( $value >= $args['maximum'] || $value <= $args['minimum'] ) {
|
||||
return new WP_Error( 'rest_invalid_param', sprintf( __( '%s must be between %d (exclusive) and %d (exclusive)' ), $param, $args['minimum'], $args['maximum'] ) );
|
||||
}
|
||||
} else if ( empty( $args['exclusiveMinimum'] ) && ! empty( $args['exclusiveMaximum'] ) ) {
|
||||
if ( $value >= $args['maximum'] || $value < $args['minimum'] ) {
|
||||
return new WP_Error( 'rest_invalid_param', sprintf( __( '%s must be between %d (inclusive) and %d (exclusive)' ), $param, $args['minimum'], $args['maximum'] ) );
|
||||
}
|
||||
} else if ( ! empty( $args['exclusiveMinimum'] ) && empty( $args['exclusiveMaximum'] ) ) {
|
||||
if ( $value > $args['maximum'] || $value <= $args['minimum'] ) {
|
||||
return new WP_Error( 'rest_invalid_param', sprintf( __( '%s must be between %d (exclusive) and %d (inclusive)' ), $param, $args['minimum'], $args['maximum'] ) );
|
||||
}
|
||||
} else if ( empty( $args['exclusiveMinimum'] ) && empty( $args['exclusiveMaximum'] ) ) {
|
||||
if ( $value > $args['maximum'] || $value < $args['minimum'] ) {
|
||||
return new WP_Error( 'rest_invalid_param', sprintf( __( '%s must be between %d (inclusive) and %d (inclusive)' ), $param, $args['minimum'], $args['maximum'] ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
<?php
|
||||
//Nothing to see here
|
||||
@@ -0,0 +1,2 @@
|
||||
<?php
|
||||
//Nothing to see here
|
||||
@@ -0,0 +1,2 @@
|
||||
<?php
|
||||
//Nothing to see here
|
||||
@@ -0,0 +1,58 @@
|
||||
<?php
|
||||
|
||||
if ( ! class_exists( 'GFForms' ) ) {
|
||||
die();
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the Gravity Forms REST API add-on.
|
||||
*
|
||||
* Includes the main class, registers it with GFAddOn, and initialises.
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*/
|
||||
class GF_REST_API_Bootstrap {
|
||||
|
||||
/**
|
||||
* Loads the required files.
|
||||
*
|
||||
* @since 2.4-beta-1
|
||||
*
|
||||
*/
|
||||
public static function load_rest_api() {
|
||||
|
||||
|
||||
$dir = plugin_dir_path( __FILE__ );
|
||||
|
||||
// Requires the class file
|
||||
require_once $dir . 'class-gf-rest-api.php';
|
||||
|
||||
require_once $dir . 'includes/class-results-cache.php';
|
||||
|
||||
|
||||
if ( ! class_exists( 'WP_REST_Controller' ) ) {
|
||||
require_once $dir . 'includes/controllers/class-wp-rest-controller.php';
|
||||
}
|
||||
|
||||
require_once $dir . 'includes/controllers/class-gf-rest-controller.php';
|
||||
|
||||
require_once $dir . 'includes/controllers/class-controller-form-entries.php';
|
||||
require_once $dir . 'includes/controllers/class-controller-form-results.php';
|
||||
require_once $dir . 'includes/controllers/class-controller-form-submissions.php';
|
||||
require_once $dir . 'includes/controllers/class-controller-form-submissions-validation.php';
|
||||
require_once $dir . 'includes/controllers/class-controller-form-feeds.php';
|
||||
require_once $dir . 'includes/controllers/class-controller-feeds.php';
|
||||
require_once $dir . 'includes/controllers/class-controller-entries.php';
|
||||
require_once $dir . 'includes/controllers/class-controller-entry-notes.php';
|
||||
require_once $dir . 'includes/controllers/class-controller-notes.php';
|
||||
require_once $dir . 'includes/controllers/class-controller-entry-notifications.php';
|
||||
require_once $dir . 'includes/controllers/class-controller-entry-properties.php';
|
||||
require_once $dir . 'includes/controllers/class-controller-forms.php';
|
||||
require_once $dir . 'includes/controllers/class-controller-form-field-filters.php';
|
||||
require_once $dir . 'includes/controllers/class-controller-feed-properties.php';
|
||||
|
||||
return GF_REST_API::get_instance();
|
||||
}
|
||||
}
|
||||
|
||||
GF_REST_API_Bootstrap::load_rest_api();
|
||||
2579
wp/wp-content/plugins/gravityforms/includes/webapi/webapi.php
Normal file
2579
wp/wp-content/plugins/gravityforms/includes/webapi/webapi.php
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user