| @@ -440,105 +440,8 @@ | ||
| 440 | 440 | return $caps; |
| 441 | 441 | } |
| 442 | 442 | |
| 443 | 443 | /** |
| 444 | - * The only role a till user may assign. | |
| 445 | - * | |
| 446 | - * Customer creation from the till always produces this role; changing a | |
| 447 | - * role is not a POS feature, so nothing legitimate needs more. | |
| 448 | - */ | |
| 449 | - private const TILL_ASSIGNABLE_ROLES = array( 'customer' ); | |
| 450 | - | |
| 451 | - /** | |
| 452 | - * The roles a POS actor may hand out, or null when the actor is not fenced. | |
| 453 | - * | |
| 454 | - * Administrators (and so multisite super admins) are not fenced. A shop | |
| 455 | - * manager — any actor with `manage_woocommerce` — follows WooCommerce's own | |
| 456 | - * list for shop managers, `woocommerce_shop_manager_editable_roles` | |
| 457 | - * (customer by default), which WooCommerce enforces only while it is active | |
| 458 | - * and only for the literal `shop_manager` role name; applying it here keeps | |
| 459 | - * that fence up when WooCommerce is deactivated (the roles and their | |
| 460 | - * capabilities persist) and for a cashier who also holds shop manager. | |
| 461 | - * Everyone else with till access gets TILL_ASSIGNABLE_ROLES. | |
| 462 | - * | |
| 463 | - * @param int $actor Acting user ID. | |
| 464 | - * | |
| 465 | - * @return array|null Role names, or null for an unfenced actor. | |
| 466 | - */ | |
| 467 | - private static function assignable_roles( int $actor ): ?array { | |
| 468 | - if ( $actor < 1 || ! user_can( $actor, 'access_woocommerce_pos' ) || user_can( $actor, 'manage_options' ) ) { | |
| 469 | - return null; | |
| 470 | - } | |
| 471 | - $allowed = self::TILL_ASSIGNABLE_ROLES; | |
| 472 | - if ( user_can( $actor, 'manage_woocommerce' ) ) { | |
| 473 | - $allowed = (array) apply_filters( 'woocommerce_shop_manager_editable_roles', self::TILL_ASSIGNABLE_ROLES ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- WooCommerce's own fence list, applied as WooCommerce applies it. | |
| 474 | - } | |
| 475 | - | |
| 476 | - return array_values( array_filter( array_map( 'strval', $allowed ) ) ); | |
| 477 | - } | |
| 478 | - | |
| 479 | - /** | |
| 480 | - * Fence the roles a till user may assign (`editable_roles` filter). | |
| 481 | - * | |
| 482 | - * The Cashier role holds `edit_users` and, on WooCommerce below 9.9, | |
| 483 | - * `promote_users` (customer creation needed it). WordPress's role-update | |
| 484 | - * checks — `WP_REST_Users_Controller::check_role_update()`, `edit_user()` | |
| 485 | - * and the users.php bulk actions — accept those two capabilities and then | |
| 486 | - * ask `get_editable_roles()` which roles the actor may hand out; nothing | |
| 487 | - * ranked them, so a cashier could set an ordinary customer's role to | |
| 488 | - * Administrator. can_modify() does not catch that: it judges the target's | |
| 489 | - * current capabilities, which a plain customer has none of until after the | |
| 490 | - * update. It only ever removes roles; it never adds one. | |
| 491 | - * | |
| 492 | - * @param array $roles Editable roles keyed by role name. | |
| 493 | - * | |
| 494 | - * @return array | |
| 495 | - */ | |
| 496 | - public static function filter_editable_roles( $roles ): array { | |
| 497 | - $roles = (array) $roles; | |
| 498 | - $allowed = self::assignable_roles( get_current_user_id() ); | |
| 499 | - if ( null === $allowed ) { | |
| 500 | - return $roles; | |
| 501 | - } | |
| 502 | - | |
| 503 | - return array_intersect_key( $roles, array_fill_keys( $allowed, true ) ); | |
| 504 | - } | |
| 505 | - | |
| 506 | - /** | |
| 507 | - * Refuse a multisite "add existing user" invite outside the fence (`invite_user` action). | |
| 508 | - * | |
| 509 | - * WordPress's wp-admin/user-new.php stores the requested role in the `new_user_<key>` | |
| 510 | - * option and only reads `get_editable_roles()` for the email's label, so an | |
| 511 | - * invite to an existing network account can carry any role; accepting it | |
| 512 | - * calls `add_user_to_blog()` with that role unchecked. Same fence as | |
| 513 | - * filter_editable_roles(): a fenced actor's invite may name only an | |
| 514 | - * assignable role, or the invite is deleted before its email goes out. | |
| 515 | - * | |
| 516 | - * @param int $user_id Invited user ID. | |
| 517 | - * @param array|null $role Role label array, null when the role was not editable. | |
| 518 | - * @param string $newuser_key Invitation key. | |
| 519 | - * | |
| 520 | - * @return void | |
| 521 | - */ | |
| 522 | - public static function refuse_unfenced_invite( $user_id, $role, $newuser_key ): void { | |
| 523 | - $allowed = self::assignable_roles( get_current_user_id() ); | |
| 524 | - if ( null === $allowed ) { | |
| 525 | - return; | |
| 526 | - } | |
| 527 | - $invite = get_option( 'new_user_' . $newuser_key ); | |
| 528 | - $requested = \is_array( $invite ) && isset( $invite['role'] ) ? (string) $invite['role'] : ''; | |
| 529 | - if ( \in_array( $requested, $allowed, true ) ) { | |
| 530 | - return; | |
| 531 | - } | |
| 532 | - delete_option( 'new_user_' . $newuser_key ); | |
| 533 | - wp_die( | |
| 534 | - esc_html__( 'Sorry, you are not allowed to give users that role.', 'woocommerce-pos' ), | |
| 535 | - '', | |
| 536 | - array( 'response' => 403 ) | |
| 537 | - ); | |
| 538 | - } | |
| 539 | - | |
| 540 | - /** | |
| 541 | 444 | * Build the staff account permission error. |
| 542 | 445 | * |
| 543 | 446 | * @return \WP_Error |
| 544 | 447 | */ |