| @@ -16,14 +16,15 @@ | ||
| 16 | 16 | use Exception; |
| 17 | 17 | use WC_Customer; |
| 18 | 18 | use WC_REST_Customers_Controller; |
| 19 | 19 | use WCPOS\WooCommercePOS\Logger; |
| 20 | -use WCPOS\WooCommercePOS\Services\Customer_Account_Guard; | |
| 20 | +use WCPOS\WooCommercePOS\Services\Permission_Rules; | |
| 21 | 21 | use WCPOS\WooCommercePOS\Services\Settings as SettingsService; |
| 22 | 22 | use WCPOS\WooCommercePOS\Services\Tax_Id_Reader; |
| 23 | 23 | use WCPOS\WooCommercePOS\Services\Tax_Id_Types; |
| 24 | 24 | use WCPOS\WooCommercePOS\Services\Tax_Id_Writer; |
| 25 | 25 | use WCPOS\WooCommercePOS\Sync\Collection_Rules; |
| 26 | +use WCPOS\WooCommercePOS\Sync\Meta_Normalizer; | |
| 26 | 27 | use WP_Error; |
| 27 | 28 | use WP_REST_Request; |
| 28 | 29 | use WP_REST_Response; |
| 29 | 30 | use WP_User; |
| @@ -128,105 +129,33 @@ | ||
| 128 | 129 | |
| 129 | 130 | return $schema; |
| 130 | 131 | } |
| 131 | 132 | |
| 132 | - /** | |
| 133 | - * Check if a given request has access to create a customer. | |
| 133 | + /** Delegate the create decision, preserving WooCommerce's request-dependent checks. | |
| 134 | 134 | * |
| 135 | - * WC checks promote_users (< 9.9) or create_customers (9.9+). The POS | |
| 136 | - * fallback checks only the version-appropriate capability so it matches | |
| 137 | - * the toggle shown on the Access settings page. | |
| 138 | - * | |
| 139 | - * @param WP_REST_Request $request Full details about the request. | |
| 140 | - * | |
| 141 | - * @return WP_Error|bool | |
| 135 | + * @param \WP_REST_Request $request Full request details. | |
| 142 | 136 | */ |
| 143 | 137 | public function create_item_permissions_check( $request ) { |
| 144 | - $permission = parent::create_item_permissions_check( $request ); | |
| 145 | - | |
| 146 | - if ( is_wp_error( $permission ) ) { | |
| 147 | - $customer_create_cap = version_compare( WC()->version, '9.9', '>=' ) | |
| 148 | - ? 'create_customers' | |
| 149 | - : 'promote_users'; | |
| 150 | - | |
| 151 | - if ( current_user_can( $customer_create_cap ) ) { | |
| 152 | - return true; | |
| 153 | - } | |
| 154 | - } | |
| 155 | - | |
| 156 | - return $permission; | |
| 138 | + return Permission_Rules::verdict( 'customers', 'create', (int) $request['id'], 0, 'v1', $request->get_params() ); | |
| 157 | 139 | } |
| 158 | 140 | |
| 159 | - /** | |
| 160 | - * Check if a given request has access to update a customer. | |
| 141 | + /** Delegate the edit decision, preserving WooCommerce's request-dependent checks. | |
| 161 | 142 | * |
| 162 | - * WCPOS never widens WooCommerce's credential fence, which refuses | |
| 163 | - * email/password changes on non-customer roles. The guard additionally | |
| 164 | - * keeps non-admins off staff accounts, testing capabilities rather than | |
| 165 | - * WooCommerce's first-role-only test. | |
| 166 | - * | |
| 167 | - * @param WP_REST_Request $request Full details about the request. | |
| 168 | - * | |
| 169 | - * @return WP_Error|bool | |
| 143 | + * @param \WP_REST_Request $request Full request details. | |
| 170 | 144 | */ |
| 171 | 145 | public function update_item_permissions_check( $request ) { |
| 172 | - return $this->wcpos_guarded_permissions_check( | |
| 173 | - (int) $request['id'], | |
| 174 | - function () use ( $request ) { | |
| 175 | - return parent::update_item_permissions_check( $request ); | |
| 176 | - } | |
| 177 | - ); | |
| 146 | + return Permission_Rules::verdict( 'customers', 'edit', (int) $request['id'], 0, 'v1', $request->get_params() ); | |
| 178 | 147 | } |
| 179 | 148 | |
| 180 | - /** | |
| 181 | - * Check if a given request has access to delete a customer. | |
| 149 | + /** Delegate the delete decision, preserving WooCommerce's request-dependent checks. | |
| 182 | 150 | * |
| 183 | - * WooCommerce refuses deleting a user whose role is outside its allowed | |
| 184 | - * list, but it reads only the FIRST role, so an administrator who also | |
| 185 | - * holds the customer role is deleted by any POS user with delete_users. | |
| 186 | - * The guard closes that by capability. | |
| 187 | - * | |
| 188 | - * @param WP_REST_Request $request Full details about the request. | |
| 189 | - * | |
| 190 | - * @return WP_Error|bool | |
| 151 | + * @param \WP_REST_Request $request Full request details. | |
| 191 | 152 | */ |
| 192 | 153 | public function delete_item_permissions_check( $request ) { |
| 193 | - return $this->wcpos_guarded_permissions_check( | |
| 194 | - (int) $request['id'], | |
| 195 | - function () use ( $request ) { | |
| 196 | - return parent::delete_item_permissions_check( $request ); | |
| 197 | - } | |
| 198 | - ); | |
| 154 | + return Permission_Rules::verdict( 'customers', 'delete', (int) $request['id'], 0, 'v1', $request->get_params() ); | |
| 199 | 155 | } |
| 200 | 156 | |
| 201 | 157 | /** |
| 202 | - * Run WooCommerce's own check behind the staff account guard. | |
| 203 | - * | |
| 204 | - * The guard runs first and can only refuse. When it clears the target, | |
| 205 | - * that target's roles are allowed through WooCommerce's shop_manager | |
| 206 | - * role-name restriction for the duration of the check, so a cleared | |
| 207 | - * subscriber or membership-plugin role is judged by capability. | |
| 208 | - * | |
| 209 | - * @param int $target_id Target user ID. | |
| 210 | - * @param callable $check Returns WooCommerce's verdict. | |
| 211 | - * | |
| 212 | - * @return WP_Error|bool | |
| 213 | - */ | |
| 214 | - private function wcpos_guarded_permissions_check( int $target_id, callable $check ) { | |
| 215 | - if ( ! Customer_Account_Guard::can_modify( get_current_user_id(), $target_id ) ) { | |
| 216 | - return Customer_Account_Guard::denial(); | |
| 217 | - } | |
| 218 | - | |
| 219 | - $restore = Customer_Account_Guard::allow_target_roles( $target_id ); | |
| 220 | - | |
| 221 | - try { | |
| 222 | - return $check(); | |
| 223 | - } finally { | |
| 224 | - $restore(); | |
| 225 | - } | |
| 226 | - } | |
| 227 | - | |
| 228 | - /** | |
| 229 | 158 | * Add extra fields to WP_REST_Controller::get_collection_params(). |
| 230 | 159 | * - add new fields to the 'orderby' enum list. |
| 231 | 160 | * - default the 'role' filter to every user, matching the proxy Read Lane. |
| 232 | 161 | */ |
| @@ -440,9 +369,20 @@ | ||
| 440 | 369 | |
| 441 | 370 | $filtered_meta_data = array_filter( |
| 442 | 371 | $raw_meta_data, |
| 443 | 372 | function ( $meta ) { |
| 444 | - return ! is_protected_meta( $meta->key, 'user' ); | |
| 373 | + if ( is_protected_meta( $meta->key, 'user' ) ) { | |
| 374 | + return false; | |
| 375 | + } | |
| 376 | + // A single enormous value fatals the response encoder no matter how few | |
| 377 | + // entries the customer has; same budget as the v2 sync lane. | |
| 378 | + if ( Meta_Normalizer::exceeds_value_budget( $meta->value ) ) { | |
| 379 | + Meta_Normalizer::note_oversized_meta( (string) $meta->key, (int) $meta->id ); | |
| 380 | + | |
| 381 | + return false; | |
| 382 | + } | |
| 383 | + | |
| 384 | + return true; | |
| 445 | 385 | } |
| 446 | 386 | ); |
| 447 | 387 | |
| 448 | 388 | // Convert to WC REST API expected format. |