From 27b255e7293579acc82ebafaec972c9070552ba9 Mon Sep 17 00:00:00 2001 From: Manzoor Wani Date: Thu, 9 Jan 2025 00:08:22 -0800 Subject: [PATCH] Social | Add site context for publicize endpoints (#40914) * Allow requests as blog in base controller * Add filters for connections controller * Add changelog * Update baseline.php * Rename the 'include' param to 'scope' for clarity * Return shared connections by default * Remove scope parameter in favour of request context * Only pass test_connections to WPCOM * Update baseline.php --- .../packages/publicize/.phan/baseline.php | 6 ++- .../add-filtering-for-publicize-endpoints | 4 ++ .../src/rest-api/class-base-controller.php | 31 +++++++++++- .../rest-api/class-connections-controller.php | 48 ++++++++++++++----- 4 files changed, 74 insertions(+), 15 deletions(-) create mode 100644 projects/packages/publicize/changelog/add-filtering-for-publicize-endpoints diff --git a/projects/packages/publicize/.phan/baseline.php b/projects/packages/publicize/.phan/baseline.php index ae1e8cfe766d4..283281754e1e6 100644 --- a/projects/packages/publicize/.phan/baseline.php +++ b/projects/packages/publicize/.phan/baseline.php @@ -17,6 +17,7 @@ // PhanPossiblyUndeclaredVariable : 2 occurrences // PhanTypeMismatchReturnProbablyReal : 2 occurrences // PhanTypeMissingReturn : 2 occurrences + // PhanUndeclaredClassMethod : 2 occurrences // PhanImpossibleCondition : 1 occurrence // PhanNoopNew : 1 occurrence // PhanParamSignatureMismatch : 1 occurrence @@ -28,6 +29,8 @@ // PhanTypeMismatchDefault : 1 occurrence // PhanTypeMismatchDimFetch : 1 occurrence // PhanTypeMismatchReturn : 1 occurrence + // PhanUndeclaredFunction : 1 occurrence + // PhanUndeclaredMethod : 1 occurrence // Currently, file_suppressions and directory_suppressions are the only supported suppressions 'file_suppressions' => [ @@ -38,7 +41,8 @@ 'src/class-publicize-ui.php' => ['PhanPluginDuplicateExpressionAssignmentOperation', 'PhanTypeMismatchReturnProbablyReal'], 'src/class-publicize.php' => ['PhanParamSignatureMismatch', 'PhanPossiblyUndeclaredVariable', 'PhanTypeMismatchArgument', 'PhanTypeMissingReturn'], 'src/class-rest-controller.php' => ['PhanPluginDuplicateConditionalNullCoalescing', 'PhanTypeMismatchReturnProbablyReal'], - 'src/rest-api/class-connections-controller.php' => ['PhanPluginMixedKeyNoKey'], + 'src/rest-api/class-base-controller.php' => ['PhanUndeclaredClassMethod', 'PhanUndeclaredFunction'], + 'src/rest-api/class-connections-controller.php' => ['PhanPluginMixedKeyNoKey', 'PhanUndeclaredMethod'], 'src/social-image-generator/class-post-settings.php' => ['PhanPluginDuplicateConditionalNullCoalescing'], 'src/social-image-generator/class-rest-settings-controller.php' => ['PhanPluginMixedKeyNoKey'], 'src/social-image-generator/class-settings.php' => ['PhanPluginDuplicateConditionalNullCoalescing'], diff --git a/projects/packages/publicize/changelog/add-filtering-for-publicize-endpoints b/projects/packages/publicize/changelog/add-filtering-for-publicize-endpoints new file mode 100644 index 0000000000000..90fd57e7a5a4b --- /dev/null +++ b/projects/packages/publicize/changelog/add-filtering-for-publicize-endpoints @@ -0,0 +1,4 @@ +Significance: patch +Type: added + +Publicize: Allow filtering of connections in publicize rest endpoint diff --git a/projects/packages/publicize/src/rest-api/class-base-controller.php b/projects/packages/publicize/src/rest-api/class-base-controller.php index acf0aa0c78cc2..86ca5c8e40a52 100644 --- a/projects/packages/publicize/src/rest-api/class-base-controller.php +++ b/projects/packages/publicize/src/rest-api/class-base-controller.php @@ -18,6 +18,13 @@ */ abstract class Base_Controller extends WP_REST_Controller { + /** + * Whether to allow requests as blog. + * + * @var bool + */ + protected $allow_requests_as_blog = false; + /** * Constructor. */ @@ -34,6 +41,22 @@ public static function is_wpcom() { return ( new Host() )->is_wpcom_simple(); } + /** + * Check if the request is authorized for the blog. + * + * @return bool + */ + protected static function is_authorized_blog_request() { + if ( self::is_wpcom() && is_jetpack_site( get_current_blog_id() ) ) { + + $jp_auth_endpoint = new \WPCOM_REST_API_V2_Endpoint_Jetpack_Auth(); + + return $jp_auth_endpoint->is_jetpack_authorized_for_site() === true; + } + + return false; + } + /** * Filters out data based on ?_fields= request parameter * @@ -59,9 +82,11 @@ public function prepare_item_for_response( $item, $request ) { /** * Verify that user can access Publicize data * + * @param WP_REST_Request $request Full details about the request. * @return true|WP_Error */ - public function get_items_permission_check() { + public function get_items_permissions_check( $request ) {// phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable + global $publicize; if ( ! $publicize ) { @@ -72,6 +97,10 @@ public function get_items_permission_check() { ); } + if ( $this->allow_requests_as_blog && self::is_authorized_blog_request() ) { + return true; + } + if ( $publicize->current_user_can_access_publicize_data() ) { return true; } diff --git a/projects/packages/publicize/src/rest-api/class-connections-controller.php b/projects/packages/publicize/src/rest-api/class-connections-controller.php index f1710bca05a93..873f61851ebc5 100644 --- a/projects/packages/publicize/src/rest-api/class-connections-controller.php +++ b/projects/packages/publicize/src/rest-api/class-connections-controller.php @@ -27,6 +27,8 @@ public function __construct() { $this->namespace = 'wpcom/v2'; $this->rest_base = 'publicize/connections'; + $this->allow_requests_as_blog = true; + add_action( 'rest_api_init', array( $this, 'register_routes' ) ); } @@ -41,7 +43,7 @@ public function register_routes() { array( 'methods' => WP_REST_Server::READABLE, 'callback' => array( $this, 'get_items' ), - 'permission_callback' => array( $this, 'get_items_permission_check' ), + 'permission_callback' => array( $this, 'get_items_permissions_check' ), 'args' => array( 'test_connections' => array( 'type' => 'boolean', @@ -165,23 +167,32 @@ public function get_item_schema() { /** * Get all connections. Meant to be called directly only on WPCOM. * - * @param bool $run_tests Whether to run tests on the connections. + * @param array $args Arguments + * - 'test_connections': bool Whether to run connection tests. + * - 'scope': enum('site', 'user') Which connections to include. * * @return array */ - protected static function get_all_connections( $run_tests = false ) { + protected static function get_all_connections( $args = array() ) { /** * Publicize instance. - * - * @var \Automattic\Jetpack\Publicize\Publicize $publicize */ global $publicize; $items = array(); + $run_tests = $args['test_connections'] ?? false; + $test_results = $run_tests ? self::get_connections_test_status() : array(); - foreach ( (array) $publicize->get_services( 'connected' ) as $service_name => $connections ) { + // If a (Jetpack) blog request, return all the connections for that site. + if ( self::is_authorized_blog_request() ) { + $service_connections = $publicize->get_all_connections_for_blog_id( get_current_blog_id() ); + } else { + $service_connections = (array) $publicize->get_services( 'connected' ); + } + + foreach ( $service_connections as $service_name => $connections ) { foreach ( $connections as $connection ) { $connection_id = $publicize->get_connection_id( $connection ); @@ -219,13 +230,15 @@ protected static function get_all_connections( $run_tests = false ) { /** * Get a list of publicize connections. * - * @param bool $run_tests Whether to run tests on the connections. + * @param array $args Arguments. + * + * @see Automattic\Jetpack\Publicize\REST_API\Connections_Controller::get_all_connections() * * @return array */ - public static function get_connections( $run_tests = false ) { + public static function get_connections( $args = array() ) { if ( self::is_wpcom() ) { - return self::get_all_connections( $run_tests ); + return self::get_all_connections( $args ); } $site_id = Manager::get_site_id( true ); @@ -234,11 +247,17 @@ public static function get_connections( $run_tests = false ) { } $path = add_query_arg( - array( 'test_connections' => $run_tests ), + array( + 'test_connections' => $args['test_connections'] ?? false, + ), sprintf( '/sites/%d/publicize/connections', $site_id ) ); - $response = Client::wpcom_json_api_request_as_user( $path, 'v2', array( 'method' => 'GET' ) ); + $blog_or_user = ( $args['scope'] ?? '' ) === 'site' ? 'blog' : 'user'; + + $callback = array( Client::class, "wpcom_json_api_request_as_{$blog_or_user}" ); + + $response = call_user_func( $callback, $path, 'v2', array( 'method' => 'GET' ), null, 'wpcom' ); if ( is_wp_error( $response ) || 200 !== wp_remote_retrieve_response_code( $response ) ) { // TODO log error. @@ -262,9 +281,12 @@ public static function get_connections( $run_tests = false ) { public function get_items( $request ) { $items = array(); - $run_tests = $request->get_param( 'test_connections' ); + // On Jetpack, we don't want to pass the 'scope' param to get_connections(). + $args = array( + 'test_connections' => $request->get_param( 'test_connections' ), + ); - foreach ( self::get_connections( $run_tests ) as $item ) { + foreach ( self::get_connections( $args ) as $item ) { $data = $this->prepare_item_for_response( $item, $request ); $items[] = $this->prepare_response_for_collection( $data );