Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add form responses v2 endpoint #29043

Merged
merged 19 commits into from
Feb 24, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Significance: minor
Type: added

Add v2/v4 endpoint for form responses inbox
2 changes: 2 additions & 0 deletions projects/packages/forms/src/class-jetpack-forms.php
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ public static function load_contact_form() {
}

add_action( 'init', '\Automattic\Jetpack\Forms\ContactForm\Util::register_pattern' );

add_action( 'rest_api_init', array( new WPCOM_REST_API_V2_Endpoint_Forms(), 'register_rest_routes' ) );
}

/**
Expand Down
167 changes: 167 additions & 0 deletions projects/packages/forms/src/class-wpcom-rest-api-v2-endpoint-forms.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
<?php
/**
* The Forms Rest Controller class.
* Registers the REST routes for Jetpack Forms (taken from stats-admin).
*
* @package automattic/jetpack-forms
*/

namespace Automattic\Jetpack\Forms;

use Automattic\Jetpack\Connection\Manager;
use WP_Error;
use WP_REST_Controller;
use WP_REST_Server;

/**
* Handles the REST routes for Form Responses, aka Feedback.
*/
class WPCOM_REST_API_V2_Endpoint_Forms extends WP_REST_Controller {
/**
* Constructor.
*/
public function __construct() {
$this->namespace = 'wpcom/v2';
$this->rest_base = 'forms';

add_action( 'rest_api_init', array( $this, 'register_rest_routes' ) );
}

/**
* Registers the REST routes.
*
* @access public
*/
public function register_rest_routes() {
// Stats for single resource type.

register_rest_route(
$this->namespace,
$this->rest_base . '/responses',
array(
'methods' => WP_REST_Server::READABLE,
'callback' => array( $this, 'get_responses' ),
'permissions_check' => array( $this, 'get_responses_permission_check' ),
'args' => array(
'limit' => array(
'default' => 20,
'type' => 'integer',
'required' => false,
'minimum' => 1,
),
'offset' => array(
'default' => 0,
'type' => 'integer',
'required' => false,
'minimum' => 0,
),
'form_id' => array(
'type' => 'integer',
'required' => false,
'minimum' => 1,
),
'search' => array(
'type' => 'string',
'required' => false,
),
),
)
);
}

/**
* Returns Jetpack Forms responses.
*
* @param WP_REST_Request $request The request sent to the WP REST API.
*
* @return WP_REST_Response A response object containing Jetpack Forms responses.
*/
public function get_responses( $request ) {
$args = array(
'post_type' => 'feedback',
'post_status' => array( 'publish', 'draft' ),
);

if ( isset( $request['form_id'] ) ) {
$args['post_parent'] = $request['form_id'];
}

if ( isset( $request['limit'] ) ) {
$args['posts_per_page'] = $request['limit'];
}

if ( isset( $request['offset'] ) ) {
$args['offset'] = $request['offset'];
}

if ( isset( $request['search'] ) ) {
$args['s'] = $request['search'];
}

$query = new \WP_Query( $args );

$responses = array_map(
function ( $response ) {
$data = \Automattic\Jetpack\Forms\ContactForm\Contact_Form_Plugin::parse_fields_from_content( $response->ID );

return array(
'id' => $response->ID,
'uid' => $data['all_fields']['feedback_id'],
'date' => get_the_date( 'c', $response ),
'author_name' => $data['_feedback_author'],
'author_email' => $data['_feedback_author_email'],
'author_url' => $data['_feedback_author_url'],
'author_avatar' => empty( $data['_feedback_author_email'] ) ? '' : get_avatar_url( $data['_feedback_author_email'] ),
'email_marketing_consent' => $data['all_fields']['email_marketing_consent'],
'ip' => $data['_feedback_ip'],
'entry_title' => $data['all_fields']['entry_title'],
'entry_permalink' => $data['all_fields']['entry_permalink'],
'subject' => $data['_feedback_subject'],
'fields' => array_diff_key(
$data['all_fields'],
array(
'email_marketing_consent' => '',
'entry_title' => '',
'entry_permalink' => '',
'feedback_id' => '',
)
),
);
},
$query->posts
);

return rest_ensure_response(
array(
'responses' => $responses,
'total' => $query->found_posts,
)
);
}

/**
* Verifies that the current user has the requird capability for viewing form responses.
*
* @return true|WP_Error Returns true if the user has the required capability, else a WP_Error object.
*/
public function get_responses_permission_check() {
$site_id = Manager::get_site_id();
if ( is_wp_error( $site_id ) ) {
return $site_id;
}

if ( ! current_user_can( 'manage_options' ) || ! is_user_member_of_blog( get_current_user_id(), $site_id ) ) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With current_user_can( 'manage_options' ) in place, then is_user_member_of_blog( get_current_user_id(), $site_id ) becomes redundant, right?

In that case we don't need the $site_id as well I guess.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

User might be member of blog but not have management capabilities? Is that not a possible scenario?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No worries, doesn't hurt anyway :)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I followed up on this conversation in #35571 after discussion in p1707435111778979-slack-C05PV073SG3

return new WP_Error(
'invalid_user_permission_jetpack_form_responses',
'unauthorized',
array( 'status' => rest_authorization_required_code() )
);
}

return true;
}
}

if ( defined( 'IS_WPCOM' ) && IS_WPCOM ) {
wpcom_rest_api_v2_load_plugin( 'Automattic\Jetpack\Forms\WPCOM_REST_API_V2_Endpoint_Forms' );
}
Original file line number Diff line number Diff line change
Expand Up @@ -2009,6 +2009,7 @@ public static function parse_fields_from_content( $post_id ) {
}

$fields['_feedback_all_fields'] = $all_values;
$fields['all_fields'] = $all_values;

$post_fields[ $post_id ] = $fields;

Expand Down
17 changes: 14 additions & 3 deletions projects/packages/forms/src/dashboard/class-dashboard.php
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,22 @@ public function load_admin_scripts( $hook ) {
'../../dist/dashboard/jetpack-forms-dashboard.js',
__FILE__,
array(
'in_footer' => true,
'textdomain' => 'jetpack-forms',
'enqueue' => true,
'in_footer' => true,
'textdomain' => 'jetpack-forms',
'enqueue' => true,
'dependencies' => array( 'wp-api-fetch' ), // this here just for testing, remove when done (apiFetch will be on build)
)
);

$api_root = defined( 'IS_WPCOM' ) && IS_WPCOM
? sprintf( '/wpcom/v2/sites/%s/', esc_url_raw( rest_url() ) ) // should we include full URL here (public-api.wordpress.com)?
: '/wp-json/wpcom/v2/';

wp_add_inline_script(
'jp-forms-dashboard',
'window.jetpackFormsData = ' . wp_json_encode( array( 'apiRoot' => $api_root ) ) . ';',
'before'
);
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Significance: minor
Type: other

Add wpcom/v2/form-responses endpoint, mapped from .com
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Significance: patch
Type: other
Comment: Updated composer.lock.


Loading