From 58da840a88c310ab8e73b9df57ed9f8fe45f4a27 Mon Sep 17 00:00:00 2001 From: Amir Date: Wed, 7 Dec 2022 17:40:03 +0400 Subject: [PATCH] Adding Spartie Roles & Permissions --- app/Actions/Menu/MenuOperation.php | 1 - app/Actions/Permissions/PermissionDelete.php | 34 ++++ .../Permissions/PermissionFormData.php | 21 +++ app/Actions/Permissions/PermissionGuards.php | 29 ++++ app/Actions/Permissions/PermissionModels.php | 33 ++++ .../Permissions/PermissionSanitizeData.php | 19 +++ app/Actions/Permissions/PermissionSave.php | 44 +++++ app/Actions/Permissions/PermissionSubmit.php | 26 +++ .../Permissions/PermissionValidation.php | 35 ++++ app/Actions/Roles/RoleDelete.php | 34 ++++ app/Actions/Roles/RoleFormData.php | 21 +++ app/Actions/Roles/RoleGuards.php | 35 ++++ app/Actions/Roles/RoleSanitizeData.php | 23 +++ app/Actions/Roles/RoleSave.php | 44 +++++ app/Actions/Roles/RoleSubmit.php | 26 +++ app/Actions/Roles/RoleValidation.php | 35 ++++ app/Http/Livewire/Admin/Permissions/Index.php | 63 +++++++ .../Permissions/PermissionsDatatable.php | 123 +++++++++++++ app/Http/Livewire/Admin/Roles/Index.php | 73 ++++++++ .../Livewire/Admin/Roles/RolesDatatable.php | 123 +++++++++++++ app/Models/Admin.php | 2 + app/Models/User.php | 2 + app/Traits/Data.php | 14 ++ app/Traits/General.php | 4 +- composer.json | 1 + composer.lock | 84 ++++++++- config/app.php | 2 +- config/permission.php | 161 ++++++++++++++++++ ..._12_07_090013_create_permission_tables.php | 142 +++++++++++++++ .../admin/permissions/index.blade.php | 44 +++++ .../livewire/admin/roles/index.blade.php | 40 +++++ routes/admin.php | 4 + 32 files changed, 1337 insertions(+), 5 deletions(-) create mode 100644 app/Actions/Permissions/PermissionDelete.php create mode 100644 app/Actions/Permissions/PermissionFormData.php create mode 100644 app/Actions/Permissions/PermissionGuards.php create mode 100644 app/Actions/Permissions/PermissionModels.php create mode 100644 app/Actions/Permissions/PermissionSanitizeData.php create mode 100644 app/Actions/Permissions/PermissionSave.php create mode 100644 app/Actions/Permissions/PermissionSubmit.php create mode 100644 app/Actions/Permissions/PermissionValidation.php create mode 100644 app/Actions/Roles/RoleDelete.php create mode 100644 app/Actions/Roles/RoleFormData.php create mode 100644 app/Actions/Roles/RoleGuards.php create mode 100644 app/Actions/Roles/RoleSanitizeData.php create mode 100644 app/Actions/Roles/RoleSave.php create mode 100644 app/Actions/Roles/RoleSubmit.php create mode 100644 app/Actions/Roles/RoleValidation.php create mode 100644 app/Http/Livewire/Admin/Permissions/Index.php create mode 100644 app/Http/Livewire/Admin/Permissions/PermissionsDatatable.php create mode 100644 app/Http/Livewire/Admin/Roles/Index.php create mode 100644 app/Http/Livewire/Admin/Roles/RolesDatatable.php create mode 100644 config/permission.php create mode 100644 database/migrations/2022_12_07_090013_create_permission_tables.php create mode 100644 resources/views/livewire/admin/permissions/index.blade.php create mode 100644 resources/views/livewire/admin/roles/index.blade.php diff --git a/app/Actions/Menu/MenuOperation.php b/app/Actions/Menu/MenuOperation.php index 2c3e496..d224328 100644 --- a/app/Actions/Menu/MenuOperation.php +++ b/app/Actions/Menu/MenuOperation.php @@ -30,7 +30,6 @@ public function save(Menu $menu) )->validate(); try { $success = DB::transaction(function () use ($menu) { - $menu->save(); return [true, $menu]; }); diff --git a/app/Actions/Permissions/PermissionDelete.php b/app/Actions/Permissions/PermissionDelete.php new file mode 100644 index 0000000..4ff31e3 --- /dev/null +++ b/app/Actions/Permissions/PermissionDelete.php @@ -0,0 +1,34 @@ +delete(); + return [true, $role]; + }); + } catch (\Exception $e) { + DB::rollback(); + return [false, $e->getMessage()]; + } + return $success; + } + + +} diff --git a/app/Actions/Permissions/PermissionFormData.php b/app/Actions/Permissions/PermissionFormData.php new file mode 100644 index 0000000..11faba1 --- /dev/null +++ b/app/Actions/Permissions/PermissionFormData.php @@ -0,0 +1,21 @@ +guard('admin')->check() && auth()->user()->hasRole('admin')) { + $guards = ['web'=>'User']; + if (count($guards) === 1) $permission['guard_name'] = array_key_first($guards); + + } elseif(auth()->guard('admin')->check() && auth()->user()->hasRole('super admin')) { + $guards = ['admin'=>'Admin']; + if (count($guards) === 1) $permission['guard_name'] = array_key_first($guards); + }else{ + $guards = ['web'=>'User']; + if (count($guards) === 1) $permission['guard_name'] = array_key_first($guards); + } + return $guards; + } + + +} diff --git a/app/Actions/Permissions/PermissionModels.php b/app/Actions/Permissions/PermissionModels.php new file mode 100644 index 0000000..21fb1c6 --- /dev/null +++ b/app/Actions/Permissions/PermissionModels.php @@ -0,0 +1,33 @@ +guard('admin')->check() ) { + $exclude = ['Admin', 'Membership', 'Team', 'TeamInvitation']; + $models = array_diff($models, $exclude); + if (count($models) === 1) $permission['model'] = array_key_first($models); + + } elseif (auth()->guard('admin')->check() && auth()->user()->hasRole('super admin')) { + if (count($models) === 1) $permission['model'] = array_key_first($models); + } else { + $exclude = ['Admin', 'Membership', 'Team', 'TeamInvitation']; + $models = array_diff($models, $exclude); + if (count($models) === 1) $permission['model'] = array_key_first($models); + } + return $models; + } + + +} diff --git a/app/Actions/Permissions/PermissionSanitizeData.php b/app/Actions/Permissions/PermissionSanitizeData.php new file mode 100644 index 0000000..67e2b18 --- /dev/null +++ b/app/Actions/Permissions/PermissionSanitizeData.php @@ -0,0 +1,19 @@ +name=ucfirst($data->name); + return $data; + } + +} diff --git a/app/Actions/Permissions/PermissionSave.php b/app/Actions/Permissions/PermissionSave.php new file mode 100644 index 0000000..696f565 --- /dev/null +++ b/app/Actions/Permissions/PermissionSave.php @@ -0,0 +1,44 @@ +set('role', $role)->fill($role->toArray()); + Validator::make( + $data->attributes, + PermissionValidation::make()->rules($this->role->id), + PermissionValidation::make()->messages(), + )->validate(); + try { + $success = DB::transaction(function () use ($role) { + $role->save(); + return [true, $role]; + }); + } catch (\Exception $e) { + DB::rollback(); + return [false, $e->getMessage()]; + } + return $success; + } + + + +} diff --git a/app/Actions/Permissions/PermissionSubmit.php b/app/Actions/Permissions/PermissionSubmit.php new file mode 100644 index 0000000..d669b66 --- /dev/null +++ b/app/Actions/Permissions/PermissionSubmit.php @@ -0,0 +1,26 @@ + PermissionSave::run($role), + 'delete' => PermissionDelete::run($role), + default => [], + }; + $thiss->dispatchBrowserEvent('FirstModel', ['show' => false]); + $thiss->emit('refreshSidebar'); + $thiss->afterSave($output, $thiss->formType, $role->name); + } +} diff --git a/app/Actions/Permissions/PermissionValidation.php b/app/Actions/Permissions/PermissionValidation.php new file mode 100644 index 0000000..3615ff1 --- /dev/null +++ b/app/Actions/Permissions/PermissionValidation.php @@ -0,0 +1,35 @@ + 'required|min:4|unique:roles,name,' . $id, + 'role.guard_name' => 'required', + ]; + } + + public function attributes($role): array + { + return [ + 'role.name' =>$role['name'], + ]; + } + + public function messages(){ + return [ + 'role.name.required' => 'Menu name is required.', + 'role.name.min' => 'Menu must be at-least 4 letters long.', + 'role.name.unique' => ':attribute menu already exists!.', + 'role.guard_name.required' => 'Guard is required.', + ]; + } +} diff --git a/app/Actions/Roles/RoleDelete.php b/app/Actions/Roles/RoleDelete.php new file mode 100644 index 0000000..5595b53 --- /dev/null +++ b/app/Actions/Roles/RoleDelete.php @@ -0,0 +1,34 @@ +delete(); + return [true, $role]; + }); + } catch (\Exception $e) { + DB::rollback(); + return [false, $e->getMessage()]; + } + return $success; + } + + +} diff --git a/app/Actions/Roles/RoleFormData.php b/app/Actions/Roles/RoleFormData.php new file mode 100644 index 0000000..d5851e4 --- /dev/null +++ b/app/Actions/Roles/RoleFormData.php @@ -0,0 +1,21 @@ +guard('admin')->check() && auth()->user()->hasRole('admin')) { + $guards = ['web'=>'User']; + if (count($guards) === 1) $role['guard_name'] = array_key_first($guards); + + } elseif(auth()->guard('admin')->check() && auth()->user()->hasRole('super admin')) { + $guards = ['admin'=>'Admin']; + if (count($guards) === 1) $role['guard_name'] = array_key_first($guards); + }else{ + $guards = ['web'=>'User']; + if (count($guards) === 1) $role['guard_name'] = array_key_first($guards); + } + return $guards; + } + + +} diff --git a/app/Actions/Roles/RoleSanitizeData.php b/app/Actions/Roles/RoleSanitizeData.php new file mode 100644 index 0000000..04a3517 --- /dev/null +++ b/app/Actions/Roles/RoleSanitizeData.php @@ -0,0 +1,23 @@ +name=ucfirst($data->name); + return $data; + } + +} diff --git a/app/Actions/Roles/RoleSave.php b/app/Actions/Roles/RoleSave.php new file mode 100644 index 0000000..6bc2e9f --- /dev/null +++ b/app/Actions/Roles/RoleSave.php @@ -0,0 +1,44 @@ +set('role', $role)->fill($role->toArray()); + Validator::make( + $data->attributes, + RoleValidation::make()->rules($this->role->id), + RoleValidation::make()->messages(), + )->validate(); + try { + $success = DB::transaction(function () use ($role) { + $role->save(); + return [true, $role]; + }); + } catch (\Exception $e) { + DB::rollback(); + return [false, $e->getMessage()]; + } + return $success; + } + + + +} diff --git a/app/Actions/Roles/RoleSubmit.php b/app/Actions/Roles/RoleSubmit.php new file mode 100644 index 0000000..97b001c --- /dev/null +++ b/app/Actions/Roles/RoleSubmit.php @@ -0,0 +1,26 @@ + RoleSave::run($role), + 'delete' => RoleDelete::run($role), + default => [], + }; + $thiss->dispatchBrowserEvent('FirstModel', ['show' => false]); + $thiss->emit('refreshSidebar'); + $thiss->afterSave($output, $thiss->formType, $role->name); + } +} diff --git a/app/Actions/Roles/RoleValidation.php b/app/Actions/Roles/RoleValidation.php new file mode 100644 index 0000000..16f49cb --- /dev/null +++ b/app/Actions/Roles/RoleValidation.php @@ -0,0 +1,35 @@ + 'required|min:4|unique:roles,name,' . $id, + 'role.guard_name' => 'required', + ]; + } + + public function attributes($role): array + { + return [ + 'role.name' =>$role['name'], + ]; + } + + public function messages(){ + return [ + 'role.name.required' => 'Menu name is required.', + 'role.name.min' => 'Menu must be at-least 4 letters long.', + 'role.name.unique' => ':attribute menu already exists!.', + 'role.guard_name.required' => 'Guard is required.', + ]; + } +} diff --git a/app/Http/Livewire/Admin/Permissions/Index.php b/app/Http/Livewire/Admin/Permissions/Index.php new file mode 100644 index 0000000..0c183f3 --- /dev/null +++ b/app/Http/Livewire/Admin/Permissions/Index.php @@ -0,0 +1,63 @@ +permission = new Permission(); + } + + /* INPUT RULES */ + public function rules(): array + { + return PermissionValidation::make()->rules(); + } + + /* SHOW MODEL FOR CREATE, UPDATE, DELETE */ + public function show($data) + { + $this->resetForm(); + + $this->permission = PermissionFormData::run(type: $data[0], row: $data[1]); + $this->models= PermissionModels::run($this->permission); + $this->guards= PermissionGuards::run($this->permission); + $this->showModal($data[0], ($data[0]==='create') ? 'Permission' :$this->permission->name); + } + + /* SUBMIT DATA FOR CREATE, UPDATE, DELETE */ + public function submit() + { + PermissionSubmit::run($this,$this->formType,$this->permission); + } + + + public function render() + { + $permissions=Permission::all(); + return view('livewire.admin.permissions.index',['permissions'=>$permissions]); + } +} diff --git a/app/Http/Livewire/Admin/Permissions/PermissionsDatatable.php b/app/Http/Livewire/Admin/Permissions/PermissionsDatatable.php new file mode 100644 index 0000000..fab7cd6 --- /dev/null +++ b/app/Http/Livewire/Admin/Permissions/PermissionsDatatable.php @@ -0,0 +1,123 @@ + null, + ]; + + + public function configure(): void + { + $this->setPrimaryKey('id') + ->setPerPageAccepted([10, 25, 50, 100]) + ->setPerPage(10) + ->setSortingStatus(true) + ->setSortingPillsStatus(false) + ->setPageName('Roles') + ->setPaginationVisibilityStatus(true) + ->setPaginationStatus(true) + ->setDefaultSort('id', 'desc') + ->setQueryStringStatus(false) + ->setThAttributes(function (Column $column) { + if ($column->isField('id')) { + return [ + 'class' => '!w-[5%]', + ]; + } elseif ($column->isField('name')) { + return [ + 'class' => '!w-[30%]', + ]; + } + elseif ($column->isField('guard_name')) { + return [ + 'class' => '!w-[30%]', + ]; + } elseif ($column->isField('created_at')) { + return [ + 'class' => '!w-[15%]', + ]; + } elseif ($column->isField('updated_at')) { + return [ + 'class' => '!w-[15%]', + ]; + } elseif ($column->getTitle() === 'Action') { + return [ + 'class' => '!w-[5%] text-center', + ]; + } + + return []; + }) + ->setThSortButtonAttributes(function (Column $column) { + if ($column->isField('created_at')) { + return [ + 'class' => 'mx-auto', + ]; + } elseif ($column->isField('updated_at')) { + return [ + 'class' => 'mx-auto', + ]; + } + + return []; + }) + ->setTdAttributes(function (Column $column, $row, $columnIndex, $rowIndex) { + if ($columnIndex === 3 || $columnIndex === 4) { + return [ + 'class' => 'text-center', + ]; + } + + return []; + }) + ->setUseHeaderAsFooterEnabled(); + } + + + public function columns(): array + { + return [ + Column::make("Id", "id") + ->searchable() + ->sortable(), + Column::make("Name", "name") + ->searchable() + ->sortable(), + Column::make("Guard Name", "guard_name") + ->searchable() + ->sortable(), + Column::make("Created at", "created_at") + ->format(fn($value, $row, Column $column) => $row->created_at->diffForHumans()) + ->sortable(), + Column::make("Updated at", "updated_at") + ->format(fn($value, $row, Column $column) => $row->created_at->diffForHumans()) + ->sortable(), + + Column::make('Action', 'ID') + ->format( + fn($value, $row, Column $column) => '
+ + + + + +
+ ' + ) + ->html(), + + ]; + } +} diff --git a/app/Http/Livewire/Admin/Roles/Index.php b/app/Http/Livewire/Admin/Roles/Index.php new file mode 100644 index 0000000..4b29576 --- /dev/null +++ b/app/Http/Livewire/Admin/Roles/Index.php @@ -0,0 +1,73 @@ +role = new Role(); + } + + /* INPUT RULES */ + public function rules(): array + { + return RoleValidation::make()->rules(); + } + + /* SHOW MODEL FOR CREATE, UPDATE, DELETE */ + public function show($data) + { + $this->resetForm(); + + $this->role = RoleFormData::run(type: $data[0], row: $data[1]); + $this->guards= RoleGuards::run($this->role); + $this->showModal($data[0], ($data[0]==='create') ? 'Role' :$this->role->name); + } + + /* SUBMIT DATA FOR CREATE, UPDATE, DELETE */ + public function submit() + { + RoleSubmit::run($this,$this->formType,$this->role); + } + + + public function render() + { + $roles=Role::all(); + return view('livewire.admin.roles.index',['roles'=>$roles]); + } +} diff --git a/app/Http/Livewire/Admin/Roles/RolesDatatable.php b/app/Http/Livewire/Admin/Roles/RolesDatatable.php new file mode 100644 index 0000000..a7d30ab --- /dev/null +++ b/app/Http/Livewire/Admin/Roles/RolesDatatable.php @@ -0,0 +1,123 @@ + null, + ]; + + + public function configure(): void + { + $this->setPrimaryKey('id') + ->setPerPageAccepted([10, 25, 50, 100]) + ->setPerPage(10) + ->setSortingStatus(true) + ->setSortingPillsStatus(false) + ->setPageName('Roles') + ->setPaginationVisibilityStatus(true) + ->setPaginationStatus(true) + ->setDefaultSort('id', 'desc') + ->setQueryStringStatus(false) + ->setThAttributes(function (Column $column) { + if ($column->isField('id')) { + return [ + 'class' => '!w-[5%]', + ]; + } elseif ($column->isField('name')) { + return [ + 'class' => '!w-[30%]', + ]; + } + elseif ($column->isField('guard_name')) { + return [ + 'class' => '!w-[30%]', + ]; + } elseif ($column->isField('created_at')) { + return [ + 'class' => '!w-[15%]', + ]; + } elseif ($column->isField('updated_at')) { + return [ + 'class' => '!w-[15%]', + ]; + } elseif ($column->getTitle() === 'Action') { + return [ + 'class' => '!w-[5%] text-center', + ]; + } + + return []; + }) + ->setThSortButtonAttributes(function (Column $column) { + if ($column->isField('created_at')) { + return [ + 'class' => 'mx-auto', + ]; + } elseif ($column->isField('updated_at')) { + return [ + 'class' => 'mx-auto', + ]; + } + + return []; + }) + ->setTdAttributes(function (Column $column, $row, $columnIndex, $rowIndex) { + if ($columnIndex === 3 || $columnIndex === 4) { + return [ + 'class' => 'text-center', + ]; + } + + return []; + }) + ->setUseHeaderAsFooterEnabled(); + } + + + public function columns(): array + { + return [ + Column::make("Id", "id") + ->searchable() + ->sortable(), + Column::make("Name", "name") + ->searchable() + ->sortable(), + Column::make("Guard Name", "guard_name") + ->searchable() + ->sortable(), + Column::make("Created at", "created_at") + ->format(fn($value, $row, Column $column) => $row->created_at->diffForHumans()) + ->sortable(), + Column::make("Updated at", "updated_at") + ->format(fn($value, $row, Column $column) => $row->created_at->diffForHumans()) + ->sortable(), + + Column::make('Action', 'ID') + ->format( + fn($value, $row, Column $column) => '
+ + + + + +
+ ' + ) + ->html(), + + ]; + } +} diff --git a/app/Models/Admin.php b/app/Models/Admin.php index 5756fea..207bbe3 100644 --- a/app/Models/Admin.php +++ b/app/Models/Admin.php @@ -11,6 +11,7 @@ use Laravel\Jetstream\HasProfilePhoto; use Laravel\Jetstream\HasTeams; use Laravel\Sanctum\HasApiTokens; +use Spatie\Permission\Traits\HasRoles; class Admin extends Authenticatable implements MustVerifyEmail { @@ -20,6 +21,7 @@ class Admin extends Authenticatable implements MustVerifyEmail use HasTeams; use Notifiable; use TwoFactorAuthenticatable; + use HasRoles; protected $guard='admin'; protected $table='admins'; diff --git a/app/Models/User.php b/app/Models/User.php index a5d9d62..991a48a 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -10,6 +10,7 @@ use Laravel\Jetstream\HasProfilePhoto; use Laravel\Jetstream\HasTeams; use Laravel\Sanctum\HasApiTokens; +use Spatie\Permission\Traits\HasRoles; class User extends Authenticatable implements MustVerifyEmail { @@ -19,6 +20,7 @@ class User extends Authenticatable implements MustVerifyEmail use HasTeams; use Notifiable; use TwoFactorAuthenticatable; + use HasRoles; /** * The attributes that are mass assignable. diff --git a/app/Traits/Data.php b/app/Traits/Data.php index 5dfb78b..8506a92 100644 --- a/app/Traits/Data.php +++ b/app/Traits/Data.php @@ -5,10 +5,24 @@ use App\Models\Guard; use App\Models\Menu; use Illuminate\Support\Facades\Auth; +use Illuminate\Support\Facades\File; use Illuminate\Support\Facades\Route; trait Data { + /* GET MODELS */ + public static function getAvailableModels(): array + { + + $models = []; + $modelsPath = app_path('Models'); + $modelFiles = File::allFiles($modelsPath); + foreach ($modelFiles as $modelFile) { + $models[] = $modelFile->getFilenameWithoutExtension(); + } + return $models; + } + /* GET URI GUARD */ public static function uri_guard($request) diff --git a/app/Traits/General.php b/app/Traits/General.php index f238e00..41d1d08 100644 --- a/app/Traits/General.php +++ b/app/Traits/General.php @@ -30,9 +30,9 @@ public function modelInfo($formType, $name, $submitName = '', $modalHeader = '') } } - public function showModal($type, $name = null) + public function showModal($type, $name) { - ($type === 'create') ? $this->modelInfo($type, 'Menu') : $this->modelInfo($type, $name); + $this->modelInfo($type, $name); $this->dispatchBrowserEvent('FirstModel', ['show' => true]); } diff --git a/composer.json b/composer.json index 6089daa..379f65e 100644 --- a/composer.json +++ b/composer.json @@ -14,6 +14,7 @@ "livewire/livewire": "^2.5", "lorisleiva/laravel-actions": "^2.4", "rappasoft/laravel-livewire-tables": "^2.8", + "spatie/laravel-permission": "^5.7", "staudenmeir/laravel-adjacency-list": "^1.0" }, "require-dev": { diff --git a/composer.lock b/composer.lock index bc92e5d..1f4cd24 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "e34f683ca5ca9dfba3aafd551567869c", + "content-hash": "280fbc80fd9f4099f3084b3c2af2f21e", "packages": [ { "name": "bacon/bacon-qr-code", @@ -3730,6 +3730,88 @@ ], "time": "2022-10-11T06:37:42+00:00" }, + { + "name": "spatie/laravel-permission", + "version": "5.7.0", + "source": { + "type": "git", + "url": "https://github.com/spatie/laravel-permission.git", + "reference": "3a9bc00e6d338a9c61f830af654aa5c326407632" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/spatie/laravel-permission/zipball/3a9bc00e6d338a9c61f830af654aa5c326407632", + "reference": "3a9bc00e6d338a9c61f830af654aa5c326407632", + "shasum": "" + }, + "require": { + "illuminate/auth": "^7.0|^8.0|^9.0", + "illuminate/container": "^7.0|^8.0|^9.0", + "illuminate/contracts": "^7.0|^8.0|^9.0", + "illuminate/database": "^7.0|^8.0|^9.0", + "php": "^7.3|^8.0|^8.1" + }, + "require-dev": { + "orchestra/testbench": "^5.0|^6.0|^7.0", + "phpunit/phpunit": "^9.4", + "predis/predis": "^1.1" + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "Spatie\\Permission\\PermissionServiceProvider" + ] + }, + "branch-alias": { + "dev-main": "5.x-dev", + "dev-master": "5.x-dev" + } + }, + "autoload": { + "files": [ + "src/helpers.php" + ], + "psr-4": { + "Spatie\\Permission\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Freek Van der Herten", + "email": "freek@spatie.be", + "homepage": "https://spatie.be", + "role": "Developer" + } + ], + "description": "Permission handling for Laravel 6.0 and up", + "homepage": "https://github.com/spatie/laravel-permission", + "keywords": [ + "acl", + "laravel", + "permission", + "permissions", + "rbac", + "roles", + "security", + "spatie" + ], + "support": { + "issues": "https://github.com/spatie/laravel-permission/issues", + "source": "https://github.com/spatie/laravel-permission/tree/5.7.0" + }, + "funding": [ + { + "url": "https://github.com/spatie", + "type": "github" + } + ], + "time": "2022-11-23T07:01:37+00:00" + }, { "name": "staudenmeir/laravel-adjacency-list", "version": "v1.11.4", diff --git a/config/app.php b/config/app.php index 9f7cfbd..c875df0 100644 --- a/config/app.php +++ b/config/app.php @@ -196,7 +196,7 @@ App\Providers\RouteServiceProvider::class, App\Providers\FortifyServiceProvider::class, App\Providers\JetstreamServiceProvider::class, - + Spatie\Permission\PermissionServiceProvider::class, ], /* diff --git a/config/permission.php b/config/permission.php new file mode 100644 index 0000000..5b6e184 --- /dev/null +++ b/config/permission.php @@ -0,0 +1,161 @@ + [ + + /* + * When using the "HasPermissions" trait from this package, we need to know which + * Eloquent model should be used to retrieve your permissions. Of course, it + * is often just the "Permission" model but you may use whatever you like. + * + * The model you want to use as a Permission model needs to implement the + * `Spatie\Permission\Contracts\Permission` contract. + */ + + 'permission' => Spatie\Permission\Models\Permission::class, + + /* + * When using the "HasRoles" trait from this package, we need to know which + * Eloquent model should be used to retrieve your roles. Of course, it + * is often just the "Role" model but you may use whatever you like. + * + * The model you want to use as a Role model needs to implement the + * `Spatie\Permission\Contracts\Role` contract. + */ + + 'role' => Spatie\Permission\Models\Role::class, + + ], + + 'table_names' => [ + + /* + * When using the "HasRoles" trait from this package, we need to know which + * table should be used to retrieve your roles. We have chosen a basic + * default value but you may easily change it to any table you like. + */ + + 'roles' => 'roles', + + /* + * When using the "HasPermissions" trait from this package, we need to know which + * table should be used to retrieve your permissions. We have chosen a basic + * default value but you may easily change it to any table you like. + */ + + 'permissions' => 'permissions', + + /* + * When using the "HasPermissions" trait from this package, we need to know which + * table should be used to retrieve your models permissions. We have chosen a + * basic default value but you may easily change it to any table you like. + */ + + 'model_has_permissions' => 'model_has_permissions', + + /* + * When using the "HasRoles" trait from this package, we need to know which + * table should be used to retrieve your models roles. We have chosen a + * basic default value but you may easily change it to any table you like. + */ + + 'model_has_roles' => 'model_has_roles', + + /* + * When using the "HasRoles" trait from this package, we need to know which + * table should be used to retrieve your roles permissions. We have chosen a + * basic default value but you may easily change it to any table you like. + */ + + 'role_has_permissions' => 'role_has_permissions', + ], + + 'column_names' => [ + /* + * Change this if you want to name the related pivots other than defaults + */ + 'role_pivot_key' => null, //default 'role_id', + 'permission_pivot_key' => null, //default 'permission_id', + + /* + * Change this if you want to name the related model primary key other than + * `model_id`. + * + * For example, this would be nice if your primary keys are all UUIDs. In + * that case, name this `model_uuid`. + */ + + 'model_morph_key' => 'model_id', + + /* + * Change this if you want to use the teams feature and your related model's + * foreign key is other than `team_id`. + */ + + 'team_foreign_key' => 'team_id', + ], + + /* + * When set to true, the method for checking permissions will be registered on the gate. + * Set this to false, if you want to implement custom logic for checking permissions. + */ + + 'register_permission_check_method' => true, + + /* + * When set to true the package implements teams using the 'team_foreign_key'. If you want + * the migrations to register the 'team_foreign_key', you must set this to true + * before doing the migration. If you already did the migration then you must make a new + * migration to also add 'team_foreign_key' to 'roles', 'model_has_roles', and + * 'model_has_permissions'(view the latest version of package's migration file) + */ + + 'teams' => false, + + /* + * When set to true, the required permission names are added to the exception + * message. This could be considered an information leak in some contexts, so + * the default setting is false here for optimum safety. + */ + + 'display_permission_in_exception' => false, + + /* + * When set to true, the required role names are added to the exception + * message. This could be considered an information leak in some contexts, so + * the default setting is false here for optimum safety. + */ + + 'display_role_in_exception' => false, + + /* + * By default wildcard permission lookups are disabled. + */ + + 'enable_wildcard_permission' => false, + + 'cache' => [ + + /* + * By default all permissions are cached for 24 hours to speed up performance. + * When permissions or roles are updated the cache is flushed automatically. + */ + + 'expiration_time' => \DateInterval::createFromDateString('24 hours'), + + /* + * The cache key used to store all permissions. + */ + + 'key' => 'spatie.permission.cache', + + /* + * You may optionally indicate a specific cache driver to use for permission and + * role caching using any of the `store` drivers listed in the cache.php config + * file. Using 'default' here means to use the `default` set in cache.php. + */ + + 'store' => 'default', + ], +]; diff --git a/database/migrations/2022_12_07_090013_create_permission_tables.php b/database/migrations/2022_12_07_090013_create_permission_tables.php new file mode 100644 index 0000000..1761a6f --- /dev/null +++ b/database/migrations/2022_12_07_090013_create_permission_tables.php @@ -0,0 +1,142 @@ +bigIncrements('id'); // permission id + $table->string('name'); // For MySQL 8.0 use string('name', 125); + $table->string('guard_name'); // For MySQL 8.0 use string('guard_name', 125); + $table->string('model'); // For MySQL 8.0 use string('model', 125); + $table->timestamps(); + + $table->unique(['name', 'guard_name']); + }); + + Schema::create($tableNames['roles'], function (Blueprint $table) use ($teams, $columnNames) { + $table->bigIncrements('id'); // role id + if ($teams || config('permission.testing')) { // permission.testing is a fix for sqlite testing + $table->unsignedBigInteger($columnNames['team_foreign_key'])->nullable(); + $table->index($columnNames['team_foreign_key'], 'roles_team_foreign_key_index'); + } + $table->string('name'); // For MySQL 8.0 use string('name', 125); + $table->string('guard_name'); // For MySQL 8.0 use string('guard_name', 125); + $table->timestamps(); + if ($teams || config('permission.testing')) { + $table->unique([$columnNames['team_foreign_key'], 'name', 'guard_name']); + } else { + $table->unique(['name', 'guard_name']); + } + }); + + Schema::create($tableNames['model_has_permissions'], function (Blueprint $table) use ($tableNames, $columnNames, $teams) { + $table->unsignedBigInteger(PermissionRegistrar::$pivotPermission); + + $table->string('model_type'); + $table->unsignedBigInteger($columnNames['model_morph_key']); + $table->index([$columnNames['model_morph_key'], 'model_type'], 'model_has_permissions_model_id_model_type_index'); + + $table->foreign(PermissionRegistrar::$pivotPermission) + ->references('id') // permission id + ->on($tableNames['permissions']) + ->onDelete('cascade'); + if ($teams) { + $table->unsignedBigInteger($columnNames['team_foreign_key']); + $table->index($columnNames['team_foreign_key'], 'model_has_permissions_team_foreign_key_index'); + + $table->primary([$columnNames['team_foreign_key'], PermissionRegistrar::$pivotPermission, $columnNames['model_morph_key'], 'model_type'], + 'model_has_permissions_permission_model_type_primary'); + } else { + $table->primary([PermissionRegistrar::$pivotPermission, $columnNames['model_morph_key'], 'model_type'], + 'model_has_permissions_permission_model_type_primary'); + } + + }); + + Schema::create($tableNames['model_has_roles'], function (Blueprint $table) use ($tableNames, $columnNames, $teams) { + $table->unsignedBigInteger(PermissionRegistrar::$pivotRole); + + $table->string('model_type'); + $table->unsignedBigInteger($columnNames['model_morph_key']); + $table->index([$columnNames['model_morph_key'], 'model_type'], 'model_has_roles_model_id_model_type_index'); + + $table->foreign(PermissionRegistrar::$pivotRole) + ->references('id') // role id + ->on($tableNames['roles']) + ->onDelete('cascade'); + if ($teams) { + $table->unsignedBigInteger($columnNames['team_foreign_key']); + $table->index($columnNames['team_foreign_key'], 'model_has_roles_team_foreign_key_index'); + + $table->primary([$columnNames['team_foreign_key'], PermissionRegistrar::$pivotRole, $columnNames['model_morph_key'], 'model_type'], + 'model_has_roles_role_model_type_primary'); + } else { + $table->primary([PermissionRegistrar::$pivotRole, $columnNames['model_morph_key'], 'model_type'], + 'model_has_roles_role_model_type_primary'); + } + }); + + Schema::create($tableNames['role_has_permissions'], function (Blueprint $table) use ($tableNames) { + $table->unsignedBigInteger(PermissionRegistrar::$pivotPermission); + $table->unsignedBigInteger(PermissionRegistrar::$pivotRole); + + $table->foreign(PermissionRegistrar::$pivotPermission) + ->references('id') // permission id + ->on($tableNames['permissions']) + ->onDelete('cascade'); + + $table->foreign(PermissionRegistrar::$pivotRole) + ->references('id') // role id + ->on($tableNames['roles']) + ->onDelete('cascade'); + + $table->primary([PermissionRegistrar::$pivotPermission, PermissionRegistrar::$pivotRole], 'role_has_permissions_permission_id_role_id_primary'); + }); + + app('cache') + ->store(config('permission.cache.store') != 'default' ? config('permission.cache.store') : null) + ->forget(config('permission.cache.key')); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + $tableNames = config('permission.table_names'); + + if (empty($tableNames)) { + throw new \Exception('Error: config/permission.php not found and defaults could not be merged. Please publish the package configuration before proceeding, or drop the tables manually.'); + } + + Schema::drop($tableNames['role_has_permissions']); + Schema::drop($tableNames['model_has_roles']); + Schema::drop($tableNames['model_has_permissions']); + Schema::drop($tableNames['roles']); + Schema::drop($tableNames['permissions']); + } +} diff --git a/resources/views/livewire/admin/permissions/index.blade.php b/resources/views/livewire/admin/permissions/index.blade.php new file mode 100644 index 0000000..52a7897 --- /dev/null +++ b/resources/views/livewire/admin/permissions/index.blade.php @@ -0,0 +1,44 @@ + + + + + + + + + {{__('Create')}} + + + + + @if($formType === 'create' || $formType === 'update') +
+ + + + + + +
+ @endif + + @if($formType === 'delete' ) +
+

WARNING! +
Are you sure you want to delete this permission?

+
+ @endif + +
+
+
+ +
+
+
diff --git a/resources/views/livewire/admin/roles/index.blade.php b/resources/views/livewire/admin/roles/index.blade.php new file mode 100644 index 0000000..5bd58de --- /dev/null +++ b/resources/views/livewire/admin/roles/index.blade.php @@ -0,0 +1,40 @@ + + + + + + + + + {{__('Create')}} + + + + + @if($formType === 'create' || $formType === 'update') +
+ + + + +
+ @endif + + @if($formType === 'delete' ) +
+

WARNING! +
Are you sure you want to delete this role?

+
+ @endif + +
+
+
+ +
+
+
diff --git a/routes/admin.php b/routes/admin.php index 921107e..d534464 100644 --- a/routes/admin.php +++ b/routes/admin.php @@ -62,6 +62,10 @@ Route::get('/menu', \App\Http\Livewire\Admin\Menu\MenuParent::class)->name('menu'); Route::get('/menu-levels', \App\Http\Livewire\Admin\Menu\Level::class)->name('menu-level'); + + Route::get('/roles', \App\Http\Livewire\Admin\Roles\Index::class)->name('roles'); + Route::get('/permissions', \App\Http\Livewire\Admin\Permissions\Index::class)->name('permissions'); + Route::put('/profile-information', [\App\Actions\Fortify\Controllers\ProfileInformationController::class, 'update'])->name('user-profile-information.update'); Route::post('/admin/two-factor-authentication', [TwoFactorAuthenticationController::class, 'store'])->name('two-factor.enable'); Route::post('/admin/confirmed-two-factor-authentication', [ConfirmedTwoFactorAuthenticationController::class, 'store'])->name('two-factor.confirm');