fix: ID resolution made consistent across all edit and delete node mu… (#902)

* fix: ID resolution made consistent across all edit and delete node mutations

* chore: linter compliances met
This commit is contained in:
Geoff Taylor
2024-11-06 15:00:11 -05:00
committed by GitHub
parent b801133db4
commit 32f8ba28ca
12 changed files with 128 additions and 103 deletions
+51 -28
View File
@@ -9,6 +9,7 @@
namespace WPGraphQL\WooCommerce\Data\Mutation;
use GraphQL\Error\UserError;
use WPGraphQL\Utils\Utils;
/**
@@ -22,8 +23,9 @@ class Order_Mutation {
* @param \WPGraphQL\AppContext $context AppContext instance.
* @param \GraphQL\Type\Definition\ResolveInfo $info ResolveInfo instance.
* @param string $mutation Mutation being executed.
* @param integer|null $order_id Order ID.
*
* @param integer|null|false $order_id Order ID.
* @throws \GraphQL\Error\UserError Error locating order.
*
* @return boolean
*/
public static function authorized( $input, $context, $info, $mutation = 'create', $order_id = null ) {
@@ -34,18 +36,38 @@ class Order_Mutation {
*/
$post_type_object = get_post_type_object( 'shop_order' );
return apply_filters(
"graphql_woocommerce_authorized_to_{$mutation}_orders",
current_user_can(
'delete' === $mutation
? $post_type_object->cap->delete_posts
: $post_type_object->cap->edit_posts
),
$order_id,
$input,
$context,
$info
);
if ( ! $order_id ) {
return apply_filters(
"graphql_woocommerce_authorized_to_{$mutation}_orders",
current_user_can( $post_type_object->cap->edit_posts ),
$order_id,
$input,
$context,
$info
);
}
/** @var false|\WC_Order $order */
$order = \wc_get_order( $order_id );
if ( false === $order ) {
throw new UserError(
sprintf(
/* translators: %d: Order ID */
__( 'Failed to find order with ID of %d.', 'wp-graphql-woocommerce' ),
$order_id
)
);
}
$post_type = get_post_type( $order_id );
if ( false === $post_type ) {
throw new UserError( __( 'Failed to identify the post type of the order.', 'wp-graphql-woocommerce' ) );
}
// Return true if user is owner or admin.
$is_owner = 0 !== get_current_user_id() && $order->get_customer_id() === get_current_user_id();
$is_admin = \wc_rest_check_post_permissions( $post_type, 'edit', $order_id );
return $is_owner || $is_admin;
}
/**
@@ -565,25 +587,26 @@ class Order_Mutation {
/**
* Validates order customer
*
* @param array $input Input data describing order.
* @param string $customer_id ID of customer for order.
*
* @return bool
*/
public static function validate_customer( $input ) {
if ( ! empty( $input['customerId'] ) ) {
// Make sure customer exists.
if ( false === get_user_by( 'id', $input['customerId'] ) ) {
return false;
}
// Make sure customer is part of blog.
if ( is_multisite() && ! is_user_member_of_blog( $input['customerId'] ) ) {
add_user_to_blog( get_current_blog_id(), $input['customerId'], 'customer' );
}
return true;
public static function validate_customer( $customer_id ) {
$id = Utils::get_database_id_from_id( $customer_id );
if ( ! $id ) {
return false;
}
return false;
if ( false === get_user_by( 'id', $id ) ) {
return false;
}
// Make sure customer is part of blog.
if ( is_multisite() && ! is_user_member_of_blog( $id ) ) {
add_user_to_blog( get_current_blog_id(), $id, 'customer' );
}
return true;
}
/**
+8 -10
View File
@@ -12,8 +12,8 @@ namespace WPGraphQL\WooCommerce\Mutation;
use GraphQL\Error\UserError;
use GraphQL\Type\Definition\ResolveInfo;
use GraphQLRelay\Relay;
use WPGraphQL\AppContext;
use WPGraphQL\Utils\Utils;
use WPGraphQL\WooCommerce\Data\Mutation\Coupon_Mutation;
use WPGraphQL\WooCommerce\Model\Coupon;
@@ -163,16 +163,14 @@ class Coupon_Create {
*/
public static function mutate_and_get_payload( $input, AppContext $context, ResolveInfo $info ) {
// Retrieve order ID.
$coupon_id = 0;
if ( ! empty( $input['id'] ) && is_numeric( $input['id'] ) ) {
$coupon_id = absint( $input['id'] );
} elseif ( ! empty( $input['id'] ) ) {
$id_components = Relay::fromGlobalId( $input['id'] );
if ( empty( $id_components['id'] ) || empty( $id_components['type'] ) ) {
throw new UserError( __( 'The "id" provided is invalid', 'wp-graphql-woocommerce' ) );
}
if ( ! empty( $input['id'] ) ) {
$coupon_id = Utils::get_database_id_from_id( $input['id'] );
} else {
$coupon_id = 0;
}
$coupon_id = absint( $id_components['id'] );
if ( false === $coupon_id ) {
throw new UserError( __( 'Coupon ID provided is invalid. Please check input and try again.', 'wp-graphql-woocommerce' ) );
}
$coupon = new \WC_Coupon( $coupon_id );
+5 -11
View File
@@ -12,8 +12,8 @@ namespace WPGraphQL\WooCommerce\Mutation;
use GraphQL\Error\UserError;
use GraphQL\Type\Definition\ResolveInfo;
use GraphQLRelay\Relay;
use WPGraphQL\AppContext;
use WPGraphQL\Utils\Utils;
use WPGraphQL\WooCommerce\Model\Coupon;
/**
@@ -87,17 +87,11 @@ class Coupon_Delete {
*/
public static function mutate_and_get_payload( $input, AppContext $context, ResolveInfo $info ) {
// Retrieve order ID.
$coupon_id = 0;
if ( ! empty( $input['id'] ) && is_numeric( $input['id'] ) ) {
$coupon_id = absint( $input['id'] );
} elseif ( ! empty( $input['id'] ) ) {
$id_components = Relay::fromGlobalId( $input['id'] );
if ( empty( $id_components['id'] ) || empty( $id_components['type'] ) ) {
throw new UserError( __( 'The "id" provided is invalid', 'wp-graphql-woocommerce' ) );
}
$coupon_id = absint( $id_components['id'] );
$coupon_id = Utils::get_database_id_from_id( $input['id'] );
if ( empty( $coupon_id ) ) {
throw new UserError( __( 'Coupon ID provided is missing or invalid. Please check input and try again.', 'wp-graphql-woocommerce' ) );
}
$coupon = new Coupon( $coupon_id );
if ( ! $coupon->ID ) {
+1 -1
View File
@@ -167,7 +167,7 @@ class Order_Create {
WC()->payment_gateways();
// Validate customer ID, if set.
if ( ! empty( $input['customerId'] ) && ! Order_Mutation::validate_customer( $input ) ) {
if ( ! empty( $input['customerId'] ) && ! Order_Mutation::validate_customer( $input['customerId'] ) ) {
throw new UserError( __( 'Customer ID is invalid.', 'wp-graphql-woocommerce' ) );
}
+12 -11
View File
@@ -12,8 +12,8 @@ namespace WPGraphQL\WooCommerce\Mutation;
use GraphQL\Error\UserError;
use GraphQL\Type\Definition\ResolveInfo;
use GraphQLRelay\Relay;
use WPGraphQL\AppContext;
use WPGraphQL\Utils\Utils;
use WPGraphQL\WooCommerce\Data\Mutation\Order_Mutation;
use WPGraphQL\WooCommerce\Model\Order;
@@ -47,11 +47,12 @@ class Order_Delete_Items {
[
'id' => [
'type' => 'ID',
'description' => __( 'Order global ID', 'wp-graphql-woocommerce' ),
'description' => __( 'Database ID or global ID of the order', 'wp-graphql-woocommerce' ),
],
'orderId' => [
'type' => 'Int',
'description' => __( 'Order WP ID', 'wp-graphql-woocommerce' ),
'type' => 'Int',
'description' => __( 'Order WP ID', 'wp-graphql-woocommerce' ),
'deprecationReason' => __( 'Use "id" field instead.', 'wp-graphql-woocommerce' ),
],
'itemIds' => [
'type' => [ 'list_of' => 'Int' ],
@@ -87,20 +88,20 @@ class Order_Delete_Items {
// Retrieve order ID.
$order_id = null;
if ( ! empty( $input['id'] ) ) {
$id_components = Relay::fromGlobalId( $input['id'] );
if ( empty( $id_components['id'] ) || empty( $id_components['type'] ) ) {
throw new UserError( __( 'The "id" provided is invalid', 'wp-graphql-woocommerce' ) );
}
$order_id = absint( $id_components['id'] );
$order_id = Utils::get_database_id_from_id( $input['id'] );
} elseif ( ! empty( $input['orderId'] ) ) {
$order_id = absint( $input['orderId'] );
} else {
throw new UserError( __( 'No order ID provided.', 'wp-graphql-woocommerce' ) );
throw new UserError( __( 'Order ID provided is missing or invalid. Please check input and try again.', 'wp-graphql-woocommerce' ) );
}
if ( ! $order_id ) {
throw new UserError( __( 'Order ID provided is invalid. Please check input and try again.', 'wp-graphql-woocommerce' ) );
}
// Check if authorized to delete items on this order.
if ( ! Order_Mutation::authorized( $input, $context, $info, 'delete-items', $order_id ) ) {
throw new UserError( __( 'User does not have the capabilities necessary to delete an order.', 'wp-graphql-woocommerce' ) );
throw new UserError( __( 'User does not have the capabilities necessary to delete order items.', 'wp-graphql-woocommerce' ) );
}
// Confirm item IDs.
+12 -11
View File
@@ -12,9 +12,9 @@ namespace WPGraphQL\WooCommerce\Mutation;
use GraphQL\Error\UserError;
use GraphQL\Type\Definition\ResolveInfo;
use GraphQLRelay\Relay;
use WC_Order_Factory;
use WPGraphQL\AppContext;
use WPGraphQL\Utils\Utils;
use WPGraphQL\WooCommerce\Data\Mutation\Order_Mutation;
use WPGraphQL\WooCommerce\Model\Order;
@@ -48,11 +48,12 @@ class Order_Delete {
[
'id' => [
'type' => 'ID',
'description' => __( 'Order global ID', 'wp-graphql-woocommerce' ),
'description' => __( 'Database ID or global ID of the order', 'wp-graphql-woocommerce' ),
],
'orderId' => [
'type' => 'Int',
'description' => __( 'Order WP ID', 'wp-graphql-woocommerce' ),
'type' => 'Int',
'description' => __( 'Order WP ID', 'wp-graphql-woocommerce' ),
'deprecationReason' => __( 'Use "id" field instead.', 'wp-graphql-woocommerce' ),
],
'forceDelete' => [
'type' => 'Boolean',
@@ -86,17 +87,17 @@ class Order_Delete {
public static function mutate_and_get_payload() {
return static function ( $input, AppContext $context, ResolveInfo $info ) {
// Retrieve order ID.
$order_id = null;
$order_id = false;
if ( ! empty( $input['id'] ) ) {
$id_components = Relay::fromGlobalId( $input['id'] );
if ( empty( $id_components['id'] ) || empty( $id_components['type'] ) ) {
throw new UserError( __( 'The "id" provided is invalid', 'wp-graphql-woocommerce' ) );
}
$order_id = absint( $id_components['id'] );
$order_id = Utils::get_database_id_from_id( $input['id'] );
} elseif ( ! empty( $input['orderId'] ) ) {
$order_id = absint( $input['orderId'] );
} else {
throw new UserError( __( 'No order ID provided.', 'wp-graphql-woocommerce' ) );
throw new UserError( __( 'Order ID provided is missing or invalid. Please check input and try again.', 'wp-graphql-woocommerce' ) );
}
if ( ! $order_id ) {
throw new UserError( __( 'Order ID provided is invalid. Please check input and try again.', 'wp-graphql-woocommerce' ) );
}
// Check if authorized to delete this order.
+15 -14
View File
@@ -12,9 +12,9 @@ namespace WPGraphQL\WooCommerce\Mutation;
use GraphQL\Error\UserError;
use GraphQL\Type\Definition\ResolveInfo;
use GraphQLRelay\Relay;
use WC_Order_Factory;
use WPGraphQL\AppContext;
use WPGraphQL\Utils\Utils;
use WPGraphQL\WooCommerce\Data\Mutation\Order_Mutation;
use WPGraphQL\WooCommerce\Model\Order;
@@ -49,15 +49,16 @@ class Order_Update {
[
'id' => [
'type' => 'ID',
'description' => __( 'Order global ID', 'wp-graphql-woocommerce' ),
'description' => __( 'Database ID or global ID of the order', 'wp-graphql-woocommerce' ),
],
'orderId' => [
'type' => 'Int',
'description' => __( 'Order WP ID', 'wp-graphql-woocommerce' ),
'type' => 'Int',
'description' => __( 'Order WP ID', 'wp-graphql-woocommerce' ),
'deprecationReason' => __( 'Use "id" field instead.', 'wp-graphql-woocommerce' ),
],
'customerId' => [
'type' => 'Int',
'description' => __( 'Order customer ID', 'wp-graphql-woocommerce' ),
'type' => 'ID',
'description' => __( 'Database ID or global ID of the customer for the order', 'wp-graphql-woocommerce' ),
],
]
);
@@ -89,15 +90,15 @@ class Order_Update {
// Retrieve order ID.
$order_id = null;
if ( ! empty( $input['id'] ) ) {
$id_components = Relay::fromGlobalId( $input['id'] );
if ( empty( $id_components['id'] ) || empty( $id_components['type'] ) ) {
throw new UserError( __( 'The "id" provided is invalid', 'wp-graphql-woocommerce' ) );
}
$order_id = absint( $id_components['id'] );
$order_id = Utils::get_database_id_from_id( $input['id'] );
} elseif ( ! empty( $input['orderId'] ) ) {
$order_id = absint( $input['orderId'] );
} else {
throw new UserError( __( 'No order ID provided.', 'wp-graphql-woocommerce' ) );
throw new UserError( __( 'Order ID provided is missing or invalid. Please check input and try again.', 'wp-graphql-woocommerce' ) );
}
if ( ! $order_id ) {
throw new UserError( __( 'Order ID provided is invalid. Please check input and try again.', 'wp-graphql-woocommerce' ) );
}
// Check if authorized to update this order.
@@ -133,7 +134,7 @@ class Order_Update {
\WC()->payment_gateways();
// Validate customer ID.
if ( ! empty( $input['customerId'] ) && ! Order_Mutation::validate_customer( $input ) ) {
if ( ! empty( $input['customerId'] ) && ! Order_Mutation::validate_customer( $input['customerId'] ) ) {
throw new UserError( __( 'New customer ID is invalid.', 'wp-graphql-woocommerce' ) );
}
@@ -147,7 +148,7 @@ class Order_Update {
}
// Actions for after the order is saved.
if ( true === $input['isPaid'] ) {
if ( isset( $input['isPaid'] ) && true === $input['isPaid'] ) {
$order->payment_complete(
! empty( $input['transactionId'] )
? $input['transactionId']
@@ -14,6 +14,7 @@ use GraphQL\Error\UserError;
use GraphQL\Type\Definition\ResolveInfo;
use GraphQLRelay\Relay;
use WPGraphQL\AppContext;
use WPGraphQL\Utils\Utils;
/**
* Class Review_Delete_Restore
@@ -130,12 +131,12 @@ class Review_Delete_Restore {
public static function mutate_and_get_payload() {
return static function ( $input, AppContext $context, ResolveInfo $info ) {
// Retrieve the product review rating for the payload.
$id_parts = Relay::fromGlobalId( $input['id'] );
if ( empty( $id_parts['id'] ) ) {
$id = Utils::get_database_id_from_id( $input['id'] );
if ( ! $id ) {
throw new UserError( __( 'Invalid Product Review ID provided', 'wp-graphql-woocommerce' ) );
}
$rating = get_comment_meta( absint( $id_parts['id'] ), 'rating' );
$rating = get_comment_meta( absint( $id ), 'rating' );
// @codingStandardsIgnoreLine
switch ( $info->fieldName ) {
+5 -7
View File
@@ -12,9 +12,9 @@ namespace WPGraphQL\WooCommerce\Mutation;
use GraphQL\Error\UserError;
use GraphQL\Type\Definition\ResolveInfo;
use GraphQLRelay\Relay;
use WPGraphQL\AppContext;
use WPGraphQL\Mutation\CommentUpdate;
use WPGraphQL\Utils\Utils;
/**
* Class Review_Update
@@ -79,12 +79,10 @@ class Review_Update {
'clientMutationId' => 1,
];
$payload = [];
$id_parts = ! empty( $input['id'] ) ? Relay::fromGlobalId( $input['id'] ) : null;
$payload['id'] = isset( $id_parts['id'] ) && absint( $id_parts['id'] ) ? absint( $id_parts['id'] ) : null;
if ( empty( $payload['id'] ) ) {
throw new UserError( __( 'The Review could not be updated', 'wp-graphql-woocommerce' ) );
$payload = [];
$id = Utils::get_database_id_from_id( $input['id'] );
if ( ! $id ) {
throw new UserError( __( 'Provided review ID missing or invalid ', 'wp-graphql-woocommerce' ) );
}
if ( array_intersect_key( $input, $skip ) !== $input ) {
+6 -2
View File
@@ -13,6 +13,7 @@ namespace WPGraphQL\WooCommerce\Mutation;
use GraphQL\Error\UserError;
use GraphQL\Type\Definition\ResolveInfo;
use WPGraphQL\AppContext;
use WPGraphQL\Utils\Utils;
/**
* Class - Tax_Rate_Create
@@ -117,7 +118,10 @@ class Tax_Rate_Create {
* @return array
*/
public static function mutate_and_get_payload( $input, AppContext $context, ResolveInfo $info ) {
$id = ! empty( $input['id'] ) ? $input['id'] : null;
$id = ! empty( $input['id'] ) ? Utils::get_database_id_from_id( $input['id'] ) : null;
if ( false === $id ) {
throw new UserError( __( 'Invalid ID provided.', 'wp-graphql-woocommerce' ) );
}
$action = ! $id ? 'create' : 'update';
$permission = ! $id ? 'create' : 'edit';
if ( ! \wc_rest_check_manager_permissions( 'settings', $permission ) ) {
@@ -217,7 +221,7 @@ class Tax_Rate_Create {
/**
* Filter tax rate object before responding.
*
* @param object $tax_rate_id The shipping method object.
* @param int $tax_rate_id The shipping method object.
* @param array $input Request input.
*/
do_action( "graphql_woocommerce_tax_rate_{$action}", $id, $input );
+6 -2
View File
@@ -13,6 +13,7 @@ namespace WPGraphQL\WooCommerce\Mutation;
use GraphQL\Error\UserError;
use GraphQL\Type\Definition\ResolveInfo;
use WPGraphQL\AppContext;
use WPGraphQL\Utils\Utils;
/**
* Class - Tax_Rate_Delete
@@ -75,11 +76,14 @@ class Tax_Rate_Delete {
throw new UserError( __( 'Sorry, you are not allowed to delete tax rates.', 'wp-graphql-woocommerce' ), \rest_authorization_required_code() );
}
global $wpdb;
$id = $input['id'];
$id = Utils::get_database_id_from_id( $input['id'] );
if ( ! $id ) {
throw new UserError( __( 'Invalid tax rate ID.', 'wp-graphql-woocommerce' ) );
}
$tax = $context->get_loader( 'tax_rate' )->load( $id );
if ( ! $tax ) {
throw new UserError( __( 'Invalid tax rate ID.', 'wp-graphql-woocommerce' ) );
throw new UserError( __( 'Failed to locate tax rate', 'wp-graphql-woocommerce' ) );
}
/**
+3 -3
View File
@@ -625,7 +625,7 @@ class OrderMutationsTest extends \Codeception\TestCase\WPTestCase {
*
* User without necessary capabilities cannot update order an order.
*/
wp_set_current_user( $this->customer );
wp_set_current_user( $this->factory->user->create( [ 'role' => 'customer' ] ) );
$actual = $this->orderMutation(
$updated_input,
'updateOrder',
@@ -902,7 +902,7 @@ class OrderMutationsTest extends \Codeception\TestCase\WPTestCase {
*
* User without necessary capabilities cannot delete order an order.
*/
wp_set_current_user( $this->customer );
wp_set_current_user( $this->factory->user->create( [ 'role' => 'customer' ] ) );
$actual = $this->orderMutation(
$deleted_input,
'deleteOrder',
@@ -1056,7 +1056,7 @@ class OrderMutationsTest extends \Codeception\TestCase\WPTestCase {
*
* User without necessary capabilities cannot delete order an order.
*/
wp_set_current_user( $this->customer );
wp_set_current_user( $this->factory->user->create( [ 'role' => 'customer' ] ) );
$actual = $this->orderMutation(
$deleted_items_input,
'deleteOrderItems',