diff --git a/src/classes/api/endpoints/class-tainacan-rest-roles-controller.php b/src/classes/api/endpoints/class-tainacan-rest-roles-controller.php index ca042d203..71ed62461 100644 --- a/src/classes/api/endpoints/class-tainacan-rest-roles-controller.php +++ b/src/classes/api/endpoints/class-tainacan-rest-roles-controller.php @@ -294,6 +294,7 @@ class REST_Roles_Controller extends REST_Controller { foreach ( $newcaps as $cap => $val ) { \wp_roles()->add_cap($role_slug, $cap, $val); + \tainacan_roles()->add_dependencies($role_slug, $cap); } diff --git a/src/classes/class-tainacan-roles.php b/src/classes/class-tainacan-roles.php index 3ec03ae47..f3882427a 100644 --- a/src/classes/class-tainacan-roles.php +++ b/src/classes/class-tainacan-roles.php @@ -5,16 +5,6 @@ use Tainacan\Repositories\Repository; class Roles { - - public static $dependencies = [ - "tainacan-items" => [ - 'edit_posts' => 'upload_files', - "edit_private_posts" => 'upload_files', - "edit_published_posts" => 'upload_files', - "edit_others_posts" => 'upload_files' - ] - ]; - private static $instance = null; private $capabilities; @@ -536,6 +526,8 @@ class Roles { } } + $collection_capabilities = tainacan_collections()->get_capabilities(); + foreach ( $caps as $cap ) { if ( array_key_exists($cap, $allcaps) && $allcaps[$cap] === true ) { @@ -548,24 +540,64 @@ class Roles { $allcaps = array_merge($allcaps, [ $cap => true ]); - } elseif ( \strpos($cap, 'tnc_col_') === 0 ) { + /** + * Handle checks for collection specific capabilities. + * Either tnc_col_* or tnc_rep_*_collections + */ + } elseif ( \strpos($cap, 'tnc_col_') === 0 || in_array( $cap, (array) $collection_capabilities ) ) { - $col_id = preg_replace('/[a-z_]+(\d+)[a-z_]+?$/', '$1', $cap ); + $check_all_collections_cap = false; + $has_all_collections_cap = false; + + + /** + * We are only interested in checks for a specific collection. + * $args[2] will be set if this came from a meta cap of a specific collection ( e.g. current_user_can('tnc_rep_edit_collection', 3) ). + */ + if ( isset( $args[2] ) && is_numeric( $args[2] ) ) { + $col_id = $args[2]; + /** + * Or we extract the collectino id from the capability itself. Example: tnc_col_3_delete_items + */ + } else { + $col_id = preg_replace('/[a-z_]+(\d+)[a-z_]+?$/', '$1', $cap ); + $check_all_collections_cap = true; + } + /** + * If there is no specific collection, do nothing. + */ if ( ! is_numeric($col_id) ) { continue; } - // check for tnc_col_all_* capabilities - $all_collections_cap = preg_replace('/([a-z_]+)(\d+)([a-z_]+?)$/', '${1}all${3}', $cap ); + // In case of a tnc_col_* capability check, + // Let's see if the user has the respective tnc_col_all_* capability + if ( $check_all_collections_cap ) { + $all_collections_cap = preg_replace('/([a-z_]+)(\d+)([a-z_]+?)$/', '${1}all${3}', $cap ); + $has_all_collections_cap = $user->has_cap( $all_collections_cap ); + } if ( $user->has_cap('manage_tainacan_collection_' . $col_id) || $user->has_cap('manage_tainacan_collection_all') || - $user->has_cap($all_collections_cap) ) { + $has_all_collections_cap + ) { + $allcaps = array_merge($allcaps, [ $cap => true ]); - } else { - // check if the user is the owner + + /** + * If a user is trying to edit a collection relying on the manage_tainacan_collection_* cap + * they will also need the edit_others_posts capability. But since it is 'manage_tainacan', + * we have to treat this here because this check will not get here since we are only handling + * caps that starts with tnc_ + */ + if ( $collection_capabilities->edit_posts === $cap ) { + $allcaps = array_merge($allcaps, [ $collection_capabilities->edit_others_posts => true ]); + } + + } elseif ( \strpos($cap, 'tnc_col_') === 0 ) { + // check if the user is the owner only when checking tnc_col_* capabilities $collection = tainacan_collections()->fetch( (int) $col_id ); if ( $collection instanceof \Tainacan\Entities\Collection ) { if ( (int) $collection->get_author_id() == (int) $user->ID ) { @@ -580,7 +612,6 @@ class Roles { return $allcaps; - } diff --git a/tests/test-api-roles.php b/tests/test-api-roles.php index dd59fb592..09c66eed9 100644 --- a/tests/test-api-roles.php +++ b/tests/test-api-roles.php @@ -234,6 +234,38 @@ class TAINACAN_REST_Roles_Controller extends TAINACAN_UnitApiTestCase { $this->assertTrue($role['capabilities']['upload_files']); } + public function test_add_dependencies_capabilities() { + $request = new \WP_REST_Request('POST', $this->namespace . '/roles'); + + $request->set_query_params(['name' => 'New role']); + + $create = $this->server->dispatch($request); + //var_dump($create); + $this->assertEquals( 201, $create->get_status() ); + + $request = new \WP_REST_Request('PATCH', $this->namespace . '/roles/tainacan-new-role'); + + $request->set_query_params( + [ + 'name' => 'Changed name', + 'capabilities' => [ + 'tnc_col_12_edit_items' => true + ] + ] + ); + + $response = $this->server->dispatch($request); + + $this->assertEquals( 200, $response->get_status() ); + + $role = \wp_roles()->roles['tainacan-new-role']; + + $this->assertArrayHasKey('tnc_col_12_edit_items', $role['capabilities']); + $this->assertTrue($role['capabilities']['tnc_col_12_edit_items']); + $this->assertArrayHasKey('upload_files', $role['capabilities']); + $this->assertTrue($role['capabilities']['upload_files']); + } + public function test_get_collection_caps() { $collection = $this->tainacan_entity_factory->create_entity( diff --git a/tests/test-capabilities.php b/tests/test-capabilities.php index 0c38b8d5a..c2f63c08b 100644 --- a/tests/test-capabilities.php +++ b/tests/test-capabilities.php @@ -829,6 +829,40 @@ class Capabilities extends TAINACAN_UnitTestCase { $this->assertEquals(3, sizeof($cols)); + } + + /** + * @group collectionss + */ + function test_manage_collection_can_edit_collection() { + global $current_user; + wp_set_current_user($this->subscriber2->ID); + + $this->assertFalse( $this->public_collection->can_edit() ); + + $this->subscriber2->add_cap( 'manage_tainacan_collection_' . $this->public_collection->get_id() ); + $current_user = $this->subscriber2; // force update current user object with new capabilities + + $this->assertTrue( $this->public_collection->can_edit() ); + + } + + /** + * @group collections + */ + function test_manage_all_collections_can_edit_collection() { + global $current_user; + wp_set_current_user($this->subscriber2->ID); + + $this->assertFalse( $this->public_collection->can_edit() ); + + $this->subscriber2->add_cap( 'manage_tainacan_collection_all' ); + $current_user = $this->subscriber2; // force update current user object with new capabilities + + $this->assertTrue( $this->public_collection->can_edit() ); + $this->assertTrue( $this->private_collection->can_edit() ); + + } /**