Skip to content

Commit

Permalink
Merge pull request #441 from bezhanSalleh/feature/tenancy
Browse files Browse the repository at this point in the history
Feature/tenancy
  • Loading branch information
bezhanSalleh authored Nov 9, 2024
2 parents 98ab121 + 5df43f5 commit 50e26aa
Show file tree
Hide file tree
Showing 36 changed files with 1,739 additions and 556 deletions.
2 changes: 1 addition & 1 deletion .phpunit.cache/test-results
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"version":"pest_2.33.1","defects":[],"times":{"P\\Tests\\DatabaseTest::__pest_evaluable_it_can_check_if_package_testing_is_configured":0,"P\\Tests\\DatabaseTest::__pest_evaluable_it_can_check_if_the_permission_name_can_be_configured_using_the_closure":0.005}}
{"version":"pest_2.36.0","defects":[],"times":{"P\\Tests\\DatabaseTest::__pest_evaluable_it_can_check_if_the_permission_name_can_be_configured_using_the_closure":0.005,"P\\Tests\\DatabaseTest::__pest_evaluable_it_can_check_if_package_testing_is_configured":0}}
222 changes: 103 additions & 119 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,81 +23,99 @@

# Shield

The easiest and most intuitive way to add access management to your Filament Admin:
- :fire: **Resources**
- :fire: **Pages**
- :fire: **Widgets**
- :fire: **Custom Permissions**
The easiest and most intuitive way to add access management to your Filament Panels.

## Features

- 🛡️ **Complete Authorization Management**
- Resource Permissions
- Page Permissions
- Widget Permissions
- Custom Permissions
- 🔄 **Multi-tenancy Support**
- 🚀 **Easy Setup & Configuration**
- 🎨 **Best UI**
- 📦 **Policy Generation**
- 🌐 **Translations Support**

## Requirements

- PHP 8.1 | 8.2 | 8.3
- Laravel v10.x | v11.x
- Filament v3.2+
- Spatie Permission v6.0+

