From 5c0e2d8caf503ddf3ab7233b65d2be4eaa398e2a Mon Sep 17 00:00:00 2001 From: Jon Waldstein Date: Fri, 16 Aug 2024 16:28:49 -0400 Subject: [PATCH 1/4] feature: scaffold Permissions facade and test --- .../Permissions/DonationFormsPermissions.php | 26 ++++++ .../Permissions/Facades/Permissions.php | 19 ++++ .../Permissions/Facades/PermissionsFacade.php | 23 +++++ .../Permissions/Facades/TestPermissions.php | 28 ++++++ .../TestDonationFormsPermissions.php | 93 +++++++++++++++++++ 5 files changed, 189 insertions(+) create mode 100644 src/Framework/Permissions/DonationFormsPermissions.php create mode 100644 src/Framework/Permissions/Facades/Permissions.php create mode 100644 src/Framework/Permissions/Facades/PermissionsFacade.php create mode 100644 tests/Unit/Framework/Permissions/Facades/TestPermissions.php create mode 100644 tests/Unit/Framework/Permissions/TestDonationFormsPermissions.php diff --git a/src/Framework/Permissions/DonationFormsPermissions.php b/src/Framework/Permissions/DonationFormsPermissions.php new file mode 100644 index 0000000000..c6d9ee3c73 --- /dev/null +++ b/src/Framework/Permissions/DonationFormsPermissions.php @@ -0,0 +1,26 @@ +assertInstanceOf( + DonationFormsPermissions::class, + Permissions::donationForms() + ); + } + +} diff --git a/tests/Unit/Framework/Permissions/TestDonationFormsPermissions.php b/tests/Unit/Framework/Permissions/TestDonationFormsPermissions.php new file mode 100644 index 0000000000..1b9e3495ca --- /dev/null +++ b/tests/Unit/Framework/Permissions/TestDonationFormsPermissions.php @@ -0,0 +1,93 @@ +user->create_and_get(); + $user->add_role($role); + + wp_set_current_user($user->ID); + + if ($shouldPass) { + $this->assertTrue( + Permissions::donationForms()->can($capability) + ); + } else { + $this->assertFalse( + Permissions::donationForms()->can($capability) + ); + } + } + + + /** + * @unreleased + * + * @return array> + */ + public function canProvider(): array + { + return [ + // true + ['give_worker', 'create', true], + ['give_worker', 'read', true], + ['give_worker', 'update', true], + ['give_worker', 'edit', true], + + ['give_manager', 'create', true], + ['give_manager', 'read', true], + ['give_manager', 'update', true], + ['give_manager', 'edit', true], + ['give_manager', 'delete', true], + + ['give_accountant', 'create', true], + ['give_accountant', 'read', true], + ['give_accountant', 'update', true], + ['give_accountant', 'edit', true], + ['give_accountant', 'read_private_give_forms', true], + + ['administrator', 'create', true], + ['administrator', 'read', true], + ['administrator', 'update', true], + ['administrator', 'edit', true], + ['administrator', 'delete', true], + + // false + ['give_accountant', 'delete', false], + + ['give_donor', 'create', false], + ['give_donor', 'read', false], + ['give_donor', 'update', false], + ['give_donor', 'edit', false], + ['give_donor', 'delete', false], + + ['give_subscriber', 'create', false], + ['give_subscriber', 'read', false], + ['give_subscriber', 'update', false], + ['give_subscriber', 'edit', false], + ['give_subscriber', 'delete', false], + + ['subscriber', 'create', false], + ['subscriber', 'read', false], + ['subscriber', 'update', false], + ['subscriber', 'edit', false], + ['subscriber', 'delete', false], + ]; + } +} From cf289ac8520bb7ea5ba72e8f95a3b872717c5111 Mon Sep 17 00:00:00 2001 From: Jon Waldstein Date: Fri, 16 Aug 2024 16:33:37 -0400 Subject: [PATCH 2/4] refactor: update to UserPermissions and start a readme --- .../{Permissions.php => UserPermissions.php} | 4 ++-- ...ssionsFacade.php => UserPermissionsFacade.php} | 2 +- src/Framework/Permissions/README.md | 15 +++++++++++++++ ...estPermissions.php => TestUserPermissions.php} | 6 +++--- .../Permissions/TestDonationFormsPermissions.php | 6 +++--- 5 files changed, 24 insertions(+), 9 deletions(-) rename src/Framework/Permissions/Facades/{Permissions.php => UserPermissions.php} (78%) rename src/Framework/Permissions/Facades/{PermissionsFacade.php => UserPermissionsFacade.php} (94%) create mode 100644 src/Framework/Permissions/README.md rename tests/Unit/Framework/Permissions/Facades/{TestPermissions.php => TestUserPermissions.php} (74%) diff --git a/src/Framework/Permissions/Facades/Permissions.php b/src/Framework/Permissions/Facades/UserPermissions.php similarity index 78% rename from src/Framework/Permissions/Facades/Permissions.php rename to src/Framework/Permissions/Facades/UserPermissions.php index 23611bf607..99f951f736 100644 --- a/src/Framework/Permissions/Facades/Permissions.php +++ b/src/Framework/Permissions/Facades/UserPermissions.php @@ -10,10 +10,10 @@ * * @method static DonationFormsPermissions donationForms() */ -class Permissions extends Facade +class UserPermissions extends Facade { protected function getFacadeAccessor(): string { - return PermissionsFacade::class; + return UserPermissionsFacade::class; } } diff --git a/src/Framework/Permissions/Facades/PermissionsFacade.php b/src/Framework/Permissions/Facades/UserPermissionsFacade.php similarity index 94% rename from src/Framework/Permissions/Facades/PermissionsFacade.php rename to src/Framework/Permissions/Facades/UserPermissionsFacade.php index 71a40a8771..1872cf5afc 100644 --- a/src/Framework/Permissions/Facades/PermissionsFacade.php +++ b/src/Framework/Permissions/Facades/UserPermissionsFacade.php @@ -11,7 +11,7 @@ * * @unreleased */ -class PermissionsFacade +class UserPermissionsFacade { /** * @unreleased diff --git a/src/Framework/Permissions/README.md b/src/Framework/Permissions/README.md new file mode 100644 index 0000000000..d3a973127b --- /dev/null +++ b/src/Framework/Permissions/README.md @@ -0,0 +1,15 @@ +# Permissions Facade + +The Permissions Facade is a class that allows you to check if a user has a specific capability or role. It is a wrapper around the WordPress `current_user_can()` function. + +Example: + +```php +use Give\Framework\Permissions\Permissions; + +if (!UserPermissions::donationForms()->can('edit')) { + throw new Exception('You do not have permission to edit donation forms.'); +} +``` +}; +``` diff --git a/tests/Unit/Framework/Permissions/Facades/TestPermissions.php b/tests/Unit/Framework/Permissions/Facades/TestUserPermissions.php similarity index 74% rename from tests/Unit/Framework/Permissions/Facades/TestPermissions.php rename to tests/Unit/Framework/Permissions/Facades/TestUserPermissions.php index 77dd51d8c9..7c35def0f0 100644 --- a/tests/Unit/Framework/Permissions/Facades/TestPermissions.php +++ b/tests/Unit/Framework/Permissions/Facades/TestUserPermissions.php @@ -3,14 +3,14 @@ namespace Give\Tests\Unit\Framework\Permissions\Facades; use Give\Framework\Permissions\DonationFormsPermissions; -use Give\Framework\Permissions\Facades\Permissions; +use Give\Framework\Permissions\Facades\UserPermissions; use Give\Tests\TestCase; use Give\Tests\TestTraits\RefreshDatabase; /** * @unreleased */ -final class TestPermissions extends TestCase +final class TestUserPermissions extends TestCase { use RefreshDatabase; @@ -21,7 +21,7 @@ public function testDonationForms(): void { $this->assertInstanceOf( DonationFormsPermissions::class, - Permissions::donationForms() + UserPermissions::donationForms() ); } diff --git a/tests/Unit/Framework/Permissions/TestDonationFormsPermissions.php b/tests/Unit/Framework/Permissions/TestDonationFormsPermissions.php index 1b9e3495ca..0b788d54f7 100644 --- a/tests/Unit/Framework/Permissions/TestDonationFormsPermissions.php +++ b/tests/Unit/Framework/Permissions/TestDonationFormsPermissions.php @@ -2,7 +2,7 @@ namespace Give\Tests\Unit\Framework\Permissions; -use Give\Framework\Permissions\Facades\Permissions; +use Give\Framework\Permissions\Facades\UserPermissions; use Give\Tests\TestCase; use Give\Tests\TestTraits\RefreshDatabase; @@ -26,11 +26,11 @@ public function testCan($role, $capability, $shouldPass): void if ($shouldPass) { $this->assertTrue( - Permissions::donationForms()->can($capability) + UserPermissions::donationForms()->can($capability) ); } else { $this->assertFalse( - Permissions::donationForms()->can($capability) + UserPermissions::donationForms()->can($capability) ); } } From fbbe3d00ffb312938b51650e34eb757a413b1e21 Mon Sep 17 00:00:00 2001 From: Jon Waldstein Date: Fri, 23 Aug 2024 11:26:06 -0400 Subject: [PATCH 3/4] feature: add abstract class and make permissions more dynamic based on cap and role --- .../Contracts/UserPermissionsInterface.php | 19 ++++++ .../Permissions/DonationFormPermissions.php | 16 +++++ .../Permissions/DonationFormsPermissions.php | 26 -------- .../Permissions/DonationPermissions.php | 17 +++++ .../Permissions/DonorPermissions.php | 17 +++++ .../Permissions/Facades/UserPermissions.php | 8 ++- .../Facades/UserPermissionsFacade.php | 24 ++++++- src/Framework/Permissions/UserPermission.php | 66 +++++++++++++++++++ .../Facades/TestUserPermissions.php | 4 +- 9 files changed, 164 insertions(+), 33 deletions(-) create mode 100644 src/Framework/Permissions/Contracts/UserPermissionsInterface.php create mode 100644 src/Framework/Permissions/DonationFormPermissions.php delete mode 100644 src/Framework/Permissions/DonationFormsPermissions.php create mode 100644 src/Framework/Permissions/DonationPermissions.php create mode 100644 src/Framework/Permissions/DonorPermissions.php create mode 100644 src/Framework/Permissions/UserPermission.php diff --git a/src/Framework/Permissions/Contracts/UserPermissionsInterface.php b/src/Framework/Permissions/Contracts/UserPermissionsInterface.php new file mode 100644 index 0000000000..d4449f6db6 --- /dev/null +++ b/src/Framework/Permissions/Contracts/UserPermissionsInterface.php @@ -0,0 +1,19 @@ +getCapability('delete'); + break; + case 'read': + case 'view': + case 'create': + case 'update': + case 'edit': + $capability = $this->getCapability('edit'); + break; + } + + return current_user_can($capability); + } + + /** + * @unreleased + */ + protected function getCapability( string $cap): string + { + $caps = $this->getCapabilities($this::getType()); + + return $caps[$cap]; + } + + /** + * @unreleased + */ + protected function getCapabilities(string $type): array + { + return [ + // Post type. + "edit" => "edit_{$type}s", + "edit_others" => "edit_others_{$type}s", + "publish" => "publish_{$type}s", + "read_private" => "read_private_{$type}s", + "delete" => "delete_{$type}s", + "delete_private" => "delete_private_{$type}s", + "delete_published" => "delete_published_{$type}s", + "delete_others" => "delete_others_{$type}s", + "edit_private" => "edit_private_{$type}s", + "edit_published" => "edit_published_{$type}s", + + // Terms / taxonomies. + "manage_terms" => "manage_{$type}_terms", + "edit_terms" => "edit_{$type}_terms", + "delete_terms" => "delete_{$type}_terms", + "assign_terms" => "assign_{$type}_terms", + + // Custom capabilities. + "view_stats" => "view_{$type}_stats", + "import" => "import_{$type}s" + ]; + } +} diff --git a/tests/Unit/Framework/Permissions/Facades/TestUserPermissions.php b/tests/Unit/Framework/Permissions/Facades/TestUserPermissions.php index 7c35def0f0..0e4ab19938 100644 --- a/tests/Unit/Framework/Permissions/Facades/TestUserPermissions.php +++ b/tests/Unit/Framework/Permissions/Facades/TestUserPermissions.php @@ -2,7 +2,7 @@ namespace Give\Tests\Unit\Framework\Permissions\Facades; -use Give\Framework\Permissions\DonationFormsPermissions; +use Give\Framework\Permissions\DonationFormPermissions; use Give\Framework\Permissions\Facades\UserPermissions; use Give\Tests\TestCase; use Give\Tests\TestTraits\RefreshDatabase; @@ -20,7 +20,7 @@ final class TestUserPermissions extends TestCase public function testDonationForms(): void { $this->assertInstanceOf( - DonationFormsPermissions::class, + DonationFormPermissions::class, UserPermissions::donationForms() ); } From 10556e166f1a805e4a5f27b6a971c648a88b14ed Mon Sep 17 00:00:00 2001 From: Jon Waldstein Date: Fri, 13 Dec 2024 14:40:10 -0500 Subject: [PATCH 4/4] tests: update to use classes --- src/Framework/Permissions/UserPermission.php | 3 +- .../TestDonationFormsPermissions.php | 130 ++++++++++-------- 2 files changed, 76 insertions(+), 57 deletions(-) diff --git a/src/Framework/Permissions/UserPermission.php b/src/Framework/Permissions/UserPermission.php index fc367afdac..0053ca4bad 100644 --- a/src/Framework/Permissions/UserPermission.php +++ b/src/Framework/Permissions/UserPermission.php @@ -1,4 +1,5 @@ getCapabilities($this::getType()); diff --git a/tests/Unit/Framework/Permissions/TestDonationFormsPermissions.php b/tests/Unit/Framework/Permissions/TestDonationFormsPermissions.php index 0b788d54f7..2c44aab500 100644 --- a/tests/Unit/Framework/Permissions/TestDonationFormsPermissions.php +++ b/tests/Unit/Framework/Permissions/TestDonationFormsPermissions.php @@ -2,7 +2,7 @@ namespace Give\Tests\Unit\Framework\Permissions; -use Give\Framework\Permissions\Facades\UserPermissions; +use Give\Framework\Permissions\DonationFormPermissions; use Give\Tests\TestCase; use Give\Tests\TestTraits\RefreshDatabase; @@ -15,79 +15,97 @@ final class TestDonationFormsPermissions extends TestCase /** * @unreleased - * @dataProvider canProvider + * @dataProvider canTrueProvider */ - public function testCan($role, $capability, $shouldPass): void + public function testCanShouldBeTrue(string $role, string $capability): void { $user = self::factory()->user->create_and_get(); - $user->add_role($role); + $user->set_role($role); wp_set_current_user($user->ID); - if ($shouldPass) { - $this->assertTrue( - UserPermissions::donationForms()->can($capability) - ); - } else { - $this->assertFalse( - UserPermissions::donationForms()->can($capability) - ); - } + $this->assertTrue( + (new DonationFormPermissions())->can($capability) + ); } + /** + * @unreleased + * @dataProvider canFalseProvider + */ + public function testCanShouldBeFalse(string $role, string $capability): void + { + $user = self::factory()->user->create_and_get(); + $user->set_role($role); + + wp_set_current_user($user->ID); + + $this->assertFalse( + (new DonationFormPermissions())->can($capability) + ); + } - /** + + /** * @unreleased * * @return array> */ - public function canProvider(): array + public function canTrueProvider(): array { return [ // true - ['give_worker', 'create', true], - ['give_worker', 'read', true], - ['give_worker', 'update', true], - ['give_worker', 'edit', true], - - ['give_manager', 'create', true], - ['give_manager', 'read', true], - ['give_manager', 'update', true], - ['give_manager', 'edit', true], - ['give_manager', 'delete', true], - - ['give_accountant', 'create', true], - ['give_accountant', 'read', true], - ['give_accountant', 'update', true], - ['give_accountant', 'edit', true], - ['give_accountant', 'read_private_give_forms', true], - - ['administrator', 'create', true], - ['administrator', 'read', true], - ['administrator', 'update', true], - ['administrator', 'edit', true], - ['administrator', 'delete', true], + ['give_worker', 'create'], + ['give_worker', 'read'], + ['give_worker', 'update'], + ['give_worker', 'edit'], + + ['give_manager', 'create'], + ['give_manager', 'read'], + ['give_manager', 'update'], + ['give_manager', 'edit'], + ['give_manager', 'delete'], + ['give_accountant', 'create'], + ['give_accountant', 'read'], + ['give_accountant', 'update'], + ['give_accountant', 'edit'], + ['give_accountant', 'read_private_give_forms'], + + ['administrator', 'create'], + ['administrator', 'read'], + ['administrator', 'update'], + ['administrator', 'edit'], + ['administrator', 'delete'], + ]; + } + + /** + * @unreleased + */ + public function canFalseProvider(): array + { + return [ // false - ['give_accountant', 'delete', false], - - ['give_donor', 'create', false], - ['give_donor', 'read', false], - ['give_donor', 'update', false], - ['give_donor', 'edit', false], - ['give_donor', 'delete', false], - - ['give_subscriber', 'create', false], - ['give_subscriber', 'read', false], - ['give_subscriber', 'update', false], - ['give_subscriber', 'edit', false], - ['give_subscriber', 'delete', false], - - ['subscriber', 'create', false], - ['subscriber', 'read', false], - ['subscriber', 'update', false], - ['subscriber', 'edit', false], - ['subscriber', 'delete', false], + ['give_accountant', 'delete'], + + ['give_donor', 'create'], + ['give_donor', 'read'], + ['give_donor', 'update'], + ['give_donor', 'edit'], + ['give_donor', 'delete'], + + ['give_subscriber', 'create'], + ['give_subscriber', 'read'], + ['give_subscriber', 'update'], + ['give_subscriber', 'edit'], + ['give_subscriber', 'delete'], + + ['subscriber', 'create'], + ['subscriber', 'read'], + ['subscriber', 'update'], + ['subscriber', 'edit'], + ['subscriber', 'delete'], ]; } }