├── .babelrc ├── .editorconfig ├── .eslintignore ├── .eslintrc ├── .gitignore ├── .lintstagedrc ├── .markdownlintrc ├── .npmignore ├── LICENSE ├── README.md ├── composer.json ├── package-lock.json ├── package.json ├── phpcs.xml ├── preview-addrole.png ├── preview-attachuser.png ├── preview-demo.gif ├── preview-roles.png ├── rollup.config.js ├── src-js └── index.js └── src-php ├── Access.php ├── Configs └── novatoolpermissions.php ├── Database ├── factories │ └── .gitignore ├── migrations │ ├── .gitignore │ └── 2019_10_09_143453_create_accesses_table.php └── seeds │ └── .gitignore ├── Nova └── AccessControl.php ├── NovaToolPermissions.php ├── Policies ├── RolePolicy.php └── UserPolicy.php ├── Providers ├── AccessControlServiceProvider.php ├── AuthServiceProvider.php └── PackageServiceProvider.php ├── Resources ├── assets │ └── js │ │ └── .gitignore ├── lang │ └── en.json └── views │ └── .gitignore ├── Role.php └── Traits ├── AccessControlGate.php └── HasAccessControl.php /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "es2015-rollup" 4 | ], 5 | "plugins": [ 6 | "transform-object-rest-spread" 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | indent_style = space 6 | indent_size = 4 7 | end_of_line = lf 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Silvanite/novatoolpermissions/2072d036a7848eedc636697675f5630b35ddcdf6/.eslintignore -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "rules": { 3 | "semi": [ 4 | "error", 5 | "never" 6 | ], 7 | "indent": [ 8 | "error", 9 | 4 10 | ], 11 | "no-console": 1, 12 | "radix": 0, 13 | "vue/html-indent": ["error", 4] 14 | }, 15 | "parserOptions": { 16 | "parser": "babel-eslint", 17 | "ecmaVersion": 6, 18 | "sourceType": "module", 19 | "impliedStrict": true 20 | }, 21 | "env": { 22 | "es6": true, 23 | "browser": true, 24 | "node": true 25 | }, 26 | "extends": [ 27 | "plugin:vue/recommended", 28 | "airbnb-base" 29 | ], 30 | "plugins": [ 31 | "vue" 32 | ] 33 | } 34 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /vendor/ 2 | /node_modules/ 3 | /dist-js/ 4 | .vs 5 | .idea 6 | composer.lock 7 | -------------------------------------------------------------------------------- /.lintstagedrc: -------------------------------------------------------------------------------- 1 | { 2 | "*.php": [ 3 | "./vendor/bin/phpcs" 4 | ], 5 | "*.js": [ 6 | "eslint" 7 | ], 8 | "*.vue": [ 9 | "eslint" 10 | ], 11 | "*.md": [ 12 | "markdownlint" 13 | ], 14 | "*.json": [ 15 | "jsonlint" 16 | ], 17 | ".*rc": [ 18 | "jsonlint" 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /.markdownlintrc: -------------------------------------------------------------------------------- 1 | { 2 | "default": true, 3 | "line-length": false 4 | } 5 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | !dist 2 | !readme.md 3 | !license 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 thesold 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Laravel Nova Permissions (Roles and Permission based Access Control (ACL)) 2 | 3 | Add Access Control by means of User based Roles and Permissions to your Nova installation. Includes default User and Role Policies which can be managed through your Nova Admin Panel. 4 | 5 | ![Tool Demo](https://raw.githubusercontent.com/Silvanite/novatoolpermissions/master/preview-demo.gif) 6 | 7 | This tool uses the [Silvanite\Brandenburg](https://github.com/Silvanite/brandenburg) package under the hood to manage user roles. Brandenburg is used because it has clear separation of concerns 8 | 9 | > *Roles* are defined in the *Database* 10 | 11 | and 12 | 13 | > *Permissions* are defined in the *Codebase* 14 | 15 | As a result, you won't see any *Permissions* resource. The *Roles* resource will get the permissions from the Gates defined in your code. 16 | 17 | ## Package maintenance 18 | 19 | Unfortunately I am no longer actively working in the Laravel ecosystem and as such am unable to maintian this package. If anyone would like to take over the maintenance of the package please get in touch (open an issue or contact me on [Twitter](https://twitter.com/m2de_io)). 20 | 21 | ## Installation 22 | 23 | Install the tool through composer 24 | 25 | ```sh 26 | composer require silvanite/novatoolpermissions 27 | ``` 28 | 29 | Run the migrations to add the database tables required by Brandenburg. 30 | 31 | ```sh 32 | php artisan migrate 33 | ``` 34 | 35 | Add the `HasRoles` trait to your User model as per the Brandenburg installation instructions. 36 | 37 | ```php 38 | // app/User.php 39 | 40 | use Silvanite\Brandenburg\Traits\HasRoles; 41 | 42 | class User extends Authenticatable 43 | { 44 | use HasRoles; 45 | ... 46 | } 47 | ``` 48 | 49 | Load it into your Nova Tools to display the Roles within your Resources 50 | 51 | ```php 52 | // app/Providers/NovaServiceProvider.php 53 | 54 | use Silvanite\NovaToolPermissions\NovaToolPermissions; 55 | 56 | public function tools() 57 | { 58 | return [ 59 | new NovaToolPermissions(), 60 | ]; 61 | } 62 | ``` 63 | 64 | You can assign Users to Roles from the Role resource, however if you want to assign Roles from your User resource you will need to add an additional relationship ... 65 | 66 | ```php 67 | // app/Nova/User.php 68 | 69 | use Silvanite\NovaToolPermissions\Role; 70 | 71 | public function fields(Request $request) 72 | { 73 | return [ 74 | ... 75 | BelongsToMany::make('Roles', 'roles', Role::class), 76 | ]; 77 | } 78 | ``` 79 | 80 | If you are not using the defaul `App\Nova\User` Resource you can customise this by publishing the `novatoolpermissions config and setting your User resource model. 81 | 82 | ```sh 83 | php artisan vendor:publish --provider="Silvanite\NovaToolPermissions\Providers\PackageServiceProvider" 84 | ``` 85 | 86 | Remove the default `viewNova` Gate to use the Gate included by this package. You will need to keep the gate() method in place, just empty it. 87 | Note: Nova will always allow access in development environments. 88 | 89 | ```php 90 | // app/Providers/NovaServiceProvider.php 91 | 92 | protected function gate() 93 | { 94 | // 95 | } 96 | ``` 97 | 98 | ## Usage 99 | 100 | Once installed, go ahead and create your first Role. E.g. `Administrator` and assign all permissions to your new Role. 101 | 102 | ![Create/Edit Roles](https://raw.githubusercontent.com/Silvanite/novatoolpermissions/master/preview-addrole.png) 103 | 104 | Finally assign the Administrator Role to your user account. 105 | 106 | ![Attach Role to User](https://raw.githubusercontent.com/Silvanite/novatoolpermissions/master/preview-attachuser.png) 107 | 108 | ![Roles index with User count](https://raw.githubusercontent.com/Silvanite/novatoolpermissions/master/preview-roles.png) 109 | 110 | **Note:** By default, the package allows anyone access to a permission if no single user has access to it. This is to prevent you from locking yourself out of features. As such, it is important to define your primary admin role which has access to all permissions, meaning nobody else has access unless you specifically grant it. 111 | 112 | ## Default Permissions 113 | 114 | This package comes with a set of default permissions to provide full access control to the package's functionality. Permissions come with default english translations to provide a better user experience. You are free to replace these with translations in your applications json translations. 115 | 116 | ```json 117 | { 118 | "viewNova": "Access Nova", 119 | "viewRoles": "View Roles", 120 | "manageRoles": "Manage Roles", 121 | "assignRoles": "Assign Roles", 122 | "viewUsers": "View Users", 123 | "manageUsers": "Manage Users" 124 | } 125 | ``` 126 | 127 | ## Custom permissions 128 | 129 | To create your own permissions, simply define them in your service provider and create a *Policy* for your resource/model. Let's work with a common *Blog* example and assume that you have a **Blog** Model and Resource in your application. 130 | 131 | Create a *Policy* for your Nova Resource 132 | 133 | Create a new policy for your blog 134 | 135 | ```sh 136 | php artisan make:policy BlogPolicy 137 | ``` 138 | 139 | Let's assign the Policy and define our Gates. 140 | 141 | ```php 142 | // app/Providers/AuthServiceProvider.php 143 | 144 | use Silvanite\Brandenburg\Traits\ValidatesPermissions; 145 | 146 | class AuthServiceProvider extends ServiceProvider 147 | { 148 | use ValidatesPermissions; 149 | 150 | protected $policies = [ 151 | \App\Blog::class => \App\Policies\BlogPolicy::class, 152 | ]; 153 | 154 | public function boot() 155 | { 156 | collect([ 157 | 'viewBlog', 158 | 'manageBlog', 159 | ])->each(function ($permission) { 160 | Gate::define($permission, function ($user) use ($permission) { 161 | if ($this->nobodyHasAccess($permission)) { 162 | return true; 163 | } 164 | 165 | return $user->hasRoleWithPermission($permission); 166 | }); 167 | }); 168 | 169 | $this->registerPolicies(); 170 | } 171 | } 172 | ``` 173 | 174 | Finally, specify the access control in your Policy as per the Nova documentation. 175 | 176 | ```php 177 | // app/Policies/BlogPolicy.php 178 | 179 | use Illuminate\Support\Facades\Gate; 180 | 181 | public function viewAny($user) 182 | { 183 | return Gate::any(['viewBlog', 'manageBlog'], $user); 184 | } 185 | 186 | public function view($user, $post) 187 | { 188 | return Gate::any(['viewBlog', 'manageBlog'], $user, $post); 189 | } 190 | 191 | public function create($user) 192 | { 193 | return $user->can('manageBlog'); 194 | } 195 | 196 | public function update($user, $post) 197 | { 198 | return $user->can('manageBlog', $post); 199 | } 200 | 201 | public function delete($user, $post) 202 | { 203 | return $user->can('manageBlog', $post); 204 | } 205 | 206 | public function restore($user, $post) 207 | { 208 | return $user->can('manageBlog', $post); 209 | } 210 | 211 | public function forceDelete($user, $post) 212 | { 213 | return $user->can('manageBlog', $post); 214 | } 215 | ``` 216 | 217 | And add your labels to your translations to keep everything tidy. 218 | 219 | ```json 220 | { 221 | "viewBlog": "View Blog", 222 | "manageBlog": "Manage Blog" 223 | } 224 | ``` 225 | 226 | This example is a super-simple implementation. You can define your Gates as in any standard Laravel Application and can simply add the additional checks to validate them against your assigned Roles and Permissions. 227 | 228 | ## Access Control 229 | 230 | Sometimes you might want to prevent some users from accessing content, but not others. To achieve this, use the included `HasAccessControl.php` trait on your model. 231 | 232 | To check if a user has the correct permissions to view your content, either load the `AccessControlServiceProvider` to register the `accessControl` gate globally. Or include the `AccessControlGate` trait on your models policy. 233 | 234 | On your Nova resource, add the AccessControl field. This will display all roles with the `canBeGivenAccess` permission. To protect content from being accessed, at least one Role has to be given access to the model, otherwise the resource will be available to everyone. 235 | 236 | ```php 237 | public function fields(Request $request) 238 | { 239 | return [ 240 | // ... 241 | AccessControl::make(), 242 | // ... 243 | ] 244 | } 245 | ``` 246 | 247 | ## Support 248 | 249 | If you require any support please contact me on [Twitter](https://twitter.com/m2de_io) or open an issue on this repository. 250 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "silvanite/novatoolpermissions", 3 | "description": "Laravel Nova Permissions (Roles and Permission based Access Control (ACL))", 4 | "keywords": [ 5 | "laravel", 6 | "nova", 7 | "tool", 8 | "acl", 9 | "roles", 10 | "permissions", 11 | "access control", 12 | "gates", 13 | "policies", 14 | "authentication", 15 | "authorization" 16 | ], 17 | "license": "MIT", 18 | "authors": [ 19 | { 20 | "name": "Marco Mark", 21 | "email": "m2de@outlook.com" 22 | } 23 | ], 24 | "require": { 25 | "php": ">=7.1.3", 26 | "laravel/framework": ">=5.6.0", 27 | "silvanite/brandenburg": "^1.0", 28 | "silvanite/novafieldcheckboxes": "^1.0", 29 | "benjaminhirsch/nova-slug-field": "^1.2.3" 30 | }, 31 | "require-dev": { 32 | "squizlabs/php_codesniffer": ">=3.1" 33 | }, 34 | "autoload": { 35 | "psr-4": { 36 | "Silvanite\\NovaToolPermissions\\": "src-php/" 37 | } 38 | }, 39 | "extra":{ 40 | "laravel": { 41 | "providers": [ 42 | "Silvanite\\NovaToolPermissions\\Providers\\AuthServiceProvider", 43 | "Silvanite\\NovaToolPermissions\\Providers\\PackageServiceProvider" 44 | ] 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@silvanite/novatoolpermissions", 3 | "version": "1.1.3", 4 | "description": "Laravel Nova Permissions (Roles and Permission based Access Control (ACL))", 5 | "main": "dist-js/index.js", 6 | "scripts": { 7 | "build": "rollup -c", 8 | "watch": "rollup -mwc", 9 | "precommit": "lint-staged", 10 | "prepublish": "npm run build", 11 | "test": "echo \"Error: no test specified\" && exit 1" 12 | }, 13 | "repository": { 14 | "type": "git", 15 | "url": "git+https://github.com/silvanite/novatoolpermissions.git" 16 | }, 17 | "keywords": [ 18 | "boilerplate" 19 | ], 20 | "author": "Marco Mark ", 21 | "license": "MIT", 22 | "bugs": { 23 | "url": "https://github.com/silvanite/novatoolpermissions/issues" 24 | }, 25 | "homepage": "https://github.com/silvanite/novatoolpermissions#readme", 26 | "devDependencies": { 27 | "babel-core": "^6.26.3", 28 | "babel-eslint": "^8.2.6", 29 | "babel-plugin-transform-object-rest-spread": "^6.26.0", 30 | "babel-preset-es2015-rollup": "^3.0.0", 31 | "eslint": "^5.1.0", 32 | "eslint-config-airbnb-base": "^13.0.0", 33 | "eslint-plugin-import": "^2.13.0", 34 | "eslint-plugin-vue": "^4.7.0", 35 | "husky": "^0.14.3", 36 | "jsonlint": "^1.6.3", 37 | "lint-staged": "^7.2.0", 38 | "markdownlint-cli": "^0.11.0", 39 | "rollup": "^0.63.2", 40 | "rollup-plugin-babel": "^3.0.7", 41 | "rollup-plugin-vue": "^4.3.1", 42 | "vue-template-compiler": "^2.5.16" 43 | }, 44 | "dependencies": {} 45 | } 46 | -------------------------------------------------------------------------------- /phpcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | The PHP Coding Standards 12 | 13 | 20 | */*.php 21 | 22 | 27 | */autoload.php 28 | */docs/* 29 | */vendor/* 30 | */node_modules/* 31 | */database/* 32 | 33 | 40 | 41 | 42 | 43 | 44 | 48 | 49 | 50 | 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /preview-addrole.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Silvanite/novatoolpermissions/2072d036a7848eedc636697675f5630b35ddcdf6/preview-addrole.png -------------------------------------------------------------------------------- /preview-attachuser.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Silvanite/novatoolpermissions/2072d036a7848eedc636697675f5630b35ddcdf6/preview-attachuser.png -------------------------------------------------------------------------------- /preview-demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Silvanite/novatoolpermissions/2072d036a7848eedc636697675f5630b35ddcdf6/preview-demo.gif -------------------------------------------------------------------------------- /preview-roles.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Silvanite/novatoolpermissions/2072d036a7848eedc636697675f5630b35ddcdf6/preview-roles.png -------------------------------------------------------------------------------- /rollup.config.js: -------------------------------------------------------------------------------- 1 | import RollupPluginVue from 'rollup-plugin-vue' 2 | import RollupPluginBabel from 'rollup-plugin-babel' 3 | 4 | export default { 5 | input: 'src-js/index.js', 6 | output: { 7 | file: 'dist-js/index.js', 8 | format: 'cjs', 9 | }, 10 | external: [ 11 | 'vue', 12 | ], 13 | plugins: [ 14 | RollupPluginVue(), 15 | RollupPluginBabel(), 16 | ], 17 | } 18 | -------------------------------------------------------------------------------- /src-js/index.js: -------------------------------------------------------------------------------- 1 | export default {} 2 | -------------------------------------------------------------------------------- /src-php/Access.php: -------------------------------------------------------------------------------- 1 | 'array', 11 | ]; 12 | 13 | protected $fillable = [ 14 | 'roles', 15 | ]; 16 | 17 | public function accessible() 18 | { 19 | return $this->morphTo(); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src-php/Configs/novatoolpermissions.php: -------------------------------------------------------------------------------- 1 | 'App\Nova\User', 9 | 10 | /** 11 | * The group associated with the resource 12 | */ 13 | 'roleResourceGroup' => 'Other', 14 | ]; 15 | -------------------------------------------------------------------------------- /src-php/Database/factories/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Silvanite/novatoolpermissions/2072d036a7848eedc636697675f5630b35ddcdf6/src-php/Database/factories/.gitignore -------------------------------------------------------------------------------- /src-php/Database/migrations/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Silvanite/novatoolpermissions/2072d036a7848eedc636697675f5630b35ddcdf6/src-php/Database/migrations/.gitignore -------------------------------------------------------------------------------- /src-php/Database/migrations/2019_10_09_143453_create_accesses_table.php: -------------------------------------------------------------------------------- 1 | bigIncrements('id'); 18 | $table->json('roles'); 19 | $table->nullableMorphs('accessible'); 20 | $table->timestamps(); 21 | }); 22 | } 23 | 24 | /** 25 | * Reverse the migrations. 26 | * 27 | * @return void 28 | */ 29 | public function down() 30 | { 31 | Schema::dropIfExists('accesses'); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src-php/Database/seeds/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Silvanite/novatoolpermissions/2072d036a7848eedc636697675f5630b35ddcdf6/src-php/Database/seeds/.gitignore -------------------------------------------------------------------------------- /src-php/Nova/AccessControl.php: -------------------------------------------------------------------------------- 1 | filter(function ($value) { 19 | return $value->hasPermission('canBeGivenAccess'); 20 | })); 21 | 22 | if (!$options->count()) { 23 | return []; 24 | } 25 | 26 | return [ 27 | Checkboxes::make(__('Roles To Allow Access'), 'access_roles')->options( 28 | $options->mapWithKeys(function ($role) { 29 | return [ 30 | $role->id => __($role->name), 31 | ]; 32 | }) 33 | ->sort() 34 | ->toArray()) 35 | ->withoutTypeCasting(), 36 | ]; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src-php/NovaToolPermissions.php: -------------------------------------------------------------------------------- 1 | can('manageRoles'); 35 | } 36 | 37 | public function update($user) 38 | { 39 | return $user->can('manageRoles'); 40 | } 41 | 42 | public function delete($user) 43 | { 44 | return $user->can('manageRoles'); 45 | } 46 | 47 | public function restore($user) 48 | { 49 | return $user->can('manageRoles'); 50 | } 51 | 52 | public function forceDelete($user) 53 | { 54 | return $user->can('manageRoles'); 55 | } 56 | 57 | public function attachAnyUser($user, $model) 58 | { 59 | return Gate::any(['assignRoles', 'manageRoles'], $user); 60 | } 61 | 62 | public function detachAnyUser($user, $model) 63 | { 64 | return $user->can('manageRoles'); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src-php/Policies/UserPolicy.php: -------------------------------------------------------------------------------- 1 | can('manageUsers'); 35 | } 36 | 37 | public function update($user) 38 | { 39 | return $user->can('manageUsers'); 40 | } 41 | 42 | public function delete($user) 43 | { 44 | return $user->can('manageUsers'); 45 | } 46 | 47 | public function restore($user) 48 | { 49 | return $user->can('manageUsers'); 50 | } 51 | 52 | public function forceDelete($user) 53 | { 54 | return $user->can('manageUsers'); 55 | } 56 | 57 | public function attachAnyRole($user, $model) 58 | { 59 | return Gate::any(['assignRoles', 'manageRoles'], $user); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src-php/Providers/AccessControlServiceProvider.php: -------------------------------------------------------------------------------- 1 | accessContent($user, $model); 22 | }); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src-php/Providers/AuthServiceProvider.php: -------------------------------------------------------------------------------- 1 | RolePolicy::class, 23 | ]; 24 | 25 | /** 26 | * Register any authentication / authorization services. 27 | * 28 | * @return void 29 | */ 30 | public function boot() 31 | { 32 | $this->policies[config('brandenburg.userModel')] = UserPolicy::class; 33 | 34 | $this->registerPolicies(); 35 | $this->defineGates(); 36 | } 37 | 38 | private function defineGates() 39 | { 40 | collect([ 41 | 'assignRoles', 42 | 'manageRoles', 43 | 'manageUsers', 44 | 'viewRoles', 45 | 'viewUsers', 46 | 'viewNova', 47 | 'canBeGivenAccess', 48 | ])->each(function ($permission) { 49 | Gate::define($permission, function ($user) use ($permission) { 50 | if ($this->nobodyHasAccess($permission)) { 51 | return true; 52 | } 53 | 54 | return $user->hasRoleWithPermission($permission); 55 | }); 56 | }); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src-php/Providers/PackageServiceProvider.php: -------------------------------------------------------------------------------- 1 | publishConfigs(); 19 | $this->loadTranslations(); 20 | $this->loadMigrations(); 21 | } 22 | 23 | /** 24 | * Register the application services. 25 | * 26 | * @return void 27 | */ 28 | public function register() 29 | { 30 | $this->mergeConfigFrom( 31 | $this->getConfigsPath(), 32 | 'novatoolpermissions' 33 | ); 34 | } 35 | 36 | /** 37 | * Publish configuration file. 38 | * 39 | * @return void 40 | */ 41 | private function publishConfigs() 42 | { 43 | $this->publishes([ 44 | $this->getConfigsPath() => config_path('novatoolpermissions.php'), 45 | ], 'config'); 46 | } 47 | 48 | private function loadTranslations() 49 | { 50 | $this->loadJSONTranslationsFrom(__DIR__.'/../Resources/lang', 'novatoolpermissions'); 51 | } 52 | 53 | private function loadMigrations() 54 | { 55 | $this->loadMigrationsFrom(__DIR__ . '/../Database/migrations'); 56 | 57 | $this->publishes([ 58 | __DIR__ . '/../Database/migrations' => base_path('database/migrations') 59 | ], 'migrations'); 60 | } 61 | 62 | /** 63 | * Get local package configuration path. 64 | * 65 | * @return string 66 | */ 67 | private function getConfigsPath() 68 | { 69 | return __DIR__.'/../Configs/novatoolpermissions.php'; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src-php/Resources/assets/js/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Silvanite/novatoolpermissions/2072d036a7848eedc636697675f5630b35ddcdf6/src-php/Resources/assets/js/.gitignore -------------------------------------------------------------------------------- /src-php/Resources/lang/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "viewNova": "Access Nova", 3 | "viewRoles": "View Roles", 4 | "manageRoles": "Manage Roles", 5 | "assignRoles": "Assign Roles", 6 | "viewUsers": "View Users", 7 | "manageUsers": "Manage Users", 8 | "canBeGivenAccess": "Can be given access" 9 | } 10 | -------------------------------------------------------------------------------- /src-php/Resources/views/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Silvanite/novatoolpermissions/2072d036a7848eedc636697675f5630b35ddcdf6/src-php/Resources/views/.gitignore -------------------------------------------------------------------------------- /src-php/Role.php: -------------------------------------------------------------------------------- 1 | sortable(), 57 | 58 | TextWithSlug::make(__('Name'), 'name')->sortable()->slug('slug'), 59 | 60 | Slug::make(__('Slug'), 'slug') 61 | ->rules('required') 62 | ->creationRules('unique:roles') 63 | ->updateRules('unique:roles,slug,{{resourceId}}') 64 | ->sortable(), 65 | 66 | Checkboxes::make(__('Permissions'), 'permissions')->options(collect(Policy::all()) 67 | ->mapWithKeys(function ($policy) { 68 | return [ 69 | $policy => __($policy), 70 | ]; 71 | }) 72 | ->sort() 73 | ->toArray()), 74 | 75 | Text::make(__('Users'), function () { 76 | return count($this->users); 77 | })->onlyOnIndex(), 78 | 79 | BelongsToMany::make(__('Users'), 'users', config('novatoolpermissions.userResource', 'App\Nova\User')) 80 | ->searchable(), 81 | ]; 82 | } 83 | 84 | /** 85 | * Get the logical group associated with the resource. 86 | * 87 | * @return string 88 | */ 89 | public static function group() 90 | { 91 | return __(config('novatoolpermissions.roleResourceGroup', static::$group)); 92 | } 93 | 94 | /** 95 | * Get the displayable label of the resource. 96 | * 97 | * @return string 98 | */ 99 | public static function label() 100 | { 101 | return __('Roles'); 102 | } 103 | 104 | /** 105 | * Get the displayable singular label of the resource. 106 | * 107 | * @return string 108 | */ 109 | public static function singularLabel() 110 | { 111 | return __('Role'); 112 | } 113 | 114 | /** 115 | * Get the cards available for the request. 116 | * 117 | * @param \Illuminate\Http\Request $request 118 | * @return array 119 | */ 120 | public function cards(Request $request) 121 | { 122 | return []; 123 | } 124 | 125 | /** 126 | * Get the filters available for the resource. 127 | * 128 | * @param \Illuminate\Http\Request $request 129 | * @return array 130 | */ 131 | public function filters(Request $request) 132 | { 133 | return []; 134 | } 135 | 136 | /** 137 | * Get the lenses available for the resource. 138 | * 139 | * @param \Illuminate\Http\Request $request 140 | * @return array 141 | */ 142 | public function lenses(Request $request) 143 | { 144 | return []; 145 | } 146 | 147 | /** 148 | * Get the actions available for the resource. 149 | * 150 | * @param \Illuminate\Http\Request $request 151 | * @return array 152 | */ 153 | public function actions(Request $request) 154 | { 155 | return []; 156 | } 157 | } 158 | -------------------------------------------------------------------------------- /src-php/Traits/AccessControlGate.php: -------------------------------------------------------------------------------- 1 | access === null) { 10 | return true; 11 | } 12 | 13 | if (!count($model->access->roles)) { 14 | return true; 15 | } 16 | 17 | if ($user === null) { 18 | return false; 19 | } 20 | 21 | return $user->roles->pluck('id')->intersect($model->access->roles)->count(); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src-php/Traits/HasAccessControl.php: -------------------------------------------------------------------------------- 1 | with = array_merge($this->with, [ 14 | 'access', 15 | ]); 16 | } 17 | 18 | protected static function boot() 19 | { 20 | parent::boot(); 21 | static::created(function ($model) { 22 | $model->access() 23 | ->create(['roles' => Arr::wrap(Request::get('access_roles', []))]); 24 | }); 25 | static::deleting(function ($model) { 26 | if ($model->access) { 27 | $access = $model->access; 28 | $access->delete(); 29 | } 30 | }); 31 | } 32 | 33 | public function access() 34 | { 35 | return $this->morphOne(Access::class, 'accessible'); 36 | } 37 | 38 | public function getAccessRolesAttribute() 39 | { 40 | return $this->access->roles ?? []; 41 | } 42 | 43 | public function setAccessRolesAttribute($roles) 44 | { 45 | if ($access = $this->access) { 46 | $access->roles = $roles; 47 | return $access->save(); 48 | } 49 | 50 | if ($this->id) { 51 | return $this->access()->create(['roles' => $roles]); 52 | } 53 | } 54 | } 55 | --------------------------------------------------------------------------------