> [!NOTE]
> For **Filament 2.x** use **[2.x](https://github.com/bezhanSalleh/filament-shield/tree/2.x)** branch
> [!IMPORTANT]
> Prior to `v3.1.0` Shield supported [spatie/laravel-permission](https://packagist.org/packages/spatie/laravel-permission):`^5.0` and now it supports version `^6.0`. Which has some breaking changes around migrations. If you are upgrading from a version prior to `v3.1.0` please make sure to remove the old migration file and republish the new one.
## Installation

1. Install the package via composer:

### 1. Install Package
```bash
composer require bezhansalleh/filament-shield
```

2. Add the `Spatie\Permission\Traits\HasRoles` trait to your User model(s):

### 2. Configure Auth Provider
Add the `HasRoles` trait to your User model:
```php
use Illuminate\Foundation\Auth\User as Authenticatable;
use Spatie\Permission\Traits\HasRoles;

class User extends Authenticatable
{
use HasRoles;

// ...
}
```
3. Publish the `config` file then setup your configuration:

### 3. Setup Shield
3.1 **Without Tenancy:**
```bash
php artisan vendor:publish --tag=filament-shield-config
php artisan shield:setup
```
4. Register the plugin for the Filament Panels you want
```php
public function panel(Panel $panel): Panel
{
return $panel
->plugins([
\BezhanSalleh\FilamentShield\FilamentShieldPlugin::make()
]);
}

3.2 **With Tenancy:**
```bash
php artisan shield:setup --tenant=App\\Models\\Team
# Replace Team with your tenant model
```
5. Now run the following command to install shield:

This command will:
- Publish core package config
- Publish core package migrations
- Run initial migrations
- Publish shield config
- Configure tenancy if specified

### 4. Install for Panel
The install command will register the plugin for your panel automatically. Choose the appropriate installation method:

4.1 **Without Tenancy:**
```bash
php artisan shield:install
php artisan shield:install admin
# Replace 'admin' with your panel ID
```
Follow the prompts and enjoy!

## Filament Panels
If you want to enable `Shield` for more than one panel then you need to register the plugin for each panel as mentioned above.
4.2 **With Tenancy:**
```bash
php artisan shield:install admin --tenant --generate-relationships
# Replace 'admin' with your panel ID
```

### Panel Access
Shield comes with the `HasPanelShield` trait which provides an easy way to integrate Shield's conventions with the Filament's panel access system.
This command will:
- Register Shield plugin for your panel
- If `--tenant` flag is provided:
- Activates tenancy features
- Makes the panel tenantable
- Adds `SyncShieldTenant` middleware to the panel
- Configures tenant model from the config
- If `--generate-relationships` flag is provided:
- Generates required relationships between resource models and the tenant model
- Adds necessary relationship methods in both the resource and tenant models

The `HasPanelShield` trait provides an implementation for the `canAccessPanel` method, determining access based on whether the user possesses the `super_admin` role or the `panel_user` role. It also assigns the `panel_user` role to the user upon creation and removes it upon deletion. Ofcourse the role names can be changed from the plugin's configuration file.
## Usage

```php
use BezhanSalleh\FilamentShield\Traits\HasPanelShield;
use Filament\Models\Contracts\FilamentUser;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Spatie\Permission\Traits\HasRoles;
#### Configuration
See [config/filament-shield.php](config/filament-shield.php) for full configuration options.

class User extends Authenticatable implements FilamentUser
{
use HasRoles;
use HasPanelShield;
// ...
}
```
#### Resources
Generally there are two scenarios that shield handles permissions for your `Filament` resources.

Expand Down Expand Up @@ -330,47 +348,7 @@ class IncomeWidget extends LineChartWidget

### Policies

#### Role Policy
##### Using Laravel 10
To ensure `RoleResource` access via `RolePolicy` you would need to add the following to your `AuthServiceProvider`:

```php
//AuthServiceProvider.php
...
protected $policies = [
'Spatie\Permission\Models\Role' => 'App\Policies\RolePolicy',
];
...
```
##### Using Laravel 11

To ensure `RoleResource` access via `RolePolicy` you would need to add the following to your `AppServiceProvider`:

```php
//AppServiceProvider.php
use Illuminate\Support\Facades\Gate;
...
public function boot(): void
{
...
Gate::policy(\Spatie\Permission\Models\Role::class, \App\Policies\RolePolicy::class);
}
...
```

**whatever your version of Laravel, you can skip it if you have enabled it from the `config`:**

```php
// config/filament-shield.php
...

'register_role_policy' => [
'enabled' => true,
],
...
```

#### Policy Path
#### Path
If your policies are not in the default `Policies` directory in the `app_path()` you can change the directory name in the config file:

```php
Expand Down Expand Up @@ -399,6 +377,7 @@ class AuthServiceProvider extends ServiceProvider

];
```

##### Using Laravel 11
```php
//AppServiceProvider.php
Expand Down Expand Up @@ -467,6 +446,43 @@ public function panel(Panel $panel): Panel
```
<img width="1161" alt="Screenshot 2023-09-24 at 10 34 31 PM" src="https://github.com/bezhanSalleh/filament-shield/assets/10007504/be42bab2-72d1-4db0-8de4-8b8fba2d4e68">

## Available Commands

### Core Commands
```bash
# Setup Shield
shield:setup [--fresh] [--minimal] [--tenant=]

# Install Shield for a panel
shield:install {panel} [--tenant] [--generate-relationships]

# Generate permissions/policies
shield:generate [options]

# Create super admin
shield:super-admin [--user=] [--panel=] [--tenant=]

# Create seeder
shield:seeder [options]

# Publish Role Resource
shield:publish {panel}
```

### Generate Command Options
```bash
--all Generate for all entities
--option=[OPTION] Override generator option
--resource=[RESOURCE] Specific resources
--page=[PAGE] Specific pages
--widget=[WIDGET] Specific widgets
--exclude Exclude entities
--ignore-config-exclude Ignore config excludes
--panel[=PANEL] Panel ID to get the components(resources, pages, widgets)
```
> [!NOTE]
> For setting up super-admin user when using tenancy/team feature consult the core package **[spatie/laravel-permission](https://spatie.be/docs/laravel-permission/v6/basic-usage/teams-permissions)**
#### Translations

Publish the translations using:
Expand All @@ -475,38 +491,6 @@ Publish the translations using:
php artisan vendor:publish --tag="filament-shield-translations"
```

## Available Filament Shield Commands

#### `shield:doctor`
- Show useful info about Filament Shield.

#### `shield:install`
Setup Core Package requirements and Install Shield. Accepts the following flags:
- `--fresh` re-run the migrations
- `--only` Only setups shield without generating permissions and creating super-admin

#### `shield:generate`
Generate Permissions and/or Policies for Filament entities. Accepts the following flags:
- `--all` Generate permissions/policies for all entities
- `--option[=OPTION]` Override the config generator option(`policies_and_permissions`,`policies`,`permissions`)
- `--resource[=RESOURCE]` One or many resources separated by comma (,)
- `--page[=PAGE]` One or many pages separated by comma (,)
- `--widget[=WIDGET]` One or many widgets separated by comma (,)
- `--exclude` Exclude the given entities during generation
- `--ignore-config-exclude` Ignore config `exclude` option during generation
- `--ignore-existing-policies` Do not overwrite the existing policies.

#### `shield:super-admin`
Create a user with super_admin role.
- Accepts an `--user=` argument that will use the provided ID to find the user to be made super admin.

### `shield:publish`
- Publish the Shield `RoleResource` and customize it however you like

### `shield:seeder`
- Deploy easily by setting up your roles and permissions or add your custom seeds


## Testing

```bash
Expand Down
11 changes: 11 additions & 0 deletions TODO
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@

Todo:
☐ Accept auth model the same way as the tenant model and set it up
☐ Remove extra info from commands
✔ Given all shield commands are destructive, add the ability to disable them in production @done(24-11-07 23:59)
☐ Make shield middleware publishable and handle if it is published
☐ Make use of the custom team foreign key
☐ checking for tables also check if team was enabled or should be enabled if already installed and the tenant flag provided
✔ Remove/replace doctor command with about command @done(24-11-08 00:00)
☐ Move tenant relationship generation to the generate command
☐ should handle if already installed for a panel but central flag. for now central is always false
5 changes: 3 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,16 +29,17 @@
"spatie/laravel-permission": "^6.0"
},
"require-dev": {
"larastan/larastan": "^2.0",
"laravel/pint": "^1.0",
"nunomaduro/collision": "^7.0|^8.0",
"larastan/larastan": "^2.0",
"orchestra/testbench": "^8.0|^9.0",
"pestphp/pest": "^2.34",
"pestphp/pest-plugin-laravel": "^2.3",
"phpstan/extension-installer": "^1.3",
"phpstan/phpstan-deprecation-rules": "^1.1",
"phpstan/phpstan-phpunit": "^1.3",
"phpunit/phpunit": "^10.1"
"phpunit/phpunit": "^10.1",
"spatie/laravel-ray": "^1.37"
},
"autoload": {
"psr-4": {
Expand Down
2 changes: 2 additions & 0 deletions config/filament-shield.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
'cluster' => null,
],

'tenant_model' => null,

'auth_provider_model' => [
'fqcn' => 'App\\Models\\User',
],
Expand Down
3 changes: 2 additions & 1 deletion phpstan.neon.dist
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,5 @@ parameters:

tmpDir: build/phpstan
checkOctaneCompatibility: true
checkModelProperties: true
checkModelProperties: true
treatPhpDocTypesAsCertain: false
5 changes: 4 additions & 1 deletion resources/lang/en/filament-shield.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

'column.name' => 'Name',
'column.guard_name' => 'Guard Name',
'column.team' => 'Team',
'column.roles' => 'Roles',
'column.permissions' => 'Permissions',
'column.updated_at' => 'Updated At',
Expand All @@ -22,8 +23,10 @@
'field.name' => 'Name',
'field.guard_name' => 'Guard Name',
'field.permissions' => 'Permissions',
'field.team' => 'Team',
'field.team.placeholder' => 'Select a team ...',
'field.select_all.name' => 'Select All',
'field.select_all.message' => 'Enable all Permissions currently <span class="text-primary font-medium">Enabled</span> for this role',
'field.select_all.message' => 'Enables/Disables all Permissions for this role',

/*
|--------------------------------------------------------------------------
Expand Down
Loading

0 comments on commit 50e26aa

Please sign in to comment.