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

This commit is contained in:
Geoff Taylor
2024-10-29 16:57:15 -04:00
parent 594bc29d6b
commit 7c10a3d44c
12 changed files with 100 additions and 101 deletions
+34 -26
View File
@@ -9,6 +9,7 @@
namespace WPGraphQL\WooCommerce\Data\Mutation;
use GraphQL\Error\UserError;
use WPGraphQL\Utils\Utils;
/**
@@ -34,18 +35,24 @@ 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 === null ) {
return apply_filters(
"graphql_woocommerce_authorized_to_{$mutation}_orders",
current_user_can($post_type_object->cap->edit_posts),
$order_id,
$input,
$context,
$info
);
}
$order = \wc_get_order( $order_id );
$post_type = get_post_type( $order_id );
// 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 +572,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,10 +12,10 @@ namespace WPGraphQL\WooCommerce\Mutation;
use GraphQL\Error\UserError;
use GraphQL\Type\Definition\ResolveInfo;
use GraphQLRelay\Relay;
use WPGraphQL\AppContext;
use WPGraphQL\WooCommerce\Data\Mutation\Coupon_Mutation;
use WPGraphQL\WooCommerce\Model\Coupon;
use WPGraphQL\Utils\Utils;
/**
* Class Coupon_Create
@@ -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,9 +12,9 @@ namespace WPGraphQL\WooCommerce\Mutation;
use GraphQL\Error\UserError;
use GraphQL\Type\Definition\ResolveInfo;
use GraphQLRelay\Relay;
use WPGraphQL\AppContext;
use WPGraphQL\WooCommerce\Model\Coupon;
use WPGraphQL\Utils\Utils;
/**
* Class Coupon_Delete
@@ -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' ) );
}
+10 -13
View File
@@ -12,10 +12,10 @@ namespace WPGraphQL\WooCommerce\Mutation;
use GraphQL\Error\UserError;
use GraphQL\Type\Definition\ResolveInfo;
use GraphQLRelay\Relay;
use WPGraphQL\AppContext;
use WPGraphQL\WooCommerce\Data\Mutation\Order_Mutation;
use WPGraphQL\WooCommerce\Model\Order;
use WPGraphQL\Utils\Utils;
/**
* Class Order_Delete_Items
@@ -45,13 +45,14 @@ class Order_Delete_Items {
public static function get_input_fields() {
return array_merge(
[
'id' => [
'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' ),
'orderId' => [
'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,16 @@ 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' ) );
}
// 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.
+7 -10
View File
@@ -12,11 +12,11 @@ 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\WooCommerce\Data\Mutation\Order_Mutation;
use WPGraphQL\WooCommerce\Model\Order;
use WPGraphQL\Utils\Utils;
/**
* Class Order_Delete
@@ -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',
@@ -88,15 +89,11 @@ class Order_Delete {
// 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' ) );
}
// Check if authorized to delete this order.
+13 -16
View File
@@ -12,11 +12,11 @@ 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\WooCommerce\Data\Mutation\Order_Mutation;
use WPGraphQL\WooCommerce\Model\Order;
use WPGraphQL\Utils\Utils;
/**
* Class Order_Update
@@ -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' ),
'orderId' => [
'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,17 +90,13 @@ 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' ) );
}
// Check if authorized to update this order.
if ( ! Order_Mutation::authorized( $input, $context, $info, 'update', $order_id ) ) {
throw new UserError( __( 'User does not have the capabilities necessary to update an order.', 'wp-graphql-woocommerce' ) );
@@ -133,7 +130,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 +144,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 ) {
+4 -5
View File
@@ -15,6 +15,7 @@ use GraphQL\Type\Definition\ResolveInfo;
use GraphQLRelay\Relay;
use WPGraphQL\AppContext;
use WPGraphQL\Mutation\CommentUpdate;
use WPGraphQL\Utils\Utils;
/**
* Class Review_Update
@@ -80,11 +81,9 @@ class Review_Update {
];
$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' ) );
$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 ) {
+5 -1
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 ) ) {
+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',