diff --git a/README.md b/README.md index 5208858..2b593f0 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,6 @@ - ✅ Statamic v4 - ✅ Statamic v5 -- ✅ Statamic API - ✅ Multisite - ❌ Eloquent Driver @@ -13,19 +12,21 @@ ## Features -Prevent users from viewing other authors' entries unless they have been explicitly authorized to do so. +Restrict entries from being listed in the control panel by the rules you define. -### Conditions to view an entry +## Upgrade Guide -A user is able to view an entry when one of the following is true: +### From 0.3.x to 0.4.x - What's Changed? -- the user is a super admin -- the field `author` of the entry matches the current user -- the user's role has permission to `View other authors' entries` for the given collection +In versions up to 0.3.x there were hard coded permissions to `view other authors' entries` on a per-collection basis. +Those permissions are now removed and will no longer have any effect by default. To achieve the similar behavior as +before, you could take a look at +the ["Using Permissions on a Per-Collection Basis"](#using-permissions-on-a-per-collection-basis) section and fine tune +it to your needs. -### Important Note - -If your entry blueprint does not have an `author` field, the addon will have **no effect**. +Also, make sure to check the `hasAnotherAuthor` function in Statamic's +default [EntryPolicy on GitHub](https://github.com/statamic/cms/blob/46b4d39cc99f3be8a12cbb7958e3caf14b01a1ba/src/Policies/EntryPolicy.php#L108) +to see how to properly check for another author in an entry. ## How to Install @@ -38,21 +39,121 @@ composer require doefom/restrict ## How to Use -### Default Behavior after Installation +By default, the addon will not restrict anything. To restrict entries, set your restriction logic in +your `AppServiceProvider.php` by providing a closure function that returns a boolean value. The function should +return `true` if the user is allowed to view the given entry, and `false` otherwise. + +### Basic Usage + +```php +use Statamic\Contracts\Auth\User; +use Statamic\Contracts\Entries\Entry; + +class AppServiceProvider extends ServiceProvider +{ + public function register(): void + { + // ... + } + + public function boot(): void + { + Restrict::setRestriction(function (User $user, Entry $entry) { + // Can view own entries only + return $entry->authors()->contains($user->id()); + }); + } +} +``` + +### Using Permissions -The addon behaves very similar to Statamic's default permission -to `Edit other authors' entries` ([https://statamic.dev/users#author-permissions](https://statamic.dev/users#author-permissions)). -It adds a new permission to each collection's permissions called `View other authors' entries`. After installing the -addon, by default a user can only view entries they've created themselves. +You can check for anything in your restriction closure. For example, you could define custom permissions in your +Statamic application and check for those: -### Giving a User Permission to View Other Authors' Entries +```php +use Statamic\Facades\Permission; + +public function boot() +{ + // Add one general permission to Statamic + Permission::extend(function () { + Permission::register('view entries without restriction') + ->label('View entries without restriction'); + }); + + Restrict::setRestriction(function (User $user, Entry $entry) { + if ($user->hasPermission('view entries without restriction')) { + // Can view all entries + return true; + } + + // Can view own entries only + return $entry->authors()->contains($user->id()); + }); +} +``` -To give a user permission to view other authors' entries, you need to assign the permission to the user's role. You can -do this in the control panel by navigating to "Permissions", selecting the role you want to edit, and checking the -permission `View other authors' entries` for the collection you want to give permission for. +### Using Permissions on a Per-Collection Basis + +Or to manage restrictions on a per-collection basis: + +```php +use Statamic\Facades\Collection; + +public function boot() +{ + // Add one permission per collection + Permission::extend(function () { + Permission::get('view {collection} entries')->addChild( + Permission::make("view {collection} entries without restriction") + ->label("View entries without restriction") + ); + }); + + Restrict::setRestriction(function (User $user, Entry $entry) { + if ($user->hasPermission("view {$entry->collectionHandle()} entries without restriction")) { + // Can view all entries in the entry's collection + return true; + } + + // Can view own entries only + return $entry->authors()->contains($user->id()); + }); +} +``` + +### Advanced Usage + +Let's say each user belongs to a company and each company has many jobs. You could make sure a user can only see jobs +of the company they belong to: + +```php +use Statamic\Facades\Permission; + +public function boot() +{ + Restrict::setRestriction(function (User $user, Entry $entry) { + if ($entry->collectionHandle() !== 'jobs') { + // Allow viewing all entries of collections other than 'jobs' + return true; + } + + // Can view jobs of own company only + return $user->get('company') === $entry->get('company'); + }); +} +``` ## Caveats +### Works with Control Panel Routes Only + +The addon only restricts entries from being listed in the control panel and therefore does not restrict entries from +being displayed on the front-end of your site or fetched from your API, that's entirely up to you. To know if the user +is currently on a control panel route we check if the route has the `statamic.cp.authenticated` middleware applied. If +so, restrict will do its thing. If not, there won't be any restrictions applied. + ### Eloquent Driver This addon does **not** work with the Eloquent driver. It only works with the default flat file driver. However, it is diff --git a/src/Facades/Restrict.php b/src/Facades/Restrict.php index a2236a1..8fef252 100644 --- a/src/Facades/Restrict.php +++ b/src/Facades/Restrict.php @@ -9,10 +9,8 @@ */ class Restrict extends Facade { - protected static function getFacadeAccessor(): string { return 'restrict'; } - } diff --git a/src/Restrict.php b/src/Restrict.php index 7ad9d13..8a63577 100644 --- a/src/Restrict.php +++ b/src/Restrict.php @@ -2,13 +2,14 @@ namespace Doefom\Restrict; +use Closure; use Illuminate\Support\Facades\Route; use Statamic\Contracts\Auth\User; use Statamic\Contracts\Entries\Entry; class Restrict { - protected $callback; + protected Closure $callback; public function __construct() { @@ -19,10 +20,8 @@ public function __construct() /** * Set the restriction callback used to determine if the current user is authorized to view the entry. - * The callback expects a User and Entry instance and should return a boolean. - * - * @param callable $callback - * @return void + * The callback expects a User and Entry instance and should return true when the user is authorized + * to view the entry and false otherwise. */ public function setRestriction(callable $callback): void { @@ -31,10 +30,6 @@ public function setRestriction(callable $callback): void /** * Check if the current user is authorized to view the entry. - * - * @param User $user - * @param Entry $entry - * @return bool */ public function isAuthorized(User $user, Entry $entry): bool { @@ -44,9 +39,6 @@ public function isAuthorized(User $user, Entry $entry): bool /** * Determine if the current user and route require restriction checks. Restriction * checks are only required for authenticated CP routes and non-super users. - * - * @param User|null $user - * @return bool */ public function isRestricted(?User $user): bool { @@ -56,8 +48,6 @@ public function isRestricted(?User $user): bool /** * Check if the current route is a CP route that requires authentication by checking * if the 'statamic.cp.authenticated' middleware is applied to the route. - * - * @return bool */ protected function isAuthenticatedCpRoute(): bool { diff --git a/src/ServiceProvider.php b/src/ServiceProvider.php index 27cac70..c96ca77 100644 --- a/src/ServiceProvider.php +++ b/src/ServiceProvider.php @@ -9,7 +9,7 @@ class ServiceProvider extends AddonServiceProvider { public function register() { - $this->app->singleton('restrict', fn() => new Restrict); + $this->app->singleton('restrict', fn () => new Restrict); } public function bootAddon(): void diff --git a/src/Stache/Query/EntryQueryBuilder.php b/src/Stache/Query/EntryQueryBuilder.php index b3f41c8..22f09cc 100644 --- a/src/Stache/Query/EntryQueryBuilder.php +++ b/src/Stache/Query/EntryQueryBuilder.php @@ -8,7 +8,6 @@ class EntryQueryBuilder extends StatamicEntryQueryBuilder { - protected function getFilteredKeys() { $resKeys = parent::getFilteredKeys(); @@ -26,5 +25,4 @@ protected function getFilteredKeys() return Restrict::isAuthorized($user, $entry); }); } - }