Tidy up permission checks

This commit is contained in:
Mike Jolley 2019-06-18 16:06:04 +01:00
parent 1f6455807d
commit 71a32c96b6
11 changed files with 467 additions and 301 deletions

View File

@ -159,6 +159,8 @@ abstract class AbstractController extends WP_REST_Controller {
return $schema;
}
/**
* Check whether a given request has permission to read webhooks.
*
@ -166,10 +168,13 @@ abstract class AbstractController extends WP_REST_Controller {
* @return \WP_Error|boolean
*/
public function get_items_permissions_check( $request ) {
if ( ! Permissions::check_resource( $this->resource_type, 'read' ) ) {
$permission = Permissions::user_can_list( $this->get_item_title() );
if ( false === $permission ) {
return new \WP_Error( 'woocommerce_rest_cannot_view', __( 'Sorry, you cannot list resources.', 'woocommerce' ), array( 'status' => rest_authorization_required_code() ) );
}
return true;
return $permission;
}
/**
@ -180,10 +185,13 @@ abstract class AbstractController extends WP_REST_Controller {
* @return bool|\WP_Error
*/
public function create_item_permissions_check( $request ) {
if ( ! Permissions::check_resource( $this->resource_type, 'create' ) ) {
$permission = Permissions::user_can_create( $this->get_item_title() );
if ( false === $permission ) {
return new \WP_Error( 'woocommerce_rest_cannot_create', __( 'Sorry, you are not allowed to create resources.', 'woocommerce' ), array( 'status' => rest_authorization_required_code() ) );
}
return true;
return $permission;
}
/**
@ -193,12 +201,14 @@ abstract class AbstractController extends WP_REST_Controller {
* @return \WP_Error|boolean
*/
public function get_item_permissions_check( $request ) {
$id = $request->get_param( 'id' );
$id = $request->get_param( 'id' );
$permission = Permissions::user_can_read( $this->get_item_title(), $id );
if ( 0 !== $id && ! Permissions::check_resource( $this->resource_type, 'read', $id ) ) {
if ( false === $permission ) {
return new \WP_Error( 'woocommerce_rest_cannot_view', __( 'Sorry, you cannot view this resource.', 'woocommerce' ), array( 'status' => rest_authorization_required_code() ) );
}
return true;
return $permission;
}
/**
@ -209,12 +219,14 @@ abstract class AbstractController extends WP_REST_Controller {
* @return bool|\WP_Error
*/
public function update_item_permissions_check( $request ) {
$id = $request->get_param( 'id' );
$id = $request->get_param( 'id' );
$permission = Permissions::user_can_edit( $this->get_item_title(), $id );
if ( 0 !== $id && ! Permissions::check_resource( $this->resource_type, 'edit', $id ) ) {
if ( false === $permission ) {
return new \WP_Error( 'woocommerce_rest_cannot_edit', __( 'Sorry, you are not allowed to edit this resource.', 'woocommerce' ), array( 'status' => rest_authorization_required_code() ) );
}
return true;
return $permission;
}
/**
@ -225,12 +237,14 @@ abstract class AbstractController extends WP_REST_Controller {
* @return bool|\WP_Error
*/
public function delete_item_permissions_check( $request ) {
$id = $request->get_param( 'id' );
$id = $request->get_param( 'id' );
$permission = Permissions::user_can_delete( $this->get_item_title(), $id );
if ( 0 !== $id && ! Permissions::check_resource( $this->resource_type, 'delete', $id ) ) {
if ( false === $permission ) {
return new \WP_Error( 'woocommerce_rest_cannot_delete', __( 'Sorry, you are not allowed to delete this resource.', 'woocommerce' ), array( 'status' => rest_authorization_required_code() ) );
}
return true;
return $permission;
}
/**
@ -241,10 +255,13 @@ abstract class AbstractController extends WP_REST_Controller {
* @return bool|\WP_Error
*/
public function batch_items_permissions_check( $request ) {
if ( ! Permissions::check_resource( $this->resource_type, 'batch' ) ) {
$permission = Permissions::user_can_batch( $this->get_item_title() );
if ( false === $permission ) {
return new \WP_Error( 'woocommerce_rest_cannot_batch', __( 'Sorry, you are not allowed to batch manipulate this resource.', 'woocommerce' ), array( 'status' => rest_authorization_required_code() ) );
}
return true;
return $permission;
}
/**
@ -293,11 +310,20 @@ abstract class AbstractController extends WP_REST_Controller {
*
* @return string
*/
protected function get_hook_suffix() {
protected function get_item_title() {
$schema = $this->get_item_schema();
return $schema['title'];
}
/**
* Return suffix for item action hooks.
*
* @return string
*/
protected function get_hook_suffix() {
return $this->get_item_title();
}
/**
* Get data for this object in the format of this endpoint's schema.
*

View File

@ -57,97 +57,6 @@ abstract class AbstractObjectsController extends AbstractController {
$this->register_batch_route();
}
/**
* Check if a given request has access to read items.
*
* @param \WP_REST_Request $request Full details about the request.
* @return \WP_Error|boolean
*/
public function get_items_permissions_check( $request ) {
if ( ! Permissions::check_post_object( $this->post_type, 'read' ) ) {
return new \WP_Error( 'woocommerce_rest_cannot_view', __( 'Sorry, you cannot list resources.', 'woocommerce' ), array( 'status' => rest_authorization_required_code() ) );
}
return true;
}
/**
* Check if a given request has access to read an item.
*
* @param \WP_REST_Request $request Full details about the request.
* @return \WP_Error|boolean
*/
public function get_item_permissions_check( $request ) {
$id = $request->get_param( 'id' );
if ( 0 !== $id && ! Permissions::check_post_object( $this->post_type, 'read', $id ) ) {
return new \WP_Error( 'woocommerce_rest_cannot_view', __( 'Sorry, you cannot view this resource.', 'woocommerce' ), array( 'status' => rest_authorization_required_code() ) );
}
return true;
}
/**
* Check if a given request has access to create an item.
*
* @param \WP_REST_Request $request Full details about the request.
* @return \WP_Error|boolean
*/
public function create_item_permissions_check( $request ) {
if ( ! Permissions::check_post_object( $this->post_type, 'create' ) ) {
return new \WP_Error( 'woocommerce_rest_cannot_create', __( 'Sorry, you are not allowed to create resources.', 'woocommerce' ), array( 'status' => rest_authorization_required_code() ) );
}
return true;
}
/**
* Check if a given request has access to update an item.
*
* @param \WP_REST_Request $request Full details about the request.
* @return \WP_Error|boolean
*/
public function update_item_permissions_check( $request ) {
$id = $request->get_param( 'id' );
if ( 0 !== $id && ! Permissions::check_post_object( $this->post_type, 'edit', $id ) ) {
return new \WP_Error( 'woocommerce_rest_cannot_edit', __( 'Sorry, you are not allowed to edit this resource.', 'woocommerce' ), array( 'status' => rest_authorization_required_code() ) );
}
return true;
}
/**
* Check if a given request has access to delete an item.
*
* @param \WP_REST_Request $request Full details about the request.
* @return bool|\WP_Error
*/
public function delete_item_permissions_check( $request ) {
$id = $request->get_param( 'id' );
if ( 0 !== $id && ! Permissions::check_post_object( $this->post_type, 'delete', $id ) ) {
return new \WP_Error( 'woocommerce_rest_cannot_delete', __( 'Sorry, you are not allowed to delete this resource.', 'woocommerce' ), array( 'status' => rest_authorization_required_code() ) );
}
return true;
}
/**
* Check if a given request has access batch create, update and delete items.
*
* @param \WP_REST_Request $request Full details about the request.
*
* @return boolean|\WP_Error
*/
public function batch_items_permissions_check( $request ) {
if ( ! Permissions::check_post_object( $this->post_type, 'batch' ) ) {
return new \WP_Error( 'woocommerce_rest_cannot_batch', __( 'Sorry, you are not allowed to batch manipulate this resource.', 'woocommerce' ), array( 'status' => rest_authorization_required_code() ) );
}
return true;
}
/**
* Get a single item.
*
@ -379,7 +288,7 @@ abstract class AbstractObjectsController extends AbstractController {
$objects = array();
foreach ( $query_results['objects'] as $object ) {
if ( ! Permissions::check_post_object( $this->post_type, 'read', $object->get_id() ) ) {
if ( ! Permissions::user_can_read( $this->post_type, $object->get_id() ) ) {
continue;
}
@ -444,7 +353,7 @@ abstract class AbstractObjectsController extends AbstractController {
$supports_trash = $this->supports_trash( $object );
if ( ! Permissions::check_post_object( $this->post_type, 'delete', $object->get_id() ) ) {
if ( ! Permissions::user_can_delete( $this->post_type, $object->get_id() ) ) {
/* translators: %s: post type */
return new \WP_Error( "woocommerce_rest_user_cannot_delete_{$this->post_type}", sprintf( __( 'Sorry, you are not allowed to delete %s.', 'woocommerce' ), $this->post_type ), array( 'status' => rest_authorization_required_code() ) );
}
@ -832,4 +741,57 @@ abstract class AbstractObjectsController extends AbstractController {
protected function get_hook_suffix() {
return $this->post_type . '_object';
}
/**
* Check if a given request has access to read a webhook.
*
* @param \WP_REST_Request $request Full details about the request.
* @return \WP_Error|boolean
*/
public function get_item_permissions_check( $request ) {
$id = $request->get_param( 'id' );
$object = $this->get_object( $id );
if ( ! $object || 0 === $object->get_id() ) {
return new \WP_Error( "woocommerce_rest_{$this->post_type}_invalid_id", __( 'Invalid ID.', 'woocommerce' ), array( 'status' => 404 ) );
}
return parent::get_item_permissions_check( $request );
}
/**
* Check if a given request has access update a webhook.
*
* @param \WP_REST_Request $request Full details about the request.
*
* @return bool|\WP_Error
*/
public function update_item_permissions_check( $request ) {
$id = $request->get_param( 'id' );
$object = $this->get_object( $id );
if ( ! $object || 0 === $object->get_id() ) {
return new \WP_Error( "woocommerce_rest_{$this->post_type}_invalid_id", __( 'Invalid ID.', 'woocommerce' ), array( 'status' => 404 ) );
}
return parent::update_item_permissions_check( $request );
}
/**
* Check if a given request has access delete a webhook.
*
* @param \WP_REST_Request $request Full details about the request.
*
* @return bool|\WP_Error
*/
public function delete_item_permissions_check( $request ) {
$id = $request->get_param( 'id' );
$object = $this->get_object( $id );
if ( ! $object || 0 === $object->get_id() ) {
return new \WP_Error( "woocommerce_rest_{$this->post_type}_invalid_id", __( 'Invalid ID.', 'woocommerce' ), array( 'status' => 404 ) );
}
return parent::delete_item_permissions_check( $request );
}
}

View File

@ -122,90 +122,6 @@ abstract class AbstractTermsContoller extends AbstractController {
$this->register_batch_route();
}
/**
* Check if a given request has access to read the terms.
*
* @param \WP_REST_Request $request Full details about the request.
* @return \WP_Error|boolean
*/
public function get_items_permissions_check( $request ) {
if ( ! Permissions::check_taxonomy( $this->taxonomy, 'read' ) ) {
return new \WP_Error( 'woocommerce_rest_cannot_view', __( 'Sorry, you cannot list resources.', 'woocommerce' ), array( 'status' => rest_authorization_required_code() ) );
}
return true;
}
/**
* Check if a given request has access to create a term.
*
* @param \WP_REST_Request $request Full details about the request.
* @return \WP_Error|boolean
*/
public function create_item_permissions_check( $request ) {
if ( ! Permissions::check_taxonomy( $this->taxonomy, 'create' ) ) {
return new \WP_Error( 'woocommerce_rest_cannot_create', __( 'Sorry, you are not allowed to create resources.', 'woocommerce' ), array( 'status' => rest_authorization_required_code() ) );
}
return true;
}
/**
* Check if a given request has access to read a term.
*
* @param \WP_REST_Request $request Full details about the request.
* @return \WP_Error|boolean
*/
public function get_item_permissions_check( $request ) {
$id = $request->get_param( 'id' );
if ( ! Permissions::check_taxonomy( $this->taxonomy, 'read', $id ) ) {
return new \WP_Error( 'woocommerce_rest_cannot_view', __( 'Sorry, you are not allowed to view this resource.', 'woocommerce' ), array( 'status' => rest_authorization_required_code() ) );
}
return true;
}
/**
* Check if a given request has access to update a term.
*
* @param \WP_REST_Request $request Full details about the request.
* @return \WP_Error|boolean
*/
public function update_item_permissions_check( $request ) {
$id = $request->get_param( 'id' );
if ( ! Permissions::check_taxonomy( $this->taxonomy, 'edit', $id ) ) {
return new \WP_Error( 'woocommerce_rest_cannot_edit', __( 'Sorry, you are not allowed to edit this resource.', 'woocommerce' ), array( 'status' => rest_authorization_required_code() ) );
}
return true;
}
/**
* Check if a given request has access to delete a term.
*
* @param \WP_REST_Request $request Full details about the request.
* @return \WP_Error|boolean
*/
public function delete_item_permissions_check( $request ) {
$id = $request->get_param( 'id' );
if ( ! Permissions::check_taxonomy( $this->taxonomy, 'delete', $id ) ) {
return new \WP_Error( 'woocommerce_rest_cannot_delete', __( 'Sorry, you are not allowed to delete this resource.', 'woocommerce' ), array( 'status' => rest_authorization_required_code() ) );
}
return true;
}
/**
* Check if a given request has access batch create, update and delete items.
*
* @param \WP_REST_Request $request Full details about the request.
* @return boolean|\WP_Error
*/
public function batch_items_permissions_check( $request ) {
if ( ! Permissions::check_taxonomy( $this->taxonomy, 'batch' ) ) {
return new \WP_Error( 'woocommerce_rest_cannot_batch', __( 'Sorry, you are not allowed to batch manipulate this resource.', 'woocommerce' ), array( 'status' => rest_authorization_required_code() ) );
}
return true;
}
/**
* Get terms associated with a taxonomy.
*

View File

@ -52,7 +52,7 @@ class CustomerDownloads extends AbstractController {
return new \WP_Error( 'woocommerce_rest_customer_invalid', __( 'Resource does not exist.', 'woocommerce' ), array( 'status' => 404 ) );
}
if ( ! Permissions::user_can( $this->resource_type, 'read', $customer->ID ) ) {
if ( ! Permissions::user_can_read( $this->resource_type, $customer->ID ) ) {
return new \WP_Error( 'woocommerce_rest_cannot_view', __( 'Sorry, you cannot list resources.', 'woocommerce' ), array( 'status' => rest_authorization_required_code() ) );
}

View File

@ -740,4 +740,68 @@ class Customers extends AbstractController {
);
return $params;
}
/**
* Check if a given ID is valid.
*
* @param \WP_REST_Request $request Full details about the request.
* @return \WP_Error|boolean
*/
protected function check_valid_customer_id( $request ) {
$id = $request->get_param( 'id' );
$user = get_userdata( $id );
if ( false === $user ) {
return new \WP_Error( 'woocommerce_rest_customer_invalid_id', __( 'Invalid ID.', 'woocommerce' ), array( 'status' => 404 ) );
}
return true;
}
/**
* Check if a given request has access to read a webhook.
*
* @param \WP_REST_Request $request Full details about the request.
* @return \WP_Error|boolean
*/
public function get_item_permissions_check( $request ) {
$check_valid = $this->check_valid_customer_id( $request );
if ( is_wp_error( $check_valid ) ) {
return $check_valid;
}
return parent::get_item_permissions_check( $request );
}
/**
* Check if a given request has access to delete an item.
*
* @param \WP_REST_Request $request Full details about the request.
* @return \WP_Error|boolean
*/
public function delete_item_permissions_check( $request ) {
$check_valid = $this->check_valid_customer_id( $request );
if ( is_wp_error( $check_valid ) ) {
return $check_valid;
}
return parent::delete_item_permissions_check( $request );
}
/**
* Check if a given request has access to update an item.
*
* @param \WP_REST_Request $request Full details about the request.
* @return \WP_Error|boolean
*/
public function update_item_permissions_check( $request ) {
$check_valid = $this->check_valid_customer_id( $request );
if ( is_wp_error( $check_valid ) ) {
return $check_valid;
}
return parent::update_item_permissions_check( $request );
}
}

View File

@ -112,35 +112,6 @@ class OrderNotes extends AbstractController {
);
}
/**
* Check whether a given request has permission to read order notes.
*
* @param \WP_REST_Request $request Full details about the request.
* @return \WP_Error|boolean
*/
public function get_items_permissions_check( $request ) {
if ( ! Permissions::check_post_object( $this->post_type, 'read' ) ) {
return new \WP_Error( 'woocommerce_rest_cannot_view', __( 'Sorry, you cannot list resources.', 'woocommerce' ), array( 'status' => rest_authorization_required_code() ) );
}
return true;
}
/**
* Check if a given request has access create order notes.
*
* @param \WP_REST_Request $request Full details about the request.
*
* @return bool|\WP_Error
*/
public function create_item_permissions_check( $request ) {
if ( ! Permissions::check_post_object( $this->post_type, 'create' ) ) {
return new \WP_Error( 'woocommerce_rest_cannot_create', __( 'Sorry, you are not allowed to create resources.', 'woocommerce' ), array( 'status' => rest_authorization_required_code() ) );
}
return true;
}
/**
* Check if a given request has access to read a order note.
*
@ -150,7 +121,7 @@ class OrderNotes extends AbstractController {
public function get_item_permissions_check( $request ) {
$order = wc_get_order( (int) $request['order_id'] );
if ( $order && ! Permissions::check_post_object( $this->post_type, 'read', $order->get_id() ) ) {
if ( $order && ! Permissions::user_can_read( $this->post_type, $order->get_id() ) ) {
return new \WP_Error( 'woocommerce_rest_cannot_view', __( 'Sorry, you cannot view this resource.', 'woocommerce' ), array( 'status' => rest_authorization_required_code() ) );
}
@ -167,7 +138,7 @@ class OrderNotes extends AbstractController {
public function delete_item_permissions_check( $request ) {
$order = wc_get_order( (int) $request['order_id'] );
if ( $order && ! Permissions::check_post_object( $this->post_type, 'delete', $order->get_id() ) ) {
if ( $order && ! Permissions::user_can_delete( $this->post_type, $order->get_id() ) ) {
return new \WP_Error( 'woocommerce_rest_cannot_delete', __( 'Sorry, you are not allowed to delete this resource.', 'woocommerce' ), array( 'status' => rest_authorization_required_code() ) );
}

View File

@ -219,7 +219,7 @@ class ProductReviews extends AbstractController {
$reviews = array();
foreach ( $query_result as $review ) {
if ( ! Permissions::check_resource( $this->resource_type, 'read', $review->comment_ID ) ) {
if ( ! Permissions::user_can_read( 'product_review', $review->comment_ID ) ) {
continue;
}
@ -983,4 +983,55 @@ class ProductReviews extends AbstractController {
return $changed;
}
/**
* Check if a given request has access to read a webhook.
*
* @param \WP_REST_Request $request Full details about the request.
* @return \WP_Error|boolean
*/
public function get_item_permissions_check( $request ) {
$id = $request->get_param( 'id' );
$check_valid = $this->get_review( $id );
if ( is_wp_error( $check_valid ) ) {
return $check_valid;
}
return parent::get_item_permissions_check( $request );
}
/**
* Check if a given request has access to delete an item.
*
* @param \WP_REST_Request $request Full details about the request.
* @return \WP_Error|boolean
*/
public function delete_item_permissions_check( $request ) {
$id = $request->get_param( 'id' );
$check_valid = $this->get_review( $id );
if ( is_wp_error( $check_valid ) ) {
return $check_valid;
}
return parent::delete_item_permissions_check( $request );
}
/**
* Check if a given request has access to update an item.
*
* @param \WP_REST_Request $request Full details about the request.
* @return \WP_Error|boolean
*/
public function update_item_permissions_check( $request ) {
$id = $request->get_param( 'id' );
$check_valid = $this->get_review( $id );
if ( is_wp_error( $check_valid ) ) {
return $check_valid;
}
return parent::update_item_permissions_check( $request );
}
}

View File

@ -561,26 +561,74 @@ class ProductVariations extends Products {
}
/**
* Check if a given request has access to update an item.
* Check if a given ID is valid.
*
* @param \WP_REST_Request $request Full details about the request.
* @return \WP_Error|boolean
*/
public function update_item_permissions_check( $request ) {
$object = $this->get_object( (int) $request['id'] );
protected function check_valid_variation_id( $request ) {
$id = $request->get_param( 'id' );
$object = $this->get_object( $id );
if ( $object && 0 !== $object->get_id() && ! Permissions::check_post_object( $this->post_type, 'edit', $object->get_id() ) ) {
return new \WP_Error( 'woocommerce_rest_cannot_edit', __( 'Sorry, you are not allowed to edit this resource.', 'woocommerce' ), array( 'status' => rest_authorization_required_code() ) );
if ( ! $object || 0 === $object->get_id() ) {
return new \WP_Error( "woocommerce_rest_{$this->post_type}_invalid_id", __( 'Invalid ID.', 'woocommerce' ), array( 'status' => 404 ) );
}
// Check if variation belongs to the correct parent product.
if ( $object && 0 !== $object->get_parent_id() && absint( $request['product_id'] ) !== $object->get_parent_id() ) {
return new \WP_Error( 'woocommerce_rest_cannot_edit', __( 'Parent product does not match current variation.', 'woocommerce' ), array( 'status' => rest_authorization_required_code() ) );
}
return true;
}
/**
* Check if a given request has access to read a webhook.
*
* @param \WP_REST_Request $request Full details about the request.
* @return \WP_Error|boolean
*/
public function get_item_permissions_check( $request ) {
$check_valid = $this->check_valid_variation_id( $request );
if ( is_wp_error( $check_valid ) ) {
return $check_valid;
}
return parent::get_item_permissions_check( $request );
}
/**
* Check if a given request has access to delete an item.
*
* @param \WP_REST_Request $request Full details about the request.
* @return \WP_Error|boolean
*/
public function delete_item_permissions_check( $request ) {
$check_valid = $this->check_valid_variation_id( $request );
if ( is_wp_error( $check_valid ) ) {
return $check_valid;
}
return parent::delete_item_permissions_check( $request );
}
/**
* Check if a given request has access to update an item.
*
* @param \WP_REST_Request $request Full details about the request.
* @return \WP_Error|boolean
*/
public function update_item_permissions_check( $request ) {
$check_valid = $this->check_valid_variation_id( $request );
if ( is_wp_error( $check_valid ) ) {
return $check_valid;
}
return parent::update_item_permissions_check( $request );
}
/**
* Get data for this object in the format of this endpoint's schema.
*
@ -721,7 +769,7 @@ class ProductVariations extends Products {
*/
$supports_trash = apply_filters( "woocommerce_rest_{$this->post_type}_object_trashable", $supports_trash, $object );
if ( ! Permissions::check_post_object( $this->post_type, 'delete', $object->get_id() ) ) {
if ( ! Permissions::user_can_delete( $this->post_type, $object->get_id() ) ) {
return new \WP_Error(
/* translators: %s: post type */
"woocommerce_rest_user_cannot_delete_{$this->post_type}", sprintf( __( 'Sorry, you are not allowed to delete %s.', 'woocommerce' ), $this->post_type ), array(

View File

@ -1142,7 +1142,7 @@ class Products extends AbstractObjectsController {
*/
$supports_trash = apply_filters( "woocommerce_rest_{$this->post_type}_object_trashable", $supports_trash, $object );
if ( ! Permissions::check_post_object( $this->post_type, 'delete', $object->get_id() ) ) {
if ( ! Permissions::user_can_delete( $this->post_type, $object->get_id() ) ) {
return new \WP_Error(
"woocommerce_rest_user_cannot_delete_{$this->post_type}",
/* translators: %s: post type */

View File

@ -17,94 +17,222 @@ defined( 'ABSPATH' ) || exit;
class Permissions {
/**
* Resource permissions required.
* Items not defined here will default to manage_woocommerce permission.
*
* @var array
*/
protected static $resource_permissions = [
'settings' => 'manage_woocommerce',
'system_status' => 'manage_woocommerce',
'attributes' => 'manage_product_terms',
'shipping_methods' => 'manage_woocommerce',
'payment_gateways' => 'manage_woocommerce',
'webhooks' => 'manage_woocommerce',
'product_reviews' => 'moderate_comments',
'customers' => [
protected static $capabilities = array(
'shop_coupon' => [
'read' => 'read_shop_coupon',
'list' => 'read_private_shop_coupons',
'create' => 'publish_shop_coupons',
'edit' => 'edit_shop_coupon',
'delete' => 'delete_shop_coupon',
'batch' => 'edit_others_shop_coupons',
],
'customer_download' => [
'read' => 'read_shop_order',
'list' => 'read_private_shop_orders',
'create' => 'publish_shop_orders',
'edit' => 'edit_shop_order',
'delete' => 'delete_shop_order',
'batch' => 'edit_others_shop_orders',
],
'customer' => [
'read' => 'list_users',
'create' => 'promote_users', // Check if current user can create users, shop managers are not allowed to create users.
'list' => 'list_users',
'create' => 'promote_users',
'edit' => 'edit_users',
'delete' => 'delete_users',
'batch' => 'promote_users',
],
];
'shop_order' => [
'read' => 'read_shop_order',
'list' => 'read_private_shop_orders',
'create' => 'publish_shop_orders',
'edit' => 'edit_shop_order',
'delete' => 'delete_shop_order',
'batch' => 'edit_others_shop_orders',
],
'product_attribute' => 'edit_product_terms',
'product_attribute_term' => [
'read' => 'manage_product_terms',
'list' => 'manage_product_terms',
'create' => 'edit_product_terms',
'edit' => 'edit_product_terms',
'delete' => 'delete_product_terms',
'batch' => 'edit_product_terms',
],
'product_cat' => [
'read' => 'manage_product_terms',
'list' => 'manage_product_terms',
'create' => 'edit_product_terms',
'edit' => 'edit_product_terms',
'delete' => 'delete_product_terms',
'batch' => 'edit_product_terms',
],
'product_review' => 'moderate_comments',
'product' => [
'read' => 'read_product',
'list' => 'read_private_products',
'create' => 'publish_products',
'edit' => 'edit_product',
'delete' => 'delete_product',
'batch' => 'edit_others_products',
],
'product_shipping_class' => [
'read' => 'manage_product_terms',
'list' => 'manage_product_terms',
'create' => 'edit_product_terms',
'edit' => 'edit_product_terms',
'delete' => 'delete_product_terms',
'batch' => 'edit_product_terms',
],
'product_tag' => [
'read' => 'manage_product_terms',
'list' => 'manage_product_terms',
'create' => 'edit_product_terms',
'edit' => 'edit_product_terms',
'delete' => 'delete_product_terms',
'batch' => 'edit_product_terms',
],
'product_variation' => [
'read' => 'read_product',
'list' => 'read_private_products',
'create' => 'publish_products',
'edit' => 'edit_product',
'delete' => 'delete_product',
'batch' => 'edit_others_products',
],
);
/**
* See if the current user can do something to a resource.
* Get capabilities required for a resource for a given context.
*
* @param string $resource Type of permission required.
* @param string $context Context. One of read, edit, create, update, delete, batch.
* @param int $resource_id Optional resource ID.
* @param string $type Item/resource type. Comes from schema title.
* @param string $context Read, edit, delete, batch, create.
* @return array List of caps to check. Defaults to manage_woocommerce.
*/
protected static function get_capabilities_for_type( $type, $context = 'read' ) {
if ( isset( self::$capabilities[ $type ][ $context ] ) ) {
$caps = self::$capabilities[ $type ][ $context ];
} elseif ( isset( self::$capabilities[ $type ] ) ) {
$caps = self::$capabilities[ $type ];
} else {
$caps = 'manage_woocommerce';
}
return is_array( $caps ) ? $caps : array( $caps );
}
/**
* Check if user has a list of caps.
*
* @param array $capabilities List of caps to check.
* @param int $object_id Object ID to check. Optional.
* @return boolean
*/
public static function check_resource( $resource, $context = 'read', $resource_id = 0 ) {
if ( ! isset( self::$resource_permissions[ $resource ] ) ) {
protected static function has_required_capabilities( $capabilities, $object_id = null ) {
$permission = true;
foreach ( $capabilities as $capability ) {
if ( ! current_user_can( $capability, $object_id ) ) {
$permission = false;
}
}
return $permission;
}
/**
* Check if user can list a collection of resources.
*
* @param string $type Item/resource type. Comes from schema title.
* @return bool True on success.
*/
public static function user_can_list( $type ) {
$capabilities = self::get_capabilities_for_type( $type, 'list' );
$permission = self::has_required_capabilities( $capabilities );
return apply_filters( 'woocommerce_rest_user_can_list', $permission, $type );
}
/**
* Check if user can read a resource.
*
* @param string $type Item/resource type. Comes from schema title.
* @param int $object_id Resource ID. 0 to check access to read all.
* @return bool True on success.
*/
public static function user_can_read( $type, $object_id = 0 ) {
if ( 0 === $object_id ) {
return false;
}
$permissions = self::$resource_permissions[ $resource ];
$capability = is_array( $permissions ) ? $permissions[ $context ] : $permissions;
$permission = current_user_can( $capability );
return apply_filters( 'woocommerce_rest_check_permissions', $permission, $context, $resource_id, $resource );
$capabilities = self::get_capabilities_for_type( $type, 'read' );
$permission = self::has_required_capabilities( $capabilities, $object_id );
return apply_filters( 'woocommerce_rest_user_can_read', $permission, $type, $object_id );
}
/**
* See if the current user can do something to a resource.
* Check if user can read a resource.
*
* @param string $taxonomy Taxonomy name.
* @param string $context Context. One of read, edit, create, update, delete, batch.
* @param int $object_id Optional object ID.
* @return boolean
* @param string $type Item/resource type. Comes from schema title.
* @param int $object_id Resource ID.
* @return bool True on success.
*/
public static function check_taxonomy( $taxonomy, $context = 'read', $object_id = 0 ) {
$contexts = array(
'read' => 'manage_terms',
'create' => 'edit_terms',
'edit' => 'edit_terms',
'delete' => 'delete_terms',
'batch' => 'edit_terms',
);
$cap = $contexts[ $context ];
$taxonomy_object = get_taxonomy( $taxonomy );
$permission = current_user_can( $taxonomy_object->cap->$cap, $object_id );
return apply_filters( 'woocommerce_rest_check_permissions', $permission, $context, $object_id, $taxonomy );
}
/**
* Check permissions of posts on REST API.
*
* @param string $post_type Post type.
* @param string $context Request context.
* @param int $object_id Post ID.
* @return bool
*/
public static function check_post_object( $post_type, $context = 'read', $object_id = 0 ) {
$contexts = array(
'read' => 'read_private_posts',
'create' => 'publish_posts',
'edit' => 'edit_post',
'delete' => 'delete_post',
'batch' => 'edit_others_posts',
);
if ( 'revision' === $post_type ) {
$permission = false;
} else {
$cap = $contexts[ $context ];
$post_type_object = get_post_type_object( $post_type );
$permission = current_user_can( $post_type_object->cap->$cap, $object_id );
public static function user_can_edit( $type, $object_id ) {
if ( 0 === $object_id ) {
return false;
}
return apply_filters( 'woocommerce_rest_check_permissions', $permission, $context, $object_id, $post_type );
$capabilities = self::get_capabilities_for_type( $type, 'edit' );
$permission = self::has_required_capabilities( $capabilities, $object_id );
return apply_filters( 'woocommerce_rest_user_can_edit', $permission, $type, $object_id );
}
/**
* Check if user can create a resource.
*
* @param string $type Item/resource type. Comes from schema title.
* @return bool True on success.
*/
public static function user_can_create( $type ) {
$capabilities = self::get_capabilities_for_type( $type, 'create' );
$permission = self::has_required_capabilities( $capabilities );
return apply_filters( 'woocommerce_rest_user_can_create', $permission, $type );
}
/**
* Check if user can delete a resource.
*
* @param string $type Item/resource type. Comes from schema title.
* @param int $object_id Resource ID.
* @return bool True on success.
*/
public static function user_can_delete( $type, $object_id ) {
if ( 0 === $object_id ) {
return false;
}
$capabilities = self::get_capabilities_for_type( $type, 'delete' );
$permission = self::has_required_capabilities( $capabilities, $object_id );
return apply_filters( 'woocommerce_rest_user_can_delete', $permission, $type, $object_id );
}
/**
* Check if user can batch update a resource.
*
* @param string $type Item/resource type. Comes from schema title.
* @return bool True on success.
*/
public static function user_can_batch( $type ) {
$capabilities = self::get_capabilities_for_type( $type, 'batch' );
$permission = self::has_required_capabilities( $capabilities );
return apply_filters( 'woocommerce_rest_user_can_batch', $permission, $type );
}
}

View File

@ -533,7 +533,7 @@ class Customers extends WC_REST_Unit_Test_Case {
$request = new WP_REST_Request( 'DELETE', '/wc/v4/customers/0' );
$request->set_param( 'force', true );
$response = $this->server->dispatch( $request );
$this->assertEquals( 400, $response->get_status() );
$this->assertEquals( 404, $response->get_status() );
}
/**